反射与注解
当我们不知道类是否加了set/get方法,但又希望能够得到它里面的一些属性或方法的时候,需要通过反射来获取,下面我创建了一个student类,但是我没有加set和get方法:
public class Student {
private Integer id;
private String name;
private String pass;
public String phone;
}
反射:先获得类,通过类.getInstance,得到对象,通过类名.getFileds可以得到类里面共有属性,如果要访问私有的,可以类名.getDeclaredFileds,可以得到类里面所有的私有属性,如果对属性赋值,需要先将可访问属性改为true,然后再利用set方法来进行赋值,详情操作见下:
Class<Student> studentClass = Student.class;//创建类
Student student = studentClass.newInstance();//创建对象
Field[] declaredFields = studentClass.getDeclaredFields();//得到全部属性
declaredFields[3].setAccessible(true);//开启访问权限
declaredFields[3].set(student,"10010");
System.out.println(student);
得到类的三种方式:
- 通过类名获得:
Class<Student> studentClass = Student.class;
- 通过对象获得:
Student student=new Student();
Class<? extends Student> aClass = student.getClass();
- 通过类的路径获得
Class<?> aClass1 = Class.forName("com.study.bean.Student");//但是这里有个泛型,如果直接创建对象会显示object
得到类之后得到属性的四种方法:
Field getDeclaredField(String name)
返回一个Field对象,得到指定已声明字段
Field[] getDeclaredFields() 返回的是Field数组,返回已声明的全部字段
Field getField(String name)
返回一个Field对象,得到指定公共成员字段
Field[] getFields() 返回的是Field数组,返回公共的全部字段
得到对象的方法:(在这里不是直接new)这里默认调用类的无参构造,如果没有无参构造会报异常:NoSuchMethodException
T newInstance()
获取构造方法:
aClass1.getConstructors()
利用对象来赋值:
void set(Object obj, Object value)
方法也是一样的方式来获取和访问:
//上面有泛型,下面需要强制转化
Student student1 = (Student) aClass1.newInstance();
Field[] declaredFields = aClass1.getDeclaredFields();
//得到类里面的公共方法:
Method setId = aClass1.getMethod("setId", Integer.class);
//赋值
setId.invoke(student1,3627);
Method getId = aClass1.getDeclaredMethod("getId");
//取值
System.out.println(getId.invoke(student1));
//得到类里面的私有方法:
Method show = aClass1.getDeclaredMethod("show", Integer.class, String.class, String.class, String.class);
//先打开权限
show.setAccessible(true);
//调用方法
show.invoke(student1, 23, "liku", "password", "1008611");
注解:
@Deprecated:标记该方法已过时
@SuppresWarning:消除编译器的警告💡
元注解:给注解加注解:
@Target:表示该注解修饰的数据类型范围
@Retention:表示该字段保留时间长短,一共有三个值:source<package<runtime
在反射中,利用getAnnotation
映射获取的注解只能获取运行时的注解,其他两种注解拿不到,当非要去获取的时候返回的将会是空值
Method show = aClass1.getDeclaredMethod("show", Integer.class, String.class, String.class, String.class);
//先打开权限
show.setAccessible(true);
//调用方法
show.invoke(student1, 23, "liku", "password", "1008611");
//获取注解:
Override annotation = show.getAnnotation(Override.class);
System.out.println("注解:"+annotation);//null
对于注解里面的属性,有默认值的可以赋值,也可以不赋值
自定义注解:关键字:@interface
/**
* 表示该注解只在构造,方法,类,接口,枚举才可使用
*/
@Target({ElementType.CONSTRUCTOR, ElementType.METHOD, ElementType.TYPE})
/**
* 表示该注解只在运行时生效
*/
@Retention(RetentionPolicy.RUNTIME)
public @interface MyAnnotation {
/**
* 属性
*
* @return
*/
int a();
/**
* 属性
*
* @return
*/
String b();
/**
* 属性
*
* @return
*/
String[] c() default {};
}
写好之后,再在上面的student类中用我们的自定义注解:
//使用的时候需要对注解里面的属性赋值
@MyAnnotation(a=23,b="world")
public class Student {
//这里的注解我没有修改默认值
@MyAnnotation(a = 3627, b = "liku")
private void show(Integer id, String name, String pass, String phone) {
System.out.println(id + " " + name + " " + pass + " " + phone);
}
//这里的注解我将注解里面的默认值修改为默认值
@MyAnnotation(a = 12, b = "hello", c = {"默认值"})
public Student(Integer id, String name, String pass, String phone) {
this.id = id;
this.name = name;
this.pass = pass;
this.phone = phone;
}
}
然后最后再通过反射来获取我们的自定义注解:
@SneakyThrows
private static void demo3() {
Class<?> aClass1 = Class.forName("com.study.bean.Student");
/**
* 获取类的注解
*/
MyAnnotation annotation = aClass1.getAnnotation(MyAnnotation.class);
System.out.println(annotation);
/**
* 获取构造方法的注解
*/
MyAnnotation annotation1 = aClass1.getConstructor().getAnnotation(MyAnnotation.class);
System.out.println(annotation1);
/**
* 获取私有方法的注解
* 需要开启访问权限
*/
Method show = aClass1.getMethod("show");
show.setAccessible(true);
MyAnnotation showAnnotation = show.getAnnotation(MyAnnotation.class);
System.out.println(showAnnotation);
}