反射机制
反射机制有什么用?
通过java语言中的反射机制可以操作字节码文件(可以读和修改字节码文件)。通过反射机制可以操作代码片段(class文件)
反射机制的相关类在哪个包下?
java.lang.reflect.*;
反射机制相关的重要类有哪些?
java.lang.Class:代表整个字节码,代表一个类型。代表整个类
java.lang.reflect.Method:代表字节码中的方法字节码。代表类中的方法
java.lang.reflect.Field:代表字节码中的属性字节码。代表类中的构造方法
java.lang.reflect.Constructor:代表字节码中的构造方法字节码。代表类中的成员变量(静态变量+实例变量)
三种方式获取java.lang.Class实例:
package com.bjpowernode.java.reflect;
import java.util.Date;
/*
要操作一个类的字节码,首先需要获取到这个类的字节码,怎么获取java.lang.Class实例?
有三种方式
第一种:Class c = Class.forName("完整类名带包名")
第二种:Class c = 对象.getClass();
第三种:Class c = 任何类型.class;
*/
public class ReflectTest01 {
public static void main(String[] args) {
/*
一、Class.forName()
1.静态方法
2.方法的参数是一个字符串
3.字符串需要的是一个完整类名
4.完整类名必须带有包名。java.lang包也不能省略
*/
Class c1 = null;
Class c2 = null;
try {
c1 = Class.forName("java.lang.String");
c2 = Class.forName("java.util.Date");
Class c3 = Class.forName("java.lang.Integer");
Class c4 = Class.forName("java.lang.System");
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
//二、java中任何一个对象都有一个方法:getClass()
String s = "abc";
Class x = s.getClass();
System.out.println(c1 == x);//true,==判断的是对象的内存地址
Date time = new Date();
Class y = time.getClass();
System.out.println(c2 == y);//c2和y两个变量中保存的内容地址都是一样的,都指向方法区中的字节码文件
//三、java语言中任何一种类型,包括基本数据类型,它都有.class属性
Class z = String.class;//z代表String类型
Class k = Date.class;//k代表Date类型
Class f = int.class;//f代表int类型
Class e = double.class;//e代表double类型
System.out.println(x==z);//true
}
}
package com.bjpowernode.java.bean;
public class User {
public User(){
System.out.println("我是无参构造");
}
public User(String s){
System.out.println("有参构造");
}
}
package com.bjpowernode.java.reflect;
import com.bjpowernode.java.bean.User;
/*
获取到Class,能干什么?
通过Class的newInstance()方法来实例化对象
注意:newInstance()方法内部实际上调用了无参构造方法,必须保证无参构造存在才可以。
*/
public class ReflectTest02 {
public static void main(String[] args) {
//这是不使用反射机制,创建对象
User user = new User();
System.out.println(user);
//下面是使用反射机制创建对象
try {
//通过反射机制,获取Class,通过Class来实例化对象
Class c = Class.forName("com.bjpowernode.java.bean.User");
//newInstance()这个方法会调用User这个类的无参数构造方法,完成对象的创建、
//重点是:newInstance()调用的是无参构造,必须保证无参构造是存在的!
Object obj = c.newInstance();
System.out.println(obj);
}catch (InstantiationException e) {
e.printStackTrace();
}catch (IllegalAccessException e) {
e.printStackTrace();
}
catch(ClassNotFoundException e) {
e.printStackTrace();
}
}
}
package com.bjpowernode.java.reflect;
import com.bjpowernode.java.bean.User;
import java.io.FileReader;
import java.util.Properties;
/*
验证反射机制的灵活性
java代码写一遍,在不改变java源码的基础之上,可以做到不同对象的实例化。
非常之灵活。(符合OCP开闭原则:对扩展开放,对修改关闭。)
*/
public class ReflectTest03 {
public static void main(String[] args) throws Exception {
//这种方式就写死了,只能创建一个User类型的对象
User user = new User();
//以下代码是灵活的,代码不需要改动,可以修改配置文件,配置文件修改之后,可以创建出不同的实例对象。
//通过IO流读取classinfo.properties文件
FileReader reader = new FileReader("D:\\IdeaProjects\\bjpowernodejavase\\chapter25\\classinfo.properties");
//创建属性类对象Map
Properties pro = new Properties();
//加载
pro.load(reader);
//关闭流
reader.close();
//通过key获取value
String className = pro.getProperty("className");
System.out.println(className);
//通过反射机制实例化对象
Class c = Class.forName(className);
Object obj = c.newInstance();
System.out.println(obj);
}
}
Class.forName()发生了什么?
如果你只是希望一个类的静态代码块执行,其他代码一律不执行,
你可以使用:
Class.forName(“完整类名”)
这个方法的执行会导致类加载,类加载时,静态代码块执行。