Java 反射
反射 Reflection
将类的各个组成部分封装为其他对象, 称为反射机制
反射是框架设计的灵魂
优点:
- 可以在程序运行过程中, 操作这些对象 (例如对某个实例一无所知的情况下, 尝试调用其方法)
- 可以解耦, 提高程序的可扩展性
Class 类
每加载一种 class,JVM就为其创建一个 Class 类型的实例,并关联起来。注意:这里的 Class 类型是一个名叫 Class 的 class。它长这样:
public final class Class {
private Class() {}
}
获取一个 class 的 反射对象(Class 实例), 有三种方法:
1) Class.forName(全类名)
-
多用于配置文件, 读取文件, 加载类
2) 类名.Class
- 多用于参数的传递
3) 对象.getClass(): 在 Object 类中定义
- 多用于对象的获取字节码的方式
同一个字节码文件(.class) 在程序里只被加载一次, 不论通过哪一种方式获取都是同一个
demo:
package com.company; public class Main { public static void main(String[] args) throws ClassNotFoundException { // forName() Class cls1 = Class.forName("com.company.Person"); System.out.println(cls1); // .class System.out.println(Person.class); // .getClass() System.out.println(new Person().getClass()); } } class Person { private String name; public void Person(String naem) { this.name = name; } public String getName() { return name; } public void setName(String name) { this.name = name; } }
反射对象的功能
-
获取成员变量
-
Field[] getFields(): 获取所有 public 修饰的成员变量
-
Field getField(String name)
-
Field[] getDeclaredFields(): 获取所有的成员变量 (不考虑修饰符)
-
Field getDeclaredField(String name)
-
-
获取构造方法
-
Constructor<?>[] getConstructors()
-
Constructor<T> getConstructor(Class<?>... parameterTypes)
-
Constructor<?>[] getDeclaredConstructor()
-
Constructor<T> getDeclaredConstructor(Class<?>... parameterTypes)
-
-
获取成员方法
-
Method[] getMethods()
-
Method getMethod(String name, Class<T>... parameterTypes)
-
Method[] getDeclaredMethods()
-
Method[] getDeclaredMethods(String name, Class<T>... parameterTypes)
-
-
获取类名, 方法名
-
String getName()
获取 / 设置字段(Field)的值
: 获取所有的成员变量 (不考虑修饰符)
Field getDeclaredField(String name)
Field 对象操作成员变量:
- 获取值:
- void get(Object obj);
- 设置值:
- void set(Object obj, Object value)
- 忽略访问修饰符的安全检查:
- setAccessible(true)
demo:
import java.lang.reflect.Field; public class Main { public static void main(String[] args) throws Exception { // .class Class pc = Person.class; // 获取所有的字段 (忽略修饰符) Field[] farray = pc.getDeclaredFields(); for (Field field:farray) { System.out.println(field.getName()); //name hobby } // 获取指定名称的字段, 并修改值 Field fh = pc.getDeclaredField("hobby"); Field fn = pc.getDeclaredField("name"); Person p = new Person(); fn.set(p, "johny"); System.out.println(fn.get(p)); // johny // 私有字段需要暴力反射 fh.setAccessible(true); fh.set(p, "我的爱好"); System.out.println(fh.get(p)); // 我的爱好 System.out.println(p.toString()); // Person{name='johny', hobby='我的爱好'} } } class Person { public String name; private String hobby; @Override public String toString() { return "Person{" + "name='" + name + '\'' + ", hobby='" + hobby + '\'' + '}'; } } 运行结果: name hobby johny 我的爱好 Person{name='johny', hobby='我的爱好'}
获取 Constructor 构造器 来创建对象
Constructor<?>[] getConstructors(): 获取所有 public 修饰的构造方法
Constructor<T> getConstructor(Class<?>... parameterTypes)
Constructor<?>[] getDeclaredConstructor(): 获取所有的构造方法 (不考虑修饰符)
Constructor<T> getDeclaredConstructor(Class<?>... parameterTypes)
Constructor 构造器来创建对象:
- public T newInstance(Object ... initargs)
demo:
import java.lang.reflect.Constructor; public class Main { public static void main(String[] args) throws Exception { // .class Class pc = Person.class; // 获取构造器 Constructor c = pc.getConstructor(String.class, String.class); // 创建对象 Object person = c.newInstance("johny", "my hobby"); System.out.println(person); // Person{name='johny', hobby='my hobby'} // 空参构造 Object person2 = pc.newInstance(); System.out.println(person2); // Person{name='null', hobby='null'} } } class Person { public String name; private String hobby; public Person(String name, String hobby) { this.name = name; this.hobby = hobby; } public Person() { } @Override public String toString() { return "Person{" + "name='" + name + '\'' + ", hobby='" + hobby + '\'' + '}'; } }
获取成员方法
Method[] getMethods(): 获取所有 public 修饰的成员方法
Method getMethod(String name, Class<T>... parameterTypes)
Method[] getDeclaredMethods(): 获取所有的成员方法 (不考虑修饰符)
Method[] getDeclaredMethods(String name, Class<T>... parameterTypes)
getName():
- Method.getName(): 获取方法名;
- Class.getName: 获取类名
demo:
import java.lang.reflect.Method; public class Main { public static void main(String[] args) throws Exception { // .class Class pc = Person.class; // 获取指定的方法 Method m1 = pc.getMethod("testMethod"); Method m2 = pc.getDeclaredMethod("argsMethod", String.class); // 调用方法 (和操作字段的形式相似) Person p = new Person(); m1.invoke(p); // 暴力反射 m2.setAccessible(true); m2.invoke(p, "hhhhhh"); // 获取方法名 System.out.println(m1.getName()); // testMethod System.out.println(m2.getName()); // argsMethod // 获取类名 System.out.println(pc.getName()); // com.company.Person } } class Person { public void testMethod(){ System.out.println("测试方法"); // 测试方法 } private void argsMethod(String args){ System.out.println("带有参数的方法, args: " + args); // 带有参数的方法, args: hhhhhh } }
一个反射的案例
实现:
-
properties 配置文件
-
反射机制
步骤:
-
将需要创建的对象的全类名和需要执行的方法定义在配置文件中
-
在程序中加载读取配置文件
-
使用反射技术来加载类文件进内存
-
创建对象
-
执行方法
code:
import java.io.InputStream; import java.lang.reflect.Method; import java.util.Properties; public class Main { public static void main(String[] args) throws Exception { // 创建配置文件对象 Properties pro = new Properties(); // 获取加载 class 目录下的配置文件 ClassLoader clsL = Main.class.getClassLoader(); InputStream is = clsL.getResourceAsStream("pro.properties"); pro.load(is); // 获取配置文件中的参数 String className = pro.getProperty("className"); String methodName = pro.getProperty("methodName"); // 创建对象, System.out.println(className); // com.company.Student Class cls = Class.forName(className); Object obj = cls.newInstance(); // 执行方法 Method m = cls.getMethod(methodName); m.invoke(obj); // i love leaning } } class Student { public void study(){ System.out.println("i love leaning"); } }
pro.properties: (参数不要带引号)
className=com.company.Student
methodName=study
ending ~

浙公网安备 33010602011771号