Java反射机制
一、什么是反射机制
  JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意方法和属性;这种动态获取信息以及动态调用对象方法的功能称为java语言的反射机制。
  
二、反射机制的作用
   在运行时判断任意一个对象所属的类;
   在运行时构造任意一个类的对象;
   在运行时判断任意一个类所具有的成员变量和方法;
   在运行时调用任意一个对象的方法;
   生成动态代理
  
三. 反射机制的优点与缺点
   反射机制的优点:可以实现动态创建对象和编译,体现出很大的灵活性(特别是在J2EE的开发中它的灵活性就表现的十分明显)。通过反射机制我们可以获得类的各种内容,进行了反编译。对于JAVA这种先编译再运行的语言来说,反射机制可以使代码更加灵活,更加容易实现面向对象。
  
   反射机制的缺点:使用反射基本上是一种解释操作,用于字段和方法接入时要远慢于直接代码。因此Java反射机制只应用在对灵活性和扩展性要求很高的系统框架上,普通程序不建议使用。使用反射会模糊程序内部逻辑:程序员希望在代码中看到程序的逻辑,反射等绕过了源代码的技术,因而会带来维护问题。反射代码比相应的直接代码更复杂。
  
四. 反射机制的示例
1.通过一个对象获得完整的包名和类名

所有类的对象其实都是Class的实例。

1 package Reflect;
 2 
 3 class Demo{
 4     //other codes...
 5 }
 6 
 7 class hello{
 8     public static void main(String[] args) {
 9         Demo demo=new Demo();
10         System.out.println(demo.getClass().getName());
11     }
12 }
13 //【运行结果】:Reflect.Demo

2.实例化Class类对象

1 package Reflect;
 2 
 3 class Demo{
 4     //other codes...
 5 }
 6 
 7 class hello{
 8     public static void main(String[] args) {
 9         Class<?> demo1=null;
10         Class<?> demo2=null;
11         Class<?> demo3=null;
12         try{
13             //一般尽量采用这种形式
14             demo1=Class.forName("Reflect.Demo");
15         }catch(Exception e){
16             e.printStackTrace();
17         }
18         demo2=new Demo().getClass();
19         demo3=Demo.class;
20 
21         System.out.println("类名称   "+demo1.getName());
22         System.out.println("类名称   "+demo2.getName());
23         System.out.println("类名称   "+demo3.getName());
24     }
25 }
26 //【运行结果】:
27 //类名称   Reflect.Demo
28 //类名称   Reflect.Demo
29 //类名称   Reflect.Demo

3.通过Class实例化其他类的对象

1 package Reflect;
 2 
 3 class Person{
 4     public String getName() {
 5         return name;
 6     }
 7     public void setName(String name) {
 8         this.name = name;
 9     }
10     public int getAge() {
11         return age;
12     }
13     public void setAge(int age) {
14         this.age = age;
15     }
16     @Override
17     public String toString(){
18         return "["+this.name+"  "+this.age+"]";
19     }
20     private String name;
21     private int age;
22 }
23 
24 class hello{
25     public static void main(String[] args) {
26         Class<?> demo=null;
27         try{
28             demo=Class.forName("Reflect.Person");
29         }catch (Exception e) {
30             e.printStackTrace();
31         }
32         Person per=null;
33         try {
34             per=(Person)demo.newInstance();
35         } catch (InstantiationException e) {
36             // TODO Auto-generated catch block
37             e.printStackTrace();
38         } catch (IllegalAccessException e) {
39             // TODO Auto-generated catch block
40             e.printStackTrace();
41         }
42         per.setName("Rollen");
43         per.setAge(20);
44         System.out.println(per);
45     }
46 }
47 //【运行结果】:
48 //[Rollen  20]

但是注意一下,当我们把Person中的默认的无参构造函数取消的时候,比如自己定义只定义一个有参数的构造函数之后,会出现错误:

比如定义了一个构造函数:

1 public Person(String name, int age) {
2         this.age=age;
3         this.name=name;
4     }

然后继续运行上面的程序,会出现:

java.lang.InstantiationException: Reflect.Person
at java.lang.Class.newInstance0(Class.java:340)
at java.lang.Class.newInstance(Class.java:308)
at Reflect.hello.main(hello.java:39)
Exception in thread "main" java.lang.NullPointerException
at Reflect.hello.main(hello.java:47)

所以大家以后再编写使用Class实例化其他类的对象的时候,一定要自己定义无参的构造函数。

4.通过Class调用其他类中的构造函数 (也可以通过这种方式通过Class创建其他类的对象)

