一、java的反射机制提供的功能:
- 在运行时判断任意一个对象所属的类
- 在运行时构造任意一个类的对象
- 在运行时判断任意一个类所具有的成员变量和方法
- 运行时获取泛型信息
- 在运行时调用任意一个对象的成员变量和方法
- 在运行时处理注解
- 生成动态代理
二、反射相关的主要API:
-
java.lang.Class : 代表一个类
1.程序经过javac.exe命令以后,会生成一个或多个字节码文件(.calss后缀)。
接着我们使用就java.exe命令对字节码文件进行解释运行,此过程相当于将某个字节码文件加载带内存中。上述过程称之为类的加载。
加载到内存中的类为运行时的类,运行时的类就作为Class的一个实例2.获取Class的实例方式
方式1(掌握):Class<> c = 类名.class
方式2(掌握):类名 对象名 = new 类名()
Class c = 对象名.getClass()
方式3(掌握):Class c = Class.forName(String classPath)(注意:会抛异常)3.那些类型可以有Class对象
1.class :外部类、成员内部类、静态内部类、局部内部类、匿名类
2.interface : 接口
3.[] : 数组
4.enum : 枚举
5.annotation : 注解@interface
6.primitive type : 基本数据类型
7.void -
java.lang.reflect.Constructor : 代表类的构造器
1.获取当前类的public构造器
Constructor[] 构造器对象名 = Class的实例名.getConstructors()2.获取当前类的所有的构造器
Constructor[] 构造器对象名 = Class的实例名.getDecleardConstructors()3.获取指定的构造器
Constructor 构造器对象名 = Class的实例名.getConstructor(参数1类型.class,…) -
创建运行时类的实例对象
方式1:使用的是类中的指定的构造器创建的类对象【不常用】
Constructor 构造器对象名 = Class的实例名.getConstructor(参数1类型.class,…) 获取指定构造器对象
构造器对象名.setAccessible(true) 表示允许操作private成员
Object obj = 构造器对象名.newInstance(参数1,…) 通过指定构造器对象创建类的对象方式2:这样直接使用的是类中的空参构造器创建的类对象【常用】
Object obj = Class的实例名.newInstance() -
java.lang.reflect.Field : 代表类的成员变量
1.获取到类中public属性(包含父类)【不建议使用
方法1:
Field[] f = Class的实例名.getFields()
方法2:
Field f = Class的实例名.getField(属性名)2.获取到类中自己的所有属性(不含有父类):【建议使用】
方法1:
Field[] f = Class的实例名.getDeclaredFields()
方法2:
Field f = Class的实例名.getDeclaredField(属性名)3.获取到属性的权限修饰符、数据类型、变量名。(了解)
int f.getModifiers() : 权限修饰符(0代表默认,1代表public,2代表private)Class f.getType().getName() : 数据类型
String f.getName() : 变量名
4.设置、获取 属性的值
非静态的属性:
前提操作:f.setAccessible(true) 表示允许操作private成员
设置:f.set(obj,value) obj表示给哪个对象的属性设置,value为设置的值
获取:f.get(obj) obj表示获取哪个对象的属性值,有返回值静态的属性:
前提操作:f.setAccessible(true) 表示允许操作private成员
设置:f.set(类.class,value) 类.class:表示当前类的静态,value为设置的值
获取:f.get(类.class) 类.class:表示当前类的静态,有返回值 -
java.lang.reflect.Method : 代表类的方法
1.获取到类中public方法(包含父类)【不推荐使用】
方法1:
Method[] m = Class的实例名.getMethods()方法2:
Method m = Class的实例名.getMethod(方法名,形参列表(默认为空))2.获取到类中自己的所有方法(不含有父类)【推荐使用】
方法1:
Method[] m = Class的实例名.getDeclaredMethods()
方法2:
Method m = Class的实例名.getDeclaredMethod(方法名,形参列表(默认为空)) 例:String型的形参列表:String.class3.调用方法
非静态方法:
前提操作:m.setAccessible(true) 表示允许操作private成员
调用:m.invoke(obj,实参1,…) obj表示给哪个对象的属性设置,实参对应的方法的形参。invoke()返回值就是类中方法的返回值静态方法:
前提操作:m.setAccessible(true) 表示允许操作private成员
调用:m.invoke(类.class,实参1,…) 类.class:表示当前类的静态,实参对应的方法的形参。invoke()返回值就是类中方法的返回值 -
…
三、方法的补充:
1.获取运行时类的父类
Class sp = Class的实例名.getSuperclass()
2.获取运行时类的带泛型的父类
Type sgp = Class的实例名.getGenericSuperclass()
3.获取运行时类的带泛型的父类的泛型(需要4步)
①Type sgp = Class的实例名.getGenericSuperclass(). : 获取运行时类的带泛型的父类
②ParameterizedType paramType = (parameterizedType)sgp : 强转
③Type[] actTypeArg = paramType.getActualTypeArguments() : 获取到实际的类型参数(也就是泛型)
④actTypeArg.getTypeName() : 获取泛型名
4.获取到当前运行时类的接口
Class[] interface = Class的实例名.getInterface()
如果想获取到其父类的接口,那么得到父类然后在getInterface()
5.获取当前运行时类所在的包
Package pk = Class的实例名.getPackage()
6.获取当前运行时类声明的注解
Annotation[] anno = Class的实例名.getAnnotations()
四、使用反射之前能对Person的操作:
- 创建Person类的实例化
- 通过对象当调用类中的非private类型的属性、方法
五、使用反射之后能对Person的操作
- 创建Person类的实例化(调用构造器)
- 调用Person中的属性
- 调用Person中的方法
- 调用Person中private的属性、方法、构造器
上述过程的相关代码举例:
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
public class ReflectionTest {
public static void main(String[] args) throws Exception {
Person p1 = new Person("Joney",18);
System.out.println(p1.age);
System.out.println(p1.toString()+"\n");
System.out.println("**************************");
//1.通过反射创建Person的对象obj
Class c = Person.class;
Object newInstance = c.newInstance();
System.out.println(newInstance.toString());
//通过getConstructor(参数1类型.class,...)获取构造器对象
Constructor constructor = c.getConstructor(String.class,int.class);//获取构造器对象
Object obj = constructor.newInstance("Mike",22);//通过构造器对象实例化Person
//通过对象调用Person的方法
System.out.println(obj.toString()+"\n"); //通过反射创建Person的对象obj调用方法
//2.调属性
Field age = c.getDeclaredField("age"); //通过getDeclaredField("属性")获取到该属性的对象
age.set(obj, 20); //修改属性值
System.out.println(obj.toString()+"\n");
//3.调方法
Method print = c.getDeclaredMethod("print");//通过getDeclaredMethod()获取到该方法的对象
print.invoke(obj); //调用该print()
System.out.println();
//4.调用private结构
//4.1通过getDeclaredConstructor((参数1类型.class,...)获取私有构造器对象
Constructor privateConstructor = c.getDeclaredConstructor(String.class);//获取私有构造器对象
privateConstructor.setAccessible(true);
Object obj2 = privateConstructor.newInstance("Tom");//创建对象
System.out.println(obj2.toString());
//4.2通过getDeclaredField("属性名")获取到私有属性的对象
Field name = c.getDeclaredField("name");
name.setAccessible(true);
name.set(obj2, "Aimy");//修改属性值
System.out.println(obj2.toString());
}
}
class Person{
private String name;
public int age;
public Person(String name, int age) {
super();
this.name = name;
this.age = age;
}
private Person(String name) {
super();
this.name = name;
}
public Person() {
super();
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public void print() {
System.out.println("我是Person的print()");
}
@Override
public String toString() {
return "Person [name=" + name + ", age=" + age + "]";
}
}