java反射

反射

  • 反射是框架设计的灵魂

  • 框架:半成品软件。可以在框架的基础上进行软件开发,简化编码

  • 反射:将类的各个组成部分封装为其他对象,这就是反射机制

    • 可以在程序运行过程中,操作这些对象。
    • 可以解耦,提高程序的可扩展性。

Java代码的三个阶段

获取Class对象的方式

  1. Class.forname(“全类名”):将字节码文件加载进内存,返回class对象。
    • 多用于配置文件,将类名定义在配置文件中。读取文件,加载类
  2. 类名.class:通过类名的属性class获取
    • 多用于参数的传递
  3. 对象.getclass():在Object类中定义
    • 多用于对象的获取字节码的方式
  4. *注意:同一个字节码文件(.class)在一次程序运行过程中,只会被加载一次,不论通过哪一种方式获取的class对象都是同一个。**
1
2
3
4
5
6
7
8
9
10
11
12
13
14
public class ReflectDemo {
public static void main(String[] args) throws Exception {
Class aClass = Class.forName("hxx.domain.Person"); //包名.类名
System.out.println(aClass);
Class aClass1 = Person.class;
System.out.println(aClass1);
Person p = new Person();
Class aClass2 = p.getClass();
System.out.println(aClass2);
//比较三个对象
System.out.println(aClass == aClass1);// true
System.out.println(aClass == aClass2);// true
}
}

class对象功能

  • 获取成员变量
    • Field[] getfields() // 获取public修饰的成员变量
    • Field[] getfields(String name) // 获取指定名称的public修饰的成员变量
    • Field[] getDeclaredFields() // 获取所有的成员变量
    • Field[] getDeclaredFields(String name) // 获取指定名称的成员变量
    • 操作:可以设置set和获取值get
    • 暴力反射:当访问非共有成员变量时,使用setAccessiable(true)忽略访问权限修饰符的安全检查
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
public static void main(String[] args) throws Exception {
//获取Person的class对象
Class personClass = Person.class;

Field[] fields = personClass.getFields();
for (Field field : fields) {
System.out.println(field);
}

Person person = new Person();
Field a = personClass.getField("a");
a.set(person,10);
Object o = a.get(person);
System.out.println(o);

Field[] declaredFields = personClass.getDeclaredFields();
for (Field declaredField : declaredFields) {
System.out.println(declaredField);
}

Field d = personClass.getDeclaredField("d"); //访问了非公有成员
//忽略访问权限修饰符的安全检查
d.setAccessible(true); //暴力反射
o = d.get(person);
System.out.println(o);
}
  • 获取构造方法
    • Constructor<?>[] getConstructors()
    • Constructor < T > getConstructor(类 <?> … parameterTypes) //
    • Constructor<?>[] geDeclaredtConstructors()
    • Constructor < T > getDeclaredConstructor(类 <?> … parameterTypes)
    • 获取到构造方法来创建对象:T newInstance(Object … initargs)
1
2
3
4
5
6
7
8
9
10
11
public static void main(String[] args) throws Exception {
//获取Person的class对象
Class personClass = Person.class;
Constructor constructor = personClass.getConstructor(String.class, int.class);
System.out.println(constructor);
Object obj = constructor.newInstance("hxx", 20); // 创建对象
System.out.println(obj);

// 空参数构造方法创建对象时,使用Class对象的newInstance方法初始化对象
//Object o1 = personClass.newInstance();
}
  • 获取成员方法
    • Method<?>[] getMethods()
    • Method< T > getMethod(String name,类 <?> … parameterTypes)
    • Method<?>[] geDeclaredtMethods()
    • Method< T > getDeclaredMethodString name,(类 <?> … parameterTypes)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public static void main(String[] args) throws Exception {
//获取Person的class对象
Class personClass = Person.class;
Person person = new Person();
/*
* 获取成员方法,传入方法名、该方法的参数列表
* */
Method setAge = personClass.getMethod("setAge", int.class);
//执行方法,Object invoke(Object obj,Object...args)
setAge.invoke(person,10);
System.out.println(person);

Method[] methods = personClass.getMethods(); // 获取所有的public修饰的方法和该类的父类的共有方法
for (Method method : methods) {
System.out.println(method.getName()); //获取方法名
}
}
  • 获取类名
    • String getname()
1
System.out.println(personClass.getName()); //获取类名

案例

  • 需求:写一个“框架”,可以帮我们创建任意类的对象,并且执行其中任意方法

  • 实现

    • 定义两个类
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    public class Person {
    public void eat(){
    System.out.println("person eat");
    }
    }
    public class Student {
    public void sleep(){
    System.out.println("Student sleep");
    }
    }
    • 将需要创建的对象的全类名和需要执行的方法定义在配置文件中
    1
    2
    3
    //配置文件为pro.properties
    className=hxx.domain.Student //选择类
    methodName=sleep //选择类中要执行的方法
    • 在程序中加载读取配置文件
    • 使用反射技术来加载类文件
    • 创建对象
    • 执行方法
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
public class ReflectTest {
public static void main(String[] args) throws Exception {
// 创建Properties对象
Properties properties = new Properties();
//加载配置文件,转换为一个集合
//获取class目录下的配置文件的字节流
ClassLoader classLoader = ReflectTest.class.getClassLoader();
InputStream is = classLoader.getResourceAsStream("pro.properties");
properties.load(is);
//获取配置文件的内容
String className = properties.getProperty("className");
String methodName = properties.getProperty("methodName");

//加载该类进内存
Class cls = Class.forName(className);
//创建类对象
//获取构造方法
Constructor constructor = cls.getConstructor();// 空参构造方法
Object obj = constructor.newInstance();
//获取方法对象
Method method = cls.getMethod(methodName);
method.invoke(obj);
}
}