Java反射是Java被视为动态语言的很重要的一个特性。
Java通过反射的Api可以做到获取运行时类的任何信息。包括其类、属性、方法、注解、父类等任何信息。并且可以直接操作任意对象的内部属性及方法。
获取Class实例的方式
Class clazz1 = Person.class;
Class extends Person> aClass = person.getClass();
Class.forName(String classPath)
Class的实例就对应着一个运行时类。 加载到内存中的运行时类,会缓存一定的时间,在此时间之内,我们可以通过不同的方式来获取此运行时类。
newInstance():调用此方法创建对应的运行时类的对象。内部调用了运行时类的空参构造器。
要想此方法能够正常的创建运行时类的对象,要求:
- 运行时类必须提供空参构造器。
- 空参构造器的访问权限得够(通常设置为public的)
系统类加载器:加载自己创建的一些类。
扩展类加载器:加载Java的lib下得扩展类。
引导类加载器:主要负责加载java的核心类库,无法加载自定义类的。
@Testpublic void testNewInstance1() throws Exception {int num = new Random().nextInt(3);String classPath = "";switch (num) {case 0: classPath = "java.util.Date"; break;case 1: classPath = "java.lang.Object"; break;case 2: classPath = "com.starcpdk.Person"; break;}Object obj = getInstance(classPath);System.out.println(obj);}/*** 创建一个指定类的对象* @param classPath 指定类的全类名* @return* @throws Exception*/public Object getInstance(String classPath) throws Exception {Class> clazz = Class.forName(classPath);return clazz.newInstance();}
// 获取当前运行时类中声明为public的构造器
Constructor>[] constructors = personClass.getConstructors();
// 获取当前运行时类的所有构造器
Constructor>[] declaredConstructors = personClass.getDeclaredConstructors();
// 获取运行时类的父类
Class super Person> superclass = personClass.getSuperclass();// 获取运行时类的带泛型的父类
Type genericSuperclass = personClass.getGenericSuperclass();// 获取运行时类的带泛型的父类
Type genericSuperclass = personClass.getGenericSuperclass();
// 获取父类的泛型类型
ParameterizedType parameterizedType = (ParameterizedType) genericSuperclass;
Type[] actualTypeArguments = parameterizedType.getActualTypeArguments();
System.out.println(((Class)actualTypeArguments[0]).getName());
// 获取运行时类实现的接口
Class>[] interfaces = personClass.getInterfaces();
// 获取运行时类的父类实现的接口。
Class>[] interfaces1 = personClass.getSuperclass().getInterfaces();
Package aPackage = personClass.getPackage();
Annotation[] annotations = personClass.getAnnotations();
// 获取当前运行时类及其所以父类中声明为public的所有方法
Method[] methods = personClass.getMethods();
// 获取当前运行时类中的所有方法。(不包含父类中声明的方法)
Method[] declaredMethods = personClass.getDeclaredMethods();@Test
public void test2() throws Exception {Class personClass = Person.class;Method[] declaredMethods = personClass.getDeclaredMethods();for (Method declaredMethod : declaredMethods) {// 4. 获取方法名System.out.print("方法名是:" + declaredMethod.getName() + ":\t");// 只能获取Runtime的生命周期的注解// 1. 获取方法声明的注解Annotation[] annotations = declaredMethod.getAnnotations();for (Annotation annotation : annotations) {System.out.print("注解是:" + annotation + "\t");}// 2、获取权限修饰符int modifiers = declaredMethod.getModifiers();System.out.print("权限修饰符是:" + Modifier.toString(modifiers) + "\t");// 3.获取返回值类型Class> returnType = declaredMethod.getReturnType();System.out.print("返回值类型是:" + returnType.getName() + "\t");// 5. 获取形参列表Class>[] parameterTypes = declaredMethod.getParameterTypes();if (!(parameterTypes == null || parameterTypes.length == 0)) {for (Class> parameterType : parameterTypes) {System.out.print("形参类型:" + parameterType.getName() + " args_" + " ");}}// 6. 抛出的异常Class>[] exceptionTypes = declaredMethod.getExceptionTypes();for (Class> exceptionType : exceptionTypes) {System.out.print("异常:" + exceptionType.getName());}System.out.println();}
}
// getFields() :获取当前运行时类及其父类声明为public访问权限的属性
Field[] fields = personClass.getFields();
// getDeclaredFields():获取当前运行时类中所有的属性。(不包含父类的属性)
Field[] declaredFields = personClass.getDeclaredFields();// 权限修饰符 数据类型 变量名
@Test
public void test1() {Class personClass = Person.class;Field[] declaredFields = personClass.getDeclaredFields();for (Field declaredField : declaredFields) {// 权限修饰符int modifiers = declaredField.getModifiers();
// System.out.println(modifiers);System.out.print(Modifier.toString(modifiers) + "\t");// 数据类型Class> type = declaredField.getType();System.out.print(type.getName() + "\t");// 变量名String name = declaredField.getName();System.out.println(name);}}
package com.starcpdk.java2;/*** @Author 姚云峰* @Email* @Date 2022/10/27 14:02* @Version 1.0*/import com.starcpdk.test.Person;
import org.junit.jupiter.api.Test;import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;/*** 调用运行类中指定的结构:属性、方法、构造器*/
public class ReflectionTest {/*** 获取*/@Testpublic void testField() throws Exception {// 获取指定的属性Class personClass = Person.class;// 创建运行时类的对象。Person person = personClass.newInstance();// 获取指定属性 , 要求运行时类中的属性声明为public的。// 通常不采用此方式Field id = personClass.getField("id");// 设置当前属性的值// 参数1:指明设置哪儿个对象的属性, 参数2:指明将此属性值设置为多少id.set(person , 1234);// 获取当前属性的值// 参数1:获取哪儿个对象的当前属性的值int pId = (int) id.get(person);System.out.println(pId);}/*** 操作运行时类中的属性。* @throws Exception*/@Testpublic void testField1() throws Exception {Class personClass = Person.class;// 创建运行时类的对象。Person person = personClass.newInstance();// 获取指定变量名的属性Field age = personClass.getDeclaredField("age");// 保证当前属性是可访问的。age.setAccessible(true);// 获取、设置指定对象的此属性的值。age.set(person , 12);Object o = age.get(person);System.out.println(o);}/*** 操作运行时类中的方法* 参数1:指明获取方法的名称。* 参数2:指明获取方法的形参列表。*/@Testpublic void testMethod() throws Exception {Class personClass = Person.class;Person person = personClass.newInstance();Method show = personClass.getDeclaredMethod("show", String.class);/*** invoke()* 参数1:方法的调用者。* 参数2:给方法形参赋值的实参。* invoke()的返回值就是对应类中调用的方法的返回值。*/show.setAccessible(true);Object hahah = show.invoke(person, "哈哈哈哈");System.out.println(hahah);Method showDesc = personClass.getDeclaredMethod("showDesc");showDesc.setAccessible(true);// 如果调用的方法没有=返回值 , 则返回nullObject invoke = showDesc.invoke(Person.class);System.out.println(invoke);}/*** 调用运行时类中指定的构造器。** 参数:指明构造器的参数列表** @throws Exception*/@Testpublic void testConstructor() throws Exception {Class personClass = Person.class;Constructor declaredConstructor = personClass.getDeclaredConstructor(String.class);declaredConstructor.setAccessible(true);Person tom = declaredConstructor.newInstance("Tom");System.out.println(tom);}
}
类中对象的个数是确定的,有限个。
枚举类中的属性的修饰符是 private final 的。
枚举类中的对象的修饰符是 public static final 的。
/*** @Author 姚云峰* @Email* @Date 2022/8/20 16:02* @Version 1.0* *
* 枚举类的使用*/
public class SeasonTest {}/*** 自定义枚举实现*/
class Season {private final String seasonName;private final String seasonDescription;private Season(String seasonName, String seasonDescription) {this.seasonName = seasonName;this.seasonDescription = seasonDescription;}public static final Season SPRING = new Season("春天" , "春暖花开");public static final Season SUMMER = new Season("夏天" , "夏日炎炎");public static final Season AUTUMN = new Season("秋天" , "秋高气爽");public static final Season WINTER = new Season("冬天" , "冰天雪地");}
/*** @Author 姚云峰* @Email* @Date 2022/8/20 16:16* @Version 1.0** 使用enum关键字创建枚举类** 常用方法:* values(): 返回一个数组,即枚举类中的所有对象* valueOf(String str) 找指定名的对象 , 如果提供的str,在枚举类对象中没有,则抛异常。IllegalArgumentException* toString() 默认返回枚举类对象名称***/
public class SeasonTestEnum {public static void main(String[] args) {System.out.println(Season1.SPRING);}
}interface Info{void show();
}// 枚举类实现接口。
// 可以统一重写接口方法
// 也可以每个枚举值都重写接口方法
enum Season1 implements Info{// 提供当前类枚举对象SPRING("春天","春暖花开"){@Overridepublic void show() {System.out.println("春天在哪儿里");}},SUMMER("夏天","夏日炎炎") {@Overridepublic void show() {System.out.println("夏宁");}},AUTUMN("秋天","秋高气爽") {@Overridepublic void show() {System.out.println("秋天不回来");}},WINTER("冬天","冰天雪地") {@Overridepublic void show() {System.out.println("大约在冬季");}};private final String seasonName;private final String seasonDescription;private Season1(String seasonName, String seasonDescription) {this.seasonName = seasonName;this.seasonDescription = seasonDescription;}// @Override// public void show() {// System.out.println("这是一个季节。。。。。。");// }
}
使用@interface关键字声明。
内部定义成员,通常使用value表示
可以指定成员的默认值,使用default定义默认值。
如果自定义的注解没有成员,表明是一个标识作用。
如果注解有成员,使用注解时需要指明成员的值。
自定义注解必须配上注解的信息处理流程(反射的方式)才有意义。
自定义注解通常都会指明两个元注解,即:@Retention \ @Target。
@Repeatable(MyAnnotations.class)
//@Inherited // 可继承注解。
@Retention(RetentionPolicy.RUNTIME)
@Target({TYPE, FIELD, METHOD, PARAMETER, CONSTRUCTOR, LOCAL_VARIABLE , TYPE_PARAMETER , TYPE_USE})
public @interface MyAnnotation {String value() default "world";
}
元注解:对现有注解进行解释说明的注解。
Retention:指明所修饰的注解的生命周期。SOURCE、CLASS、RUNTIME。
Target:修饰该注解的作用域的。
上一篇:ITSS认证是什么