反射详解
一、什么是反射?
在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意方法和属性;这种动态获取信息以及动态调用对象方法的功能称为java语言的反射机制。
二、与反射相关的类
类名 | 用途 |
---|---|
Class类 | 代表类的实体,在运行的Java应用程序中表示类和接口 |
Field类 | 代表类的成员变量(成员变量也称为类的属性) |
Method类 | 代表类的方法 |
Constructor类 | 代表类的构造方法 |
三、Class类
public final class Class<T> implements java.io.Serializable, GenericDeclaration,Type,AnnotatedElement
{}
Class类表示正在运行的Java应用程序中的类和接口。
1、获取Class类实例
以下知识点代码:
public class Person {
//私有属性
private String name;
//公有属性
public int age;
/**
* 公有无参构造
*/
public Person() {
}
/**
* 私有构造
* @param name
*/
private Person(String name) {
this.name = name;
}
/**
* 公有构造
* @param name 姓名
* @param age 年龄
*/
public Person(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public Person setName(String name) {
this.name = name;
return this;
}
public int getAge() {
return age;
}
public Person setAge(int age) {
this.age = age;
return this;
}
/**
* 公有方法
*/
public void show() {
System.out.println("I am a good gay!");
}
/**
* 私有方法
* @return 国籍
*/
private String showNation() {
System.out.println("I am an American");
return "America";
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
1)通过类的Class属性
Class pClass1=Person.class;
//class org.lc.reflect_test.Person
System.out.println(pClass1);
2)通过类的实例的getClass()方法
Person person=new Person();
Class pClass2 = person.getClass();
//class org.lc.reflect_test.Person
System.out.println(pClass2);
3)通过Class.forName获取
Class pClass3= Class.forName("org.lc.reflect_test.Person");
//class java.lang.String
Class sClass= Class.forName("java.lang.String");
System.out.println(sClass);
//class org.lc.reflect_test.Person
4)通过类加载器获取
//通过当前线程获取类加载器
Class pClass4 = Thread.currentThread().getContextClassLoader().loadClass("org.lc.reflect_test.Person");
//通过当前启动类获取类加载器
Class pClass5 = T1.class.getClassLoader().loadClass("org.lc.reflect_test.Person");
//class org.lc.reflect_test.Person
System.out.println(pClass4);
//class org.lc.reflect_test.Person
System.out.println(pClass5);
5)总结
//true
System.out.println((pClass1==pClass2) & (pClass3==pClass4));
通过反射获取到的运行时的类的Class对象时,它们的实例都是相同的。在内存中保存一份,无需重复创建。
2、可以获取Class的结构实例
public static void main(String[] args) throws ClassNotFoundException {
//类
Class c1 = Object.class;
//接口
Class c2 = Comparable.class;
//一维数组
Class c3 = String[].class;
//二维数组
Class c4 = int[][].class;
//枚举
Class c5 = ElementType.class;
//基本类型
Class c6 = int.class;
//无返回类型
Class c7 = void.class;
//获取Class类的自身Class
Class c8 = Class.class;
int[] a = new int[10];
int[] b = new int[100];
//true 只要元素类型和维度一致,就是同一个Class
System.out.println(a.getClass()==b.getClass());
}
3、获取运行时类的实例对象
通过Class中的newInstance()方法获取实例对象
- 注意 该无参构造器不能为私有,因为
newInstance()
方法默认的还是调用的无参构造器
public static void main(String[] args) throws IOException, IllegalAccessException, InstantiationException {
Class personClass = Person.class;
Person o = (Person)personClass.newInstance();
//Person{name='null', age=0}
System.out.println(o);
}
以下知识点代码:
Person.java
@MyAnnotation(value = "哈哈哈") public class Person extends Creature<String> implements Comparable<String>,MyInterface{ private String name; protected Date birthday; int age; public int id; public Person() { } @MyAnnotation(value = "呵呵呵") private Person(String name) { this.name=name; } public Person(String name, int age) { this.name=name; this.age=age; } @MyAnnotation(value = "啧啧啧") private String showNation(String nation) throws NullPointerException,IndexOutOfBoundsException{ System.out.println("my nationality is:" + nation); return nation; } public String play(String interest) { System.out.println("my interest is :"+interest); return interest; } private static void selfDescription() { System.out.println(" i am a good gay"); } @Override public int compareTo(String o) { return 0; } @Override public void info() { System.out.println("i am a people"); } @Override public String toString() { return "Person{" + "name='" + name + '\'' + ", birthday=" + birthday + ", age=" + age + ", id=" + id + '}'; } }
Creature.java
public class Creature<T> implements Serializable { private char gender; public double weight; private void breath() { System.out.println("animals breath"); } public void eat() { System.out.println("animals eating"); } }
MyInterface.java
public interface MyInterface { void info(); }
MyAnnotation.java
//target:可用在类上,字段,方法,参数,构造器 ,本地局部变量上 @Target({TYPE, FIELD, METHOD, PARAMETER, CONSTRUCTOR, LOCAL_VARIABLE}) //在运行时可以获得此注解 @Retention(RetentionPolicy.RUNTIME) public @interface MyAnnotation { //定义属性value ,默认值hello String value() default "hello"; }
4、 获取属性
①获取当前类和父类的所有public属性
Class personClass = Person.class;
//获取所有的属性
//只能获取属性为public的,且从父类继承的属性也为public的
Field[] fields = personClass.getFields();
for (Field field : fields) {
//public int org.lc.reflect_01.Person.id
//public double org.lc.reflect_01.Creature.weight
System.out.println(field);
}
②获取所有本类的所有(任意访问修饰符)属性(不包括父类的属性)
Class personClass = Person.class;
//获取所有属性
//只能获取本类的中的所有属性(任意访问修饰符)
Field[] declaredFields = personClass.getDeclaredFields();
for (Field field : declaredFields) {
//private java.lang.String org.lc.reflect_01.Person.name
//protected java.util.Date org.lc.reflect_01.Person.birthday
//int org.lc.reflect_01.Person.age
//public int org.lc.reflect_01.Person.id
System.out.println(field);
}
5、获取方法
①获取所有本类中和父类中的所有public方法 (只能为public)
Class personClass=Person.class;
Method[] methods = personClass.getMethods();
for (Method method : methods) {
//public int org.lc.reflect_01.Person.compareTo(java.lang.String)
//public int org.lc.reflect_01.Person.compareTo(java.lang.Object)
//public void org.lc.reflect_01.Person.info()
//public java.lang.String org.lc.reflect_01.Person.play(java.lang.String)
//....
System.out.println(method);
}
②获取本类中的所有(任意访问修饰符)方法(不包括父类的方法)
Class personClass=Person.class;
Method[] declaredMethods = personClass.getDeclaredMethods();
for (Method method : declaredMethods) {
//public int org.lc.reflect_01.Person.compareTo(java.lang.String)
//public int org.lc.reflect_01.Person.compareTo(java.lang.Object)
//public java.lang.String org.lc.reflect_01.Person.play(java.lang.String)
//public void org.lc.reflect_01.Person.info()
//private java.lang.String org.lc.reflect_01.Person.showNation(java.lang.String)
System.out.println(method);
}
6、获取构造器
①获取本类中所有为public的构造器
Class personClass = Person.class;
//获取当前运行类的public修饰的构造器
Constructor[] constructors = personClass.getConstructors();
for (Constructor constructor : constructors) {
System.out.println(constructor);
}
public org.lc.reflect_01.Person(java.lang.String,int)
public org.lc.reflect_01.Person()
②获取本类中所有的构造器(任意访问修饰符)
Class personClass = Person.class;
//获取当前类的所有的构造器(任何访问修饰符)
Constructor[] declaredConstructors = personClass.getDeclaredConstructors();
for (Constructor constructor : declaredConstructors) {
System.out.println(constructor);
}
public org.lc.reflect_01.Person(java.lang.String,int)
private org.lc.reflect_01.Person(java.lang.String)
public org.lc.reflect_01.Person()
7、获取父类
8、获取带泛型的父类
9、获取带泛型父类的泛型
Class personClass = Person.class;
//1、获取父类
Class superclass = personClass.getSuperclass();
//class org.lc.reflect_01.Creature
System.out.println(superclass);
System.out.println("---------");
//2、取带泛型的父类
Type genericSuperclass = personClass.getGenericSuperclass();
//org.lc.reflect_01.Creature<java.lang.String>
System.out.println(genericSuperclass.getTypeName());
System.out.println("-----");
//获取带泛型父类的泛型
Type genericSuperclass1 = personClass.getGenericSuperclass();
ParameterizedType parameterizedType= (ParameterizedType) genericSuperclass1;
//父类的泛型,可能有多个 Creature<T,V,N>
Type[] actualTypeArguments = parameterizedType.getActualTypeArguments();
//[class java.lang.String]
System.out.println(Arrays.toString(actualTypeArguments));
11、 获取类实现的接口
Class personClass = Person.class;
//1、获取当前类的实现接口
Class[] interfaces = personClass.getInterfaces();
//[interface java.lang.Comparable, interface org.lc.reflect_01.MyInterface]
System.out.println(Arrays.toString(interfaces));
//2、获取当前类的父类实现的接口
Class[] interfaces1 = personClass.getSuperclass().getInterfaces();
//[interface java.io.Serializable]
System.out.println(Arrays.toString(interfaces1));
12、获取当前类的包名
13、获取当前类的所有注解
Class personClass = Person.class;
//1、获取当前类的包名
Package aPackage = personClass.getPackage();
//package org.lc.reflect_01
System.out.println(aPackage);
System.out.println("----------");
//2、获取当前类的所有注解
Annotation[] annotations = personClass.getAnnotations();
//[@org.lc.reflect_01.MyAnnotation(value=哈哈哈)]
System.out.println(Arrays.toString(annotations));
四、Field属性类
1、获取访问修饰符
getModifiers()
2、获取数据类型
getType()
3、获取变量名
getName()
public static void main(String[] args) {
Class personClass = Person.class;
for (Field field : personClass.getDeclaredFields()) {
//1、访问修饰符
//访问修饰符对应的整数
int modifiers = field.getModifiers();
//private 对应的整数为2
//protected 对应的整数4
// 默认不写 对应的整数为0
//public 对应的整数为1
//将访问修饰符转为真正的字符串
System.out.print("访问修饰符:"+modifiers+"="+Modifier.toString(modifiers));
//2、获取数据类型
Class type = field.getType();
System.out.print("\t类型名:"+type.getName());
//3、获取变量名
String name = field.getName();
System.out.println("\t变量名:"+name);
}
}
访问修饰符:2=private 类型名:java.lang.String 变量名:name
访问修饰符:4=protected 类型名:java.util.Date 变量名:birthday
访问修饰符:0= 类型名:int 变量名:age
访问修饰符:1=public 类型名:int 变量名:id
五、Method方法类
1、获取在该方法上的所有注解
2、获取访问修饰符
3、返回值类型
4、方法名
5、获取形参列表
6、获取所有的异常
public static void main(String[] args) {
Class personClass=Person.class;
Method[] declaredMethods = personClass.getDeclaredMethods();
for (Method method : declaredMethods) {
//1、获取方法上所有的注解
//注意这里声明的注解 必须 @Retention(RetentionPolicy.RUNTIME) 运行时可获取
Annotation[] annotations = method.getAnnotations();
for (Annotation annotation : annotations) {
System.out.print("注解:"+annotation);
}
//2、获取访问修饰符
System.out.print("\t"+Modifier.toString(method.getModifiers()));
//3、返回值类型
System.out.print("\t"+method.getReturnType().getName());
//4、方法名
System.out.print("\t"+method.getName());
//5、获取形参列表
Class[] parameterTypes = method.getParameterTypes();
//若没有参数则不获取参数
if (!(parameterTypes == null || parameterTypes.length == 0)) {
System.out.print("(");
for (int i = 0; i < parameterTypes.length; i++) {
//变量到最后一个参数换行
if (i == parameterTypes.length - 1) {
System.out.print(parameterTypes[i].getName()+" arg_"+i+")");
break;
}
System.out.print(parameterTypes[i].getName()+" arg_"+i+",");
}
}else{
System.out.println();
}
//6、获取所有的异常
Class[] exceptionTypes = method.getExceptionTypes();
if (!(exceptionTypes == null || exceptionTypes.length == 0)) {
System.out.print(" throws ");
for (int i = 0; i < exceptionTypes.length; i++) {
if (i == exceptionTypes.length - 1) {
System.out.println(exceptionTypes[i].getName());
break;
}
System.out.print(exceptionTypes[i].getName()+",");
}
}else{
System.out.println();
}
}
}
public int compareTo(java.lang.String arg_0)
public volatile int compareTo(java.lang.Object arg_0)
public java.lang.String play(java.lang.String arg_0)
public void info
注解:@org.lc.reflect_01.MyAnnotation(value=啧啧啧) private java.lang.String showNation(java.lang.String arg_0,int arg_1) throws java.lang.NullPointerException,java.lang.IndexOutOfBoundsException
六、调用运行时类中指定结构:属性、方法、构造器
1、调用属性
getDeclaredField(String name)
(不适用)
①通过 //1、获取Class对象
Class personClass = Person.class;
//2、通过Class对象创建类的实例对象
Person person = (Person)personClass.newInstance();
//3、获取属性(获取的为本类和父类的public属性) 注意:此时获取的属性必须为public
Field id = personClass.getField("id");
//4、为该属性设置值
id.set(person, 11);
//5、获取该属性的值
int x = (int)id.get(person);
System.out.println(x);
getField(String name)
(常用)
②通过 //1、获取Class对象
Class personClass = Person.class;
//2、通过Class对象创建类的实例对象
Person person = (Person)personClass.newInstance();
//3、获取属性(获取的为本类的所有属性)
Field name = personClass.getDeclaredField("name");
//3'当获取的属性为private私有的属性时,进行访问设值的时候需要设置访问权限setAccessible为true
name.setAccessible(true);
//4、为该属性设置值
name.set(person, "张三");
//5、获取该属性的值
String x = (String)name.get(person);
System.out.println(x);
2、调用方法
public Method getDeclaredMethod(String name, Class<?>... parameterTypes)
- name:要获得的方法名称
- parameterTypes:参数列表对应的Class类
public Object invoke(Object obj, Object... args)
参数
obj:实例对象
args:传入的实际的方法参数
返回值
- 调用该方法的返回值
①调用实例方法
//1、获取Class对象
Class personClass = Person.class;
//2、通过Class对象创建类的实例对象
Person person = (Person)personClass.newInstance();
//3、获取方法
Method showNation = personClass.getDeclaredMethod("showNation", String.class);
//3' 当获取的方法为private私有类型时,同理也必须设置setAccessible为true.代表可访问
showNation.setAccessible(true);
//4、回调方法并获取返回值
Object cn = showNation.invoke(person, "CN");
//CN
System.out.println(cn);
②调用静态方法
//1、获取Class对象
Class personClass = Person.class;
//2、通过Class对象创建类的实例对象
Person person = (Person)personClass.newInstance();
//3、获取方法
Method selfDescription = personClass.getDeclaredMethod("selfDescription");
//3'、使private方法可访问
selfDescription.setAccessible(true);
//回调方法的实例类型可传null或者selfDescription.invoke(null);
Object invoke = selfDescription.invoke(Person.class);
//若方法没有返回值则返回 null
//null
System.out.println(invoke);
③调用构造器
newInstance()
方法 (常用)
1)使用Class的 //1、获取Class对象
Class personClass = Person.class;
//2、直接通过newInstance回去默认的无参构造器
Person person = (Person) personClass.newInstance();
System.out.println(person);
getDeclaredConstructor
(不常用)
2)使用 //1、获取Class对象
Class personClass = Person.class;
//2、获取无参的构造器
// Constructor declaredConstructor = personClass.getDeclaredConstructor();
//2、获取有参构造器,传入指定的参数的Class类
Constructor declaredConstructor = personClass.getDeclaredConstructor(String.class);
//3若构造器为private私有的,则需要设置访问权限为true
declaredConstructor.setAccessible(true);
//4、若为无参构造器则无需传入参数,有参构造器则需要传入实参值
Person person = (Person) declaredConstructor.newInstance("张三");
//Person{name='张三', birthday=null, age=0, id=0}
System.out.println(person);