1 package Reflect;
 2 
 3 import java.lang.reflect.Constructor;
 4 
 5 class Person{
 6     public Person() {   
 7 
 8     }
 9     public Person(String name){
10         this.name=name;
11     }
12     public Person(int age){
13         this.age=age;
14     }
15     public Person(String name, int age) {
16         this.age=age;
17         this.name=name;
18     }
19     public String getName() {
20         return name;
21     }
22     public int getAge() {
23         return age;
24     }
25     @Override
26     public String toString(){
27         return "["+this.name+"  "+this.age+"]";
28     }
29     private String name;
30     private int age;
31 }
32 
33 class hello{
34     public static void main(String[] args) {
35         Class<?> demo=null;
36         try{
37             demo=Class.forName("Reflect.Person");
38         }catch (Exception e) {
39             e.printStackTrace();
40         }
41         Person per1=null;
42         Person per2=null;
43         Person per3=null;
44         Person per4=null;
45         //取得全部的构造函数
46         Constructor<?> cons[]=demo.getConstructors();
47         try{
48             per1=(Person)cons[0].newInstance();
49             per2=(Person)cons[1].newInstance("Rollen");
50             per3=(Person)cons[2].newInstance(20);
51             per4=(Person)cons[3].newInstance("Rollen",20);
52         }catch(Exception e){
53             e.printStackTrace();
54         }
55         System.out.println(per1);
56         System.out.println(per2);
57         System.out.println(per3);
58         System.out.println(per4);
59     }
60 }
61 //【运行结果】:
62 //[null  0]
63 //[Rollen  0]
64 //[null  20]
65 //[Rollen  20]

5.返回一个类实现的接口

1 package Reflect;
 2 
 3 interface China{
 4     public static final String name="Rollen";
 5     public static  int age=20;
 6     public void sayChina();
 7     public void sayHello(String name, int age);
 8 }
 9 
10 class Person implements China{
11     public Person() {
12 
13     }
14     public Person(String sex){
15         this.sex=sex;
16     }
17     public String getSex() {
18         return sex;
19     }
20     public void setSex(String sex) {
21         this.sex = sex;
22     }
23     @Override
24     public void sayChina(){
25         System.out.println("hello ,china");
26     }
27     @Override
28     public void sayHello(String name, int age){
29         System.out.println(name+"  "+age);
30     }
31     private String sex;
32 }
33 
34 class hello{
35     public static void main(String[] args) {
36         Class<?> demo=null;
37         try{
38             demo=Class.forName("Reflect.Person");
39         }catch (Exception e) {
40             e.printStackTrace();
41         }
42         //保存所有的接口
43         Class<?> intes[]=demo.getInterfaces();
44         for (int i = 0; i < intes.length; i++) {
45             System.out.println("实现的接口   "+intes[i].getName());
46         }
47     }
48 }
49 //【运行结果】:
50 //实现的接口   Reflect.China

(以下几个例子,都会用到这个例子的Person类,所以为节省篇幅,此处不再粘贴Person的代码部分,只粘贴主类hello的代码)

6.取得其他类中的父类

1 class hello{
 2     public static void main(String[] args) {
 3         Class<?> demo=null;
 4         try{
 5             demo=Class.forName("Reflect.Person");
 6         }catch (Exception e) {
 7             e.printStackTrace();
 8         }
 9         //取得父类
10         Class<?> temp=demo.getSuperclass();
11         System.out.println("继承的父类为:   "+temp.getName());
12     }
13 }
14 //【运行结果】
15 //继承的父类为:   java.lang.Object

7.获得其他类中的全部构造函数

1 //这个例子需要在程序开头添加import java.lang.reflect.*;
 2 class hello{
 3     public static void main(String[] args) {
 4         Class<?> demo=null;
 5         try{
 6             demo=Class.forName("Reflect.Person");
 7         }catch (Exception e) {
 8             e.printStackTrace();
 9         }
10         Constructor<?>cons[]=demo.getConstructors();
11         for (int i = 0; i < cons.length; i++) {
12             System.out.println("构造方法:  "+cons[i]);
13         }
14     }
15 }
16 //【运行结果】:
17 //构造方法:  public Reflect.Person()
18 //构造方法:  public Reflect.Person(java.lang.String)


 1 class hello{
 2     public static void main(String[] args) {
 3         Class<?> demo=null;
 4         try{
 5             demo=Class.forName("Reflect.Person");
 6         }catch (Exception e) {
 7             e.printStackTrace();
 8         }
 9         Constructor<?>cons[]=demo.getConstructors();
10         for (int i = 0; i < cons.length; i++) {
11             Class<?> p[]=cons[i].getParameterTypes();
12             System.out.print("构造方法:  ");
13             int mo=cons[i].getModifiers();
14             System.out.print(Modifier.toString(mo)+" ");
15             System.out.print(cons[i].getName());
16             System.out.print("(");
17             for(int j=0;j<p.length;++j){
18                 System.out.print(p[j].getName()+" arg"+i);
19                 if(j<p.length-1){
20                     System.out.print(",");
21                 }
22             }
23             System.out.println("){}");
24         }
25     }
26 }
27 //【运行结果】:
28 //构造方法:  public Reflect.Person(){}
29 //构造方法:  public Reflect.Person(java.lang.String arg1){}

