第一句子网 - 唯美句子、句子迷、好句子大全
第一句子网 > java反射学习_Java反射学习:深入学习Java反射机制

java反射学习_Java反射学习:深入学习Java反射机制

时间:2018-12-28 10:56:20

相关推荐

java反射学习_Java反射学习:深入学习Java反射机制

一、Java反射的理解(反射是研究框架的基础之一)

Java反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性;这种动态获取的信息以及动态调用对象的方法的功能称为Java语言的反射机制。

二、逐步分析

1、关于Class

1、Class是一个类,一个描述类的类(也就是描述类本身),封装了描述方法的Method,描述字段的Filed,描述构造器的Constructor等属性

2、对象照镜子后(反射)可以得到的信息:某个类的数据成员名、方法和构造器、某个类到底实现了哪些接口。

3、对于每个类而言,JRE 都为其保留一个不变的 Class 类型的对象。一个 Class 对象包含了特定某个类的有关信息。

4、Class 对象只能由系统建立对象

5、一个类在 JVM 中只会有一个Class实例

下面创建一个例子:后面的分析均以此案例为基准。

创建一个空接口:(后面会不断补充)

1 packagecom.xfwl.reflection;2

3 public interfaceIHuman {4

5 }

创建一个空基类:(后面会不断补充)

1 packagecom.xfwl.reflection;2

3 public classHuman {4

5 }

创建一个子类:(后面会不断补充)

1 packagecom.xfwl.reflection;2

3 public class Person extends Human implementsIHuman {4 /**

5 * 默认default修饰6 */

7 String name;8 /**

9 * private修饰10 */

11 private intage;12 /**

13 * public修饰14 */

15 public char sex='M';16 /**

17 * 无参构造18 */

19 publicPerson(){20 System.out.println("无参构造!!!");21 }22 /**

23 * 有参构造24 */

25 public Person(String name,int age,charsex){26 System.out.println("有参构造!!!");27 this.name=name;28 this.age=age;29 this.sex=sex;30 }31 publicString getName() {32 returnname;33 }34 public voidsetName(String name) {35 this.name =name;36 }37 public intgetAge() {38 returnage;39 }40 public void setAge(intage) {41 this.age =age;42 }43 public chargetSex() {44 returnsex;45 }46 public void setSex(charsex) {47 this.sex =sex;48 }49 publicString toString() {50 return "Person{" +

51 "name='" + name + '\'' +

52 ", age=" + age +

53 ", sex='" + sex + '\'' +

54 '}';55 }56 }

2、反射获取类对象的三种方式(通过一个Junit测试来说明)

1 packagecom.xfwl.reflection;2

3 importorg.junit.Test;4 /**

5 * 测试类6 * @function7 *@author小风微凉8 * @time -6-3 下午12:28:389 */

10 public classTestAction {11 /**

12 * 反射机制获取类有三种方法13 */

14 @Test15 public void testGetClass() throwsClassNotFoundException {16 Class clazz = null;17

18 //1 直接通过类名.Class的方式得到

19 clazz = Person.class;20 System.out.println("通过类名: " +clazz);21

22 //2 通过对象的getClass()方法获取,这个使用的少(一般是传的是Object,不知道是什么类型的时候才用)

23 Object obj = newPerson();24 clazz =obj.getClass();25 System.out.println("通过getClass(): " +clazz);26

27 //3 通过全类名获取,用的比较多,但可能抛出ClassNotFoundException异常

28 clazz = Class.forName("com.xfwl.reflection.Person");29 System.out.println("通过全类名获取: " +clazz);30 }31 }

运行结果:

通过类名: classcom.xfwl.reflection.Person

无参构造!!!

通过getClass():classcom.xfwl.reflection.Person

通过全类名获取:class com.xfwl.reflection.Person

特别注意:(以下2中方式不会调用构造方法,因为没有实例化操作)

//1 直接通过类名.Class的方式得到

clazz = Person.class;//3 通过全类名获取,用的比较多,但可能抛出ClassNotFoundException异常

clazz = Class.forName("com.xfwl.reflection.Person");

