反射概述、获取字节码文件方法、Class对象功能、两个重要案例
目录
反射概述
框架:半成品软件。框架的灵魂、可以在框架的基础上进行软件开发,简化编码
反射:将类的各个组成部分封装为其他对象,这就是反射机制
- 好处:
1.可以在程序运行过程中,操作这些对象
2.可以解耦,提高程序的可拓展性
获取字节码文件的三种方法
- 调用Class类的forName(全类名)方法 (java的第一阶段)
多用于配置文件,将类名定义在配置文件中。读取文件,加载类 - 已经创建类后可以用 类名.class 来获取字节码文件 (java的第二阶段)
多用于参数的传递 - 已经创建类对象后可以用Object类中的getClass()方法来获取字节码文件 (java的第三阶段)
多用于获取对象的字节码方式
代码示例:
public class Person {
public static void main(String[] args) throws Exception {
Student c=new Student();
Class cls1 = c.getClass();
Class cls2 = Student.class;
Class cls3 = Class.forName("test_practice1.Student");
System.out.println(cls1);
System.out.println(cls2);
System.out.println(cls3);
System.out.println( cls1 == cls2); //注意==号是比较内存(堆内存)中的地址是否相同
System.out.println( cls1 == cls3);
}
}
注:同一个字节码文件(*.class)再一次程序运行过程中,只会被加载一次,
无论通过哪一种方式获取的class对象都是同一个。
Class对象功能
获取成员变量方法
| 方法名 | 作用 |
|---|---|
| Field[] getField() | 获取所有public修饰的成员变量 |
| Field getField(String name) | 获取name的成员变量值 |
| Field[] getDeclaredFields() | 获取所有成员变量 不考虑修饰符(但不能直接设置由private修饰的成员变量) |
| Field getDeclaredField() | 获取成员变量 不考虑修饰符(但不能直接设置由private修饰的成员变量) |
代码示例:
public class Person {
public static void main(String[] args) throws Exception {
Student s=new Student();
Class c1 = Student.class;
Class c2 = s.getClass();
Class c3 = Class.forName("test_practice1.Student");
System.out.println("-----------------"); //Field[] getFields();
Field[] f1 = c1.getFields();
for(Field x:f1){
System.out.println(x);
}
System.out.println("-----------------"); //Field getField(String name);
Field cls = c2.getField("cls");
cls.set(s,"张三"); //Field类中提供了get()方法和set()方法
Object o = cls.get(s);
System.out.println(o);
System.out.println("-----------------"); //Filed[] getDeclaredFields();
Field[] f2 = c3.getDeclaredFields();
for(Field x:f2){
System.out.println(x);
}
System.out.println("-----------------"); //Field getDeclaredField(String name);
Field score = c3.getDeclaredField("id");
//注意:不能直接设置成员变量为protected时的成员 即使用setAccessible(true);也不行 依然会报错
score.setAccessible(true);
//设置private修饰的成员变量时用setAccessible(true);忽略访问权限修饰符的安全检查即可
score.set(s,99);
Object o1 = score.get(s);
System.out.println(o1);
}
}
获取构造函数方法
| 方法名 | 作用 |
|---|---|
| Constructor<?>[] getConstructors() | 获取所有构造方法 |
| Constructor<?> getConstructor() | 获取构造方法,在获取带参构造函数时只需要加入相应形参即可 |
| Constructor<?>[] getDeclaredConstructors() | 获取所有构造方法 无视修饰符 |
| Constructor<?> getDeclaredConstructor() | 获取构造方法 |
public class Person {
public static void main(String[] args) throws Exception {
Class studentClass = Student.class;
Constructor constructor1 = studentClass.getConstructor();
System.out.println(constructor1);
System.out.println("------------");
Object o = constructor1.newInstance();
System.out.println(o);
System.out.println("------------");
Constructor constructor2 = studentClass.getConstructor(String.class,int.class,String.class,int.class); //获取带参构造方法需要在形参中添加例如:String.class
Object o2 = constructor2.newInstance("张三", 1,"001",100);
System.out.println(o2);
}
}
获取成员方法
| 方法名 | 作用 |
|---|---|
| Method[] getMethods() | 获取所有成员方法 |
| Method getmethod(String name,类<?>…parameterTypes) | 获取成员方法 |
| Method[] getDeclaredMethods() | 获取所有成员方法 |
| Method getDeclaredMethod(String name,类<?>…parameterTypes) | 获取成员方法 |
代码示例:
public class Person {
public static void main(String[] args) throws Exception {
Class studentClass = Student.class;
Method eat = studentClass.getMethod("eat", String.class);
//获取带参构造需要在getMethod()中添加方法名和形参 例:"eat",String.class
Student s=new Student();
eat.invoke(s,"苹果");
//Object invoke():调用带参方法时invoke()中需要添加上成员变量
}
}
注:所有带Declared的方法中都可以设置setAccessible(true)来设置和访问private修饰过的构造函数和成员变量,protected修饰的除外
案例
通过反射越过泛型检查用ArrayList集合中添加一个String类型的数据
代码示例:
ArrayList<Integer> array=new ArrayList<Integer>();
array.add(123);
Class<? extends ArrayList> c = array.getClass();
//先获取ArrayList对象的Class对象,再调用反射机制访问类中的add(Object o);方法添加一个字符串进入该集合
Method add = c.getMethod("add", Object.class);
add.invoke(array,"hello");
System.out.println(array);
**通过反射来调用配置文件中的指定文件和指定的方法
Properties类的运用(Properties常用方法load()、Property(String key))
代码示例:
//加载数据
Properties prop=new Properties();
FileInputStream fis=new FileInputStream("D:\\NewCompiler\\IDEA\\Practice\\src\\test_practice2\\pro.properties"); //配置文件地址
prop.load(fis); //注意load(InputStream); 传入的是一个输入流
String className = prop.getProperty("className");
String methodName = prop.getProperty("methodName");
Class<?> c1 = Class.forName(className);
Constructor<?> constructor = c1.getConstructor(); //先要调用出构造方法获取一个对象才可以调用对象中的方法
Object o = constructor.newInstance();
Method m = c1.getMethod(methodName);
m.invoke(o);
pro配置文件中的内容:
pro.properties:
className=test_practice2.Teacher
methodName=teach
#键=值
#key=value
阿里云工作强度 667人发布