8.取得其他类的全部属性,将这些整理在一起,也就是通过class取得一个类的全部框架

1 class hello {
 2     public static void main(String[] args) {
 3         Class<?> demo = null;
 4         try {
 5             demo = Class.forName("Reflect.Person");
 6         } catch (Exception e) {
 7             e.printStackTrace();
 8         }
 9         System.out.println("===============本类属性========================");
10         // 取得本类的全部属性
11         Field[] field = demo.getDeclaredFields();
12         for (int i = 0; i < field.length; i++) {
13             // 权限修饰符
14             int mo = field[i].getModifiers();
15             String priv = Modifier.toString(mo);
16             // 属性类型
17             Class<?> type = field[i].getType();
18             System.out.println(priv + " " + type.getName() + " "
19                     + field[i].getName() + ";");
20         }
21         System.out.println("===============实现的接口或者父类的属性========================");
22         // 取得实现的接口或者父类的属性
23         Field[] filed1 = demo.getFields();
24         for (int j = 0; j < filed1.length; j++) {
25             // 权限修饰符
26             int mo = filed1[j].getModifiers();
27             String priv = Modifier.toString(mo);
28             // 属性类型
29             Class<?> type = filed1[j].getType();
30             System.out.println(priv + " " + type.getName() + " "
31                     + filed1[j].getName() + ";");
32         }
33     }
34 }
35 //【运行结果】:
36 //===============本类属性========================
37 //private java.lang.String sex;
38 //===============实现的接口或者父类的属性========================
39 //public static final java.lang.String name;
40 //public static final int age;

9.通过反射调用其他类中的方法

1 class hello {
 2     public static void main(String[] args) {
 3         Class<?> demo = null;
 4         try {
 5             demo = Class.forName("Reflect.Person");
 6         } catch (Exception e) {
 7             e.printStackTrace();
 8         }
 9         try{
10             //调用Person类中的sayChina方法
11             Method method=demo.getMethod("sayChina");
12             method.invoke(demo.newInstance());
13             //调用Person的sayHello方法
14             method=demo.getMethod("sayHello", String.class,int.class);
15             method.invoke(demo.newInstance(),"Rollen",20);
16         }catch (Exception e) {
17             e.printStackTrace();
18         }
19     }
20 }
21 //【运行结果】:
22 //hello ,china
23 //Rollen  20

10.调用其他类的set和get方法

1 class hello {
 2     public static void main(String[] args) {
 3         Class<?> demo = null;
 4         Object obj=null;
 5         try {
 6             demo = Class.forName("Reflect.Person");
 7         } catch (Exception e) {
 8             e.printStackTrace();
 9         }
10         try{
11          obj=demo.newInstance();
12         }catch (Exception e) {
13             e.printStackTrace();
14         }
15         setter(obj,"Sex","男",String.class);
16         getter(obj,"Sex");
17     }
18 
19     /**
20      * @param obj   操作的对象
21      * @param att   操作的属性
22      * */
23     public static void getter(Object obj, String att) {
24         try {
25             Method method = obj.getClass().getMethod("get" + att);
26             System.out.println(method.invoke(obj));
27         } catch (Exception e) {
28             e.printStackTrace();
29         }
30     }
31 
32     /**
33      * @param obj   操作的对象    
34      * @param att   操作的属性
35      * @param value 设置的值
36      * @param type  参数的属性
37      * */
38     public static void setter(Object obj, String att, Object value,
39             Class<?> type) {
40         try {
41             Method method = obj.getClass().getMethod("set" + att, type);
42             method.invoke(obj, value);
43         } catch (Exception e) {
44             e.printStackTrace();
45         }
46     }
47 }// end class
48 //【运行结果】:
49 //男

11.通过反射操作属性

1 class hello {
 2     public static void main(String[] args) throws Exception {
 3         Class<?> demo = null;
 4         Object obj = null;
 5 
 6         demo = Class.forName("Reflect.Person");
 7         obj = demo.newInstance();
 8 
 9         Field field = demo.getDeclaredField("sex");
10         field.setAccessible(true);
11         field.set(obj, "男");
12         System.out.println(field.get(obj));
13     }
14 }// end class

12.通过反射取得并修改数组的信息

1 import java.lang.reflect.*;
 2 
 3 class hello{
 4     public static void main(String[] args) {
 5         int[] temp={1,2,3,4,5};
 6         Class<?>demo=temp.getClass().getComponentType();
 7         System.out.println("数组类型: "+demo.getName());
 8         System.out.println("数组长度  "+Array.getLength(temp));
 9         System.out.println("数组的第一个元素: "+Array.get(temp, 0));
10         Array.set(temp, 0, 100);
11         System.out.println("修改之后数组第一个元素为: "+Array.get(temp, 0));
12     }
13 }
14 //【运行结果】:
15 //数组类型: int
16 //数组长度  5
17 //数组的第一个元素: 1
18 //修改之后数组第一个元素为: 100

