反射
将类的各个组成部分封装成其他对象
好处
1.可以在程序运行过程中,操作这些对象
2.可以解耦,提高程序可扩展性
如图,类文件通过类加载器载入时,类本身(注意不是类创造的对象)被分为三种对象,可分别对其操作
获取Class对象的方式
1.Class.forName("全类名"): 将字节码文件加载进内存,返回Class对象
多用于配置文件,从文件中读取类名,加载类
2.类名.class: 通过类名的属性class获取
多用于参数的传递
Class cls2 = Calculate.class;
3.对象.class.getclass()方法
多用于对象获取字节码的方式
Calculate calculate1 = new Calculate();
Class cls3 = calculate1.getClass();
注:同一个字节码文件(*.class)在一次程序运行过程中,只会被加载一次,不论通过哪一种方式获取的Class对象都是同一个。(注意区分class对象和堆内对象,class对象相当于方法区内的此类所在地址)
System.out.println(cls1==cls2);
System.out.println(cls1==cls3);
//结果都是true
Class对象获取功能
1.获取成员变量们
* getFields(): 获取所有public修饰的成员变量
Field[] fields = cls1.getFields();
* getField(String name) 获取指定名称的public修饰的成员变量(private会报错)
Field field=cls1.getField("str");
------------------------------------------------------------------------------------------------------
* getDeclaredFields() 获取所有的成员变量,不考虑修饰符
* getDeclaredField(String name)
//示例
Class cls1 = Class.forName("Calculate"); //加载Cal类
Field field=cls1.getDeclaredField("x"); //x为private修饰的变量
field.setAccessible(true); //暴力反射,使field可修改x变量
Calculate calculate=new Calculate();//创建cal对象
field.set(calculate,12);//修改cal对象的值
2.获取构造方法们
* getConstructors()
* getConstructor()
* getDeclaredConstructor()
* getDeclaredConstructors()
public Calculate(String str) {this.str = str;}
Class cls1 = Class.forName("com.company.Calculate");
Constructor cls = cls1.getConstructor(String.class);
Calculate cal = (Calculate) cls.newInstance("liuyu");
System.out.println(cal.str);
3.3. 获取成员方法们:
* getMethods()
* getMethod(String MethodName,Class... args)
* getDeclaredMethods()
* getDeclaredMethod(String MethodName,Class... args)
public void add(Integer x,Integer y);
Class cls1 = Class.forName("com.company.Calculate");
Method add = cls1.getMethod("add", Integer.class, Integer.class);
Calculate calculate = new Calculate("sfd");
System.out.println(add.invoke(calculate, 1, 2));
4. 获取全类名
* String getName()
Class cls1 = Class.forName("com.company.Calculate");
System.out.println(cls1.getName());
//输出结果
com.company.Calculate
反射实例(反射怎么方便我们)
* 需求:写一个"框架",不能改变该类的任何代码的前提下,可以帮我们创建任意类的对象,并且执行其中任意方法
* 实现:
1. 配置文件
2. 反射
* 步骤:
1. 将需要创建的对象的全类名和需要执行的方法定义在配置文件中
2. 在程序中加载读取配置文件
3. 使用反射技术来加载类文件进内存
4. 创建对象
5. 执行方法
//config.properties
ClassName=com.company.Calculate
MethodName=add
//Main.java
public static void main(String[] args) throws Exception {
String className, methodName;
--------------------------------获取config.properties内容----------------------------------------
Properties in = new Properties();
ClassLoader classLoader = Main.class.getClassLoader();
InputStream inputStream = classLoader.getResourceAsStream("config.properties");
in.load(inputStream);
className = in.getProperty("ClassName");
methodName = in.getProperty("MethodName");
-----------------------------------------------------------------------------------------------------------
Class cls = Class.forName(className); //加载类
Constructor con = cls.getConstructor(String.class); //获取构造函数
Object obj = con.newInstance("liuyu");//创建对象
Method method = cls.getMethod(methodName, Integer.class, Integer.class);//获取方法
System.out.println(method.invoke(obj, 1, 2));//调用方法
}