首页 > 代码库 > 黑马程序员——反射

黑马程序员——反射

JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性;这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制。
Java反射机制主要提供了以下功能: 在运行时判断任意一个对象所属的类;在运行时构造任意一个类的对象;在运行时判断任意一个类所具有的成员变量和方法;在运行时调用任意一个对象的方法;生成动态代理。
有时候我们说某个语言具有很强的动态性,有时候我们会区分动态和静态的不同技术与作法。我们朗朗上口动态绑定(dynamic binding)、动态链接(dynamic linking)、动态加载(dynamic loading)等。然而“动态”一词其实没有绝对而普遍适用的严格定义,有时候甚至像面向对象当初被导入编程领域一样,一人一把号,各吹各的调。
一般而言,开发者社群说到动态语言,大致认同的一个定义是:“程序运行时,允许改变程序结构或变量类型,这种语言称为动态语言”。从这个观点看,Perl,Python,Ruby是动态语言,C++,Java,C#不是动态语言。
尽管在这样的定义与分类下Java不是动态语言,它却有着一个非常突出的动态相关机制:Reflection。这个字的意思是“反射、映象、倒影”,用在Java身上指的是我们可以于运行时加载、探知、使用编译期间完全未知的classes。换句话说,Java程序可以加载一个运行时才得知名称的class,获悉其完整构造(但不包括methods定义),并生成其对象实体、或对其fields设值、或唤起其methods。这种“看透class”的能力(the ability of the program to examine itself)被称为introspection(内省、内观、反省)。Reflection和introspection是常被并提的两个术语。
Java如何能够做出上述的动态特性呢?这是一个深远话题,本文对此只简单介绍一些概念。整个篇幅最主要还是介绍Reflection APIs,也就是让读者知道如何探索class的结构、如何对某个“运行时才获知名称的class”生成一份实体、为其fields设值、调用其methods。本文将谈到java.lang.Class,以及java.lang.reflect中的Method、Field、Constructor等等classes。package cn.itcast.com;
 
import java.lang.reflect.Array;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.Arrays;
 
public class ReflectText {
 
    /**
     * @param args
     */
    public static void main(String[] args)throws Exception {
        // TODO Auto-generated method stub
        String str1 =  "abc";
        Class cls1 = str1.getClass();
        Class cls2 = String.class;
        Class cls3 = Class.forName("java.lang.String");
        System.out.println(cls1==cls2);
        System.out.println(cls1==cls2);
        
        System.out.println(cls1.isPrimitive());//cls1是否是基本类型字节码false  String非基本类型
        System.out.println(int.class.isPrimitive());//true
        System.out.println(int.class==Integer.class);//flse
        System.out.println(int.class==Integer.TYPE);//true
        System.out.println(int[].class.isPrimitive());//false
        System.out.println(int[].class.isArray());//ture
        
        /*得到某个类的所有构造方法
         * Constructor[] constructors = Class.forName("类名").getConstructors();
        */
        //编译器只看代码的定义
        //得到String的构造方法夸号里的是该构造方法的参数,说明是返回这个构造方法字节码
        Constructor constructor1 = String.class.getConstructor(StringBuffer.class);
        String str5 = (String)constructor1.newInstance(new StringBuffer("abc"));
        System.out.println(str5.charAt(2));
        
        ReflectPoint pt1 = new ReflectPoint(3,5);
        Field fieldY = pt1.getClass().getField("y");
        //fieldY是对应是类上的变量而 不是不是对应某个指定对象上的变量!!!
        System.out.println(fieldY.get(pt1));//取出pt1对应的fieldY值=5
        
        //y是共有的,而x是私有的要改变访问方法
        Field fieldX = pt1.getClass().getDeclaredField("x");
        //能访问但不能读取值
        fieldX.setAccessible(true);
        System.out.println(fieldX.get(pt1));
        
        changeStringValue(pt1);
        System.out.println(pt1);
        
        
        //Method类中的方法
        //用字节码得到String中的charAt方法再去作用str1这个对象
        //str1.charAt(1);
        //String对象下的charAt方法charAt方法的参数是int
        //methodCharAt是一个方法对象
        Method methodCharAt = String.class.getMethod("charAt", int.class);
        //用反射机制得到字节码中某个方法,再用这个方法去作用这个对象
        //用methodCharAt方法对象去调用(invoke)这个方法(charAt)
        //如果invoke第一个参数是null则他调用的是静态方法
        System.out.println(methodCharAt.invoke(str1,2));
        
        //在程序中直接用静态的方式调用main方法
        TestArguements.main(new String[]{"111","222","333"});
        
        //用反射机制来调用main
        String startingClassName = args[0];
        Class clazz = Class.forName(startingClassName);
        Method mainMethod = clazz.getMethod("main", String[].class);
        //Method mainMethod = Class.forName(startingClassName.getClass().getMethod("main",String[].class));
        //mainMethod.invoke(null,new String[]{"111","222","333"});
        //上面这种方法不行,虽然是一个字符串数组,但jdk1.5把他拆开看做3个,就有3各参数,与main的参数个数不一致
        mainMethod.invoke(null,new Object[]{new String[]{"111","222","333"}});//封装成一个对象数组
    
        int[] a1 = new int[]{1,2,3};
        int[] a2 = new int[4];
        int[][] a3 = new int[2][3];
        String[] a4 = new String[]{"a","b","c"};
        System.out.println(a1.getClass() == a2.getClass());//ture同一类型的字节码  int  且一维
        //System.out.println(a1.getClass() == a4.getClass());//false
        //System.out.println(a1.getClass() == a3.getClass());
        System.out.println(a1.getClass().getName());//[I  说明是整型
        System.out.println(a1.getClass().getSuperclass().getName());//java.lang.Object
        System.out.println(a4.getClass().getSuperclass().getName());//java.lang.Object
    
        /*Object可以引用任何的类,像int double char这类是基本类型,Object不能引用,
         * 但是可以引用他们的封装类,Integer Double这种,
         * 因此,Object数组能放除了8个基本类型之外的所有类
         * */
        Object Obj1 = a1;
        Object Obj2 = a4;
        //Object[] Obj3 = a1;//不对  a1是一维数组,里面每个元素师基本数据类型
        //String对象类型,二维数据分为一维数组装了几个一维数组,其中一维数组是对象
        Object[] Obj4 = a3;
        Object[] Obj5 = a4;
        
        System.out.println(a1);
        System.out.println(a4);
        //Arrays.asList(对象类型)
        System.out.println(Arrays.asList(a1));//整数不打印出每个元素,把所有数据看做一个内容
        System.out.println(Arrays.asList(a4));//打印出每个元素
        
        
        printObject(a4);// a回车b回车c
        printObject("xyz");//xyz
    }
    