13.通过反射修改数组大小

1 class hello{
 2     public static void main(String[] args) {
 3         int[] temp={1,2,3,4,5,6,7,8,9};
 4         int[] newTemp=(int[])arrayInc(temp,15);
 5         print(newTemp);
 6         System.out.println("=====================");
 7         String[] atr={"a","b","c"};
 8         String[] str1=(String[])arrayInc(atr,8);
 9         print(str1);
10     }
11     /**
12      * 修改数组大小
13      * */
14     public static Object arrayInc(Object obj,int len){
15         Class<?>arr=obj.getClass().getComponentType();
16         Object newArr=Array.newInstance(arr, len);
17         int co=Array.getLength(obj);
18         System.arraycopy(obj, 0, newArr, 0, co);
19         return newArr;
20     }
21     /**
22      * 打印
23      * */
24     public static void print(Object obj){
25         Class<?>c=obj.getClass();
26         if(!c.isArray()){
27             return;
28         }
29         System.out.println("数组长度为: "+Array.getLength(obj));
30         for (int i = 0; i < Array.getLength(obj); i++) {
31             System.out.print(Array.get(obj, i)+" ");
32         }
33     }
34 }
35 //【运行结果】:
36 //数组长度为: 15
37 //1 2 3 4 5 6 7 8 9 0 0 0 0 0 0 =====================
38 //数组长度为: 8
39 //a b c null null null null null

14.动态代理

首先来看看如何获得类加载器:

1 class test{
 2 
 3 }
 4 class hello{
 5     public static void main(String[] args) {
 6         test t=new test();
 7         System.out.println("类加载器  "+t.getClass().getClassLoader().getClass().getName());
 8     }
 9 }
10 //【程序输出】:
11 //类加载器  sun.misc.Launcher$AppClassLoader

其实在java中有三种类类加载器。

1)Bootstrap ClassLoader 此加载器采用c++编写,一般开发中很少见。

2)Extension ClassLoader 用来进行扩展类的加载,一般对应的是jre\lib\ext目录中的类

3)AppClassLoader 加载classpath指定的类,是最常用的加载器。同时也是java中默认的加载器。

如果想要完成动态代理,首先需要定义一个InvocationHandler接口的子类,已完成代理的具体操作。

1 package Reflect;
 2 
 3 import java.lang.reflect.*;
 4 
 5 //定义项目接口
 6 interface Subject {
 7     public String say(String name, int age);
 8 }
 9 
10 // 定义真实项目
11 class RealSubject implements Subject {
12     @Override
13     public String say(String name, int age) {
14         return name + "  " + age;
15     }
16 }
17 
18 class MyInvocationHandler implements InvocationHandler {
19     private Object obj = null;
20 
21     public Object bind(Object obj) {
22         this.obj = obj;
23         return Proxy.newProxyInstance(obj.getClass().getClassLoader(), obj
24                 .getClass().getInterfaces(), this);
25     }
26 
27     @Override
28     public Object invoke(Object proxy, Method method, Object[] args)
29             throws Throwable {
30         Object temp = method.invoke(this.obj, args);
31         return temp;
32     }
33 }
34 
35 class hello {
36     public static void main(String[] args) {
37         MyInvocationHandler demo = new MyInvocationHandler();
38         Subject sub = (Subject) demo.bind(new RealSubject());
39         String info = sub.say("Rollen", 20);
40         System.out.println(info);
41     }
42 }
43 //【运行结果】:
44 //Rollen  20

类的生命周期

在一个类编译完成之后,下一步就需要开始使用类,如果要使用一个类,肯定离不开JVM。在程序执行中JVM通过装载,链接,初始化这3个步骤完成。

类的装载是通过类加载器完成的,加载器将.class文件的二进制文件装入JVM的方法区,并且在堆区创建描述这个类的java.lang.Class对象。用来封装数据。 但是同一个类只会被类装载器装载以前

链接就是把二进制数据组装为可以运行的状态。

链接分为校验,准备,解析这3个阶段:
校验 一般用来确认此二进制文件是否适合当前的JVM(版本),
准备 就是为静态成员分配内存空间。并设置默认值
解析 指的是转换常量池中的代码作为直接引用的过程,直到所有的符号引用都可以被运行程序使用(建立完整的对应关系)。

完成之后,类型也就完成了初始化,初始化之后类的对象就可以正常使用了,直到一个对象不再使用之后,将被垃圾回收。释放空间。当没有任何引用指向Class对象时就会被卸载,结束类的生命周期。