这是我参与「第三届青训营 -后端场」笔记创作活动的第2篇笔记
反射
1.获取Class对象的三种方法
1.Class.forName("全类名");(调用Class类的静态方法) 2.类名.class(调用类的class属性) 3.对象.getClass() (getClass方法在Object中定义)
Class<?> aClass = Class.forName("domain.Person");
Class<Person> personClass = Person.class;
Class<? extends Person> aClass1 = new Person().getClass();
System.out.println(aClass==personClass);//true
System.out.println(personClass==aClass1);//true
同一个类获取的Class的对象都是同一个
即:每个类编译成的.class文件在入内存被ClassLoader(类加载器)处理只会生成一个Class对象
(插入泛型复习)
类型通配符一般是使用?代替具体的类型参数。例如 List<?> 在逻辑上是List,List 等所有List<具体类型实参>的父类。(?可以表示所有类)
- 表示该通配符所代表的类型是T类型的子类。
- 表示该通配符所代表的类型是T类型的父类。
2.class对象的功能
1.获取功能
1.获取成员变量
| 类型 | 方法名 | 作用 |
|---|---|---|
Field | getField(String name) | 获取指定public修饰的成员变量 |
Field[] | getFields() | 获取全部public修饰的成员变量 |
Field表示的是成员变量类型的对象,它有两个方法:
- a.get(Object o) 获取o对象的成员变量a的值
- a.set(Object o,Object value) 设置o对象的成员变量a的值为value
- a.setAccessible(true)忽略访问权限修饰符的安全检查
| 类型 | 方法名 | 作用 |
|---|---|---|
Field | getDeclaredField(String name) | 获取指定的成员变量 |
Field[] | getDeclaredFields() | 获取所有的成员变量 |
在使用私有的Field对象时,应该写一条语句:field.setAccessible(true)(暴力发射,屏蔽修饰符);才能使用field的方法
不仅成员变量有这个方法,构造方法和成员方法都有暴力反射的方法,屏蔽修饰符。因此,在反射面前,没有什么是公有的私有的
2.获取构造方法
| 类型 | 方法名 传入对应构造函数的参数的类字节码对象 |
|---|---|
Constructor<T> | getConstructor(Class<?>... parameterTypes) |
Constructor<?>[] | getConstructors() |
| 类型 | 方法名 |
|---|---|
Constructor<T> | getDeclaredConstructor(Class<?>... parameterTypes) |
Constructor<?>[] | getDeclaredConstructors() |
构造方法对象的作用是创建对象,constructor.newInstance(传入对应实际参数)
public Person() {
}
public Person(String name, Integer age) {(构造器传入的参数类型都必须是类,不然getConstructor找不到)
this.name = name;
this.age = age;
}
Class<Person> personClass = Person.class;
Constructor<Person> constructor = personClass.getConstructor(String.class, Integer.class);
//利用构造方法对象创建Person对象 构造方法对象.newInstance
Object cqt = constructor.newInstance("cqt", 19);
System.out.println(cqt.toString());
Constructor<Person> constructor1 = personClass.getConstructor();
Person person = constructor1.newInstance();
System.out.println(person.toString());
//空参的构造函数也可以直接使用类字节码对象的newInstance方法 类字节码对象.newInstance
Person person1 = personClass.newInstance();
System.out.println(person1.toString());
3.获取成员方法
| 类型 | 方法名 方法名 参数字节码对象 |
|---|---|
Method | getMethod(String name, Class<?>... parameterTypes) |
Method[] | getMethods() |
| 类型 | 方法名 |
|---|---|
Method | getDeclaredMethod(String name, Class<?>... parameterTypes) |
Method[] | getDeclaredMethods() |
成员方法的作用,使用方法method.invoke(参数);还有getName()获取方法名
public void eat(){
System.out.println("eat.....");
}
public void eat(String food){
System.out.println("eat....."+food);
}
Class<Person> personClass = Person.class;
//获取无参方法,直接传入方法名即可
Method eat = personClass.getMethod("eat");
//运行方法,和成员变量一样,首先得传入对应对象
Person person = new Person();
eat.invoke(person);
//获取有参方法,与构造方法类似
Method eat1 = personClass.getMethod("eat", String.class);
eat1.invoke(person,"rice");
Method[] methods = personClass.getMethods();
for (Method method : methods) {
System.out.println(method);
String name = method.getName();
System.out.println(name);
}
4.获取类名
| 类型 | 方法名 |
|---|---|
String | getName() |
String name = personClass.getName();
System.out.println(name);//domain.Person
3.框架设计
设计一款可以调用任意对象的任意无参方法的框架
1.一个pro.properties文件,里面保存需要运行类的方法的全类名和方法名
className=Person
methodName=eat
2.一个ReflectTest类,里面完成框架的实现
1.读取properties的文件里面的全类名和方法
2.利用Class.forName("全类名")获得类的字节码对象
3.字节码对象getMethod获得方法对象
4.字节码对象new Instance获得一个类对象
5.利用method.invoke(Object O)使用方法
public class ReflectTest {
public static void main(String[] args) throws Exception {
String className;
String methodName;
//获取properties文件的方法 一
Properties properties = new Properties();
//获取类加载器->获取文件字节流
ClassLoader classLoader = ReflectTest.class.getClassLoader();
//调用类加载器的getResourceAsStream方法可以得到文件的字节流->获取文件字节流
InputStream resourceAsStream = classLoader.getResourceAsStream("pro.properties");
//Properties对象不能直接加载文件,需要加载文件的字节流->加载Properties
properties.load(resourceAsStream);
className= properties.getProperty("className");
methodName=properties.getProperty("methodName");
/*
//获取properties文件的方法二
ResourceBundle bundle = ResourceBundle.getBundle("pro.properties");
className = bundle.getString("className");
methodName=bundle.getString("methodName");
*/
Class<?> aClass = Class.forName(className);
Method method = aClass.getMethod(methodName);
Object o = aClass.newInstance();
method.invoke(o);
}
}
\