漫谈反射

反射

理解反射的概念

反射就是把Java类中的各种成分映射相成Java类。

比如:众多的人用一个Person类来表示,那么众多的Java类就用一个Class类来表示。


反射也称为对类的解剖。把类的各个组成部分映射成一个个对应的Java类。

比如:一个类有:成员变量,方法,构造方法,包等等信息。

利用反射技术能够对一个类进行解剖。

事实上仅仅要拿到Java类的字节码相应的Class对象,就等于拿到了Java类中的各个成分。

反射的基石就是Class。

Class类

Class类用于表示.class文件,是全部载入进内存的字节码对象的父类。所以能够通过Class得到执行时的类。


怎样得到某个class文件相应的class对象呢?

方法有3种:

1)类名.class 比如,Person.class。

2)对象.getClass() 比如。new Data().getClass()。

3)Class.forName("包名.类名"); 比如,Class.forName("java.lang.String");

代码演示样例:

public class ClassTest{

public static void main(String...args)throws Exception{

String str = "abc";

Class cls1 =String.class;

Class cls2 = str.getClass();

Class cls3 = Class.forName("java.lang.String");

System.out.println(cls1 == cls2);//true

System.out.println(cls2 == cls3);//true

}

}


注意:字节码文件是唯一的,所以不管怎么获取。都是同一份字节码文件。



九个提前定义Class实例对象(八大原始类型+void)

Class 类的实例表示正在执行的 Java 应用程序中的类和接口。

枚举是一种类,凝视是一种接口。

每一个数组属于被映射为 Class 对象的一个类,全部具有同样元素类型和维数的数组都共享该Class 对象。

主要的 Java 类型(boolean、byte、char、short、int、long、float 和 double)和keyword void也表示为 Class 对象。

注意:

1、int.class == Integer.TYPE。

2、数组类型的Class实例对象Class.isArray()为true。

3、反射并非Java 5.0的新特性。

Java 5.0 代码演示样例:

package com.itheima.day01;

public class ReflectTest {

public static void main(String[] args) {

System.out.println("推断int基本数据类型和Integer的基本数据类型"

+ "是不是同一个Class对象 结果为:"+(int.class == Integer.TYPE));

System.out.println("推断int.class是不是基本数据类型 结果为:"+int.class.isPrimitive());

System.out.println("推断是不是数组类型 结果为:"+int[].class.isArray());

}

}

总之,仅仅要是在源程序中出现的类型,都有各自的Class实例对象,比如。int.classint[].class。


一个类中的每一个成员都能够用对应的反射API类的一个实例对象来表示。通过调用Class类的方法能够得到这些实例对象后。得到这些实例对象后有什么用呢?怎么用呢?这正是学习和应用反射的要点。



构造方法的反射应用(Coustructor类)


Constructor类的实例对象代表类的一个构造方法。

反射公共。私有和保护的构造方法:

反射公共的须要的方法是:getConstructor();

反射私有的须要的方法是:getDeclaredConstructor();

Constructor对象代表一个构造方法。Constructor对象有的方法:得到构造方法名字。得到所属于的类,产生实例对象。


得到某个类空參数构造方法。例:

Constructor constructor = Class.forName("java.lang.String").getConstructor();

得到某个类全部的构造方法,例:

Constructor [] constructors= Class.forName("java.lang.String").getConstructors();

得到某一个带參数的构造方法,例:

Constructor constructor =Class.forName("java.lang.String").getConstructor(StringBuffer.class);


注意:一个类有多个构造方法,用什么方式能够区分清楚想得到当中的哪个方法呢?依据參数的个数和类型,比如,Class.getMethod(name,Class... args)中的args參数就代表所要获取的那个方法的各个參数的类型的列表。重点:參数类型用什么方式表示?用Class实例对象。


利用构造方法创建实例对象:

通常方式:String instance = new String(new StringBuffer("黑马程序猿"));

反射方式:String instance = (String)constructor.newInstance("黑马程序猿");

//调用获得的方法时要用到上面同样类型的实例对象

