java中的反射机制

概念:

JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性;这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制。也就是说,通过class文件对象去使用该文件的成员变量、构造方法以及成员方法。

 

在Class类中:

成员变量: Field  构造方法:Constructor  成员方法:Method

 

获取Class文件对象的方式:

方式一:Object类的getClass方法

Person p = new Person();
Class c = p.getClass();

方式二:数据类型的静态属性class

Person p = new Person();
Class c = p2.getClass();

方式三:Class类中的静态方法forName

Class c = Class.forName("Person");

在开发中我们尽量使用第三种方式,因为我们可以根据配置文件动态的获取到字节码文件对象,节省了修改的时间。

在这里举例怎样通过配置文件动态的获取字节码对象

1.创建一个txt文件,创建键值对数据:

className=com.zhousong.test.Person  (value是包名+类名)

methodName=show  方法名,也可以加成员变量名

2.在com.zhousong.test包下创建Person类

3.测试类:

 1 public class Test {
 2     public static void main(String[] args) throws Exception {
 3         // 加载键值对数据
 4         Properties prop = new Properties();
 5         FileReader fr = new FileReader("test.txt");
 6         prop.load(fr);
 7         fr.close();
 8 
 9         // 获取数据
10         String className = prop.getProperty("className");
11         String methodName = prop.getProperty("show");
12 
13         // 反射
14         Class c = Class.forName(className);
15 
16         Constructor con = c.getConstructor();
17         Object obj = con.newInstance();
18 
19         // 调用方法
20         Method m = c.getMethod(methodName);
21         m.invoke(obj);
22     }
23 }

 

构造方法:

在Class类中获取构造方法比较常用的方法

public Constructor<T> getConstructor(Class<?>... parameterTypes) 这里获取的是带参的公共构造方法,返回的构造方法必须是public修饰的,当然也可以不带参数,这就要看你的构造方法是怎么写的。

public Constructor<TgetDeclaredConstructor(Class<?>... parameterTypes)  这里返回的是所有的构造方法,这就要看你的构造方法使用什么修饰的,进行选择。
 

Person类:

 1 public class Person {
 2     private String name;
 3     int age;
 4     public String address;
 5     public Person(String name, int age, String address) {
 6         super();
 7         this.name = name;
 8         this.age = age;
 9         this.address = address;
10     }
11     public Person() {
12         super();
13         // TODO Auto-generated constructor stub
14     }
15     public String getName() {
16         return name;
17     }
18     public void setName(String name) {
19         this.name = name;
20     }
21     public int getAge() {
22         return age;
23     }
24     public void setAge(int age) {
25         this.age = age;
26     }
27     public String getAddress() {
28         return address;
29     }
30     public void setAddress(String address) {
31         this.address = address;
32     }
33     @Override
34     public String toString() {
35         return "Person [name=" + name + ", age=" + age + ", address=" + address + "]";
36     }
37     
38     public void show(){
39         System.out.println("show");
40     }
41     
42     private void function(){
43         System.out.println("function");
44     }
45     //私有构造方法
46     private Person(String name){
47         this.name = name;
48     }
49 }

测试类:

 1 public class ReflectDemo3 {
 2     public static void main(String[] args) throws Exception{
 3         //获取字节码文件对象
 4         Class c = Class.forName("com.zhousong_01.Person");
 5         //获取构造方法对象,返回所有的构造方法
 6         Constructor s = c.getDeclaredConstructor(String.class);
 7         //暴力访问,要取消Java语言的访问检查,这样就能访问私有的构造方法
 8         s.setAccessible(true);
 9         //这里访问的是私有的构造方法
10         Object objc = s.newInstance("东方不败");
11         System.out.println(objc);
12         
13     }
14 }

注意点:访问私有构造方法,要设置暴力访问,取消Java语言的访问检查。

成员变量:

获取成员变量的方法:

public Field getField(String name)  这里获取的是用public修饰的单个成员变量信息,name就是要访问的成员变量。

public Field getDeclaredField (String name)   这里获取的是所有的成员变量信息

测试类:

 1 public class ReflectDemo {
 2     public static void main(String[] args)throws Exception {
 3         //获取字节码文件对象
 4         Class c = Class.forName("com.zhousong_01.Person");
 5         //获取构造方法对象,通过无参构造方法创建对象
 6         Constructor cs = c.getConstructor();
 7         Object objc = cs.newInstance();
 8         System.out.println(objc);
 9         //获取单个成员变量
10         Field ageField = c.getDeclaredField("age");
11         ageField.setAccessible(true);
12         ageField.set(objc, 33);
13         System.out.println(objc);
14         
15         //访问私有变量
16         Field nameField = c.getDeclaredField("name");
17         nameField.setAccessible(true);
18         nameField.set(objc, "小明");
19         System.out.println(objc);
20         
21         Field addressField = c.getField("address");
22         addressField.set(objc, "天朝");
23         System.out.println(objc);
24         
25     }
26 }

 

成员方法:

获取成员方法常用的方法:

public Method getMethod(String name,Class<?>... parameterTypes)      同上,返回的是用public修饰的方法
public Method getDeclaredMethod(String name,Class<?>... parameterTypes)      返回的是所有的方法
测试类:
 1 public class ReflectDemo {
 2     public static void main(String[] args) throws Exception {
 3         // 获取字节码文件对象
 4         Class c = Class.forName("cn.itcast_01.Person");
 5         //通过构造方法获取Object对象
 6         Constructor con = c.getConstructor();
 7         Object obj = con.newInstance();
 8 
 9         // 第一个参数表示的方法名,第二个参数表示的是方法的参数的class类型
10         Method m1 = c.getMethod("show");
11         // 返回值是Object接收,第一个参数表示对象是谁,第二参数表示调用该方法的实际参数
12         m1.invoke(obj); // 调用obj对象的m1方法
13       }
14 }

练习题:给出ArrayList<Integer>对象,添加字符串

分析:ArrayList限制类型必须是Integer类型,常规方法是无法添加字符串的,那么就要通过反射了。

 1 public class ReflectDemo {
 2     public static void main(String[] args) throws NoSuchMethodException, SecurityException, IllegalAccessException, IllegalArgumentException, InvocationTargetException {
 3         ArrayList<Integer> array = new ArrayList<Integer>();
 4         //获取ArrayList字节码对象
 5         Class c = array.getClass();
 6         //将add方法可以添加的类型变成Object类型,那么就可以添加字符串了
 7         Method m = c.getMethod("add", Object.class);
 8         m.invoke(array, "hello");
 9         System.out.println(array);
10     }
11 }

 

 
 

 

posted @ 2017-01-03 11:51  ReShadow  阅读(291)  评论(0编辑  收藏  举报