反射
文章目录
- 基本使用
- 反射机制
- java程序在计算机有三个阶段
- 反射相关的主要类
- 反射调用优化
- Class类的常用方法
- 获取Class对象的6种方式
- 哪些类型有Class对象
- 类加载
- 类加载时机
- 类加载过程图
- 通过反射获取类的结构信息
- 第一组:java.lang.Class类
- 第二组:java.lang.reflect.Filed类
- 第三组:java.lang.reflect.Method类
- 第四组:java.lang.reflect.Constructor类
- 通过反射创建对象
- 通过反射访问类中的成员
基本使用
Properties prop = new Properties();
prop.load(new FileInputStream("src\\re.properties"));
String classfullpath = prop.getProperty("classfullpath").toString();
String method = prop.getProperty("method").toString();
System.out.println("classfullpath = " + classfullpath);
System.out.println("method = " + method);
// 加载类,返回Class类型的对象cls
Class cls = Class.forName(classfullpath);
// 通过 cls 得到你加载的类 com.hspedu.Cat 的对象实例
Object obj = cls.newInstance();
System.out.println("o的运行类型=" + obj.getClass());
// 通过cls得到你加载的类 com.hspedu.Cat 的 methodName "hi" 的对象方法
// 即: 在反射中,可以把方法视为对象(万物皆对象)
Method method1 = cls.getMethod(method);
// 通过method1 调用方法:即通过方法对象实现调用方法
method1.invoke(obj); // 传统方法 对象.方法(),反射机制 方法.invoke(对象)
反射机制
1.反射机制允许程序在执行期借助于Reflection API取得任何类的内部信息(化比如成员变量,构造器,成员方法等等),并能操作对象的属性及方法。反射在设计模式和框架底层都会用到
2.加载完类之后,在堆中就产生了一个Class类型的对象(一个类只有一个Class对象),
这个对象包含了类的完整结构信息。通过这个对象得到类的结构。这个对象就像一面镜子,透过这个镜子看到类的结构,所以,形象的称之为:反射
java程序在计算机有三个阶段
反射相关的主要类
1.java.lang.Class:代表一个类,Class对象表示某个类加载后在堆中的对像
2.java.lang.reflect.Method:代表类的方法
3.java.lang.reflect…Field:代表类的成损变量
4.java.lang.reflect…Constructor::代表类的构造方法
这些类在java.lang.reflection
反射调用优化
.setAccessible(true); // 关闭访问检查, 大约提升30%速度
Class类的常用方法
获取Class对象的6种方式
1.编译阶段
Class.forName()
应用场景:多用于配置文件,读取类全路径,加载类.
2.加载阶段
类.class
应用场景:多用于参数传递,比如通过反射得到对应构造器对象
3.Runtime运行阶段
对象.getClass()
4.通过类加载器得到一个Class对象
5.基本数据(int,char,boolean,float,double,byte,long,short)按如下方式得到Class类对象
6.基本数据类型对应的包装类,可以通过.type得到Class类对像
哪些类型有Class对象
如下类型有Class对象
1.外部类,成员内部类,静态内部类,局部内部类,匿名内部类
2.interface:接口
3.数组
4.enum:枚举
5.annotation: 注解
6.基本数据类型
7.void
类加载
静态加载:编译时加载相关的类,如果没有则报错,依赖性太强
动态加载:运行时加载需要的类,如果运行时不用该类,即使不存在该类,则不报错,降低了依赖性
类加载时机
1.当创建对象时(new) // 静态加载
2.当子类被加载时,父类也加载 // 静态加载
3.调用类中的静态成员时 // 静态加载
4.通过反射 // 动态加载
类加载过程图
通过反射获取类的结构信息
第一组:java.lang.Class类
1.getName:获取全类名
2.getSimpleName:获取简单类名
3.getFields:获取所有public修饰的属性,包含本类以及父类的
4.getDeclaredFields:获取本类中所有属性
5.getMethods:获取所有public修饰的方法,包含本类以及父类的
6.getDeclaredMethods:获取本类中所有方法
7.getConstructors::获取本类所有public修饰的构造器
8.getDeclaredConstructors获取本类中所有构造器
9.getPackage:以Package形式返回包信息
10.getSuperClass:以Class形式返回父类信息
11.getInterfaces:以Class形式返回接口信息
12.getAnnotations:以Annotationl形式返回注解信息
第二组:java.lang.reflect.Filed类
1.getModifiers:以int形式返回修饰符
[说明:默认修饰符是0,public是1,private是2,protected是4,
static是8,final是16],public(1)+static(8)=9
2.getType:以Class形式返回类型
3.getName:返回属性名
第三组:java.lang.reflect.Method类
1.getModifiers:以int形式返回修饰符
[说明:默认修饰符是0,public是1,private是2,protected是4,
static是8,final是16]
2.getReturnType:以Class形式获取返回类型
3.getName:返回方法名
4.getParameterTypes:以Class返回参数类型数组
第四组:java.lang.reflect.Constructor类
1.getModifiers:以int形式返回修饰符
2.getName:返回构造器名(全类名)
3.getParameterTypes:以Class[]返回参数类型数组
通过反射创建对象
1.方式一:调用类中的public修饰的无参构造器
2.方式二:调用类中的指定构造器
3.Class类相关方法
newInstance:调用类中的无参构造器,获取对应类的对象
getConstructor(Class.clazz):根据参数列表,获取对应的构造器对象
getDecalaredConstructor(Class.clazz):根据参数列表,获取对应的构造器对象
4.Constructor类相关方法
setAccessible:暴破
newlnstance(Object…obj):调用构造器
Class<?> userClass = Class.forName("com.hspedu.refilection.User");
// 获取User类的无参构造方法
Constructor<?> constructor = userClass.getConstructor();
// 使用无参构造方法创建User对象
Object o = constructor.newInstance();
// 打印创建的User对象
System.out.println(o);
// 获取User类的带有一个String参数的构造方法
Constructor<?> constructor1 = userClass.getConstructor(String.class);
// 使用带有一个String参数的构造方法创建User对象,参数为"hsp"
Object o1 = constructor1.newInstance("hsp");
// 打印创建的User对象
System.out.println(o1);
// 获取User类的私有构造方法,该方法带有两个参数:String和int
Constructor<?> constructor2 = userClass.getDeclaredConstructor(String.class, int.class);
// 设置私有构造方法为可访问
constructor2.setAccessible(true);
// 使用私有构造方法创建User对象,参数为"小明"和20
Object o2 = constructor2.newInstance("小明", 20);
// 打印创建的User对象
System.out.println(o2);
通过反射访问类中的成员
访问属性
1.根据属性名获取Field对象
Field f=clazz对象.getDeclaredField(属性名);
2.暴破:f.setAccessible(true); //f是Field
3.访问
f.set(o,值);
syso(f.get(o));
4.如果是静态属性,则set和get中的参数o,可以写成null
访问方法
1.根据方法名和参数列表获取Method方法对象:
Method m=clazz.getDeclaredMethod(方法名,XX.class); //得到本类的所有方法
2.获取对象:Object o = clazz.newlnstance();
3.暴破:m.setAccessible(true);
4.访问:Object returnValue=m.invoke(o,实参列表);
5.注意:如果是静态方法,则invoke的参数o,可以写成null!