Class
和class
是不同的两个点,Class本身也是一个类型,和String、List本身没有什么差异, 而class
只是一个关键字。Class可以理解为某个类型的元信息,包含其对应的构造函数(Constructor)
、方法(Method)
、属性(Field)
以及其他相关信息(比如注解等信息)。
通过反射,也就是操作Class具体的对象,我们可以在运行期获取一个类型中各种访问权限的构造器、方法、属性,灵活的去创建某个类型的实例,调用其方法,设置其属性。可以认为这是Java提供的一个外挂,让我们可以做一些常规操作不能做到的操作。
Class的实例是由JVM进行创建的,并不能手动创建,只能进行获取,通过不同方式获取的Class实例都是同一个实例。
获取Class对象的方法有三种,如下代码示例
package com.kimzing.demo.reflect.demo;
import com.kimzing.demo.reflect.PersonReflect;
/**
* 获取Class对象的三种方式.
*
* @author KimZing - [email protected]
* @since 2020/3/31 11:28
*/
public class ClassDemo {
public static void main(String[] args) throws ClassNotFoundException {
// 通过实例获取,需要导入对应包并创建实例
PersonReflect personReflect = new PersonReflect();
Class<? extends PersonReflect> clazz1 = personReflect.getClass();
// 通过类获取,需要导入对应包
Class<PersonReflect> clazz2 = PersonReflect.class;
// 通过全路径获取,最灵活的方式,无需任何依赖,只需要传入包路径+类名即可
Class<?> clazz3 = Class.forName("com.kimzing.demo.reflect.PersonReflect");
// 结果为true,代表获取的Class对象都是同一个实例
System.out.println(clazz1 == clazz2);
System.out.println(clazz2 == clazz3);
}
}
构造器、方法、属性都具有public、protected、default、private等权限修饰符。
Class对象包含类型的Constructor、Method、Field等信息,只要调用Class的相应方法即可获取,而这些方法的命名是具有共同的特征的。
获取所有公开的构造器使用getConstructors()
。获取所有(包含public/protected/default/private)的构造器使用getDeclaredConstructors()
获取所有公开的方法使用getMethods()
,同时会返回父类的所有公开方法。获取所有访问权限的方法使用getDeclaredMethods()
。
获取所有公开权限的属性getFields()
,同时会返回父类的公开属性。获取所有访问权限的属性.getDeclaredFields()
上面是获取的结果都是数组,也可以单独获取某个构造器、方法、属性
获取公开的构造器getConstructor(Class>... parameterTypes)
,parameterTypes指的是构造器的参数。获取非公开的构造器getDeclaredConstructor(Class>... parameterTypes)
获取某个公开的方法getMethod(String name, Class>... parameterTypes)
,name指的是对应的方法名,而parameterTypes指的是对应的方法参数。获取非公开的某个方法使用getDeclaredMethod(String name, Class>... parameterTypes)
。
获取某个公开的属性getField(String name)
,name指的是属性的名称。获取非公开的属性getDeclaredField(String name)
。
总结一下:
get{元信息名}s
getDeclared{元信息名}s
调用Constructor实例的newInstance(Object ... initargs)
方法执行对应的构造函数,如果构造器是非公开的,那么需要先设置setAccessible(boolean flag)
为true
才可以调用。
调用Method实例的invoke(Object obj, Object... args)
方法执行对应的方法,obj指的是要执行方法的主体,也就是哪个对象执行这个方法,而args则是对应的参数。如果该方法是静态方法,obj可为null。如果方法是非公开的,那么需要先设置setAccessible(boolean flag)
为true
才可以调用。
调用Field实例的set(Object obj, Object value)
,obj代表设置哪个对象的相应属性值,value代表要设置的属性的值。调用Field实例的get(Object obj)
获取obj对象的对应的属性的值。如果获取的是静态的属性,那么obj可以为null。
package com.kimzing.demo.reflect;
import java.time.LocalDateTime;
/**
* 反射的目标.
*
* @author KimZing - [email protected]
* @since 2020/3/31 10:27
*/
public class PersonReflect {
public String name;
protected Integer age;
Double amount;
public static String hello = "HELLO";
private LocalDateTime birth;
public PersonReflect() {
}
public PersonReflect(String str) {
System.out.println("公开构造函数:" + str);
}
PersonReflect(int i) {
System.out.println("默认构造函数" + i);
}
protected PersonReflect(String str, int i) {
System.out.println("受保护的构造函数" + str + i);
}
private PersonReflect(char ch) {
System.out.println("私有构造函数" + ch);
}
public void method1() {
System.out.println("public method");
}
void method2(String str) {
System.out.println("public method" + str);
}
protected void method3() {
System.out.println("protected method");
}
private void method4(Integer integer) {
System.out.println("private method" + integer);
}
public static void hello() {
System.out.println("Hello");
}
}
package com.kimzing.demo.reflect.demo;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
/**
* 构造器反射.
*
* @author KimZing - [email protected]
* @since 2020/3/31 11:26
*/
public class ConstructorReflectDemo {
public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
Class<?> pClass = Class.forName("com.kimzing.demo.reflect.PersonReflect");
System.out.println("----获取所有的公有构造方法");
Constructor<?>[] constructors = pClass.getConstructors();
for (Constructor<?> constructor : constructors) {
System.out.println(constructor);
}
System.out.println("----获取所有的构造方法,包含protected default private");
constructors = pClass.getDeclaredConstructors();
for (Constructor<?> constructor : constructors) {
System.out.println(constructor);
}
System.out.println("----获取单个公开的构造方法");
Constructor<?> constructor = pClass.getConstructor(String.class);
System.out.println(constructor);
System.out.println("----获取私有的构造方法");
constructor = pClass.getDeclaredConstructor(char.class);
System.out.println(constructor);
System.out.println("----使用反射得到的构造器创建实例");
// 任何包均可直接获取
System.out.println("--公开构造方法");
constructor = pClass.getConstructor(String.class);
constructor.newInstance("Hello");
// protected/default/private 均需要设置权限,如果和反射操作类处于同一个包下则无需设置权限
System.out.println("--受保护的构造方法");
constructor = pClass.getDeclaredConstructor(String.class, int.class);
constructor.setAccessible(true);
Object hello = constructor.newInstance("hello", 18);
System.out.println("--默认的构造方法");
constructor = pClass.getDeclaredConstructor(int.class);
constructor.setAccessible(true);
constructor.newInstance(24);
System.out.println("--私有的构造方法");
constructor = pClass.getDeclaredConstructor(char.class);
constructor.setAccessible(true);
constructor.newInstance('a');
}
}
package com.kimzing.demo.reflect.demo;
import com.kimzing.demo.reflect.PersonReflect;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
/**
* 方法反射.
*
* @author KimZing - [email protected]
* @since 2020/3/31 13:20
*/
public class MethodReflectDemo {
public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InstantiationException, InvocationTargetException {
Class<?> pClass = Class.forName("com.kimzing.demo.reflect.PersonReflect");
System.out.println("----获取公开方法,包含父类方法");
Method[] methods = pClass.getMethods();
for (Method method : methods) {
System.out.println(method);
}
System.out.println("----获取所有方法,包含非公开的方法");
methods = pClass.getDeclaredMethods();
for (Method method : methods) {
System.out.println(method);
}
System.out.println("----获取单个的公开方法");
Method method1 = pClass.getMethod("method1");
System.out.println(method1);
System.out.println("----获取单个的非公开的方法");
Method method4 = pClass.getDeclaredMethod("method4", Integer.class);
System.out.println(method4);
System.out.println("----执行公开方法");
PersonReflect personReflect = (PersonReflect) pClass.newInstance();
method1.invoke(personReflect);
System.out.println("----执行非公开方法");
method4.setAccessible(true);
method4.invoke(personReflect, 12);
System.out.println("----执行静态方法");
Method hello = pClass.getMethod("hello");
hello.invoke(null);
}
}
package com.kimzing.demo.reflect.demo;
import com.kimzing.demo.reflect.PersonReflect;
import java.lang.reflect.Field;
import java.time.LocalDateTime;
/**
* 属性反射.
*
* @author KimZing - [email protected]
* @since 2020/3/31 13:07
*/
public class FieldReflectDemo {
public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException, IllegalAccessException, InstantiationException {
Class<?> pClass = Class.forName("com.kimzing.demo.reflect.PersonReflect");
System.out.println("----获取公开的属性");
Field[] fields = pClass.getFields();
for (Field field : fields) {
System.out.println(field);
}
System.out.println("----获取所有的属性");
fields = pClass.getDeclaredFields();
for (Field field : fields) {
System.out.println(field);
}
System.out.println("----获取单个公开的属性");
Field name = pClass.getField("name");
System.out.println(name);
System.out.println("----获取非公开的属性");
Field birth = pClass.getDeclaredField("birth");
System.out.println(birth);
System.out.println("----设置属性的值");
PersonReflect personReflect = (PersonReflect) pClass.newInstance();
System.out.println("--设置公开的属性");
name.set(personReflect, "KimZing");
System.out.println("name的值为" + personReflect.name);
System.out.println("--设置非公开的属性,并读取非公开属性");
birth.setAccessible(true);
birth.set(personReflect, LocalDateTime.now());
System.out.println("birth的值为" + birth.get(personReflect));
System.out.println("----获取静态的属性");
Field hello = pClass.getField("hello");
System.out.println(hello.get(null));
}
}