2016/05/04(反射)

反射:重点----每天都用反射,但是每天都不写反射    
Java的反射技术是java程序的特征之一,它允许运行中的Java程序对自身进行检查,或者说“自审”,并能直接操作程序的内部属性。

使用反射可以获得Java类中各个成员的名称并显示出来。简单的说,反射就是让你可以通过名称来得到对象(类,属性,方法)的技术。

反射的作用
 可以通过反射机制发现对象的类型,发现类型的方法/属性/构造器
 可以创建对象并访问任意对象方法和属性等

主要点:运行时探究和使用编译时未知的类

Dog d1 = new Dog();这样一个类在创造的时候经历了哪些过程呢?
简单的来说
类加载:由类加载器完成,类的class文件读入内存后,就会创建一个java.lang.Class对象。一旦某个类被载入JVM中,同一个类就不会再次被载入。
连接:把类的二进制数据合并到JRE中。

初始化 :JVM负责对类进行初始化,也就是对静态属性进行初始化。在Java类中,对静态属性指定初始值的方式有两种:
(1)声明静态属性时指定初始值;
(2)使用静态初始化块为静态属性指定初始值。

在我们上边的案例中:
1.JVM利用DogClassLoader先将Dog类加载到内存,然后马上产生了一个Class类型的对象,该对象可以看成是一个模型,以后无论创建多少个Dog类的实例都是利用该模型来生成。
---所以一个类所对应的Class类型的对象只有一个。

根据这个模型生成Dog类实例反射正是利用了java的这种加载方式主动完成了对象的创建及使用。

使用反射:
遵循三个步骤
第一步是获得你想操作的类的 java.lang.Class 对象
第二步是调用诸如 getDeclaredMethods 的方法
第三步使用 reflection API 来操作这些信息


简单案例01:
  Class c1 = String.class;
  Class c2 = Class.forName("java.lang.String");
  Class c3 = "abc".getClass();


实验2:通过反射做一些事情
  Integer a=13;
  Class c=a.getClass();//获得了a的类型


案例03:
  Integer a=13;
  Class c=a.getClass();
  Field[] field=c.getDeclaredFields();
  for(Field f:field){
   System.out.print(f.getType()+" ");
   System.out.println(f.getName());
  }
我们获得了Integer类中的所有属性
那能不能修改呢?
  Dog d=new Dog();
  Class clazz=d.getClass();
  Field field=clazz.getDeclaredField("num");
  field.set(d, 1000);
  System.out.println(field.get(d));


案例04:
  Class c1=Outer.class;
  Method[] methods=c1.getDeclaredMethods();
  for(Method method:methods){
   System.out.print(method.getName()+" ");
   System.out.print(method.getReturnType()+" ");
   System.out.println(method.getParameterTypes());//这里如果是数组的话该怎么处理
  }
获得该类中所有的方法
  Dog d=new Dog();
  Class clazz=d.getClass();
  Method method=clazz.getDeclaredMethod("show",int.class,String.class);
  method.invoke(d,10,"zhangsan");

案例05:
 Integer a=13;
  Class c=a.getClass();
  Class c1=Outer.class;
  Constructor [] constructors=c.getDeclaredConstructors();
  for(Constructor constructor:constructors){
   System.out.print(constructor.getName()+" ");
   System.out.println(Arrays.toString(constructor.getParameterTypes()));
  }
获得所有的构造函数
 

重点:通过反射来创造类的实例

实验01:
通过类名来创建类实例
  Class cls=Outer.class;//obj指向的A类的对象 总体来说还是Object
  Object o=cls.newInstance();
------------------------------------------------------注意它和我们的实例对象一样吗
 Class<?> clazz=Class.forName("包名.类名");
 Wode o=(Wode) clazz.newInstance();

注意点:
Class.forName() 静态方法,可以利用类名在 CLASSPATH 中查找对应的类,并且装载到内
存, 返回这个” class“
Class.forName()加载类的过程采用” 懒惰方式,即检查发现如果已经加载了(内存中存在)就丌再加载,直接返回已经加载的类,相当于“手工”去检查内存中是否已经加载了某个类

.newInstance()方法,会利用默认(无参数)构造器创建类实例(实例对象)


补充点:获得class对象三种方式
方式一:如果一个类的实例已经得到,你可以使用
        【Class c = 对象名.getClass(); 】
       例:  TextField t = new TextField();
               Class c = t.getClass(); 
               Class s = c.getSuperclass();

方式二:如果你在编译期知道类的名字,你可以使用如下的方法                 
  【 Class c = JButton.class;  】
  或者         Class c = Integer.TYPE;

如果类名在编译期不知道, 但是在运行期可以获得, 你可以使用下面的方法
            【 Class c = Class.forName(strg); 】


在这里要注意:
newInstance: 弱类型。低效率。只能调用无参构造。
new: 强类型。相对高效。能调用任何public构造。
newInstance()是实现IOC、反射、面对接口编程 和 依赖倒置 等技术方法的必然选择,new 只能实现具体类的实例化,不适合于接口编程。


通过反射操作对象属性

  Class clss=Outer.class;
  Object o=clss.newInstance();
  Field field=clss.getDeclaredField("num");
  Object val=field.get(o);
  System.out.println(val);

上边的实验,我们发现用这种方式也是可以的Class cls=Outer.class;
--------------------------
接着上边的实验,我们发现了
  Object val=field.get(o);
  val=15;
  Object val2=field.get(o);
  System.out.println(val);
通过这种方式完全可以修改我们的属性

原文地址:https://www.cnblogs.com/chenyangpeng/p/5459925.html