    private static void printObject(Object obj){
        Class clazz = obj.getClass();
        if(clazz.isArray()){
            int len = Array.getLength(obj);
            for(int i=0;i<len;i++){
                System.out.println(Array.get(obj, i));
            }
        }else{
            System.out.println(obj);
        }
    }
 
    private static void changeStringValue(Object obj)throws Exception {
        // TODO Auto-generated method stub
        Field[] fields = obj.getClass().getFields();
        for(Field field : fields){
            //不能写field.getType().equals(String.class)
            //虽然正确但字节码只有一份肯定比较的是地址,上面的有语义错误
            if(field.getType() == String.class){
                String oldValue = http://www.mamicode.com/(String)field.get(obj);
                String newValue = http://www.mamicode.com/oldValue.replace(‘b‘, ‘a‘);
                field.set(obj, newValue);
            }
        }
    }
 
}
class TestArguements
{
    public static void main(String[] args){
        for(String arg : args){
            System.out.println(arg);
        }
    }
}
 
package cn.itcast.day1;
 
import java.util.Date;
 
public class ReflectPoint {
    
    private Date birthday = new Date();
    private int x;
    public int y;
    public String str1 = "ball";
    public String str2 = "basketball";
    public String str3 = "itcast";
    
    public Date getBirthday() {
        return birthday;
    }
    public void setBirthday(Date birthday) {
        this.birthday = birthday;
    }
    public int getX() {
        return x;
    }
    public void setX(int x) {
        this.x = x;
    }
    public int getY() {
        return y;
    }
    public void setY(int y) {
        this.y = y;
    }
    public ReflectPoint(int x, int y) {
        super();
        this.x = x;
        this.y = y;
    }
    public String toString(){
        return str1+":"+str2+":"+str3;
    }
    @Override
    public int hashCode() {
        final int prime = 31;
        int result = 1;
        result = prime * result + x;
        result = prime * result + y;
        return result;
    }
    @Override
    public boolean equals(Object obj) {
        if (this == obj)
            return true;
        if (obj == null)
            return false;
        if (getClass() != obj.getClass())
            return false;
        ReflectPoint other = (ReflectPoint) obj;
        if (x != other.x)
            return false;
        if (y != other.y)
            return false;
        return true;
    }
    
}
 
详情请查看:http://edu.csdn.net/heima

黑马程序员——反射