2022-08-10 第4组 蒋萍 注解和反射的简单介绍

本篇只是简单介绍注解的概念以及通过反射获取到类对象的一个简单例子

关于反射可以参考:

https://www.pdai.tech/md/java/basic/java-basic-x-reflection.html

注解和反射

JDK5才引入的:

Annotation

image-20220810085320779

  • 可以自己创建注解

元注解

专门给注解加的注解

注解中可以有方法

定义方法的格式:返回值 方法名();

可以通过default指定默认值,如果没有默认值,使用时要注意传入对应的参数

如果想在使用时不用指定具体名字,

如果不学反射,注解没啥用

在Java整个注解体系中有三个非常重要的主干类

1、Annotation 接口

2、ElementType 枚举,指定注解类型(注解出现在哪里)

3、RetentionPolicy 枚举,指定注解的策略(不同类型的策略指定的注解的作用域不同)

​ SOURCE : 注解仅存在于编译器处理期间,编译器处理完后,该注解就没用了

​ CLASS:注解在.class文件中依然有效

​ RUNTIME:编译期不起作用,只有在运行期才由JVM读取

java自带的10个注解,4个在java.lang.annotation包下,剩下的在java.lang

2、反射

详细的可以参考这篇:

https://www.pdai.tech/md/java/basic/java-basic-x-reflection.html

为什么要学反射?

开发中基本用不上反射,

是什么?

在类运行时,可以任意构造一个类对象,构造对象的属性和方法,调用其对象爱你过方法,这种动态创建获取对象,反射机制。

拿来做什么?

  • 利用Class类动态创建获取对象

定义一个Person类,里面 私有成员属性,提供相应get、set方法,提供全参、无参构造

先看原始通过类拿到对象的方式:

image-20220810194354386

2.1 利用反射获取类对象

先看一下Class类:

image-20220810204103330

主要有三种方式:

  • 类名.class

    Person.class

  • 对象.getClass()

    new Person().getClass()

  • Class.forName(全限定类名)

    Class.forName("com.jr.reflect.Person")

下面演示的是第三种方式

2.1.1 利用构造器创建

加载类名,获取类对象,通过构造方法获取对象

找到构造器创建对象,通过类对象找到构造器,构造器名和类名相同

Class clz = Class.forName("com.jr.reflect.Person"); 
// 注意异常ClassNotFoundException
Constructor constructor = clz.getDeclaredConstructor(String.class,int.class);
// NoSuchMethodException
Person person1 = (Person)constructor.newInstance("小李",20);
// InstantiationException, IllegalAccessException, 
// IllegalArgumentException,
// InvocationTargetException
System.out.println(person1);
  • 注意处理异常

image-20220810204953065

2.2.2 利用字节码直接实例化

不推荐使用

image-20220810210300896

2.2 利用反射给对象属性赋值

无参构造实例化对象,然后给属性赋值,得先得到这个对象

/* 获得一个类的字节码 */

Class clz = Class.forName("com.jr.reflect.Person");
Person person = (Person) clz.newInstance();

Field name = clz.getDeclaredField("name");
Field age = clz.getDeclaredField("age");


/* private修饰的属性不能直接 如果要使用先设置属性可以访问 */
name.setAccessible(true);
age.setAccessible(true);

// 给属性赋值
name.set(person,"小李");
age.set(person,19);

// 如果是静态成员变量 不需要对象就可以赋值 name.set(null,"姓名")
System.out.println(person);

image-20220810212002158

2.3 利用反射调用类对象方法

/*获得一个类的字节码*/
Class pClass = Class.forName("com.bjsxt.demo1.Person");
Constructor cons = pClass.getDeclaredConstructor(int.class, String.class, String.class);
Person person = (Person)cons.newInstance(1, "小明", "男");
// 1、执行一个无参数无返回值的方法
// 获取要调用的方法的Method对象
Method showNameMethod = pClass.getDeclaredMethod("showName");
// 让method调用invoke方法 代表让当前方法执行
// 如果是实例方法,在方法执行时,一定需要一个对象才行
// 如果该方法执行需要参数,那么还要传入实参
showNameMethod.invoke(person);
// 2、如果执行一个有参数有返回值的方法
// 那么需要在调用时传入实参,sum是方法名,后面的是参数类型
Method sumMethod = pClass.getDeclaredMethod("sum", int.class, double.class);
// 设置方法时可以访问的 以免方法是private修饰造成方法不可方法
sumMethod.setAccessible(true);
double res=(double)sumMethod.invoke(person,1,3.14);
System.out.println(res);
// 3、执行一个静态方法
// 静态方法可以用对象去调用,也可以用类名去调用
// 所以在执行静态方法是可以不传入对象
Method setFirstname = pClass.getDeclaredMethod("setFirstname", String.class);
setFirstname.invoke(null,"李");
System.out.println(person)
posted @ 2022-08-10 21:46  来日可追  阅读(18)  评论(0编辑  收藏  举报