通过Class类中的newInstance()方法也可创建类的实例,其内部工作原理是先得无參的构造方法,再用构造方法创建实例对象。

代码演示样例:

package com.itheima.day01;

import java.lang.reflect.Constructor;

public class ReflectTest {

public static void main(String[] args) throws Exception {

Class clszz = Class.forName("java.lang.String");

Constructor constructor = clszz.getConstructor(StringBuffer.class);

String str = (String) constructor.newInstance(new StringBuffer("黑马程序猿"));

char [] chs = str.toCharArray();

for(int x = 0; x<chs.length;x++){

System.out.println(chs[x]);

}

}
}

成员变量的反射(Field类)

Field类代表反射某个类中的一个成员变量。


问题:得到的Field对象是相应到类上面的成员变量。还是相应到对象上的成员变量?类仅仅有一个。而该类的实例对象有多个,假设是与对象关联,那关联的是哪个对象呢?所以字段fieldAge 代表的是Age的定义,而不是详细的Age变量。

(注意訪问权限的问题)也就是说,定义的是类对象,而非对象的对象。

当我们须要对其操作的时候。须要确定是那个详细的对象。

代码演示样例:

package com.itheima.study;

public class Person {

public int age;

private int height;

public Person(int age,int height){

this.age=age;

this.height=height;

}

}


package com.itheima.study;

import java.lang.reflect.Field;

public class ReflectTest{

public static void main(String...args) throws Exception{

Person p = new Person(20,30);

Field fieldAge = p.getClass().getField("age");

System.out.println(fieldAge.get(p));

}

}

练习:将随意一个对象中的全部String类型的成员变量所相应的字符串内容中的“b"改为"a"。

public class ReflectPoint  
{  
   private int x;  
   public int y;  
   public String str1="blue";  
   private String str2="bubble";  
   public String str3="soso";  
    public ReflectPoint(int x, int y)  
    {  
        super();  
        this.x = x;  
        this.y = y;  
    }  
      
    public String toString()  
    {  
        return str1+" "+str2+" "+str3;  
    }  
    
}  

public class Reflect {


/**
* 练习:将随意一个对象中的全部String类型的成员变量所相应的字符串内容中的“b"改为"a"。



*/
public static void main(String[] args) throws Exception {
Constructor[]  constructors=String.class.getConstructors();//得到String类的全部公共构造方法  
        Constructor constructor=String.class.getConstructor(StringBuffer.class);//得到指定參数的构造方法  
        //用构造方法创建实例  
        String s=(String)constructor.newInstance(new StringBuffer("黑马"));  
        System.out.println(s);           
        //Class类里面的无參构造方法                                                        
        Date date=(Date)Class.forName("java.util.Date").newInstance();  
        System.out.println(date);  
          
        ReflectPoint rp=new ReflectPoint(3,3);  
        Field fieldY=rp.getClass().getField("y");//注意fieldY不是对象的变量,是所在类的变量  
        int rpY=(Integer) fieldY.get(rp);//依据对象取得变量的值  
        System.out.println(rpY);  
          
        Field fieldX=rp.getClass().getDeclaredField("x");//由于x被private修饰  
        fieldX.setAccessible(true);//把私有的变量设置成能够訪问  
        System.out.println(fieldX.get(rp));  
          
        value(rp);  
        System.out.println(rp);
       
}

private static void value(Object  obj) throws Exception {
Field[]  fields=obj.getClass().getFields();
for (Field field : fields) {
if (field.getType()==String.class) {//getType()返回一个 Class 对象。它标识了此 Field 对象所表示字段的声明类型
String  oldvalue=(String) field.get(obj);// 返回指定对象上此 Field 表示的字段的值
String  newvalue=oldvalue.replace('b','a');//把b变成a
field.set(obj, newvalue);//将指定对象变量上此 Field 对象表示的字段设置为指定的新值。

}
}
}


}


posted @ 2017-05-07 17:06  claireyuancy  阅读(150)  评论(0编辑  收藏  举报