Java反射、注解、枚举
创始人
2024-04-02 07:02:10
0

1.反射

一、什么是反射?

Java反射是Java被视为动态语言的很重要的一个特性。
Java通过反射的Api可以做到获取运行时类的任何信息。包括其类、属性、方法、注解、父类等任何信息。并且可以直接操作任意对象的内部属性及方法。

二、反射能用来做什么?

  1. 在运行时判断任意一个对象所属的类。
  2. 在运行时构造任意一个类的对象。
  3. 在运行时判断任意一个类所具有的成员变量和方法。
  4. 在运行时获取泛型信息。
  5. 在运行时调用任意一个对象成员变量和方法。
  6. 在运行时处理注解。
  7. 生成动态代理。

三、获取class实例的方式。

获取Class实例的方式

  • 方式一:调用运行时类的属性。 .class Class clazz1 = Person.class;
  • 方式二:通过运行时类的对象 调用getClass这个方法 Class aClass = person.getClass();
  • 方式三:调用Class的静态方法 Class.forName(String classPath)
  • 方式四:使用类的加载器:ClassLoader

Class的实例就对应着一个运行时类。 加载到内存中的运行时类,会缓存一定的时间,在此时间之内,我们可以通过不同的方式来获取此运行时类。

四、通过反射创建运行时类的对象。

newInstance():调用此方法创建对应的运行时类的对象。内部调用了运行时类的空参构造器。

要想此方法能够正常的创建运行时类的对象,要求:

  1. 运行时类必须提供空参构造器。
  2. 空参构造器的访问权限得够(通常设置为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();}

七、创建对象的几种方式

  1. new + 构造器
  2. 调用方法获取实例。XXX、XXXs、XXXFactory、XXXBuilder等。
  3. clone方法克隆对象。
  4. 反射方式创建对象。调用newInstance()使用类或者构造器调用。

八、clazz获取一些结构。

  1. 获取构造器。
// 获取当前运行时类中声明为public的构造器
Constructor[] constructors = personClass.getConstructors();
// 获取当前运行时类的所有构造器
Constructor[] declaredConstructors = personClass.getDeclaredConstructors();
  1. 获取运行时类的父类
// 获取运行时类的父类
Class 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());
  1. 获取运行时类实现的接口
// 获取运行时类实现的接口
Class[] interfaces = personClass.getInterfaces();
// 获取运行时类的父类实现的接口。
Class[] interfaces1 = personClass.getSuperclass().getInterfaces();
  1. 获取当前运行时类 所在的包
Package aPackage = personClass.getPackage();
  1. 获取运行时类 声明的注解
Annotation[] annotations = personClass.getAnnotations();
  1. 获取运行时类的方法
// 获取当前运行时类及其所以父类中声明为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();}
}
  1. 获取运行时类的属性结构
// 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);}}
  1. 使用运行时类中的一些属性或方法
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);}
}

2. 枚举

一、什么是枚举

类中对象的个数是确定的,有限个。
枚举类中的属性的修饰符是 private final 的。
枚举类中的对象的修饰符是 public static final 的。

二、枚举类常用方法

  • values(): 返回一个数组,即枚举类中的所有对象
  • valueOf(String str) 找指定名的对象 , 如果提供的str,在枚举类对象中没有,则抛异常。IllegalArgumentException
  • toString() 默认返回枚举类对象名称

三、例子

/*** @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:修饰该注解的作用域的。

相关内容

热门资讯

喜欢穿一身黑的男生性格(喜欢穿... 今天百科达人给各位分享喜欢穿一身黑的男生性格的知识,其中也会对喜欢穿一身黑衣服的男人人好相处吗进行解...
发春是什么意思(思春和发春是什... 本篇文章极速百科给大家谈谈发春是什么意思,以及思春和发春是什么意思对应的知识点,希望对各位有所帮助,...
网络用语zl是什么意思(zl是... 今天给各位分享网络用语zl是什么意思的知识,其中也会对zl是啥意思是什么网络用语进行解释,如果能碰巧...
为什么酷狗音乐自己唱的歌不能下... 本篇文章极速百科小编给大家谈谈为什么酷狗音乐自己唱的歌不能下载到本地?,以及为什么酷狗下载的歌曲不是...
家里可以做假山养金鱼吗(假山能... 今天百科达人给各位分享家里可以做假山养金鱼吗的知识,其中也会对假山能放鱼缸里吗进行解释,如果能碰巧解...
华为下载未安装的文件去哪找(华... 今天百科达人给各位分享华为下载未安装的文件去哪找的知识,其中也会对华为下载未安装的文件去哪找到进行解...
四分五裂是什么生肖什么动物(四... 本篇文章极速百科小编给大家谈谈四分五裂是什么生肖什么动物,以及四分五裂打一生肖是什么对应的知识点,希...
怎么往应用助手里添加应用(应用... 今天百科达人给各位分享怎么往应用助手里添加应用的知识,其中也会对应用助手怎么添加微信进行解释,如果能...
客厅放八骏马摆件可以吗(家里摆... 今天给各位分享客厅放八骏马摆件可以吗的知识,其中也会对家里摆八骏马摆件好吗进行解释,如果能碰巧解决你...
苏州离哪个飞机场近(苏州离哪个... 本篇文章极速百科小编给大家谈谈苏州离哪个飞机场近,以及苏州离哪个飞机场近点对应的知识点,希望对各位有...