反射

本篇文章依旧采用小例子来说明,因为我始终觉的,案例驱动是最好的,要不然只看理论的话,看了也不懂,不过建议大家在看完文章之后,在回过头去看看理论,会有更好的理解。

下面开始正文。

 

【案例1】通过一个对象获得完整的包名和类名

 1 package Reflect;
 2  
 3 /**
 4  * 通过一个对象获得完整的包名和类名
 5  * */
 6 class Demo{
 7     //other codes...
 8 }
 9  
10 class hello{
11     public static void main(String[] args) {
12         Demo demo=new Demo();
13         System.out.println(demo.getClass().getName());
14     }
15 }
16 【运行结果】:Reflect.Demo

添加一句:所有类的对象其实都是Class的实例。

【案例2】实例化Class类对象

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

类名称   Reflect.Demo

类名称   Reflect.Demo

类名称   Reflect.Demo

【案例3】通过Class实例化其他类的对象

通过无参构造实例化对象

 

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

 1 但是注意一下,当我们把Person中的默认的无参构造函数取消的时候,比如自己定义只定义一个有参数的构造函数之后,会出现错误:
 2 
 3 比如我定义了一个构造函数:
 4 
 5 1
 6 2
 7 3
 8 4
 9 public Person(String name, int age) {
10         this.age=age;
11         this.name=name;
12     }
13 然后继续运行上面的程序,会出现:
14 
15 java.lang.InstantiationException: Reflect.Person
16 
17     at java.lang.Class.newInstance0(Class.java:340)
18 
19     at java.lang.Class.newInstance(Class.java:308)
20 
21     at Reflect.hello.main(hello.java:39)
22 
23 Exception in thread "main" java.lang.NullPointerException
24 
25     at Reflect.hello.main(hello.java:47)
26 
27 所以大家以后再编写使用Class实例化其他类的对象的时候,一定要自己定义无参的构造函数

 

类的生命周期

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

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

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

 

链接分为校验,准备,解析这3个阶段

校验一般用来确认此二进制文件是否适合当前的JVM(版本),

准备就是为静态成员分配内存空间,。并设置默认值

解析指的是转换常量池中的代码作为直接引用的过程,直到所有的符号引用都可以被运行程序使用(建立完整的对应关系)

完成之后,类型也就完成了初始化,初始化之后类的对象就可以正常使用了,直到一个对象不再使用之后,将被垃圾回收。释放空间。

当没有任何引用指向Class对象时就会被卸载,结束类的生命周期

将反射用于工厂模式

 

posted @ 2016-06-01 15:54  北城以北冬季飘雪  阅读(94)  评论(0编辑  收藏  举报