概述
JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性;这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制。
要想解剖一个类,必须先要获取到该类的字节码文件对象。而解剖使用的就是Class类中的方法.所以先要获取到每一个字节码文件对应的Class类型的对象.
以上的总结就是什么是反射
反射就是把java类中的各种成分映射成一个个的Java对象
例如:一个类有:成员变量、方法、构造方法、包等等信息,利用反射技术可以对一个类进行解剖,把个个组成部分映射成一个个对象。
(其实:一个类中这些成员方法、构造方法、在加入类中都有一个类来描述)
如图是类的正常加载过程:反射的原理在与class对象。
熟悉一下加载的时候:Class对象的由来是将class文件读入内存,并为之创建一个Class对象。
目录
Reflection 反射
反射的定义
反射机制:
在程序运行时可以加载,探知,使用编译期间完全未知的类
程序在运行状态中,可以动态加载一个只有名称的类,对于任意一个加载的类,都能够知道这个类的所有属性和方法;同时任意一个对象也都能够调用它的任意一个方法和属性。同时一个类只有一个反射对象,比如多次调用Class.forName得到的也是相同对象
形象的说:
使用以下反射代码来获取一个类的对象
Class c = Class.forName("com.company.project.ClassName");
当加载完成后,堆内存中就产生了一个ClassName类型的对象,通过这个对象我们就可以看到类的结构,这个就时反射
反射的作用
动态加载类、动态获取类的信息(属性、方法、构造器)
动态构造对象
动态调用类和对象的任意方法、构造器
动态调用和处理属性
获取泛型信息
处理注解
Class类
public final class Class
Class类的类表示正在运行的Java应用程序中的类和接口。 枚举是一种类,一个注解是一种接口。 每个数组也属于一个反映为类对象的类,该对象由具有相同元素类型和维数的所有数组共享。 原始Java类型( boolean , byte , char , short , int , long , float和double ),和关键字void也表示为类对象。Class没有公共构造函数。 相反, Class对象由Java虚拟机自动构建,因为加载了类,并且通过调用类加载器中的defineClass方法。
简单的说就是:
Class类十分特殊,用来表示java中类型 (class/interface/enum/annotation/primitive type/void)本身。
Class类的对象包含了某个被加载类的结构。一个被加载的类对应一个 Class对象
JVM来创建Class对象,当加载器(class loader)的defineClass()被 JVM调用,JVM 便自动产生一个Class 对象
Class类是Reflection反射的基础,任何要动态加载,运行的类,都必须先获得对于的Class对象
Class类的对象获取
.getClass()方法
Class.forName()方法–使用最多
.class语法
package JavaCore.Reflection;
/*******************************************************************************
* @Description: 获取Class对象
* @Aha-eureka: Class类是Reflection反射的基础,任何要动态加载,运行的类,都必须先获得对于的Class对象
******************************************************************************/
public class Reflection_GetClass {
public static void main( String[] args ) throws ClassNotFoundException {
String path = "JavaCore.Reflection.User_Demo";
//获取Class的几种方式
{
//一个类只有一个Class对象
Class clazz1 = Class.forName(path);
Class clazz11=Class.forName(path);
System.out.println(clazz1.hashCode());//相同hashcode
System.out.println(clazz11.hashCode());//相同hashcode
}
{
User_Demo user_demo = new User_Demo();
Class clazz2 = user_demo.getClass();
Class clazz3 = User_Demo.class;
System.out.println(clazz2 == clazz3);//true
}
}
}
获取基本数据类型的Class对象
Class类可以直接获取基本数据类型的Class对象,但是在数组中,多维的数组就是不同的class对象,不同类型的数组也是不同的class对象
int[] arr0 = new int[5];
int[] arr01 = new int[15];
long[] arr02 = new long[15];
int[][] arr1 = new int[5][5];
System.out.println(arr0.getClass() + " " + arr0.getClass().hashCode());//class [I 920011586
System.out.println(arr01.getClass() + " " + arr01.getClass().hashCode());//class [I 920011586
System.out.println(arr02.getClass() + " " + arr02.getClass().hashCode());//class [J 2017354584
System.out.println(arr1.getClass() + " " + arr1.getClass().hashCode());//class [[I 2017354584
Class API
方法含义备注public String getName()返回由类对象表示的实体的名称(类,接口,数组类,原始类型或void),作为String返回由类对象表示的实体的名称(类,接口,数组类,原始类型或void),作为String
public Field getField(String name)获取指定属性名的属性注意只能获得public属性
public Field[] getFields()获取所有的公共方法的属性数组
public Field getDeclaredField(String name)返回指定的名字的属性包括私有属性
public Field[] getDeclaredFields()返回所有的属性数组包括私有的
同理…Method/Constructor
同理…DeclaredMethods/Constructors
public Mehod getDeclaredMethod(String name,Class>…parameterTypes返回指定参数类型的方法,Class>…parameterTypes可变参数参入的是对于类型的Class类针对方法的多态性(重载)进行针对的获取,即对于方法有传参则必须传入对于的Class对象
public Constructor获取指定传参的构造器
package JavaCore.Reflection;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
public class Reflection_Dynamic {
static Class clazz;
static{
String path = "JavaCore.Reflection.User_Demo";
try {
clazz=Class.forName(path);
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
public static void useReflection() throws IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException, NoSuchFieldException {
//这里newInstance实际就是在调用对于类的无参构造器,如果对于的类没有无参构造器则会抛出InstantiationException
User_Demo demo = (User_Demo) clazz.newInstance();
//使用特定的构造器新建对象
Constructor constructor = User_Demo.class.getDeclaredConstructor(String.class, int.class);
User_Demo demo1 = (User_Demo) constructor.newInstance("Swagger", 26);
System.out.println(demo1);
/**
* 使用反射调用普通方法
* 1.先获取到Class对象,并获取一个新的对象A
* 2.然后通过Class对象获得方法对象Method
* 3.使用Method.invoke(Object A,args...)方法调用类的方法
*/
User_Demo A = (User_Demo) clazz.newInstance();
Method method = clazz.getDeclaredMethod("setName", String.class);
method.setAccessible(true);
method.invoke(A, "Swagger1");
System.out.println(A);
/**
* 通过反射操作属性
*
*/
User_Demo fDemo = (User_Demo) clazz.newInstance();
Field f = clazz.getDeclaredField("name");
f.setAccessible(true);//使用这个setAccessible(true)来设置可以访问私有方法和属性
f.set(fDemo, "Ranger");//
System.out.println(fDemo);
}
}
反射操作泛型
Java采用泛型擦除的机制来引入泛型。Java中的泛型仅仅是给编译器javac使用的,确保数据 的安全性和免去强制类型转换的麻烦。但是,一旦编译完成,所有的和泛型有关的类型全部 擦除。
为了通过反射操作这些类型以迎合实际开发的需要,Java就新增了ParameterizedType, GenericArrayType,TypeVariable 和WildcardType几种类型来代表不能被归一到Class 类中的类型但是又和原始类型齐名的类型
反射操作注解
public static void main(String[] args) {
try {
Class clazz = Class.forName("类的相对路径和类名");
//获得类的所有有效注解
Annotation[] annotations=clazz.getAnnotations();
for (Annotation a : annotations) {
System.out.println(a);
}
//获得类的指定的注解SxtTable就是一个注解
SxtTable st = (SxtTable) clazz.getAnnotation(SxtTable.class);
System.out.println(st.value());
//获得类的属性的注解,columnName(),type(),length()就是SxtTable第一的注解方法或者属性,因为注解就是一种特殊的接口,他的属性值就是调用其方法
Field f = clazz.getDeclaredField("studentName");
SxtField sxtField = f.getAnnotation(SxtField.class);
System.out.println(sxtField.columnName()+"--"+sxtField.type()+"--"+sxtField.length());
//根据获得的表名、字段的信息,拼出DDL语句,然后,使用JDBC执行这个SQL,在数据库中生成相关的表
} catch (Exception e) {
e.printStackTrace();
}
}
反射的性能问题
反射访问相对正常的访问大概要慢30倍
setAccessible
setAccessible设为true:取消反射时的对象安全检查,false则进行安全检查;
当禁止安全检查时就能:
1.访问私有属性
2.同时也能提高反射的运行速度
如果setAccessible(true)禁用安全检查则能将反射访问效率提升4倍,所以当频繁的调用反射时可以禁用安全检查来提升效率
作者:
喜欢围棋和编程。查看的所有文章
最后
以上就是天真水杯为你收集整理的java的反射机制速度很慢_java反射机制Reflection浅析的全部内容,希望文章能够帮你解决java的反射机制速度很慢_java反射机制Reflection浅析所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复