反射
java.lang.Class类
Java反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性;这种动态获取的信息以及动态调用对象的方法的功能称为Java语言的反射机制。
要想解剖一个类,必须先要获取到该类的Class对象。而剖析一个类或用反射解决具体的问题就是使用相关API(1)java.lang.Class(2)java.lang.reflect.*。所以,Class对象是反射的根源。
获取Class对象的四种方式
(1)类型名.class
要求编译期间已知类型
(2)对象.getClass()
获取对象的运行时类型
(3)Class.forName(类型全名称)
可以获取编译期间未知的类型
(4)ClassLoader的类加载器对象.loadClass(类型全名称)
可以用系统类加载对象或自定义加载器对象加载指定路径下的类型
public class TestClass {
@Test
public void test05() throws ClassNotFoundException{
Class c = TestClass.class;
ClassLoader loader = c.getClassLoader();
Class c2 = loader.loadClass("com.atguigu.test05.Employee");
Class c3 = Employee.class;
System.out.println(c2 == c3);
}
@Test
public void test03() throws ClassNotFoundException{
Class c2 = String.class;
Class c1 = "".getClass();
Class c3 = Class.forName("java.lang.String");
System.out.println(c1 == c2);
System.out.println(c1 == c3);
}
}
反射的应用
获取类的详细信息
可以获取:包、修饰符、类型名、父类(包括泛型父类)、父接口(包括泛型父接口)、成员(属性、构造器、方法)、注解(类上的、方法上的、属性上的)
获取类的:包、修饰符、全类名、父类、实现的接口名
public class TestClassInfo {
public static void main(String[] args) throws NoSuchFieldException, SecurityException {
//1、先得到某个类型的Class对象
Class clazz = String.class;
//比喻clazz好比是镜子中的影子
//2、获取类信息
//(1)获取包对象,即所有java的包,都是Package的对象
Package pkg = clazz.getPackage();
System.out.println("包名:" + pkg.getName());
//(2)获取修饰符
//其实修饰符是Modifier,里面有很多常量值
/*
* 0x是十六进制
* PUBLIC = 0x00000001; 1 1
* PRIVATE = 0x00000002; 2 10
* PROTECTED = 0x00000004; 4 100
* STATIC = 0x00000008; 8 1000
* FINAL = 0x00000010; 16 10000
* ...
*
* 设计的理念,就是用二进制的某一位是1,来代表一种修饰符,整个二进制中只有一位是1,其余都是0
*
* mod = 17 0x00000011
* if ((mod & PUBLIC) != 0) 说明修饰符中有public
* if ((mod & FINAL) != 0) 说明修饰符中有final
*/
int mod = clazz.getModifiers();
System.out.println(Modifier.toString(mod));
//(3)全类名
String name = clazz.getName();
System.out.println(name);
//(4)父类,父类也有父类对应的Class对象
Class superclass = clazz.getSuperclass();
System.out.println(superclass);
//(5)父接口们
Class[] interfaces = clazz.getInterfaces();
for (Class class1 : interfaces) {
System.out.println(class1);
}
注解(类上的、方法上的、属性上的)
//获取类上的注解
//假设有一个类 MyClass,我们在其上定义了一个注解 @MyAnnotation。
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@Retention(RetentionPolicy.RUNTIME)
@interface MyAnnotation {
String value() default "class annotation";
}
@MyAnnotation("This is a class annotation")
class MyClass {
// 类体
}
//获取类上的注解:
public class AnnotationExample {
public static void main(String[] args) {
Class<MyClass> clazz = MyClass.class;
MyAnnotation annotation = clazz.getAnnotation(MyAnnotation.class);
if (annotation != null) {
System.out.println("Class Annotation: " + annotation.value());
}
}
}
//判断一个类、方法或属性上是否存在特定的注解
//判断类上的注解
//假设我们有一个自定义注解 @MyAnnotation,并在一个类上使用它:
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@Retention(RetentionPolicy.RUNTIME)
@interface MyAnnotation {
String value() default "class annotation";
}
@MyAnnotation("This is a class annotation")
class MyClass {
// 类体
}
//判断类上是否存在该注解:
public class AnnotationCheck {
public static void main(String[] args) {
Class<MyClass> clazz = MyClass.class;
// 判断类上是否存在 MyAnnotation 注解
if (clazz.isAnnotationPresent(MyAnnotation.class)) {
System.out.println("MyClass has MyAnnotation.");
} else {
System.out.println("MyClass does not have MyAnnotation.");
}
}
}
获取类的成员(属性、构造器、方法)
//(1)类的属性, 你声明的一个属性,它是Field的对象
/* Field clazz.getField("name") 根据属性名获取一个属性对象,但是只能得到公共的
Field[] clazz.getFields(); 获取所有公共的属性[会获取到父类的公共属性]
Field clazz.getDeclaredField("name") 根据属性名获取一个属性对象[任何类型]
Field[] clazz.getDeclaredFields() 获取所有已声明的属性[包括私有属性,不会获取到父类属性]
*/
//根据属性名获取一个属性对象,但是只能得到公共的[可以获取到父类的公共属性]
Field field = studentClass.getField("name");
System.out.println("field = " + field);
//获取所有公共的属性[会获取到父类的公共属性]
Field[] fields = studentClass.getFields();
for (Field field : fields) {
System.out.println("field = " + field);
}
//根据属性名获取一个属性对象,可以获取已声明的[包括私有属性,不包括父类属性]
Field valueField = clazz.getDeclaredField("value");
System.out.println("valueField = " + field);
//获取所有已声明的属性[包括私有属性,不包括父类属性]
Field[] declaredFields = clazz.getDeclaredFields();
for (Field field : declaredFields) {
System.out.println("field = " + field);
}
//获取父类的所有属性:首先获取父类对象 getSuperclass();然后通过父类对象获取所有属性
Class<? super Student> superclass = studentClass.getSuperclass();
Field[] declaredFields1 = superclass.getDeclaredFields();
for (Field field : declaredFields1) {
System.out.println("field = " + field1);
}
//(2)构造器
/*
获取公共无参构造器对象[只能public]
Constructor clazz.getConstructor();
获取所有公共的构造器对象[不会获取到父类构造器]
Constructor<?>[] clazz.getConstructors();
获取无参构造器对象[任何类型(public、protected、default、private)]
Constructor clazz.getDeclaredConstructor();
获取所有构造器对象[任何类型(public、protected、default、private),不会获取到父类构造器]
Constructor<?>[] clazz.getDeclaredConstructors();
无参构造器(参数表里写上参数)就是获取有参构造器***
clazz.getDeclaredConstructor(参数表)
*/
//获取无参构造器对象
Constructor<Student> constructor = studentClass.getConstructor();
//获取所有公共的构造器[不会获取到父类构造器]
Constructor<?>[] constructors = studentClass.getConstructors();
////获取无参构造器对象
Constructor<Student> declaredConstructor = studentClass.getDeclaredConstructor();
//获取所有构造器对象[不会获取到父类构造器]
Constructor<?>[] constructors = clazz.getDeclaredConstructors();
for (Constructor constructor : constructors) {
//获取构造器的修饰符、构造器名称、构造器形参列表 、抛出的异常列表
int modifiers = constructor.getModifiers();
System.out.println("构造器的修饰符:" + Modifier.toString(modifiers));
String name = constructor.getName();
System.out.println("构造器名:" + name);
//形参列表
System.out.println("形参列表:");
Class[] parameterTypes = constructor.getParameterTypes();
for (Class parameterType : parameterTypes) {
System.out.println(parameterType);
}
//异常列表
System.out.println("异常列表:");
Class<?>[] exceptionTypes = constructor.getExceptionTypes();
for (Class<?> exceptionType : exceptionTypes) {
System.out.println(exceptionType);
}
}
//(3)方法们
/*
根据方法名获取一个方法对象,但是只能得到公共的
Method clazz.getMethod("name");
获取所有公共的方法对象[会获取到父类方法]
Method[] clazz.getMethods();
根据方法名获取一个方法对象[任何类型(public、protected、default、private)]
Method clazz.getDeclaredMethod("name");
获取所有方法对象[任何类型(public、protected、default、private),不会获取到父类方法]
Method[] clazz.getDeclaredMethods();
*/
//根据方法名获取一个方法对象,但是只能得到公共的
Method method = studentClass.getMethod("study");
//获取所有公共的方法对象[会获取到父类方法]
Method[] methods = studentClass.getMethods();
//根据方法名获取一个方法对象[任何类型(public、protected、default、private)]
Method declaredMethod = studentClass.getDeclaredMethod("sleep");
//获取所有方法对象[任何类型(public、protected、default、private),不会获取到父类方法]
Method[] declaredMethods = clazz.getDeclaredMethods();
for (Method method : declaredMethods) {
//获取方法的修饰符、返回值类型、方法名、形参列表 、异常列表
int modifiers = method.getModifiers();
System.out.println("方法的修饰符:" + Modifier.toString(modifiers));
Class<?> returnType = method.getReturnType();
System.out.println("返回值类型:" + returnType);
String name2 = method.getName();
System.out.println("方法名:" + name2);
//形参列表
System.out.println("形参列表:");
Class[] parameterTypes = method.getParameterTypes();
for (Class parameterType : parameterTypes) {
System.out.println(parameterType);
}
//异常列表
System.out.println("异常列表:");
Class<?>[] exceptionTypes = method.getExceptionTypes();
for (Class<?> exceptionType : exceptionTypes) {
System.out.println(exceptionType);
}
}
创建任意引用类型的对象并赋值(调构造器赋值)
两种方式:
- 1、直接通过Class对象来实例化(要求必须有无参构造)
- 2、通过获取构造器对象来进行实例化
方式一的步骤:
(1)获取该类型的Class对象(2)创建对象
如果构造器的权限修饰符修饰的范围不可见,也可以调用setAccessible(true)
@Test
public void test2()throws Exception{
Class<?> clazz = Class.forName("com.chs.test.Student");
//Caused by: java.lang.NoSuchMethodException: com.chs.test.Student.<init>()
//即说明Student没有无参构造,就没有无参实例初始化方法<init>
Object stu = clazz.newInstance();
System.out.println(stu);
}
@Test
public void test1() throws ClassNotFoundException, InstantiationException, IllegalAccessException{
//Student obj = new Student();//编译期间无法创建
Class<?> clazz = Class.forName("com.chs.test.Student");
//clazz代表com.chs.test.Student类型
//clazz.newInstance()创建的就是Student的对象
Object obj = clazz.newInstance();
System.out.println(obj);
}
方式二的步骤:
(1)获取该类型的Class对象(2)获取构造器对象(3)创建对象
如果构造器的权限修饰符修饰的范围不可见,也可以调用setAccessible(true)
示例代码:
public class TestNewInstance {
@Test
public void test3()throws Exception{
//(1)获取Class对象
Class<?> clazz = Class.forName("com.chs.test.Student");
/*
* 获取Student类型中的有参构造
* 如果构造器有多个,我们通常是根据形参【类型】列表来获取指定的一个构造器的
* 例如:public Student(int id, String name)
*/
//(2)获取构造器对象
Constructor<?> constructor = clazz.getDeclaredConstructor(int.class,String.class);
//(3)创建实例对象
// T newInstance(Object... initargs) 这个Object...是在创建对象时,给有参构造的实参列表
Object obj = constructor.newInstance(2,"张三");
System.out.println(obj);
}
//访问私有构造器
@Test
public void test05() throws Exception{
//1.获取Class 对象
Class<Person> personClass = Person.class;
//2.获取指定的构造器
Constructor<Person> c = personClass.getDeclaredConstructor(String.class, int.class, double.class);
//3.禁止java语言的权限访问检测
c.setAccessible(true);
//4.给成员变量赋值
Person person = c.newInstance("王安石", 30, 9898.6);
//5.展示结果
System.out.println("person = " + person);
}
}
操作任意类型的属性
(1)获取该类型的Class对象
Class clazz = Class.forName("com.chs.bean.User");
(2)获取属性对象
Field field = clazz.getDeclaredField("username");
(3)设置属性可访问
field.setAccessible(true);
(4)创建实例对象:如果操作的是非静态属性,需要创建实例对象
Object obj = clazz.newInstance();
(5)设置属性值
field.set(obj,"chai");
(6)获取属性值
Object value = field.get(obj);
如果操作静态变量,那么实例对象可以省略,用null表示
(5)设置属性值
field.set(null,"chai");
(6)获取属性值
Object value = field.get(null);
示例代码:
//操作静态变量
@Test
public void test01() throws NoSuchFieldException, IllegalAccessException {
//1.获取Class对象
Class<Monkey> monkeyClass = Monkey.class;
//2.获取指定的属性
Field message = monkeyClass.getDeclaredField("message");
//3.设置私有的属性可以操作
message.setAccessible(true);
//4.给属性赋值
message.set(null,"HelloWorld");
//5.获取属性值
Object value = message.get(null);
System.out.println("value = " + value);
}
//操作普通变量
@Test
public void test02() throws Exception {
//1.获取Class对象
Class<Monkey> monkeyClass = Monkey.class;
//2.获取指定的属性
Field gender = monkeyClass.getDeclaredField("gender");
//todo 设置私有的属性可以访问
gender.setAccessible(true);
//3.创建对象
Monkey monkey = monkeyClass.newInstance();
System.out.println("monkey = " + monkey);
//4.给属性赋值
//todo 给monkey 对象的gender 属性赋值 为 男
gender.set(monkey,'男');
//5.展示对象
System.out.println("monkey = " + monkey);
}
调用任意类型的方法
(1)获取该类型的Class对象
Class clazz = Class.forName("com.chs.service.UserService");
(2)获取方法对象
Method method = clazz.getDeclaredMethod("login",String.class,String.class);
(3)创建实例对象
Object obj = clazz.newInstance();
(4)调用方法
Object result = method.invoke(obj,"chai","123);
如果方法的权限修饰符修饰的范围不可见,也可以调用setAccessible(true)
method .setAccessible(true);
如果方法是静态方法,实例对象也可以省略,用null代替
Object result = method.invoke(null,"chai","123);
示例代码:
//操作静态方法
@Test
public void test04() throws Exception{
//todo 私有的静态方法
//1.获取Class对象
Class<Animal> animalClass = Animal.class;
//2.获取指定的方法
Method isPrimeNum = animalClass.getDeclaredMethod("isPrimeNum", int.class);
//3.设置私有方法可以使用
isPrimeNum.setAccessible(true);
//4.执行方法 获取结果
Object invoke = isPrimeNum.invoke(null, 20);
//5.输出结果
System.out.println("invoke = " + invoke);
}
//操作普通方法
@Test
public void test03() throws NoSuchMethodException, InstantiationException, IllegalAccessException, InvocationTargetException {
//todo 公共的实例方法
//1.获取Class对象
Class<Animal> aClass = Animal.class;
//2.获取指定的方法
Method sum = aClass.getMethod("sum", int.class, int.class);
//3.创建对象
Animal animal = aClass.newInstance();
//4.调用方法
sum.invoke(animal,89,20);
}
标签:反射,JAVA,System,clazz,获取,println,Class,out
From: https://www.cnblogs.com/21CHS/p/18528875