准备工作:创建一个类
package com.chengyu.reference;
public class ReferenceBean {
private int age;
public static final String NAME = "ko";
public String phone;
public ReferenceBean(int age, String phone) {
this.age = age;
this.phone = phone;
}
public ReferenceBean() {
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getPhone() {
return phone;
}
public void setPhone(String phone) {
this.phone = phone;
}
}
获取Class对象的方式
1、Class.forName("类的权限定名"):返回对应的Class对象(多用于配置文件中)
2、类名.Class:通过类名的属性class来获取(多用于参数传递)
3、对象.getClass:getClass()方法在Object类中定义(多用于对象的获取字节码方式)
下面上代码
public static void classTest()throws Exception
{
/**
* 1.使用Class.forName
* 2.使用类名.class
* 3.使用对象.getClass()
*/
Class<?> forName = Class.forName("com.chengyu.reference.ReferenceBean");
Class<?> className = ReferenceBean.class;
ReferenceBean r = new ReferenceBean();
Class<?> classGet = r.getClass();
System.out.println(forName.hashCode());
System.out.println(className.hashCode());
System.out.println(classGet.hashCode());
}
执行结果
我们发现打印的结果相同,所以同一个字节码文件(.class)在一次程序运行过程中,只会被加载一次,不论通过那种方式获取的Class对象都是同一个(所以在使用
synchronized (类名.class){}进行对对象加锁时,锁的是同一个Class对象)
获取成员变量
public static void fieldGet() throws Exception
{
Class<?> forName = Class.forName("com.chengyu.reference.ReferenceBean");
Field[] fields = forName.getFields(); //获取到所有public修饰的属性
for(Field f : fields)
{
System.out.println("public 修饰的属性:" + f.getName());
}
System.out.println("======forName.getFields()======");
Field phone = forName.getField("phone"); //根据属性名来获取public属性
System.out.println("根据属性名获取public属性:" + phone.getName());
System.out.println("==========forName.getField(\"phone\")==========");
Field[] declaredFields = forName.getDeclaredFields(); //获取到所有的属性包括private的
for(Field fs : declaredFields)
{
System.out.println("所有的属性:" + fs.getName());
}
System.out.println("==========forName.getDeclaredFields()==========");
Field age = forName.getDeclaredField("age"); //根据指定的属性名获取属性包括private
System.out.println("根据属性名获取属性:"+ age.getName());
System.out.println("=======forName.getDeclaredField(\"age\")=====");
}
执行结果
对属性的修改:我们对类进行一下修改 添加一个private的常量
package com.chengyu.reference;
public class ReferenceBean {
private int age;
public static final String NAME = "ko";
public String phone;
private final String IDNO = "123456";
public String getIDNO() {
return IDNO;
}
public ReferenceBean(int age, String phone) {
this.age = age;
this.phone = phone;
}
public ReferenceBean() {
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getPhone() {
return phone;
}
public void setPhone(String phone) {
this.phone = phone;
}
}
下面对属性进行修改
/**
* 修改属性
*/
public static void modifyField() throws Exception
{
Class<?> forName = Class.forName("com.chengyu.reference.ReferenceBean");
ReferenceBean bean = (ReferenceBean)forName.newInstance();
//修改public 修饰的属性
Field phone = forName.getField("phone");
System.out.println("修改之前phone属性的值:" + bean.getPhone());
phone.set(bean,"13088888888"); //使用反射进行修改public修饰的属性
System.out.println("修改public修饰的属性phone:"+bean.getPhone());
Field age = forName.getDeclaredField("age");
System.out.println("修改之前age的值" + bean.getAge());
age.setAccessible(true); //这里需要跳过修饰符检查 就是所谓的暴力获取权限
age.set(bean,18); //修改private修饰的属性
System.out.println("修改private修饰的属性age:" + bean.getAge());
Field idno = forName.getDeclaredField("IDNO");
System.out.println("修改之前IDNO属性的值:" + bean.getIDNO());
idno.setAccessible(true);
idno.set(bean,"987654321"); //修改private final修饰的常量
System.out.println("修改private修饰的常量IDNO:" + bean.getIDNO());
}
执行结果
我们发现对private final修饰的常量的修改好像并未成功,但真的是这样么?
System.out.println("修改private修饰的常量IDNO:" + idno.get(bean));
我们在这里修改一下,使用反射的方式去获取修改后的值,运行结果如下:
这说明我们修改是成功的,其实主要原因是编译器优化造成的,在get方法中给我返回的值是修改之前的值,而并非常量的引用,所以在我们调用get方法去获取值的时候给我返回的就是没有修改的值,我们在这里将常量的声明稍作修改,骗一下编译器。
private final String IDNO = ""==null?"":"123456";
然后将获取的方法改回之前使用get方式
System.out.println("修改private修饰的常量IDNO:" + bean.getIDNO());
然后我们在运行一下,看看运行的结果。
完美!!!修改成功
接下来我们对private static final修饰的成员变量进行修改,代码如下
public static void test07() throws Exception
{
Class<?> forName = Class.forName("com.chengyu.reference.ReferenceBean");
ReferenceBean bean = (ReferenceBean)forName.newInstance();
//修改 被final和static修饰的属性
Field name = forName.getField("NAME");
System.out.println("修改前常量NAME:"+bean.getNAME());
name.setAccessible(true);
Field m = name.getClass().getDeclaredField("modifiers");
m.setAccessible(true);
int mod = name.getModifiers(); //保存修改之前NAME的访问权限
m.setInt(name, name.getModifiers() & ~Modifier.FINAL); //去掉final权限
name.set(bean,"CY");
m.setInt(name, mod); //NAME常量的权限修改回之前的访问权限
System.out.println("修改被static和final关键字修饰的常量NAME:"+bean.getNAME());
}
在这里使用set方法是直接修改不了的,反射是不能修改被static和final同时修饰的常量,但是我们可以通过获取的Field来修改常量的访问权限,这里我们可以看一下Field类
这个类中有一个字段modifiers表示字段的访问权限,但是并没有给我们提供修改这个字段的方法,但是我们依然可以使用反射的方式进行修改这个字段,我们看到这个字段是int类型
我们在看一下具体的表示我们查看一下Modifier类
我们可以看到我们设置的权限为public static final 使用的是16进制表示
如果是public权限 则int类型的最低位表示
如果是static权限 则int类型的从右边到左边第四位表示
如果是final权限 则int类型的从右边到左边第五位表示
所以public static final 权限使用二进制就是 00000000 00000000 00000000 00011001
最后的和就是25,然后我们使用代码来验证一下
public static void test07() throws Exception
{
Class<?> forName = Class.forName("com.chengyu.reference.ReferenceBean");
ReferenceBean bean = (ReferenceBean)forName.newInstance();
//修改 被final和static修饰的属性
Field name = forName.getField("NAME");
System.out.println("修改前常量NAME:"+bean.getNAME());
name.setAccessible(true);
Field m = name.getClass().getDeclaredField("modifiers");
m.setAccessible(true);
int mod = name.getModifiers(); //保存修改之前NAME的访问权限
System.out.println("修改之前的权限:" + mod);
m.setInt(name, name.getModifiers() & ~Modifier.FINAL); //去掉final权限
name.set(bean,"CY");
System.out.println("修改后的权限:" + name.getModifiers());
m.setInt(name, mod); //NAME常量的权限修改回之前的访问权限
System.out.println("修改被static和final关键字修饰的常量NAME:"+bean.getNAME());
}
我们来看一下结果
所以我们可以知道这个字段上二进制的每一个位置所表示的权限。所以我们可以是用位运算进行修改权限。修改一下我们的代码
public static void test07() throws Exception
{
Class<?> forName = Class.forName("com.chengyu.reference.ReferenceBean");
ReferenceBean bean = (ReferenceBean)forName.newInstance();
//修改 被final和static修饰的属性
Field name = forName.getField("NAME");
System.out.println("修改前常量NAME:"+bean.getNAME());
name.setAccessible(true);
Field m = name.getClass().getDeclaredField("modifiers");
m.setAccessible(true);
System.out.println("修改之前的权限:" + name.getModifiers());
m.setInt(name, name.getModifiers() & ~Modifier.FINAL); //去掉final权限
name.set(bean,"CY");
System.out.println("修改后的权限:" + name.getModifiers());
m.setInt(name, name.getModifiers() | Modifier.FINAL); //NAME常量的权限修改回之前的访问权限
System.out.println("修改回来的权限是:" + name.getModifiers());
System.out.println("修改被static和final关键字修饰的常量NAME:"+bean.getNAME());
}
然后我们看一下运行结果:
OK!完全没有问题,这下我们可以看到反射的威力了吧!
接下来我们来看一下反射是如何来操作构造方法的,修改一下我们的类,添加构造方法和toString方法
package com.chengyu.reference;
public class ReferenceBean {
private int age;
public static final String NAME = ""==null?"":"ko";
public String phone;
private final String IDNO = ""==null?"":"123456";
public static String getNAME() {
return NAME;
}
public String getIDNO() {
return IDNO;
}
public ReferenceBean(int age, String phone) {
this.age = age;
this.phone = phone;
}
private ReferenceBean(int age)
{
this.age = age;
}
public ReferenceBean() {
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getPhone() {
return phone;
}
public void setPhone(String phone) {
this.phone = phone;
}
@Override
public String toString() {
return "ReferenceBean{" +
"age=" + age +
", phone='" + phone + '\'' +
", IDNO='" + IDNO + '\'' +
'}';
}
}
接下来我们看看如何操作构造函数
public static void constuctorTest() throws Exception
{
Class<?> forName = Class.forName("com.chengyu.reference.ReferenceBean");
Constructor<?>[] constructors = forName.getConstructors(); //获取所有的被public修饰的构造方法
for(Constructor c: constructors)
{
System.out.println("获取到的所有被public修饰的构造方法: " + c);
}
Constructor<?> constructor = forName.getConstructor(int.class, String.class); //根据参数列表获取指定的public修饰的构造方法
Object o = constructor.newInstance(18, "13584789546"); //创建对象
System.out.println("根据参数列表获取指定的public修饰的构造方法创建的对象: " + o);
Constructor<?> [] declaredConstructor = forName.getDeclaredConstructors();//获取到所有的构造函数包括private修饰的
for(Constructor cc : declaredConstructor)
{
System.out.println("获取到的所有的构造函数包括private修饰的: " + cc);
}
Constructor<?> declaredConstructor1 = forName.getDeclaredConstructor(int.class);//获取到指定参数列表的构造函数,包括private修饰的
declaredConstructor1.setAccessible(true); //跳过权限检查
Object o1 = declaredConstructor1.newInstance(18); //创建对象
System.out.println("根据指定参数获取到的private修饰的构造函数创建的对象 : " + o1);
}
然后我们来看看运行的结果
完全没有问题
这里如果我们如果使用无参的构造函数我们可以直接使用
forName.getClass().newInstance();这种方式来创建对象
接下来我们看看怎样使用反射对方法进行操作
首先修改一下我们的类
package com.chengyu.reference;
public class ReferenceBean {
private int age;
public static final String NAME = ""==null?"":"ko";
public String phone;
private final String IDNO = ""==null?"":"123456";
public static String getNAME() {
return NAME;
}
public String getIDNO() {
return IDNO;
}
public ReferenceBean(int age, String phone) {
this.age = age;
this.phone = phone;
}
private ReferenceBean(int age)
{
this.age = age;
}
public ReferenceBean() {
}
private String study(String name)
{
System.out.println(name + "在学习。。。。。");
return name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getPhone() {
return phone;
}
public void setPhone(String phone) {
this.phone = phone;
}
@Override
public String toString() {
return "ReferenceBean{" +
"age=" + age +
", phone='" + phone + '\'' +
", IDNO='" + IDNO + '\'' +
'}';
}
}
然后上代码
public static void methodTest()throws Exception
{
Class<?> forName = Class.forName("com.chengyu.reference.ReferenceBean");
ReferenceBean bean = (ReferenceBean)forName.newInstance();
Method[] methods = forName.getMethods();//获取所有被public修饰的方法包含父类的方法
for(Method m : methods)
{
System.out.println("获取所有被public修饰的方法包含父类的方法 : " + m);
}
Method setAge = forName.getMethod("setAge", int.class); //根据方法名称和参数列表获取指定方法
setAge.invoke(bean, 18); //方法调用第一个参数是对象的实例,第二个参数是给setAge方法传入的参数
System.out.println("根据方法名称和参数列表获取指定方法,然后调用方法: " + bean.getAge()); //这里我们进行一下验证看看age是否设置进去了
Method[] declaredMethods = forName.getDeclaredMethods(); //获取所有的方法包括被private的修饰的不包含父类的方法
for(Method mm : declaredMethods)
{
System.out.println("获取所有的方法包括被private的修饰的不包含父类的方法" + mm);
}
Method study = forName.getDeclaredMethod("study", String.class);//根据方法名和参数列表获取指定的方法(可以获取到private修饰的方法)
study.setAccessible(true); //跳过访问权限检查
Object ss = study.invoke(bean, "学生"); //在这里我们可以获取到方法的返回值
System.out.println("根据方法名和参数列表获取指定的方法(可以获取到private修饰的方法),获取到的返回值是 : " + String.valueOf(ss));
}
看一下我们的运行结果
接下来我们看看怎么利用反射对注解进行解析
添加一个自定义注解
package com.chengyu.reference;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target({ElementType.TYPE,ElementType.METHOD,ElementType.FIELD}) //这里是元注解,表示我自定义的注解可以在类、方法、属性上使用
@Retention(RetentionPolicy.RUNTIME) //这个表示注解保留的阶段为运行时 我们要是反射来获取所有不能将注解保留在其他阶段 否者就获取不到注解了
public @interface MyAnn {
int age() default 18;
String name() default "KO";
}
修改一下我们的类 在类、方法、属性上添加注解
package com.chengyu.reference;
@MyAnn
public class ReferenceBean {
private int age;
public static final String NAME = ""==null?"":"ko";
@MyAnn(age = 15,name = "小小")
public String phone;
private final String IDNO = ""==null?"":"123456";
public static String getNAME() {
return NAME;
}
public String getIDNO() {
return IDNO;
}
public ReferenceBean(int age, String phone) {
this.age = age;
this.phone = phone;
}
private ReferenceBean(int age)
{
this.age = age;
}
public ReferenceBean() {
}
@MyAnn(age = 20,name = "KO大师")
private String study(String name)
{
System.out.println(name + "在学习。。。。。");
return name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getPhone() {
return phone;
}
public void setPhone(String phone) {
this.phone = phone;
}
@Override
public String toString() {
return "ReferenceBean{" +
"age=" + age +
", phone='" + phone + '\'' +
", IDNO='" + IDNO + '\'' +
'}';
}
}
然后我们来看看如何使用反射来解析注解
public static void annTest() throws Exception
{
Class<?> forName = Class.forName("com.chengyu.reference.ReferenceBean");
ReferenceBean bean = (ReferenceBean)forName.newInstance();
boolean annotationPresent = forName.isAnnotationPresent(MyAnn.class);//首先判断我们类上面是否使用了MyAnn注解
Annotation[] annotations = forName.getAnnotations(); //这里是获取所有的注解
for(Annotation a : annotations)
{
System.out.println("获取类上所有的注解: " + a);
}
if(annotationPresent)
{
MyAnn annotation = forName.getAnnotation(MyAnn.class); //在指定获取注解是需要进行判断是否使用了这个注解
System.out.println("指定获取类上面的注解: name = " + annotation.name() + " age = " + annotation.age() );
}
Field phone = forName.getField("phone");
Annotation[] annotations1 = phone.getAnnotations(); //获取成员变量上所有的注解
for(Annotation a : annotations1)
{
System.out.println("获取指定成员变量上所有的注解:" + a);
}
boolean annotationPresent1 = phone.isAnnotationPresent(MyAnn.class);
if(annotationPresent1)
{
MyAnn annotation = phone.getAnnotation(MyAnn.class);//指定获取成员变量上的注解
int age = annotation.age();
String name = annotation.name();
phone.set(bean,name); //将注解上的name赋值给phone字段
System.out.println("指定获取成员变量上的注解 : " + bean.getPhone());
}
Method study = forName.getDeclaredMethod("study", String.class);
Annotation[] annotations2 = study.getAnnotations(); //获取方法上所有的注解
for(Annotation aa : annotations2)
{
System.out.println("获取方法上所有的注解:" + aa);
}
boolean annotationPresent2 = study.isAnnotationPresent(MyAnn.class);
if(annotationPresent2)
{
MyAnn annotation = study.getAnnotation(MyAnn.class);//指定获取方法上的注解
int age = annotation.age();
String name = annotation.name();
study.setAccessible(true); //跳过权限检查
Object invoke = study.invoke(bean, name);//将注解的name信息作为study方法的入参,调用study方法,获取到返回信息进行打印
System.out.println("指定获取方法上的注解:" + String.valueOf(invoke));
}
}
然后看一下执行结果
到此为止,反射的基本用法已经介绍完了,我们可以看得到反射的强大,写这篇文章希望能够帮助大家更好的理解反射,java的反射使用的地方很多很多,在很多的框架中都使用到了反射。
最后上传一下最终版本的代码,供大家测试使用
package com.chengyu.reference;
import java.lang.annotation.Annotation;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
public class ReferenceTest
{
public static void main(String[] args) throws Exception {
//classTest();
//fieldGet();
//modifyField();
//test07();
//constuctorTest();
//methodTest();
annTest();
}
/**
* 获取Class对象
*/
public static void classTest()throws Exception
{
/**
* 1.使用Class.forName
* 2.使用类名.class
* 3.使用对象.getClass()
*/
Class<?> forName = Class.forName("com.chengyu.reference.ReferenceBean");
Class<?> className = ReferenceBean.class;
ReferenceBean r = new ReferenceBean();
Class<?> classGet = r.getClass();
System.out.println(forName.hashCode());
System.out.println(className.hashCode());
System.out.println(classGet.hashCode());
}
/**
* 获取属性
*/
public static void fieldGet() throws Exception
{
Class<?> forName = Class.forName("com.chengyu.reference.ReferenceBean");
Field[] fields = forName.getFields(); //获取到所有public修饰的属性
for(Field f : fields)
{
System.out.println("public 修饰的属性:" + f.getName());
}
System.out.println("======forName.getFields()======");
Field phone = forName.getField("phone"); //根据属性名来获取public属性
System.out.println("根据属性名获取public属性:" + phone.getName());
System.out.println("==========forName.getField(\"phone\")==========");
Field[] declaredFields = forName.getDeclaredFields(); //获取到所有的属性包括private的
for(Field fs : declaredFields)
{
System.out.println("所有的属性:" + fs.getName());
}
System.out.println("==========forName.getDeclaredFields()==========");
Field age = forName.getDeclaredField("age"); //根据指定的属性名获取属性包括private
System.out.println("根据属性名获取属性:"+ age.getName());
System.out.println("=======forName.getDeclaredField(\"age\")=====");
}
/**
* 修改属性
*/
public static void modifyField() throws Exception
{
Class<?> forName = Class.forName("com.chengyu.reference.ReferenceBean");
ReferenceBean bean = (ReferenceBean)forName.newInstance();
//修改public 修饰的属性
Field phone = forName.getField("phone");
System.out.println("修改之前phone属性的值:" + bean.getPhone());
phone.set(bean,"13088888888"); //使用反射进行修改public修饰的属性
System.out.println("修改public修饰的属性phone:"+bean.getPhone());
Field age = forName.getDeclaredField("age");
System.out.println("修改之前age的值" + bean.getAge());
age.setAccessible(true); //这里需要跳过修饰符检查 就是所谓的暴力获取权限
age.set(bean,18); //修改private修饰的属性
System.out.println("修改private修饰的属性age:" + bean.getAge());
Field idno = forName.getDeclaredField("IDNO");
System.out.println("修改之前IDNO属性的值:" + bean.getIDNO());
idno.setAccessible(true);
idno.set(bean,"987654321"); //修改private final修饰的常量
System.out.println("修改private修饰的常量IDNO:" + bean.getIDNO());
}
public static void test07() throws Exception
{
Class<?> forName = Class.forName("com.chengyu.reference.ReferenceBean");
ReferenceBean bean = (ReferenceBean)forName.newInstance();
//修改 被final和static修饰的属性
Field name = forName.getField("NAME");
System.out.println("修改前常量NAME:"+bean.getNAME());
name.setAccessible(true);
Field m = name.getClass().getDeclaredField("modifiers");
m.setAccessible(true);
System.out.println("修改之前的权限:" + name.getModifiers());
m.setInt(name, name.getModifiers() & ~Modifier.FINAL); //去掉final权限
name.set(bean,"CY");
System.out.println("修改后的权限:" + name.getModifiers());
m.setInt(name, name.getModifiers() | Modifier.FINAL); //NAME常量的权限修改回之前的访问权限
System.out.println("修改回来的权限是:" + name.getModifiers());
System.out.println("修改被static和final关键字修饰的常量NAME:"+bean.getNAME());
}
public static void constuctorTest() throws Exception
{
Class<?> forName = Class.forName("com.chengyu.reference.ReferenceBean");
Constructor<?>[] constructors = forName.getConstructors(); //获取所有的被public修饰的构造方法
for(Constructor c: constructors)
{
System.out.println("获取到的所有被public修饰的构造方法: " + c);
}
Constructor<?> constructor = forName.getConstructor(int.class, String.class); //根据参数列表获取指定的public修饰的构造方法
Object o = constructor.newInstance(18, "13584789546"); //创建对象
System.out.println("根据参数列表获取指定的public修饰的构造方法创建的对象: " + o);
Constructor<?> [] declaredConstructor = forName.getDeclaredConstructors();//获取到所有的构造函数包括private修饰的
for(Constructor cc : declaredConstructor)
{
System.out.println("获取到的所有的构造函数包括private修饰的: " + cc);
}
Constructor<?> declaredConstructor1 = forName.getDeclaredConstructor(int.class);//获取到指定参数列表的构造函数,包括private修饰的
declaredConstructor1.setAccessible(true); //跳过权限检查
Object o1 = declaredConstructor1.newInstance(18); //创建对象
System.out.println("根据指定参数获取到的private修饰的构造函数创建的对象 : " + o1);
}
public static void methodTest()throws Exception
{
Class<?> forName = Class.forName("com.chengyu.reference.ReferenceBean");
ReferenceBean bean = (ReferenceBean)forName.newInstance();
Method[] methods = forName.getMethods();//获取所有被public修饰的方法包含父类的方法
for(Method m : methods)
{
System.out.println("获取所有被public修饰的方法包含父类的方法 : " + m);
}
Method setAge = forName.getMethod("setAge", int.class); //根据方法名称和参数列表获取指定方法
setAge.invoke(bean, 18); //方法调用第一个参数是对象的实例,第二个参数是给setAge方法传入的参数
System.out.println("根据方法名称和参数列表获取指定方法,然后调用方法: " + bean.getAge()); //这里我们进行一下验证看看age是否设置进去了
Method[] declaredMethods = forName.getDeclaredMethods(); //获取所有的方法包括被private的修饰的不包含父类的方法
for(Method mm : declaredMethods)
{
System.out.println("获取所有的方法包括被private的修饰的不包含父类的方法" + mm);
}
Method study = forName.getDeclaredMethod("study", String.class);//根据方法名和参数列表获取指定的方法(可以获取到private修饰的方法)
study.setAccessible(true); //跳过访问权限检查
Object ss = study.invoke(bean, "学生"); //在这里我们可以获取到方法的返回值
System.out.println("根据方法名和参数列表获取指定的方法(可以获取到private修饰的方法),获取到的返回值是 : " + String.valueOf(ss));
}
public static void annTest() throws Exception
{
Class<?> forName = Class.forName("com.chengyu.reference.ReferenceBean");
ReferenceBean bean = (ReferenceBean)forName.newInstance();
boolean annotationPresent = forName.isAnnotationPresent(MyAnn.class);//首先判断我们类上面是否使用了MyAnn注解
Annotation[] annotations = forName.getAnnotations(); //这里是获取所有的注解
for(Annotation a : annotations)
{
System.out.println("获取类上所有的注解: " + a);
}
if(annotationPresent)
{
MyAnn annotation = forName.getAnnotation(MyAnn.class); //在指定获取注解是需要进行判断是否使用了这个注解
System.out.println("指定获取类上面的注解: name = " + annotation.name() + " age = " + annotation.age() );
}
Field phone = forName.getField("phone");
Annotation[] annotations1 = phone.getAnnotations(); //获取成员变量上所有的注解
for(Annotation a : annotations1)
{
System.out.println("获取指定成员变量上所有的注解:" + a);
}
boolean annotationPresent1 = phone.isAnnotationPresent(MyAnn.class);
if(annotationPresent1)
{
MyAnn annotation = phone.getAnnotation(MyAnn.class);//指定获取成员变量上的注解
int age = annotation.age();
String name = annotation.name();
phone.set(bean,name); //将注解上的name赋值给phone字段
System.out.println("指定获取成员变量上的注解 : " + bean.getPhone());
}
Method study = forName.getDeclaredMethod("study", String.class);
Annotation[] annotations2 = study.getAnnotations(); //获取方法上所有的注解
for(Annotation aa : annotations2)
{
System.out.println("获取方法上所有的注解:" + aa);
}
boolean annotationPresent2 = study.isAnnotationPresent(MyAnn.class);
if(annotationPresent2)
{
MyAnn annotation = study.getAnnotation(MyAnn.class);//指定获取方法上的注解
int age = annotation.age();
String name = annotation.name();
study.setAccessible(true); //跳过权限检查
Object invoke = study.invoke(bean, name);//将注解的name信息作为study方法的入参,调用study方法,获取到返回信息进行打印
System.out.println("指定获取方法上的注解:" + String.valueOf(invoke));
}
}
}
package com.chengyu.reference;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target({ElementType.TYPE,ElementType.METHOD,ElementType.FIELD}) //这里是元注解,表示我自定义的注解可以在类、方法、属性上使用
@Retention(RetentionPolicy.RUNTIME) //这个表示注解保留的阶段为运行时 我们要是反射来获取所有不能将注解保留在其他阶段 否者就获取不到注解了
public @interface MyAnn {
int age() default 18;
String name() default "KO";
}
package com.chengyu.reference;
@MyAnn
public class ReferenceBean {
private int age;
public static final String NAME = ""==null?"":"ko";
@MyAnn(age = 15,name = "小小")
public String phone;
private final String IDNO = ""==null?"":"123456";
public static String getNAME() {
return NAME;
}
public String getIDNO() {
return IDNO;
}
public ReferenceBean(int age, String phone) {
this.age = age;
this.phone = phone;
}
private ReferenceBean(int age)
{
this.age = age;
}
public ReferenceBean() {
}
@MyAnn(age = 20,name = "KO大师")
private String study(String name)
{
System.out.println(name + "在学习。。。。。");
return name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getPhone() {
return phone;
}
public void setPhone(String phone) {
this.phone = phone;
}
@Override
public String toString() {
return "ReferenceBean{" +
"age=" + age +
", phone='" + phone + '\'' +
", IDNO='" + IDNO + '\'' +
'}';
}
}
代码中有很多注释,所以就不在啰嗦了,欢迎大家留言。
原创不易,不喜勿喷,有更好的建议,欢迎留言!!