反射概述
反射就是根据字节码文件,反射类的信息,方法,构造方法,字段等类的内容,根据字节码文件创建对象,调用方法的技术
反射的基础是Class对象
把一组小狗可以抽象为Dog类,把一组小猪抽象为pig类,把一组人抽象为Person类,把Dog/Pig/Person/String/System等所有的类抽象为Class类, Class类描述所有的类的共同特征
如何获得Class对象?
- 每个类都有class属性 Class class1 = Test01.class;
- 每个对象都有getClass()方法 Class class2 = new Test01().getClass();
- Class.forName(完整类名)
Class class3 = Class.forName(“com.node.chapter08.demo01.Test01”);
注意:Class<?> class4 = int.class;
Class<?> class6 = Integer.TYPE;
System.out.println( class4 == class6 ); //true
Class.forName()返回Class对象时,会把参数指定的类加载到内存中
反射类信息
class1.getModifiers() 返回类的修饰符
class1.getName() 返回完整类名
class1.getSimpleName() 简易类名
class1.getSuperClass() 父类
class1.getInterfaces() 接口
public static void main(String[] args) {
//1)创建Class对象
Class<?> class1 = String.class;
// Class<?> class1 = Integer.class;
StringBuilder sb = new StringBuilder();
//2)反射类的信息
//2.1 修饰符
int mod = class1.getModifiers(); //方法返回类的修饰符,是一个整数
String modifier = Modifier.toString(mod);
sb.append( modifier );
//2.2 类名
sb.append(" class ");
// sb.append( class1.getName() ) ; //getName()r返回完整类名
sb.append( class1.getSimpleName() ) ; //返回简易类名
//2.3 父类
Class<?> superclass = class1.getSuperclass();
//判断父类是否为Object
if ( Object.class != superclass ) {
sb.append(" extends ");
sb.append( superclass.getSimpleName() );
}
//2.4 接口,getInterfaces()返回接口数组, 如果类没有实现接口,返回的数组长度为0
Class<?>[] interfaces = class1.getInterfaces();
if( interfaces.length > 0 ){ //实现了接口
sb.append(" implements ");
//遍历接口数组
for( int i = 0 ; i<interfaces.length ; i++){
sb.append( interfaces[i].getSimpleName() );
//接口之间使用逗号分隔
if ( i < interfaces.length - 1) {
sb.append(",");
}
}
}
System.out.println( sb );
}
访问字段
通过反射技术访问字段
class1.getField(字段名) 返回指定字段名的公共字段
class1.getDeclaredField(字段名) 返回指定名称的字段(即使它是私有的)
class1.newInstance() 创建一个实例(创建一个对象)
field.set(对象名, 字段的值); 设置字段的值
field.get(对象名); 返回字段的值
field.setAccessible(true); 设置字段的可访问性
public static void main(String[] args) throws NoSuchFieldException, SecurityException, InstantiationException, IllegalAccessException {
//1) 创建Class对象,
Class<?> class1 = Person.class;
//2) 反射name字段
Field nameF = class1.getField("name");
//3) 通过反射技术创建对象(实例), 默认调用类的无参构造
Object p1 = class1.newInstance(); //相当于new Person()
//4)设置字段的值
nameF.set(p1, "lisi"); //p1.setName("lisi")
//5)返回字段的值
System.out.println( p1 );
System.out.println( nameF.get(p1) ); //p1.getName()
//6)访问私有字段: age
// Field ageF = class1.getField("age"); //只能返回公共字段
Field ageF = class1.getDeclaredField("age"); //返回字段
ageF.setAccessible(true); //设置字段的可访问性
ageF.set(p1, 18);
System.out.println( ageF.get(p1));
System.out.println( p1 );
}
访问方法
通过反射技术调用方法
class1.getMethod(方法名, 参数类型列表) 反射指定方法签名的公共方法 method.invoke(实例名, 方法的实参列表) 调用方法
public static void main(String[] args) throws NoSuchMethodException, SecurityException, InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException {
//1) 创建Class对象
Class<?> class1 = Person.class;
//2) 反射show()方法
Method showM = class1.getMethod("show", null);
//3)通过反射技术创建实例
Object obj = class1.newInstance(); //new Person()
//4)调用方法
showM.invoke(obj, null); //obj.show()
//5)反射set(String, int)方法
Method setM = class1.getMethod("set", String.class , int.class );
setM.invoke(obj, "lisi", 66);
showM.invoke(obj);
System.out.println( obj );
}
读取配置文件的信息
有时会把类名保存到配置文件中, 通过Properties读取配置文件的类名 , 通过反射创建对象
public static void main(String[] args) throws IOException, ClassNotFoundException, InstantiationException, IllegalAccessException {
//读取配置文件的类名
Properties properties = new Properties();
InputStream inStream = Test.class.getResourceAsStream("/com/bjpowernode/chapter08/demo02/config.properties");
properties.load(inStream);
String className = properties.getProperty("classname");
//通过反射技术,根据完整类名创建对象
Class<?> class1 = Class.forName(className);
Collection<?> collection = (Collection<?>) class1.newInstance();
}