3、利用newInstance创建对象:调用的类必须有无参的构造器

1 /**

2 * Class类的newInstance()方法,创建类的一个对象。3 *@throwsClassNotFoundException4 *@throwsIllegalAccessException5 *@throwsInstantiationException6 */

7 @Test8 public voidtestNewInstance()9 throwsClassNotFoundException, IllegalAccessException, InstantiationException {10

11 Class clazz = Class.forName("com.xfwl.reflection.Person");12

13 //使用Class类的newInstance()方法创建类的一个对象14 //实际调用的类的那个 无参数的构造器(这就是为什么写的类的时候,要写一个无参数的构造器,就是给反射用的)15 //一般的,一个类若声明了带参数的构造器,也要声明一个无参数的构造器

16 Object obj =clazz.newInstance();17 System.out.println(obj);18 }

测试结果:

那么,如果删除Person.java中的无参构造,继续测试,结果如下:

4、ClassLoader类加载器

1 /**

2 * ClassLoader类装载器3 */

4 @Test5 public void testClassLoader1() throwsClassNotFoundException, IOException {6 //1、获取一个系统的类加载器

7 ClassLoader classLoader =ClassLoader.getSystemClassLoader();8 System.out.println("系统的类加载器-->" +classLoader);9

10 //2、获取系统类加载器的父类加载器(扩展类加载器(extensions classLoader))

11 classLoader =classLoader.getParent();12 System.out.println("扩展类加载器-->" +classLoader);13

14 //3、获取扩展类加载器的父类加载器15 //输出为Null,无法被Java程序直接引用

16 classLoader =classLoader.getParent();17 System.out.println("启动类加载器-->" +classLoader);18

19 //4、测试当前类由哪个类加载器进行加载 ,结果就是系统的类加载器

20 classLoader = Class.forName("com.xfwl.reflection.Person").getClassLoader();21 System.out.println("当前类由哪个类加载器进行加载-->"+classLoader);22

23 //5、测试JDK提供的Object类由哪个类加载器负责加载的24 //输出为Null,无法被Java程序直接引用

25 classLoader = Class.forName("java.lang.Object").getClassLoader();26 System.out.println("JDK提供的Object类由哪个类加载器加载-->" +classLoader);27 }

测试结果:

系统的类加载器-->sun.misc.Launcher$AppClassLoader@18b4aac2

扩展类加载器-->sun.misc.Launcher$ExtClassLoader@614c5515

启动类加载器-->null当前类由哪个类加载器进行加载-->sun.misc.Launcher$AppClassLoader@18b4aac2

JDK提供的Object类由哪个类加载器加载-->null

5、反射机制通过加载器获取流对象:getResourceAsStream方法

1 /**

2 * 反射机制通过加载器获取流对象:getResourceAsStream方法3 *@throwsClassNotFoundException4 *@throwsIOException5 */

6 @Test7 public void testGetResourceAsStream() throwsClassNotFoundException, IOException {8 //调用getResourceAsStream 获取类路径下的文件对应的输入流

9 /**

10 * 特别说明:11 * getResourceAsStream("path"),path的路径和new Person()的位置有关12 */

13

14 InputStream in = newPerson().getClass().getClassLoader()15 .getResourceAsStream("com/xfwl/reflection/test.properties");16 System.out.println("in: " +in);17

18 Properties properties = newProperties();19 properties.load(in);20 System.out.println("文件内容:"+properties);21 System.out.println("name: "+properties.getProperty("name"));22 System.out.println("age: " + properties.getProperty("age"));23 System.out.println("sex: "+properties.getProperty("sex"));24 System.out.println("desc: " + properties.getProperty("desc"));25 }

test.properties文件内容如下:文件编码格式:ISO-8859-1

name=\u5C0F\u98CE\u5FAE\u51C9\u0087\u0089

age=23sex=M

desc=\u53CD\u5C04\u673A\u5236\u5B66\u4E60

运行结果:(直接解析会出现乱码问题,这个可以通过new String(乱码格式处理参数)来处理)

无参构造!!!

in: java.io.BufferedInputStream@215be6bb

