【JavaSE】反射学习笔记
反射
-一个需求引出反射
-
请看下面问题
-
根据配置文件re.properties指定信息,创建Cat对象并调用方法
classfullpath=com.xijie.Cat method=hi
思考:不使用反射技术,你能做出来吗?
-
这样的需求在框架中运用特别多,即通过外部文件配置,在不修改源码的情况下,来控制程序,也符合设计模式的OCP(Open Close Principle开闭原则:软件应当对扩展开放,对修改关闭)
-
(没有反射就没有各种牛逼的框架,可以说反射是java各类框架的灵魂)
-
快速入门案例
-
配置文件
re.properties
:className=com.xijie.reflect.question.Cat methods=eat,run,eat,sleepy,sleep
-
Cat类
package com.xijie.reflect.question;public class Cat {public void eat(){System.out.println("猫在吃饭...");}public void run(){System.out.println("猫在跑步...");}public void sleepy(){System.out.println("猫困了...");}public void sleep(){System.out.println("猫睡了...");} }
-
主类
package com.xijie.reflect.question;import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.IOException; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.util.Properties;/*** 反射机制所解决的问题:不修改源码的情况下,如何修改程序的功能?* 需求:调用配置文件中指定的类及其方法序列,创建Cat对象,并按配置文件中指定的方法序列调用方法,方法序列中方法名以逗号分隔*/ public class ReflectQuestion {public static void main(String[] args) throws IOException, ClassNotFoundException, InstantiationException, IllegalAccessException, NoSuchMethodException, InvocationTargetException {//1. 读取配置文件项目Properties properties=new Properties();properties.load(new FileInputStream("src\\com\\xijie\\reflect\\question\\re.properties"));String className=properties.getProperty("className");String[] methods=properties.getProperty("methods").split(",");System.out.println("读取的类名:"+className);System.out.print("读取的方法序列:");for (String method : methods) {System.out.print(method+" ");}System.out.println();//2. 根据类名加载类并创建一个对象Class cls=Class.forName(className);Object o=cls.newInstance();System.out.println("创建的对象的运行类型:"+o.getClass().toString());//3. 循环遍历methods中的方法名,创建方法对象,并调用o对象中的方法for (String method : methods) {//从加载的类中,根据方法名,获取方法Method m=cls.getMethod(method);//方法绑定对象来执行m.invoke(o);}//4. 完毕System.out.println("程序执行完毕...");} }
-
-
-反射机制
-
Java Reflection
- 反射机制允许程序在执行期借助于ReflectionAPI取得任何类的内部信息(比如成员变量,构造器,成员方法等等),并能操作对象的属性及方法。反射在设计模式和框架底层都会用到。
- 加载完类之后,在堆中就产生了一个Class类型的对象(一个类只有一个Class对象),这个对象包含了类的完整结构信息。通过这个对象得到类的结构。这个对象就像一面镜子,透过这个镜子看到类的结构,所以,形象的称之为:反射。
-
Java反射机制原理说明
- Java程序在计算机中有三个阶段,分别是:Compile编译阶段、Classload类加载阶段、Runtime运行阶段。
- 编译阶段中,.java源代码文件通过javac工具编译为.class字节码文件。字节码文件中包含源代码文件中除了注释外的所有信息,包括文件头、常量池、类\接口定义、字段表、方法表、属性表、附加信息。
- 类加载阶段中,字节码文件通过ClassLoader类加载器加载到堆中,生成一系列Class类对象,类对象中包含了字节码文件中的主要信息。类对象的每个元素都由对应的类对象来储存,例如类成员变量存储在Field[] fields中,成员方法存储在Methods[] ms中。这个阶段体现了Java的反射思想。
- 在运行阶段,JVM使用类对象创建各类对象,并且在创建的对象中标记了它是哪个类的对象。
-
Java反射机制可以完成:
- 在运行时判断任意一个对象所属的类
- 在运行时构造任意一个类的对象
- 在运行时得到任意一个类所具有的成员变量和方法
- 在运行时调用任意一个对象的成员变量和方法
- 生成动态代理
-
反射相关的主要类
-
java.lang.Class:代表一个类,Class对象表示某个类加载后在堆中的对象
-
java.lang.reflect.Method:代表类的方法
-
java.lang.reflect.Field:代表类的成员变量
-
java.lang.reflect.Constructor:代表类的构造方法
这些类在java.lang.reflection包中
-
反射相关主要类案例演示
package com.xijie.reflect.mainClass;import java.io.IOException; import java.lang.reflect.Constructor; import java.lang.reflect.Field; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method;/*** 反射机制所解决的问题:不修改源码的情况下,如何修改程序的功能?* 需求:调用配置文件中指定的类及其方法序列,创建Cat对象,并按配置文件中指定的方法序列调用方法,方法序列中方法名以逗号分隔*/ public class MainClass {public static void main(String[] args) throws IOException, ClassNotFoundException, InstantiationException, IllegalAccessException, NoSuchMethodException, InvocationTargetException, NoSuchFieldException {//1. 根据类名加载类并创建一个对象Class cls=Class.forName("com.xijie.reflect.mainClass.Cat");Object o=cls.newInstance();System.out.println("创建的对象的运行类型:"+o.getClass().toString());//2. 通过Method类获取方法,包括无参方法和有参方法Method walkMethod=cls.getMethod("walk");walkMethod.invoke(o);Method talkMethod=cls.getMethod("talk",String.class);talkMethod.invoke(o,"大家好,我是喵喵");//3. 通过Field获取成员变量,如果要获取私有变量,需要关闭权限检查,但是这样会破坏封装性Field nameField=cls.getField("name");//获取公有属性Field ageField=cls.getDeclaredField("age");//获取已声明的私有属性ageField.setAccessible(true);//打破私有属性的访问限制System.out.println("猫咪的名字是:"+nameField.get(o));System.out.println("猫咪的年龄是:"+ageField.get(o));//4. 通过Constructor获取构造器,包括无参构造器和有参构造器Constructor nonVarConstructor=cls.getConstructor();Constructor varConstructor=cls.getConstructor(String.class);System.out.println(nonVarConstructor);System.out.println(varConstructor);//E. 完毕System.out.println("程序执行完毕...");} }
package com.xijie.reflect.mainClass;public class Cat {public String name="喵喵";private int age=10;public Cat() {System.out.println("调用了猫咪的无参构造方法");}public Cat(String name) {System.out.println("调用了猫咪的有参构造方法");}public void walk(){System.out.println("小猫走路");}public void talk(String str){System.out.println("小猫说:"+str);} }
-
-
反射的优点和缺点
- 优点:可以动态的创建和使用对象(也是框架底层核心),使用灵活,没有反射机制,框架技术就失去底层支撑。
- 缺点:使用反射基本是解释执行,对执行速度有影响。
-
反射调用优化-关闭访问检查
-
Method和Field、Constructor对象都有setAccessible()方法
-
setAccessible作用是启动和禁用访问安全检查的开关
-
参数值为true表示反射的对象在使用时取消访问检查,提高反射的效率。参数值为false则表示反射的对象执行访问检查
-
反射缺点及优化案例演示
package com.xijie.reflect.defect;import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method;public class Defect {private static final int LOOP_NUM=2000000000;public static void main(String[] args) throws ClassNotFoundException, InvocationTargetException, InstantiationException, IllegalAccessException, NoSuchMethodException {long startTime;startTime=System.currentTimeMillis();m1();System.out.println("普通方法调用执行时间:"+(System.currentTimeMillis()-startTime));startTime=System.currentTimeMillis();m2();System.out.println("反射方法调用执行时间:"+(System.currentTimeMillis()-startTime));startTime=System.currentTimeMillis();m3();System.out.println("反射优化方法调用执行时间:"+(System.currentTimeMillis()-startTime));}/*** 用普通方法调用cat对象的方法*/private static void m1(){Cat cat=new Cat();for (int i = 0; i < LOOP_NUM; i++) {cat.m();}}/*** 用反射方法调用cat对象的方法*/private static void m2() throws ClassNotFoundException, InstantiationException, IllegalAccessException, NoSuchMethodException, InvocationTargetException {Class cls=Class.forName("com.xijie.reflect.defect.Cat");Object o=cls.newInstance();Method m=cls.getMethod("m");for (int i= 0; i< LOOP_NUM; i++) {m.invoke(o);}}/*** 用反射方法禁用权限检查调用cat对象的方法*/private static void m3() throws ClassNotFoundException, InstantiationException, IllegalAccessException, NoSuchMethodException, InvocationTargetException {Class cls=Class.forName("com.xijie.reflect.defect.Cat");Object o=cls.newInstance();Method m=cls.getMethod("m");m.setAccessible(true);for (int i= 0; i< LOOP_NUM; i++) {m.invoke(o);}} }
package com.xijie.reflect.defect;public class Cat {public void m(){} }
-
-Class类
-
基本介绍:
- Class也是类,因此也继承Object类
- Class类对象不是new出来的,而是系统创建的
- 对于某个类的Class类对象,在内存中只有一份,因为类只加载一次
- 每个类的实例都会记得自己是由哪个Class实例所生成
- 通过Class可以完整地得到一个类的完整结构,通过一系列API
- Class对象是存放在堆的
- 类的字节码二进制数据,是放在方法区的,有的地方称为类的元数据(包括方法代码,变量名,方法名,访问权限等等)https://www.zhihu.com/question/38496907
-
Class类的常用方法
方法名 功能说明 static Class forName(String name) 返回指定类名name的Class对象 Object newInstance() 调用缺省构造函数,返回该Class对象的一个实例 getName() 返回此Class对象所表示的实体(类、接口、数组类、基本类型等)名称 Class getSuperClass() 返回当前Class对象的父类的Class对象 Class getInterfaces() 获取当前Class对象的接口 Class [] getClassLoader() 返回该类的类加载器 Class getSuperclass() 返回表示此Class所表示的实体的超类的Class Construstor[] getConstructors() 返回一个包含某些Constructor对象的数组 Field[] getDeclaredFields() 返回Field对象的一个数组 Method getMethod (String name,Class … paramTypes) 返回一个Method对象,此对象的形参类型为paramTypes -
常用方法案例
package com.xijie.reflect.class_;import java.lang.reflect.Field;public class ClassMethods {public static void main(String[] args) throws Exception {String classPath="com.xijie.reflect.class_.Car";//获取car类对应的class对象System.out.println("获取car类对应的class对象");Class cls=Class.forName(classPath);//输出clsSystem.out.println("输出cls:"+cls);//得到包名Package carPackage=cls.getPackage();System.out.println("得到包名:"+carPackage);//得到全类名System.out.println("得到全类名:"+cls.getName());//通过cls创建对象实例Object o=cls.newInstance();System.out.println("通过cls对象创建对象实例"+o);//通过反射获取属性Field field=cls.getField("brand");System.out.println("获取属性:"+field);//通过反射设置属性值System.out.println("通过反射设置属性值:"+field.get(o));//获取所有属性Field[] fields=cls.getFields();System.out.print("获取所有属性:");for (Field f : fields) {System.out.print(f+"|");}System.out.println();} }
package com.xijie.reflect.class_;public class Car {public String brand="吉利";public int price=1000000; }
-获取Class对象的六种方式
-
前提:已知一个类的全类名,且该类在类路径下,可通过Class类的静态方法forName(获取,可能抛出ClassNotFoundException。
实例:Class cls1= Class.forName(“java.lang.Cat” ):
应用场景:多用于配置文件,读取类全路径,加载类。
-
前提:若已知具体的类,通过类的class获取,该方式最为安全可靠,程序性能最高。
实例:Class cls2=Cat.class;
应用场景:多用于参数传递,比如通过反射得到对应构造器对象
-
前提:已知某个类的实例,调用该实例的getClass0方法获取Class对象,
实例:Class clazz = 对象.getClassO:
应用场景:通过创建好的对象,获取Class对象
-
其他方式
ClassLoader cl= 对象.getClassO.getClassLoaderO:
Class clazz4=cl.loadClass("类的全类名”):
-
基本数据(int,char,boolean,float,double,byte,long,short)按如下方式得到Class类对象
Classcls=基本数据类型.class
-
基本数据类型对应的包装类,可以通过.type得到Class类对象
Class cls=包装类.TYPE
-
案例演示
package com.xijie.reflect.getClass_;/*** 演示获取class的方式*/ public class GetClass {public static void main(String[] args) throws ClassNotFoundException {String classPath="com.xijie.reflect.getClass_.Car";//1. 前提:已知一个类的全类名,且该类在类路径下,可通过Class类的静态方法forName(获取,可能抛出ClassNotFoundException。// 应用场景:多用于配置文件,读取类全路径,加载类。Class cls=Class.forName(classPath);System.out.println("1. 通过全类名获取类对象:"+cls);//2. 前提:若已知具体的类,通过类的class获取,该方式最为安全可靠,程序性能最高。// 应用场景:多用于参数传递,比如通过反射得到对应构造器对象System.out.println("2. 通过已知的类获取类对象:"+Car.class);//3. 前提:已知某个类的实例,调用该实例的getClass方法获取Class对象// 应用场景:通过创建好的对象,获取Class对象Car car=new Car();System.out.println("3. 通过已创建的对象获取类对象:"+car.getClass());//4. 其他方式,通过classLoader获取类ClassLoader cl=cls.getClassLoader();System.out.println("4. 通过类加载器获取类对象:"+cl.loadClass(classPath));//5. 基本数据(int,char,boolean,float,double,byte,long,short)按如下方式得到Class类对象System.out.println("5. 获取基本数据类型的类对象:"+byte.class);//6. 基本数据类型对应的包装类,可以通过.type得到Class类对象System.out.println("6. 获取基本包装类的类对象:"+Byte.TYPE);System.out.println("基本包装类型的类对象和基本数据类型的类对象是同一个吗?:"+(byte.class==Byte.class));System.out.println("基本包装类型的类对象和基本数据类型的基本数据类型是同一个吗?:"+(byte.class==Byte.TYPE));} }
-哪些类型有Class对象?
-
如下类型有Class对象
- 外部类,成员内部类,静态内部类,局部内部类,匿名内部类
- interface:接口
- 数组
- enum:枚举
- annotation:注解
- 基本数据类型
- void
- Class对象本身
-
应用实例 AllTypeClass.java
package com.xijie.reflect.allTypeClass;import java.io.Serializable; import java.lang.annotation.Target;public class AllTypeClass {class Dog{ }public static void main(String[] args) {//1. 外部类,成员内部类,静态内部类,局部内部类,匿名内部类System.out.println("1. 外部类,成员内部类,静态内部类,局部内部类,匿名内部类:"+Dog.class);//2. interface:接口System.out.println("2. interface:接口:"+ Serializable.class);//3. 数组System.out.println("3. 数组:"+int[].class);//4. enum:枚举System.out.println("4. enum:枚举:"+Thread.State.class);//5. annotation:注解System.out.println("5. annotation:注解:"+ Target.class);//6. 基本数据类型System.out.println("6. 基本数据类型:"+int.class);//7. voidSystem.out.println("7. void:"+void.class);//8. Class对象本身System.out.println("8. Class对象本身:"+Class.class);} }
-类加载
-
基本说明
反射机制是java实现动态语言的关键,也就是通过反射实现类动态加载。-
静态加载:编译时加载相关的类,如果没有则报错,依赖性太强
-
动态加载:运行时加载需要的类,如果运行时不用该类,则不报错,降低了依赖性
-
举例说明
package com.xijie.reflect.classLoad;import java.lang.reflect.Method; import java.util.Scanner;public class ClassLoad {public static Scanner scanner=new Scanner(System.in);public static void main(String[] args) {System.out.print("请输入一个字符:");String c=scanner.next();switch (c){case "1"://静态加载在编译阶段完成//如果编译器找不到类,则编译报错Computer computer=new Computer();computer.compute();break;case "2":try{//反射加载的类在运行时才加载,所以即使找不到类,也会通过编译//在运行时找不到类,才会抛出异常Class cls=Class.forName("com.xijie.reflect.classLoad.Person");Object o=cls.newInstance();Method method=cls.getMethod("hi");method.invoke(o);}catch (Exception e){e.printStackTrace();}break;default:System.out.println("啥也不做");break;}System.out.println("执行结束...");} }class Computer{ public void compute(){System.out.println("计算机在计算");}}//class Person{public void hi(){System.out.println("蛤咯你好");}}
-
-
类加载时机
- 当创建对象时(new):静态加载
- 当子类被加载时:静态加载
- 调用类中的静态成员时:静态加载
- 通过反射:动态加载
-
类加载阶段及内存布局概述
-
Java源码经过javac编译后产生字节码文件.class,通过java运行后进入类加载阶段
-
类加载分为三个阶段
-
加载Loading阶段
加载阶段将class文件读入方法区,并在堆中创建java.lang.Class对象,此过程由类加载器完成
-
连接Linking阶段:包含验证verification、准备Preparation、解析Resolution三个子阶段
连接阶段将类的二进制数据合并到jre中
-
初始化initialization阶段
初始化阶段由JVM负责,主要是初始化静态成员
-
-
类加载后内存布局情况
- 方法区存储类的字节码二进制数据
- 堆区存储类的Class对象
-
-
加载阶段
JVM在该阶段的主要目的是将字节码从不同的数据源(可能是class文件、也可能是jar包,甚至网络)转化为二进制字节流加载到内存中,并生成一个代表该类的java.lang.Class对象
-
连接阶段-验证
- 目的是为了确保ClaSs文件的字节流中包含的信息符合当前虚拟机的要求,并且不会危害虚拟机自身的安全。
- 包括:文件格式验证(是否以魔数oxcafebabe开头)、元数据验证、字节码验证和符号引用验证
- 可以考虑使用-Xverify:none参数来关闭大部分的类验证措施,缩短虚拟机类加载的时间。
-
连接阶段-准备
JVM会在该阶段对静态变量,分配内存并默认初始化(对应数据类型的默认初始值,如0、OL、null、false等)。这些变量所使用的内存都将在方法区中进行分配。
-
连接阶段-解析
虚拟机将常量池内的符号引用替换为直接引用的过程。
-
初始化
- 到初始化阶段,才真正开始执行类中定义的Java程序代码,此阶段是执行0方法的过程。
- 0方法是由编译器按语句在源文件中出现的顺序,依次自动收集类中的所有静态变量的赋值动作和静态代码块中的语句,并进行合并。
- 虚拟机会保证一个类的0方法在多线程环境中被正确地加锁、同步,如果多个线程同时去初始化一个类,那么只会有一个线程去执行这个类的()方法,其他线程都需要阻塞等待,直到活动线程执行()方法完毕
-通过反射获取类的结构信息
由于Class类的方法众多,这里列举一些常用的方法,以对反射获取类的结构信息构建一个相对系统的认识。
-
第一组 java.lang.Class类
- getName:获取全类名
- getSimpleName:获取简单类名
- getFields:获取所有public修饰的属性,包含本类以及父类的
- getDeclaredFields:获取本类中所有属性
- getMethods:获取所有public修饰的方法,包含本类以及父类的
- getDeclaredMethods:获取本类中所有方法
- getConstructors:获取所有public修饰的构造器,包含本类以及父类的
- getDeclaredConstructors:获取本类中所有构造器
- getPackage:以Package形式返回包信息
- getSuperClass:以Class形式返回父类信息
- getInterfaces:以Class[形式返回接口信息
- getAnnotations:以Annotation[形式返回注解信息
-
第二组:Java.lang.reflect.Field类
- getModifiers:以int形式返回修饰符
[说明:默认修饰符是0,public是1,private是2,protected是4,static是8,final是16] - getType:以Class形式返回类型
- getName:返回属性名
- getModifiers:以int形式返回修饰符
-
第三组:java.lang.reflect.Method类
- getModifiers求以int形式返回修饰符
[说明:默认修饰符是0,public是1,private是2,protected是4,
static是8,final 是16] - getReturnType:以Class形式获取返回类型
- getName:返回方法名
- getParameterTypes:以Class[返回参数类型数组
- getModifiers求以int形式返回修饰符
-
案例演示
package com.xijie.reflect.classInfo;import java.io.Serializable; import java.lang.annotation.Annotation; import java.lang.reflect.Constructor; import java.lang.reflect.Field; import java.lang.reflect.Method;public class ClassInfo {public static void main(String[] args) throws Exception{Class clsPerson=Class.forName("com.xijie.reflect.classInfo.Person");Class cls=null;Class[] clses=null;Object oPerson=clsPerson.newInstance();Field[] fields=null;Method[] methods=null;Constructor[] constructors=null;Package pkg=null;Annotation[] annotations=null;Field field=null;//- 第一组 java.lang.Class类//1. getName:获取全类名System.out.println("-----获取全类名");System.out.println(clsPerson.getName());//2. getSimpleName:获取简单类名System.out.println("-----获取简单类名");System.out.println(clsPerson.getSimpleName());//3. getFields:获取所有public修饰的属性,包含本类以及父类的System.out.println("-----获取所有public修饰的属性");fields=clsPerson.getFields();printArray(fields);//4. getDeclaredFields:获取本类中所有属性System.out.println("-----获取本类中所有属性");fields=clsPerson.getDeclaredFields();printArray(fields);//5. getMethods:获取所有public修饰的方法,包含本类以及父类的System.out.println("-----获取所有public修饰的方法");methods=clsPerson.getMethods();printArray(methods);//6. getDeclaredMethods:获取本类中所有方法,不包含父类的方法System.out.println("-----获取本类中所有方法");methods=clsPerson.getDeclaredMethods();printArray(methods);//7. getConstructors:获取所有public修饰的构造器,包含本类以及父类的System.out.println("-----获取所有public修饰的构造器");constructors=clsPerson.getConstructors();printArray(constructors);//8. getDeclaredConstructors:获取本类中所有构造器System.out.println("-----获取本类中所有构造器");constructors=clsPerson.getDeclaredConstructors();printArray(constructors);//9. getPackage:以Package形式返回包信息System.out.println("-----以Package形式返回包信息");pkg=clsPerson.getPackage();System.out.println(pkg);//10. getSuperClass:以Class形式返回父类信息System.out.println("-----以Class形式返回父类信息");cls=clsPerson.getSuperclass();System.out.println(cls);//11. getInterfaces:以Class[形式返回接口信息System.out.println("-----以Class[形式返回接口信息");clses=clsPerson.getInterfaces();printArray(clses);//12. getAnnotations:以Annotation[形式返回注解信息System.out.println("-----以Annotation[形式返回注解信息");annotations=clsPerson.getAnnotations();printArray(annotations);// - 第二组:Java.lang.reflect.Field类//1. getModifiers:以int形式返回修饰符// [说明:默认修饰符是0,public是1,private是2,protected是4,static是8,final是16]//2. getType:以Class形式返回类型//3. getName:返回属性名System.out.println("-----以int形式返回修饰符,以Class形式返回类型,返回属性名");fields=clsPerson.getDeclaredFields();for (Field field1 : fields) {System.out.println(field1.getName()+" "+field1.getType()+" "+field1.getModifiers());}// - 第三组: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[返回参数类型数组System.out.println("-----以int形式返回修饰符,以Class形式获取返回类型,返回方法名,以Class[返回参数类型数组");methods=clsPerson.getDeclaredMethods();for (Method method : methods) {System.out.println(method.getModifiers()+" "+method.getReturnType()+" "+method.getName());clses=method.getParameterTypes();printArray(clses);}}private static void printArray(Object[] objects){if(objects == null){return;}for (Object object : objects) {System.out.println(object+" ");}} }@Deprecated @SuppressWarnings({"all"}) class Person implements Serializable{public String name;protected int age;double salary;private boolean isThinking;public Person(){}protected Person(int age){this.age=age;}Person(int age,double salary){this.age=age;this.salary=salary;}private Person(int age,double salary,boolean isThinking){this.age=age;this.salary=salary;this.isThinking=isThinking;}protected void inLove(){System.out.println("I'm in love");}void work(){System.out.println("I'm working");}private void thinking(){System.out.println("I think....");}public void saySomething(String str){System.out.println("str");} }
-通过反射创建对象
-
方式一:调用类中的public修饰的无参构造器
-
方式二:调用类中的指定构造器
-
Class类相关方法
- newInstance:调用类中的无参构造器,获取对应类的对象
- getConstructor(Class…clazz):根据参数列表,获取对应的构造器对象
- getDecalaredConstructor(Class…clazz):根据参数列表,获取对应的构造器对象
-
Constructor类相关方法
- setAccessible:暴破
- newlnstance(Object…obj):调用构造器
-
案例演示
package com.xijie.reflect.createClass;import java.lang.reflect.Constructor;public class CreateClass {public static void main(String[] args) throws Exception{Class cls=Class.forName("com.xijie.reflect.createClass.User");Object o=null;Constructor constructor=null;//通过公有无参构造函数创建实例o=cls.newInstance();System.out.println(o);//通过公有有参构造函数创造实例constructor=cls.getConstructor(String.class);o=constructor.newInstance("小华");System.out.println(o);//通过私有有参构造函数创造实例constructor=cls.getDeclaredConstructor(int.class,String.class);constructor.setAccessible(true);o=constructor.newInstance(13,"小明");System.out.println(o);} }class User{private int age;private String name;public User(){}public User(String name){this.name=name;}private User(int age, String name){this.age=age;this.name=name;}@Overridepublic String toString(){return "User:[age:"+age+",name:"+name+"]";} }
-通过反射访问类中的属性、方法
-
访问属性
- 根据属性名获取Field对象
Field f=clazz对象.getDeclaredField(属性名); - 暴破:f.setAccessible(true);//f 是Field
- 访问
f.set(o,值);
syso(f.get(o); - 如果是静态属性,则set和get中的参数o,可以写成null
- 根据属性名获取Field对象
-
访问方法
- 根据方法名和参数列表获取Method方法对象:Method m=
clazz.getDeclaredMethod(方法名,XX.class); - 获取对象:Object o=clazz.newlnstance0;
- 暴破:m.setAccessible(true);
- 访问:Object returnValue=m.invoke(o,实参列表);
- 注意:如果是静态方法,则invoke的参数o,可以写成null!!
- 根据方法名和参数列表获取Method方法对象:Method m=
-
案例演示
package com.xijie.reflect.classFieldMethod;import java.lang.reflect.Field; import java.lang.reflect.Method;public class ClassFieldMethod {public static void main(String[] args) throws Exception{Class cls=Class.forName("com.xijie.reflect.classFieldMethod.User");Object o=cls.newInstance();System.out.println(o);//获取并修改公有属性Field field=cls.getField("age");field.set(o,10);System.out.println(o);//获取并修改私有静态属性field=cls.getDeclaredField("name");field.setAccessible(true);field.set(o,"Mike");System.out.println(o);field.set(null,"Mary");System.out.println(o);//调用公有方法Method method=cls.getMethod("hi", String.class);method.invoke(o,"哈咯");//调用私有静态方法method=cls.getDeclaredMethod("hi", String.class, int.class, String.class);method.setAccessible(true);method.invoke(o,"1",1,"2");method.invoke(null,"2",2,"3");} }class User{public int age;private static String name;public User(){}public void hi(String str){System.out.println(str);}public static void hi(String str,int age,String name){System.out.println("super hi");}@Overridepublic String toString(){return "User:[age:"+age+",name:"+name+"]";} }