1. 概述
- 反射是Java中操作对象的一种机制,它允许程序在执行期间获取任何类的内部信息,并直接操作任意对象的内部属性及方法,这使得Java语言具有一定的动态性,运用更加灵活。
- 使用反射可以降低代码的耦合度、实现动态代理等
- 使用反射会降低一定的性能,使用不当会造成很高的资源消耗。
2. Class对象
- Class对象是实现反射的关键,它包含了一个类的完整的结构信息
- 一个类只有一个Class对象
- Clas对象的声明:Class Class对象名
- Class本身也是一个类
- Class对象只能由系统建立
- 同一个类创建的不同实例对象指向同一个Class对象
- 一个Class对象对应一个加载到JVM中的一个.class文件
- 通过反射可以获取类的结构:
- Field:属性(字段)
- Method:方法
- Constructor:构造器
- Superclass:父类对象
- interface:接口
- Annotation:注解
- …
3. 获取Class对象
-
获取Class对象有五种方式:
- 通过”类名.class“获取
- 通过实例对象调用getClass()方法获取
- 通过Class.forName()方法传入类的全名获取
- 通过”类名.TYPE“获取,只适用于基本数据类型
- 利用ClassLoder获取
// 获取类的Class对象 public class ReflectionDemo01 { public static void main(String[] args) throws ClassNotFoundException { // 通过类获取Class对象 Class personClass1 = Person.class; // 通过实例获取Class对象 Class personClass2 = new Person().getClass(); // 通过类的全类名获取Class对象,会抛出一个ClassNotFoundException异常 Class personClass3 = Class.forName("com.example.reflection.Person"); // “类名.TYPE”获取Class对象,只适用于内置基本数据类型 Class integerClass = Integer.TYPE; System.out.println(personClass1.hashCode()); System.out.println(personClass2.hashCode()); System.out.println(personClass3.hashCode()); System.out.println(integerClass.hashCode()); /* 一个结果: 356573597 356573597 356573597 1735600054 (前三个hashCode一样,说明一个类只有一个Class对象) */ } } // 一个实体类pojo class Person { // 属性 private String name; private int age; // 无参构造 public Person() {} // 全参构造 public Person(String name, int age) { this.name = name; this.age = age; } // Set/Get方法 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; } // 重写toString方法 @Override public String toString() { return "Person{" + "name='" + name + '\'' + ", age=" + age + '}'; } }
-
能够获取Class对象的类型:
- class(外部类、成员内部类、静态内部类、局部内部类、匿名内部类)
- interface(接口)
- [](数组)
- enum(枚举)
- @interface(注解)
- primitive_type(基本数据类型)
- void
import java.lang.annotation.ElementType; // 有Class对象的类型 public class ReflectionDemo02 { public static void main(String[] args) throws ClassNotFoundException { // class(外部类、成员内部类、静态内部类、局部内部类、匿名内部类) Class objectClass = Object.class; // interface(接口) Class runnableClass = Runnable.class; // [](数组) Class arrayClass = int[].class; // enum(枚举) Class elementTypeClass = ElementType.class; // @interface(注解) Class overrideClass = Override.class; // primitive_type(基本数据类型) Class integerClass = int.class; // void Class voidClass = void.class; } }
4. 反射获取类的属性、方法、构造器
- 获取属性:
- Class对象.getFields():获取本类所有(包括继承的)公共属性(字段)
- Class对象.getDeclaredFields():获取本类所有属性(字段)
- Class对象.getField():获取本类指定的一个(包括继承的)公共属性(字段)
- Class对象.getDeclaredField():获取本类指定的一个属性(字段)
- 获取方法:
- Class对象.getMethods():获取本类所有(包括继承的)公共方法
- Class对象.getDeclaredMethods():获取本类所有方法
- Class对象.getMethod():获取本类指定的一个(包括继承的)公共方法
- Class对象.getDeclaredMethod():获取本类指定的一个方法
- 获取构造器:
- Class对象.getConstructors():获取本类所有公共构造器
- Class对象.getDeclaredConstructors():获取本类所有构造器
- Class对象.getConstructor():获取本类指定的一个公共构造器
- Class对象.getDeclaredConstructor():获取本类指定的一个构造器
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
// 获取Class对象的属性、方法、构造器
public class ReflectionDemo03 {
public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException, NoSuchMethodException {
// 获取一个Class对象
Class person2Class = Person2.class;
// 属性(字段)
System.out.println("========属性(字段)========");
Field[] fields;
fields = person2Class.getFields(); // 获取本类所有(包括继承的)公共属性(字段)
for (Field field : fields) {
System.out.println("getFields:"+field);
}
fields = person2Class.getDeclaredFields(); // 获取本类所有属性(字段)
for (Field field : fields) {
System.out.println("getDeclaredFields:"+field);
}
Field field;
field = person2Class.getField("alias"); // 获取本类指定的一个(包括继承的)公共属性(字段)
System.out.println("getField:"+field);
field = person2Class.getDeclaredField("name"); // 获取本类指定的一个属性(字段)
System.out.println("getDeclaredField:"+field);
// 方法
System.out.println("========方法========");
Method[] methods;
methods = person2Class.getMethods(); // 获取本类所有(包括继承的)公共方法
for (Method method : methods) {
System.out.println("getMethods:"+method);
}
methods = person2Class.getDeclaredMethods(); // 获取本类所有方法
for (Method method : methods) {
System.out.println("getDeclaredMethods:"+method);
}
Method method;
method = person2Class.getMethod("setName", String.class); // 获取本类指定的一个(包括继承的)公共方法
System.out.println("getMethod:"+method);
method = person2Class.getDeclaredMethod("test"); // 获取本类指定的一个方法
System.out.println("getDeclaredMethod:"+method);
// 构造器
System.out.println("========构造器========");
Constructor[] constructors;
constructors = person2Class.getConstructors(); // 获取本类所有的公共构造器
for (Constructor constructor : constructors) {
System.out.println("getConstructors:"+constructors);
}
constructors = person2Class.getDeclaredConstructors(); // 获取本类所有的构造器
for (Constructor constructor : constructors) {
System.out.println("getDeclaredConstructors:"+constructors);
}
Constructor constructor;
constructor = person2Class.getConstructor(String.class,int.class); // 获取本类指定的一个公共构造器
System.out.println("getConstructor:"+constructor);
constructor = person2Class.getDeclaredConstructor(String.class); // 获取本类指定的一个构造器
System.out.println("getDeclaredConstructor:"+constructor);
/*
结果:
========属性(字段)========
getFields:public java.lang.String com.example.reflection.Person2.alias
getDeclaredFields:private java.lang.String com.example.reflection.Person2.name
getDeclaredFields:public java.lang.String com.example.reflection.Person2.alias
getDeclaredFields:private int com.example.reflection.Person2.age
getField:public java.lang.String com.example.reflection.Person2.alias
getDeclaredField:private java.lang.String com.example.reflection.Person2.name
========方法========
getMethods:public java.lang.String com.example.reflection.Person2.toString()
getMethods:public java.lang.String com.example.reflection.Person2.getName()
getMethods:public void com.example.reflection.Person2.setName(java.lang.String)
getMethods:public int com.example.reflection.Person2.getAge()
getMethods:public void com.example.reflection.Person2.setAge(int)
getMethods:public final void java.lang.Object.wait() throws java.lang.InterruptedException
getMethods:public final void java.lang.Object.wait(long,int) throws java.lang.InterruptedException
getMethods:public final native void java.lang.Object.wait(long) throws java.lang.InterruptedException
getMethods:public boolean java.lang.Object.equals(java.lang.Object)
getMethods:public native int java.lang.Object.hashCode()
getMethods:public final native java.lang.Class java.lang.Object.getClass()
getMethods:public final native void java.lang.Object.notify()
getMethods:public final native void java.lang.Object.notifyAll()
getDeclaredMethods:public java.lang.String com.example.reflection.Person2.toString()
getDeclaredMethods:public java.lang.String com.example.reflection.Person2.getName()
getDeclaredMethods:public void com.example.reflection.Person2.setName(java.lang.String)
getDeclaredMethods:private void com.example.reflection.Person2.test()
getDeclaredMethods:public int com.example.reflection.Person2.getAge()
getDeclaredMethods:public void com.example.reflection.Person2.setAge(int)
getMethod:public void com.example.reflection.Person2.setName(java.lang.String)
getDeclaredMethod:private void com.example.reflection.Person2.test()
========构造器========
getConstructors:[Ljava.lang.reflect.Constructor;@14ae5a5
getConstructors:[Ljava.lang.reflect.Constructor;@14ae5a5
getDeclaredConstructors:[Ljava.lang.reflect.Constructor;@7f31245a
getDeclaredConstructors:[Ljava.lang.reflect.Constructor;@7f31245a
getDeclaredConstructors:[Ljava.lang.reflect.Constructor;@7f31245a
getConstructor:public com.example.reflection.Person2(java.lang.String,int)
getDeclaredConstructor:private com.example.reflection.Person2(java.lang.String)
*/
}
}
class Person2 {
private String name;
public String alias;
private int age;
public Person2() {}
private Person2(String name) {
this.name = name;
}
public Person2(String name, int age) {
this.name = name;
this.age = age;
}
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;
}
private void test() {
System.out.println("test");
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
5. 动态的创建对象及操作
- 通过反射动态创建对象有两种方法:
- 通过Class对象直接创建对象(本质上是调用无参构造器创建对象)
- 先通过Class对象获取构造器,再通过构造器创建对象
- 反射操作方法:Class对象获取方法后,通过invoke(对象,参数值)调用方法
- 反射操作属性:Class对象获取属性后,通过set(对象,参数值)方法给属性赋值
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
// 通过反射动态的创建对象及操作对象(属性、方法)
public class ReflectionDemo04 {
public static void main(String[] args) throws IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException, NoSuchFieldException {
// 获取一个Class对象
Class person3Class = Person3.class;
/* ********创建对象******** */
// 通过Class对象直接创建对象
Person3 person1 = (Person3)person3Class.newInstance(); // 本质上是调用无参构造器创建对象
System.out.println(person1);
// 先通过Class对象获取构造器,再通过构造器创建对象
Constructor constructor = person3Class.getDeclaredConstructor(String.class, int.class);
Person3 person2 = (Person3)constructor.newInstance("小明", 18);
System.out.println(person2);
/* ********操作方法******** */
// 获取方法
Method setName = person3Class.getDeclaredMethod("setName", String.class);
// 通过invoke(对象,参数值)调用方法
setName.invoke(person1,"张三");
System.out.println(person1.getName());
/* ********操作属性(字段)******** */
// 获取属性(字段)
Field age = person3Class.getDeclaredField("age");
// 若属性的访问权限有限制,还需要打开访问权限(关闭Java程序的安全检测):setAccessible(true)
age.setAccessible(true); // setAccessible还可以提高效率
// 通过set(对象,参数值)方法给属性赋值
age.set(person1,20);
System.out.println(person1.getAge());
/*
结果:
Person{name='null', age=0}
Person{name='小明', age=18}
张三
20
*/
}
}
class Person3 {
private String name;
public String alias;
private int age;
public Person3() {}
private Person3(String name) {
this.name = name;
}
public Person3(String name, int age) {
this.name = name;
this.age = age;
}
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;
}
private void test() {
System.out.println("test");
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
6. 反射获取泛型
- 获取泛型:Class对象.getGenericParameterTypes()
import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.List;
import java.util.Map;
// 通过反射获取泛型
public class ReflectionDemo05 {
// 参数值为泛型的方法
public void test01(Map<String,Integer> map, List<String> list) {
System.out.println("test01");
}
// 返回值为泛型的方法
public List<String> test02() {
return null;
}
public static void main(String[] args) throws NoSuchMethodException {
// 获取一个Class对象
Class aClass = ReflectionDemo05.class;
/* ********获取参数值为泛型的方法的泛型信息******** */
// 获取方法
Method test01 = aClass.getMethod("test01", Map.class, List.class);
// 获取泛型参数类型
Type[] genericParameterTypes = test01.getGenericParameterTypes();
for (Type genericParameterType : genericParameterTypes) {
System.out.println(genericParameterType);
if(genericParameterType instanceof ParameterizedType) {
Type[] actualTypeArguments = ((ParameterizedType) genericParameterType).getActualTypeArguments();
for (Type actualTypeArgument : actualTypeArguments) {
System.out.println(actualTypeArgument);
}
}
}
/* ********获取返回值为泛型的方法的泛型信息******** */
// 获取方法
Method test02 = aClass.getMethod("test02", null);
// 获取泛型参数类型
Type genericReturnType = test02.getGenericReturnType();
System.out.println(genericReturnType);
if(genericReturnType instanceof ParameterizedType) {
Type[] actualTypeArguments = ((ParameterizedType) genericReturnType).getActualTypeArguments();
for (Type actualTypeArgument : actualTypeArguments) {
System.out.println(actualTypeArgument);
}
}
/*
结果:
java.util.Map<java.lang.String, java.lang.Integer>
class java.lang.String
class java.lang.Integer
java.util.List<java.lang.String>
class java.lang.String
java.util.List<java.lang.String>
class java.lang.String
*/
}
}
7. 反射获取注解
- 获取注解:Class对象.getAnnotations()
import java.lang.annotation.*;
import java.lang.reflect.Field;
// 通过反射获取注解
public class ReflectionDemo06 {
public static void main(String[] args) {
// 获取一个Class对象
Class studentClass = Student.class;
/* ********获取类的注解******** */
// 获取注解
Annotation[] annotations = studentClass.getAnnotations();
System.out.println(annotations);
// 获取注解的值
for (Annotation annotation : annotations) {
AnnoTable annoTable = (AnnoTable)annotation;
System.out.println(annoTable.value());
}
/* ********获取属性(字段)的注解******** */
// 获取字段
Field[] fields = studentClass.getDeclaredFields();
for (Field field : fields) {
// 获取注解
Annotation[] annotations1 = field.getAnnotations();
System.out.println(annotations1);
// 获取注解的值
for (Annotation annotation : annotations1) {
AnnoField annoField = (AnnoField)annotation;
System.out.println(annoField.columnName());
System.out.println(annoField.type());
System.out.println(annoField.length());
}
}
/*
结果:
[Ljava.lang.annotation.Annotation;@60e53b93
student
[Ljava.lang.annotation.Annotation;@6f94fa3e
id
int
8
[Ljava.lang.annotation.Annotation;@5e481248
name
varchar
8
[Ljava.lang.annotation.Annotation;@66d3c617
age
int
4
*/
}
}
@AnnoTable("student")
class Student {
@AnnoField(columnName = "id", type = "int", length = 8)
private int id;
@AnnoField(columnName = "name", type = "varchar", length = 8)
private String name;
@AnnoField(columnName = "age", type = "int", length = 4)
private int age;
public Student() {}
public Student(int id, String name, int age) {
this.id = id;
this.name = name;
this.age = age;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
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;
}
@Override
public String toString() {
return "Student{" +
"id=" + id +
", name='" + name + '\'' +
", age=" + age +
'}';
}
}
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@interface AnnoTable {
String value();
}
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@interface AnnoField {
String columnName();
String type();
int length();
}