文件内容:{age=23, name=小风微凉??, sex=M, desc=反射机制学习}

name: 小风微凉??age:23sex: M

desc: 反射机制学习

6、反射机制获取类中的方法:Method: 对应类中的方法

现在给Person类添加一个private方法、一个public 方法、一个defaut 方法、一个protected方法

1 /**

2 * Java权限有四个,分别为public,protected,默认,private,其开放程度依次降低3 * public可供所有类访问4 * protected继承可见5 * private只能类本身内部的方法可以访问6 */

7 public voidmethod_public(){8 System.out.println("method_public");9 }10 public void method_public_2(String name,int age,char sex){//public 带参数

11 System.out.println("method_public_2");12 String info="Person{" +

13 "name='" + name + '\'' +

14 ", age=" + age +

15 ", sex='" + sex + '\'' +

16 '}';17 System.out.println(info);18 }19 protected voidmethod_protected(){20 System.out.println("method_protected");21 }22 protected void method_protected_2(String info){//protected 带参数

23 System.out.println("method_protected_2:"+info);24 }25 voidmethod_default(){26 System.out.println("method_default");27 }28 void method_default_2(String info){//默认修饰符 带参数

29 System.out.println("method_default_2:"+info);30 }31 private voidmethod_private(){32 System.out.println("method_private");33 }34 private void method_private_2(String info){//private 带参数

35 System.out.println("method_private_2:"+info);36 }

开始测试如何通过反射机制使用这些方法

1 /**

2 * 如何通过反射机制使用这些方法3 *@throwsClassNotFoundException4 *@throwsNoSuchMethodException5 *@throwsIllegalAccessException6 *@throwsInstantiationException7 *@throwsInvocationTargetException8 */

