Java反射学习:深入学习Java反射机制
一、Java反射的理解(反射是研究框架的基础之一)
Java反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性;这种动态获取的信息以及动态调用对象的方法的功能称为Java语言的反射机制。
二、逐步分析
参考:https://blog.csdn.net/u012585964/article/details/52011138
1、关于Class
1、Class是一个类,一个描述类的类(也就是描述类本身),封装了描述方法的Method,描述字段的Filed,描述构造器的Constructor等属性
2、对象照镜子后(反射)可以得到的信息:某个类的数据成员名、方法和构造器、某个类到底实现了哪些接口。
3、对于每个类而言,JRE 都为其保留一个不变的 Class 类型的对象。 一个 Class 对象包含了特定某个类的有关信息。
4、Class 对象只能由系统建立对象
5、一个类在 JVM 中只会有一个Class实例
下面创建一个例子:后面的分析均以此案例为基准。
创建一个空接口:(后面会不断补充)
1 package com.xfwl.reflection; 2 3 public interface IHuman { 4 5 }
创建一个空基类:(后面会不断补充)
1 package com.xfwl.reflection; 2 3 public class Human { 4 5 }
创建一个子类:(后面会不断补充)
1 package com.xfwl.reflection; 2 3 public class Person extends Human implements IHuman { 4 /** 5 * 默认default修饰 6 */ 7 String name; 8 /** 9 * private修饰 10 */ 11 private int age; 12 /** 13 * public修饰 14 */ 15 public char sex='M'; 16 /** 17 * 无参构造 18 */ 19 public Person(){ 20 System.out.println("无参构造!!!"); 21 } 22 /** 23 * 有参构造 24 */ 25 public Person(String name,int age,char sex){ 26 System.out.println("有参构造!!!"); 27 this.name=name; 28 this.age=age; 29 this.sex=sex; 30 } 31 public String getName() { 32 return name; 33 } 34 public void setName(String name) { 35 this.name = name; 36 } 37 public int getAge() { 38 return age; 39 } 40 public void setAge(int age) { 41 this.age = age; 42 } 43 public char getSex() { 44 return sex; 45 } 46 public void setSex(char sex) { 47 this.sex = sex; 48 } 49 public String toString() { 50 return "Person{" + 51 "name='" + name + '\'' + 52 ", age=" + age + 53 ", sex='" + sex + '\'' + 54 '}'; 55 } 56 }
2、反射获取类对象的三种方式(通过一个Junit测试来说明)
1 package com.xfwl.reflection; 2 3 import org.junit.Test; 4 /** 5 * 测试类 6 * @function 7 * @author 小风微凉 8 * @time 2018-6-3 下午12:28:38 9 */ 10 public class TestAction { 11 /** 12 * 反射机制获取类有三种方法 13 */ 14 @Test 15 public void testGetClass() throws ClassNotFoundException { 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 = new Person(); 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 }
运行结果:
通过类名: class com.xfwl.reflection.Person 无参构造!!! 通过getClass(): class com.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 * @throws ClassNotFoundException 4 * @throws IllegalAccessException 5 * @throws InstantiationException 6 */ 7 @Test 8 public void testNewInstance() 9 throws ClassNotFoundException, 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类加载器
类加载器详解:
http://blog.csdn.net/ochangwen/article/details/51473120
1 /** 2 * ClassLoader类装载器 3 */ 4 @Test 5 public void testClassLoader1() throws ClassNotFoundException, 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 * @throws ClassNotFoundException 4 * @throws IOException 5 */ 6 @Test 7 public void testGetResourceAsStream() throws ClassNotFoundException, IOException { 8 //调用getResourceAsStream 获取类路径下的文件对应的输入流 9 /** 10 * 特别说明: 11 * getResourceAsStream("path"),path的路径和new Person()的位置有关 12 */ 13 14 InputStream in = new Person().getClass().getClassLoader() 15 .getResourceAsStream("com/xfwl/reflection/test.properties"); 16 System.out.println("in: " +in); 17 18 Properties properties = new Properties(); 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=23 sex=M desc=\u53CD\u5C04\u673A\u5236\u5B66\u4E60
运行结果:(直接解析会出现乱码问题,这个可以通过new String(乱码格式处理参数)来处理)
无参构造!!! in: java.io.BufferedInputStream@215be6bb 文件内容:{age=23, name=小风微凉??, sex=M, desc=反射机制学习} name: 小风微凉?? age: 23 sex: M desc: 反射机制学习
6、反射机制获取类中的方法:Method: 对应类中的方法
现在给Person类添加一个private 方法、一个public 方法、一个defaut 方法、一个protected方法
1 /** 2 * Java权限有四个,分别为public,protected,默认,private,其开放程度依次降低 3 * public可供所有类访问 4 * protected继承可见 5 * private只能类本身内部的方法可以访问 6 */ 7 public void method_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 void method_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 void method_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 void method_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 * @throws ClassNotFoundException 4 * @throws NoSuchMethodException 5 * @throws IllegalAccessException 6 * @throws InstantiationException 7 * @throws InvocationTargetException 8 */ 9 @Test 10 public void testMethod() throws ClassNotFoundException, 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 void com.xfwl.reflection.Person.method_private() private 有参:private void com.xfwl.reflection.Person.method_private_2(java.lang.String) public 有参:private void com.xfwl.reflection.Person.method_private_2(java.lang.String) 无参构造!!! method_public_2 Person{name='小风微凉', age=23, sex='M'}
继续分析一下:
JDK中的获取方法
获取方法:默认只能获取public修饰的方法
1 @CallerSensitive 2 public Method[] getMethods() throws SecurityException { 3 checkMemberAccess(Member.PUBLIC, Reflection.getCallerClass(), true); 4 return copyMethods(privateGetPublicMethods()); 5 }
获取方法:所有修饰权限的方法都可以获得
@CallerSensitive public Method[] getDeclaredMethods() throws SecurityException { checkMemberAccess(Member.DECLARED, Reflection.getCallerClass(), true); return copyMethods(privateGetDeclaredMethods(false)); }
获取方法:获取指定的方法(所有修饰权限)
1 /** 2 * @jls 8.2 Class Members 3 * @jls 8.4 Method Declarations 4 * @since JDK1.1 5 */ 6 @CallerSensitive 7 public Method getDeclaredMethod(String name, Class<?>... parameterTypes) 8 throws NoSuchMethodException, 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 return method; 15 }
分析一下上面这个方法:
String name:方法的名称
Class<?>... parameterTypes:一个或多个方法参数的类型,注意要一一对应,否则会报错的哦
执行方法:invoke(方法对象,方法实际参数)
1 @CallerSensitive 2 public Object invoke(Object obj, Object... args) 3 throws IllegalAccessException, IllegalArgumentException, 4 InvocationTargetException 5 { 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 return ma.invoke(obj, args); 17 }
7、反射机制获取类中的方法:Method: 对应基类或接口中的方法
上面分析了,如何通过反射拿到当前本类里面的各个修饰权限的方法,下面来继续分析一下,如何读取父类或实现的接口中的方法:
现在,给父类添加一些方法,在接口中定义一些方法:
接口中的方法声明:
1 package com.xfwl.reflection; 2 3 public interface IHuman { 4 5 void eat(); 6 void eat(String info); 7 }
Person.java实现接口方法
1 public void eat() { 2 System.out.println("实现接口的方法:eat()无参:"); 3 } 4 public void eat(String info) { 5 System.out.println("实现接口的方法:eat()有参:"+info); 6 }
父类中的方法定义:
1 package com.xfwl.reflection; 2 3 public class Human { 4 public void play_public(){ 5 System.out.println("public无参:play_public"); 6 } 7 public void play_public_2(String info){ 8 System.out.println("public有参:play_public2:"+info); 9 } 10 protected void play_protected(){ 11 System.out.println("protected无参:play_protected"); 12 } 13 protected void play_protected_2(String info){ 14 System.out.println("protected有参:play_protected_2:"+info); 15 } 16 void play_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 void play_private(){ 23 System.out.println("private无参:play_private"); 24 } 25 private void play_private_2(String info){ 26 System.out.println("private有参:play_private_2:"+info); 27 } 28 }
开始测试:
1、拿到当前Person类反射对象,能否得到接口中的方法
1 /** 2 * 反射机制获取类中的方法:Method: 对应基类或接口中的方法 3 * @throws ClassNotFoundException 4 * @throws SecurityException 5 * @throws NoSuchMethodException 6 * @throws InstantiationException 7 * @throws InvocationTargetException 8 * @throws IllegalArgumentException 9 * @throws IllegalAccessException 10 */ 11 @Test 12 public void testInterfaceOrSupperClass() throws ClassNotFoundException, 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 * @throws ClassNotFoundException 4 * @throws SecurityException 5 * @throws NoSuchMethodException 6 * @throws InstantiationException 7 * @throws InvocationTargetException 8 * @throws IllegalArgumentException 9 * @throws IllegalAccessException 10 */ 11 @Test 12 public void testInterfaceOrSupperClass() throws ClassNotFoundException, 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 notifyAll <----------------父类中所有的方法:仅仅父类中的方法--------------------> play_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 int age; 9 /** 10 * public修饰 11 */ 12 public char sex='M'; 13 /** 14 * protected修饰 15 */ 16 protected boolean isBeauty=true;
开始测试:如何获取
1 /** 2 * 反射机制获取类中的字段属性:Field字段 3 * @throws ClassNotFoundException 4 * @throws SecurityException 5 * @throws NoSuchFieldException 6 * @throws IllegalAccessException 7 * @throws IllegalArgumentException 8 */ 9 @Test 10 public void testFiled() throws ClassNotFoundException, 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("<------------获取指定名字的Field以及类型--------------------------->"); 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("<----------获取指定对象的Field的值 ----------------------------->"); 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("<----------设置指定对象的Field的值----------------------------->"); 37 //设置指定对象的Field的值 38 field1.set(person, "反射学习A"); 39 System.out.println("设置指定对象字段'name'的Field的值=: " + person.name); 40 41 System.out.println("<----------若该字段是私有的,需要调用setAccessible(true)方法----------------------------->"); 42 //若该字段是私有的,需要调用setAccessible(true)方法 43 field2 = clazz.getDeclaredField("age"); 44 field2.setAccessible(true); 45 System.out.println("获取指定私有字段名=: " + field2.getName()); 46 }
测试结果:
<----遍历拿到字段:开始---------------------> name age sex isBeauty <------------获取指定名字的Field以及类型---------------------------> 获取指定Field名=: name,类型:class java.lang.String 获取指定Field名=: age,类型:int 获取指定Field名=: sex,类型:char 获取指定Field名=: isBeauty,类型:boolean <----------获取指定对象的Field的值 -----------------------------> 有参构造!!! 获取指定对象字段'name'的Field的值=: 小风微凉 <----------设置指定对象的Field的值-----------------------------> 设置指定对象字段'name'的Field的值=: 反射学习A <----------若该字段是私有的,需要调用setAccessible(true)方法-----------------------------> 获取指定私有字段名=: age
8、反射机制获取类中的构造器:构造器(Constructor)
Person的构造器
1 /** 2 * 无参构造 3 */ 4 public Person(){ 5 System.out.println("无参构造!!!"); 6 } 7 /** 8 * 有参构造 9 */ 10 public Person(String name,int age,char sex){ 11 System.out.println("有参构造!!!"); 12 this.name=name; 13 this.age=age; 14 this.sex=sex; 15 }
@Test测试
1 /** 2 * 构造器:开发用的比较少 3 */ 4 @Test 5 public void testConstructor() throws ClassNotFoundException, NoSuchMethodException, 6 IllegalAccessException, InvocationTargetException, InstantiationException { 7 String className = "com.xfwl.reflection.Person"; 8 Class<Person> clazz = (Class<Person>) Class.forName(className); 9 10 //1.获取Constructor对象 11 Constructor<Person>[] constructors = 12 (Constructor<Person>[]) Class.forName(className).getConstructors(); 13 14 System.out.println("<-------------打印所有的构造器---------------------->"); 15 for (Constructor<Person> constructor: constructors) { 16 System.out.println(constructor); 17 } 18 System.out.println("<------------------------------------------------>"); 19 Constructor<Person> 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 }
运行结果:
<-------------打印所有的构造器----------------------> public com.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)
基本的 Annotation
自定义 Annotation
1 package com.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 implements IHuman { 9 10 @Retention(RetentionPolicy.RUNTIME) //运行时检验 11 @Target(value = {ElementType.METHOD}) //作用在方法上 12 public @interface AgeValidator { 13 14 int min(); 15 int max(); 16 } 17 //......其余部分省略 18 }
1 /** 2 * 自定义一个注解:检查年龄范围 3 * @function 4 * @author 小风微凉 5 * @time 2018-6-3 下午3:56:03 6 */ 7 @Retention(RetentionPolicy.RUNTIME) //运行时检验 8 @Target(value = {ElementType.METHOD}) //作用在方法上 9 public @interface AgeValidator { 10 int min(); 11 int max(); 12 }
@Test测试
1 /** 2 * 通过反射才能获取注解 3 */ 4 @Test 5 public void testAnnotation() throws Exception { 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 instanceof AgeValidator){ 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信息
JDK 的元Annotation
1 package com.xfwl.reflect; 2 3 public class UserBean { 4 5 private String uname; 6 private String upwd; 7 public UserBean(){ 8 this.setUname("xfwl"); 9 this.setUpwd("123456"); 10 } 11 public UserBean(String uname,String upwd){ 12 this.setUname(uname); 13 this.setUpwd(uname); 14 } 15 public void logIn(UserBean user){ 16 System.out.println("用户登录:uname="+this.getUname()+",upwd="+this.getUpwd()); 17 } 18 public String getUname() { 19 return uname; 20 } 21 private void logOut(UserBean user){ 22 System.out.println("用户退出:uname="+this.getUname()+",upwd="+this.getUpwd()); 23 } 24 public void setUname(String uname) { 25 this.uname = uname; 26 } 27 28 public String getUpwd() { 29 return upwd; 30 } 31 32 public void setUpwd(String upwd) { 33 this.upwd = upwd; 34 } 35 }
测试类:ReflectAction.java
1 package com.xfwl.reflect; 2 3 import java.lang.reflect.Method; 4 5 6 public class ReflectAction { 7 /** 8 * @param args 9 */ 10 public static void main(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 }
运行结果:没有执行:logOut()
修改:
1 public void logOut(UserBean user){ 2 System.out.println("用户退出:uname="+this.getUname()+",upwd="+this.getUpwd()); 3 }
即可执行:logOut()