9 @Test10 public void testMethod() throwsClassNotFoundException, NoSuchMethodException,11 IllegalAccessException, InstantiationException, InvocationTargetException {12 Class clazz = Class.forName("com.xfwl.reflection.Person");13

14 //1、得到clazz 对应的类中有哪些方法,不能获取private方法

15 Method[] methods =clazz.getMethods();16 System.out.println("通过反射机制可以拿到的方法:clazz.getMethods()");17 for(Method method : methods){18 System.out.println(method.getName());19 }20 System.out.println("");21

22 //2、获取所有的方法(且只获取当着类声明的方法,包括private方法)

23 Method[] methods2 =clazz.getDeclaredMethods();24 System.out.println("通过反射机制可以拿到的方法:clazz.getDeclaredMethods()");25 for(Method method : methods2){26 System.out.println(method.getName());27 }28 System.out.println("");29 System.out.println("通过反射机制可以拿到指定的方法:clazz.getDeclaredMethod()");30 //3、获取指定的方法

31 Method method1= clazz.getDeclaredMethod("method_private");32 System.out.println("private 无参:"+method1);33

34 Method method2 = clazz.getDeclaredMethod("method_private_2",String.class);//第一个参数是方法名,后面的是方法里的参数

35 System.out.println("private 有参:"+method2);36

37 Method method3 = clazz.getDeclaredMethod("method_public_2",String.class,int.class,char.class);//第一个参数是方法名,后面的是方法里的参数

38 System.out.println("public 有参:"+method2);39

40 //4、执行方法!

41 Object obj =clazz.newInstance();42 method3.invoke(obj, "小风微凉", 23,'M'); //执行方法:invoke(类对象)43 }

测试结果:

通过反射机制可以拿到的方法:clazz.getMethods():不能获取private/protected/default方法

toString

getName

setName

method_public_2

setAge

method_public

getSex

getAge

setSex

wait

wait

wait

equals

hashCode

getClass

notify

notifyAll通过反射机制可以拿到的方法:clazz.getDeclaredMethods():获取所有修饰权限的方法

toString

getName

setName

method_private_2

method_private

method_public_2

setAge

method_public

method_default

method_default_2

getSex

getAge

setSex

method_protected

method_protected_2通过反射机制可以拿到指定的方法:clazz.getDeclaredMethod()private 无参:private voidcom.xfwl.reflection.Person.method_private()private 有参:private voidcom.xfwl.reflection.Person.method_private_2(java.lang.String)public 有参:private voidcom.xfwl.reflection.Person.method_private_2(java.lang.String)

无参构造!!!

method_public_2

Person{name='小风微凉', age=23, sex='M'}

继续分析一下:

JDK中的获取方法

获取方法:默认只能获取public修饰的方法

1 @CallerSensitive2 public Method[] getMethods() throwsSecurityException {3 checkMemberAccess(Member.PUBLIC, Reflection.getCallerClass(), true);4 returncopyMethods(privateGetPublicMethods());5 }

获取方法:所有修饰权限的方法都可以获得

@CallerSensitivepublic Method[] getDeclaredMethods() throwsSecurityException {

checkMemberAccess(Member.DECLARED, Reflection.getCallerClass(),true);return copyMethods(privateGetDeclaredMethods(false));

}

获取方法:获取指定的方法(所有修饰权限)

1 /**

2 * @jls 8.2 Class Members3 * @jls 8.4 Method Declarations4 *@sinceJDK1.15 */

6 @CallerSensitive7 public Method getDeclaredMethod(String name, Class>... parameterTypes)8 throwsNoSuchMethodException, SecurityException {9 checkMemberAccess(Member.DECLARED, Reflection.getCallerClass(), true);10 Method method = searchMethods(privateGetDeclaredMethods(false), name, parameterTypes);11 if (method == null) {12 throw new NoSuchMethodException(getName() + "." + name +argumentTypesToString(parameterTypes));13 }14 returnmethod;15 }

分析一下上面这个方法:

String name:方法的名称

Class>... parameterTypes:一个或多个方法参数的类型,注意要一一对应,否则会报错的哦

执行方法:invoke(方法对象,方法实际参数)

1 @CallerSensitive2 publicObject invoke(Object obj, Object... args)3 throwsIllegalAccessException, IllegalArgumentException,4 InvocationTargetException5 {6 if (!override) {7 if (!Reflection.quickCheckMemberAccess(clazz, modifiers)) {8 Class> caller =Reflection.getCallerClass();9 checkAccess(caller, clazz, obj, modifiers);10 }11 }12 MethodAccessor ma = methodAccessor; //read volatile

13 if (ma == null) {14 ma =acquireMethodAccessor();15 }16 returnma.invoke(obj, args);17 }

7、反射机制获取类中的方法:Method: 对应基类或接口中的方法

上面分析了,如何通过反射拿到当前本类里面的各个修饰权限的方法,下面来继续分析一下,如何读取父类或实现的接口中的方法:

现在,给父类添加一些方法,在接口中定义一些方法:

接口中的方法声明:

1 packagecom.xfwl.reflection;2

3 public interfaceIHuman {4

5 voideat();6 voideat(String info);7 }

Person.java实现接口方法

1 public voideat() {2 System.out.println("实现接口的方法:eat()无参:");3 }4 public voideat(String info) {5 System.out.println("实现接口的方法:eat()有参:"+info);6 }

父类中的方法定义:

1 packagecom.xfwl.reflection;2

3 public classHuman {4 public voidplay_public(){5 System.out.println("public无参:play_public");6 }7 public voidplay_public_2(String info){8 System.out.println("public有参:play_public2:"+info);9 }10 protected voidplay_protected(){11 System.out.println("protected无参:play_protected");12 }13 protected voidplay_protected_2(String info){14 System.out.println("protected有参:play_protected_2:"+info);15 }16 voidplay_default(){17 System.out.println("默认修饰符无参:play_default");18 }19 void play_default_2(String info){//默认修饰符 带参数

20 System.out.println("默认修饰符有参:play_default_2:"+info);21 }22 private voidplay_private(){23 System.out.println("private无参:play_private");24 }25 private voidplay_private_2(String info){26 System.out.println("private有参:play_private_2:"+info);27 }28 }

开始测试:

1、拿到当前Person类反射对象,能否得到接口中的方法

1 /**

2 * 反射机制获取类中的方法:Method: 对应基类或接口中的方法3 *@throwsClassNotFoundException4 *@throwsSecurityException5 *@throwsNoSuchMethodException6 *@throwsInstantiationException7 *@throwsInvocationTargetException8 *@throwsIllegalArgumentException9 *@throwsIllegalAccessException10 */

11 @Test12 public void testInterfaceOrSupperClass() throwsClassNotFoundException, NoSuchMethodException, SecurityException, IllegalAccessException, IllegalArgumentException, InvocationTargetException, InstantiationException{13 Class clazz = Class.forName("com.xfwl.reflection.Person");14 //拿到当前Person类反射对象,能否得到接口中的方法

15 for(Method method : clazz.getMethods()){16 System.out.println(method.getName());17 }18 //获取当前类实现的接口中的方法

19 Method method1= clazz.getDeclaredMethod("eat");20 Method method2= clazz.getDeclaredMethod("eat",String.class);21 //执行

22 method1.invoke(clazz.newInstance());23 method2.invoke(clazz.newInstance(),"eat有参数");24 }

测试结果:(可以拿到实现的接口中的方法并执行)

toString

getName

setName

eat

eat

method_public_2

setAge

getSex

setSex

getAge

method_public

play_public_2

play_public

wait

wait

wait

equals

hashCode

getClass

notify

notifyAll

无参构造!!!

实现接口的方法:eat()无参:

无参构造!!!

实现接口的方法:eat()有参:eat有参数

2、拿到当前Person类反射对象,能否获取父类中的方法

通过当前反射对象,拿到父类反射对象

1 Class clazz = Class.forName("com.xfwl.reflection.Person");2 Class superClazz = clazz.getSuperclass();

1 /**

2 * 反射机制获取类中的方法:Method: 对应基类或接口中的方法3 *@throwsClassNotFoundException4 *@throwsSecurityException5 *@throwsNoSuchMethodException6 *@throwsInstantiationException7 *@throwsInvocationTargetException8 *@throwsIllegalArgumentException9 *@throwsIllegalAccessException10 */

11 @Test12 public void testInterfaceOrSupperClass() throwsClassNotFoundException, NoSuchMethodException, SecurityException, IllegalAccessException, IllegalArgumentException, InvocationTargetException, InstantiationException{13 Class clazz = Class.forName("com.xfwl.reflection.Person");14 System.out.println("");15 //拿到当前Person类反射对象,能否获取父类中的方法

16 Class superClazz =clazz.getSuperclass();17 for(Method method : superClazz.getMethods()){18 System.out.println(method.getName());19 }20 System.out.println("");21 //拿到父类中的所有权限修饰符修饰的方法

22 for(Method method : superClazz.getDeclaredMethods()){23 System.out.println(method.getName());24 }25 }

运行结果:

play_public

play_public_2

wait

wait

wait

equals

toString

hashCode

getClass

notify

notifyAllplay_private_2

play_public

play_public_2

play_private

play_protected

play_default

play_protected_2

play_default_2

那么可以执行父类中的方法吗?

1 //是否可以通过子类对象拿到父类中的方法

2 Method method3= clazz.getDeclaredMethod("play_public");3 Method method4= clazz.getDeclaredMethod("play_public_2",String.class);4 Method method5= clazz.getDeclaredMethod("play_private");5 Method method6= clazz.getDeclaredMethod("play_private_2",String.class);

上面代码报错,说明不可以,public修饰的方法也拿不到

1 Method method7= superClazz.getDeclaredMethod("play_public");2 Method method8= superClazz.getDeclaredMethod("play_public_2",String.class);3 Method method9= superClazz.getDeclaredMethod("play_private");4 Method method10= superClazz.getDeclaredMethod("play_private_2",String.class);

上面代码正常执行,说明父类的反射对象可以拿到自己的public或private方法

1 //使用子类的反射对象执行方法

2 method7.invoke(clazz.newInstance());3 method8.invoke(clazz.newInstance(), "play_public_2有参数");4 method9.invoke(clazz.newInstance()); //无法执行,Junit报错

5 method10.invoke(clazz.newInstance(), "play_private_2有参数");//无法执行,Junit报错

1 //使用父类的反射对象执行方法

2 method7.invoke(superClazz.newInstance());3 method8.invoke(superClazz.newInstance(), "play_public_2有参数");4 method9.invoke(superClazz.newInstance()); //无法执行,Junit报错

5 method10.invoke(superClazz.newInstance(), "play_private_2有参数");//无法执行,Junit报错

上面代码执行部分报错,说明通过子类的反射对象和拿到的父类反射对象,也仅仅只能执行public和protected和default默认修饰的方法,不能执行private修饰的方法

7、反射机制获取类中的字段属性:Field字段

1 /**

2 * 默认default修饰3 */

4 String name;5 /**

6 * private修饰7 */

8 private intage;9 /**

10 * public修饰11 */

12 public char sex='M';13 /**

14 * protected修饰15 */

16 protected boolean isBeauty=true;

开始测试:如何获取

1 /**

2 * 反射机制获取类中的字段属性:Field字段3 *@throwsClassNotFoundException4 *@throwsSecurityException5 *@throwsNoSuchFieldException6 *@throwsIllegalAccessException7 *@throwsIllegalArgumentException8 */

9 @Test10 public void testFiled() throwsClassNotFoundException, NoSuchFieldException, SecurityException, IllegalArgumentException, IllegalAccessException{11 //拿到反射Class对象

12 Class clazz = Class.forName("com.xfwl.reflection.Person");13 //获取Field的数组,私有字段也能获取

14 Field[] fields =clazz.getDeclaredFields();15 System.out.println("");16 for(Field field: fields) {17 System.out.println(field.getName());18 }19 System.out.println("");20 //获取指定名字的Field(如果是私有的,见下面的4)

21 Field field1 = clazz.getDeclaredField("name");22 System.out.println("获取指定Field名=: " + field1.getName()+",类型:"+field1.getType());23 Field field2 = clazz.getDeclaredField("age");24 System.out.println("获取指定Field名=: " + field2.getName()+",类型:"+field2.getType());25 Field field3 = clazz.getDeclaredField("sex");26 System.out.println("获取指定Field名=: " + field3.getName()+",类型:"+field3.getType());27 Field field4 = clazz.getDeclaredField("isBeauty");28 System.out.println("获取指定Field名=: " + field4.getName()+",类型:"+field4.getType());29

30 System.out.println("");31 Person person = new Person("小风微凉", 12,'M');32 //获取指定对象的Field的值

33 Object val =field1.get(person);34 System.out.println("获取指定对象字段'name'的Field的值=: " +val);35

36 System.out.println("");37 //设置指定对象的Field的值

38 field1.set(person, "反射学习A");39 System.out.println("设置指定对象字段'name'的Field的值=: " +person.name);40

41 System.out.println("");42 //若该字段是私有的,需要调用setAccessible(true)方法

43 field2 = clazz.getDeclaredField("age");44 field2.setAccessible(true);45 System.out.println("获取指定私有字段名=: " +field2.getName());46 }

测试结果:

name

age

sex

isBeauty获取指定Field名=: name,类型:classjava.lang.String

获取指定Field名=: age,类型:int获取指定Field名=: sex,类型:char获取指定Field名=: isBeauty,类型:boolean

有参构造!!!

获取指定对象字段'name'的Field的值=: 小风微凉设置指定对象字段'name'的Field的值=: 反射学习A获取指定私有字段名=: age

8、反射机制获取类中的构造器:构造器(Constructor)

Person的构造器

1 /**

2 * 无参构造3 */

4 publicPerson(){5 System.out.println("无参构造!!!");6 }7 /**

8 * 有参构造9 */

10 public Person(String name,int age,charsex){11 System.out.println("有参构造!!!");12 this.name=name;13 this.age=age;14 this.sex=sex;15 }

@Test测试

1 /**

2 * 构造器:开发用的比较少3 */

4 @Test5 public void testConstructor() throwsClassNotFoundException, NoSuchMethodException,6 IllegalAccessException, InvocationTargetException, InstantiationException {7 String className = "com.xfwl.reflection.Person";8 Class clazz = (Class) Class.forName(className);9

10 //1.获取Constructor对象

11 Constructor[] constructors =

12 (Constructor[]) Class.forName(className).getConstructors();13

14 System.out.println("");15 for (Constructorconstructor: constructors) {16 System.out.println(constructor);17 }18 System.out.println("");19 Constructor constructor = clazz.getConstructor(String.class, int.class,char.class);20 System.out.println("拿到指定的-->" +constructor);21

22 //2.调用构造器的newInstance()方法创建对象

23 Object obj= constructor.newInstance("changwen", 11,'M');24 }

运行结果:

publiccom.xfwl.reflection.Person()public com.xfwl.reflection.Person(java.lang.String,int,char)拿到指定的-->public com.xfwl.reflection.Person(java.lang.String,int,char)

有参构造!!!

9、反射机制获取类中的注解:注解(Annotation)

•从JDK5.0开始,Java增加了对元数据(MetaData)的支持,也就是Annotation(注释)

•Annotation其实就是代码里的特殊标记,这些标记可以在编译,类加载,运行时被读取,并执行相应的处理.通过使用Annotation,程序员可以在不改变原有逻辑的情况下,在源文件中嵌入一些补充信息.

•Annotation可以像修饰符一样被使用,可用于修饰包,类,构造器,方法,成员变量,参数,局部变量的声明,这些信息被保存在Annotation的“name=value”对中.

•Annotation能被用来为程序元素(类,方法,成员变量等)设置元数据

基本的Annotation

•使用Annotation时要在其前面增加@符号,并把该Annotation当成一个修饰符使用.用于修饰它支持的程序元素

•三个基本的Annotation:

–@Override:限定重写父类方法,该注释只能用于方法

–@Deprecated:用于表示某个程序元素(类,方法等)已过时

–@SuppressWarnings:抑制编译器警告.

自定义Annotation

•定义新的Annotation类型使用@interface关键字

•Annotation的成员变量在Annotation定义中以无参数方法的形式来声明.其方法名和返回值定义了该成员的名字和类型.

•可以在定义Annotation的成员变量时为其指定初始值,指定成员变量的初始值可使用default关键字

•没有成员定义的Annotation称为标记;包含成员变量的Annotation称为元数据Annotation

1 packagecom.xfwl.reflection;2

3 import java.lang.annotation.ElementType;

4 import java.lang.annotation.Retention;

5 import java.lang.annotation.RetentionPolicy;

6 import java.lang.annotation.Target;7

8 public class Person extends Human implementsIHuman {9

10 @Retention(RetentionPolicy.RUNTIME) //运行时检验

11 @Target(value = {ElementType.METHOD}) //作用在方法上

12 public @interfaceAgeValidator {13

14 intmin();15 intmax();16 }17 //......其余部分省略

18 }

1 /**

2 * 自定义一个注解:检查年龄范围3 * @function4 *@author小风微凉5 * @time -6-3 下午3:56:036 */

7 @Retention(RetentionPolicy.RUNTIME) //运行时检验

8 @Target(value = {ElementType.METHOD}) //作用在方法上

9 public @interfaceAgeValidator {10 intmin();11 intmax();12 }

@Test测试

1 /**

2 * 通过反射才能获取注解3 */

4 @Test5 public void testAnnotation() throwsException {6 //这样的方式不能使用注解

7 /*Person person3 = new Person();8 person3.setAge(10);*/

9

10 //拿到反射Class对象

11 String className = "com.xfwl.reflection.Person";12 Class clazz =Class.forName(className);13 Object obj =clazz.newInstance();14 //拿到指定方法

15 Method method = clazz.getDeclaredMethod("setAge",int.class);16 int val =40;17

18 //获取注解

19 Annotation annotation = method.getAnnotation(AgeValidator.class);20 if (annotation != null){21 if (annotation instanceofAgeValidator){22 AgeValidator ageValidator =(AgeValidator) annotation;23

24 if (val< ageValidator.min() || val>ageValidator.max()){25 throw new RuntimeException("数值超出范围");26 }27 }28 }29 //执行方法

30 method.invoke(obj, val);31 System.out.println(obj);32 }

运行结果:

无参构造!!!

Person{name='null', age=40, sex='M'}

获取指定注解:

//获取注解

Annotation annotation = method.getAnnotation(AgeValidator.class);

获取所有注解:

1 //获取所有注解

2 Annotation[] arr=clazz.getDeclaredAnnotations();

提取Annotation信息

•JDK5.0在java.lang.reflect包下新增了AnnotatedElement接口,该接口代表程序中可以接受注释的程序元素

•当一个Annotation类型被定义为运行时Annotation后,该注释才是运行时可见,当class文件被载入时保存在class文件中的Annotation才会被虚拟机读取

•程序可以调用AnnotationElement对象的如下方法来访问Annotation信息

–获取Annotation实例:

•getAnnotation(ClassannotationClass)

JDK的元Annotation

•JDK的元Annotation用于修饰其他Annotation定义

•@Retention:只能用于修饰一个Annotation定义,用于指定该Annotation可以保留多长时间,@Rentention包含一个RetentionPolicy类型的成员变量,使用@Rentention时必须为该value成员变量指定值:

–RetentionPolicy.CLASS:编译器将把注释记录在class文件中.当运行Java程序时,JVM不会保留注释.这是默认值

–RetentionPolicy.RUNTIME:编译器将把注释记录在class文件中.当运行Java程序时, JVM会保留注释.程序可以通过反射获取该注释

–RetentionPolicy.SOURCE:编译器直接丢弃这种策略的注释

•@Target:用于修饰Annotation定义,用于指定被修饰的Annotation能用于修饰哪些程序元素.@Target也包含一个名为value的成员变量.

•@Documented:用于指定被该元Annotation修饰的Annotation类将被javadoc工具提取成文档.

•@Inherited:被它修饰的Annotation将具有继承性.如果某个类使用了被@Inherited修饰的Annotation,则其子类将自动具有该注释

后续补充整理:

(1)通过getDeclaredMethod拿到的方法,可以获取个中修饰符修饰的方法名称和对象,但是private的方法无法invoke执行

UserBean.java

1 packagecom.xfwl.reflect;2

3 public classUserBean {4

5 privateString uname;6 privateString upwd;7 publicUserBean(){8 this.setUname("xfwl");9 this.setUpwd("123456");10 }11 publicUserBean(String uname,String upwd){12 this.setUname(uname);13 this.setUpwd(uname);14 }15 public voidlogIn(UserBean user){16 System.out.println("用户登录:uname="+this.getUname()+",upwd="+this.getUpwd());17 }18 publicString getUname() {19 returnuname;20 }21 private voidlogOut(UserBean user){22 System.out.println("用户退出:uname="+this.getUname()+",upwd="+this.getUpwd());23 }24 public voidsetUname(String uname) {25 this.uname =uname;26 }27

28 publicString getUpwd() {29 returnupwd;30 }31

32 public voidsetUpwd(String upwd) {33 this.upwd =upwd;34 }35 }

View Code

测试类:ReflectAction.java

1 packagecom.xfwl.reflect;2

3 importjava.lang.reflect.Method;4

5

6 public classReflectAction {7 /**

8 *@paramargs9 */

10 public static voidmain(String[] args) {11 UserBean jack=null;12 UserBean tom=null;13 Class tomC=null;14 try{15 jack=(UserBean)Class.forName("com.xfwl.reflect.UserBean").newInstance();16 //jack.logIn();

17

18 tomC=Class.forName("com.xfwl.reflect.UserBean");19 tom=(UserBean) tomC.newInstance();20 Method[] methods =tomC.getDeclaredMethods();21 for(Method method : methods){22 if("logOut".equals(method.getName())){23 method=tomC.getDeclaredMethod(method.getName(),UserBean.class);24 System.out.println(method);25 method.invoke(tomC.newInstance(),tom);26 }27 }28 }catch(Exception e){29

30

31 }32

33 }34

35 }

View Code

运行结果:没有执行:logOut()

修改:

1 public voidlogOut(UserBean user){2 System.out.println("用户退出:uname="+this.getUname()+",upwd="+this.getUpwd());3 }

即可执行:logOut()

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。