反射(Reflect)

反射 

    提到反射可能会使我们联想到光学中的反射概念,在Java中又是另外一个概念:
    平时我们照镜子的时候,在镜子后面会有自己的影子,其实java中的反射也是类似的
        ,一个类或者对象通过反射可以
    获得自身的对象,该对象是一个java.lang.Class 的对象(就像一个镜像文件)。

    一个对象或者类获得自身的Class对象的过程称为反射。

    有两种方法可以获得自身的Class对象引用(对每一个被装载的类型(类或接口),虚拟机都会为它创建一个
    java.lang.Class的实例):
    1) Class c = Class.forName(“com.briup.ch06.Student”);    //虚拟机中没有该类的Class的实例对象
    2) Class c = stu.getClass();                        //虚拟机已经存在Class的实例对象
       Class c = this.getClass();                            ////虚拟机已经存在Class的实例对象

    注意:类和它所创建的所有对象通过反射获得的Class对象都是同一个,在这个例子中是com.briup.ch06.Student

    反射可以让我们利用这个Class对象来获取和修改私有的变量和方法,不通过共有的方法去获得(原来我们例子都是通过
    一个public的方法来设置和获取私有的变量),可以破坏数据的封装性。

    常用到反射方式:
    1) 可以创建对象
    2) 可以访问对象中的属性
    3) 可以访问对象中的方法。
    4) 可以访问对象中的构造器。

1)Class类型 java.lang.Class类
    Class是对java中所有类型的抽象。即一个Class类型对象可以表示出java中任意一种类型。
    每种类型在加载到内存后,内存中都会生产一个与之对应的Class类型对象(有且只有一个),用来表示该类型。

    每个类型都有且只有一个Class类型对象与之对应,通过这个Class类型对象就可以获得到该类型中的各种信息。

    Class类是Java反射的入口.
    反射机制通过在运行时探查字段和方法,从而可以帮助写出通用性很好的程序,这项能力对系统编程来说特别有用,但
    它并不适合于应用编程。而且,反射是脆弱的——编译不能帮助你发现编译错误,任何错误在运行时被发现并且都会导
    致异常。

        1.表示基本类型
        Class c = int.class;
        System.out.println(c.isPrimitive());//true
        System.out.println(c.getName());//int
        
        注:其他基本类型的情况类似

    2.表示类类型
        注:s.getClass()方法返回的是变量s所指向对象的实现类型的Class对象。
        Student s = new Student();
        Class c1 = s.getClass();
        Class c2 = Student.class;
        System.out.println(c1 == c2);//true
        
        //p指向的对象实际类型是Student
        Person p = new Student();
        Class c1 = p.getClass();//c1表示Student类型
        Class c2 = Person.class;//c2表示Person类型
        System.out.println(c1 == c2);//false

    3.表示接口类型
        Action a = new Student();
        Class c1 = a.getClass();//c1表示Student类型
        Class c2 = Action.class;//c2表示Action类型
        System.out.println(c1 == c2);//false

        System.out.println(c2.isInterface());//true

    
    4.表示数组类型
        int[] a = new int[4];
        Class c1 = a.getClass();
        Class c2 = int[].class;
        System.out.println(c1 == c2);//true
        System.out.println(c1.isArray());//true

        Class c3 = c1.getComponentType();//c3表示该数组是使用什么类型声明出来的
        System.out.println(c3.getName());//int
        

        
        Student[] a = new Student[4];
        Class c1 = a.getClass();
        Class c2 = Student[].class;
        System.out.println(c1 == c2);//true
        System.out.println(c1.isArray());//true

        Class c3 = c1.getComponentType();//c3表示该数组是使用什么类型声明出来的
        System.out.println(c3.getName());//com.briup.test.Student


2)获得一个类类型的Class对象的三种方式
    以上几种情况中,所以最多的还是类类型的Class对象
    1.使用对象调用getClass方法获得
        getClass是Object中的final修饰的方法,每个对象都可以调用而且不能重写
        Student s = new Student();
        Class c = s.getClass();

    2.使用类名获得
        Class c = Student.class;

    3.使用Class类中的forName方法获得
        //这种方法很灵活,只需一个String类型参数即可
        //而String类型的数据改变起来很容易
        //注意该方法是会抛出异常的
        Class c = Class.forName("com.briup.test.Student");

    注:以上三种方法获得的同一个对象(==比较),因为每个类型内存都有且只有一个Class类型对象


4)反射机制中的常见类的含义
    java.lang包下:
    Class  类    对java中所有类型抽象而得来的
    package类    对java中所有包抽象而得来的

    java.lang.reflect包下:
    Modifier    类    对java中所有修饰符抽象而得来的
    Field        类    对java中所有属性抽象而得来的
    Method        类    对java中所有方法抽象而得来的
    Constructor 类    对java中所有构造器抽象而得来的
    Array        类    提供了对数组对象的动态访问
    

5)使用Class类型对象获得类中的信息
    1.获得该类所处的包的信息
        Student s = new Student();
        Class c = s.getClass();
        System.out.println(c.getPackage().getName());

    2.获得该类的修饰符信息
        //每个修饰符对应一个int值
        //如果有多个修饰符则int值相加
        Student s = new Student();
        Class c = s.getClass();
        System.out.println(c.getModifiers());

        System.out.println(Modifier.PUBLIC);
        System.out.println(Modifier.FINAL);

    3.获得该类的名字
        Student s = new Student();
        Class c = s.getClass();
        System.out.println(c.getName());
    
    4.获得该类的父类的Class对象
        Student s = new Student();
        Class c = s.getClass();
        //superclass表示其父类型的Class对象
        Class superclass = c.getSuperclass();
        System.out.println(superclass.getName());

        例如:
        Class c = Object.class;
        Class superclass = c.getSuperclass();
        System.out.println(superclass.getName());
        //运行报错,因为Object没有父类
        

        例如:
        //判断c1是不是c2的子类型
        //判断c3是不是c2的子类型
        Class c1 = Student.class;
        Class c2 = Person.class;
        Class c3 = String.class
        System.out.println(c2.isAssignableFrom(c1));//true
        System.out.println(c2.isAssignableFrom(c3));//false
    
    5.获得该类所实现的接口类型的Class对象
        Student s = new Student();
        Class c = s.getClass();
        Class[] interfaces = c.getInterfaces();
        for(Class clazz:interfaces){
            System.out.println(clazz.getName());
        }

        例如:
        //判断c1是不是c2的实现类
        //判断c3是不是c2的实现类
        Class c1 = Student.class;
        Class c2 = Action.class;
        Class c3 = String.class
        System.out.println(c2.isAssignableFrom(c1));//true
        System.out.println(c2.isAssignableFrom(c3));//false

    
    6.获得该类中所有的属性
        Student s = new Student();
        Class c = s.getClass();
        Field[] declaredFields = c.getDeclaredFields();
        
        for(Field f:declaredFields){
            System.out.println(f.getModifiers());
            System.out.println(f.getType().getName());
            System.out.println(f.getName());
        }
        注:
        getDeclaredFields()方法返回类中声明的属性,包括私有的
        getFields()方法只返回类中public修饰的属性,包括继承的

        
        例如:
        //获得某个指定的属性(也包括私有属性)
        Student s = new Student();
        Class c = s.getClass();
        Field f = c.getDeclaredField("score");
        System.out.println(f.getModifiers());
        System.out.println(f.getType().getName());
        System.out.println(f.getName());


    7.获得该类中所有的方法
        Student s = new Student();
        Class c = s.getClass();
        Method[] declaredMethods = c.getDeclaredMethods();
        for(Method m:declaredMethods){
            System.out.println(m.getModifiers());
            System.out.println(m.getReturnType().getName());
            System.out.println(m.getName());
            System.out.println(Arrays.toString(m.getParameterTypes()));
            System.out.println(Arrays.toString(m.getExceptionTypes()));
        }

        注:
        getDeclaredMethods()方法返回类中声明的方法,包括私有的
        getMethods()方法只返回类中public修饰的方法,包括继承的
        

        例如:
        //获得某个指定的方法(也包括私有方法)
        Student s = new Student();
        Class c = s.getClass();
        Method m = c.getDeclaredMethod("print");
        System.out.println(m.getModifiers());
        System.out.println(m.getReturnType().getName());
        System.out.println(m.getName());
        System.out.println(Arrays.toString(m.getParameterTypes()));
        System.out.println(Arrays.toString(m.getExceptionTypes()));


    8.获得该类中所有的构造器
        Student s = new Student();
        Class c = s.getClass();
        Constructor[] declaredConstructors = c.getDeclaredConstructors();
        for(Constructor con:declaredConstructors){
            System.out.println(con.getModifiers());
            System.out.println(con.getName());
            System.out.println(Arrays.toString(con.getParameterTypes()));
            System.out.println(Arrays.toString(con.getExceptionTypes()));
        }

        注:
        getDeclaredConstructors()方法返回类中所有构造器
        getConstructors()方法只返回类中public修饰的构造器
        
        
        例如:
        //获得某个指定的构造器(也包括私有构造器)
        Student s = new Student();
        Class c = s.getClass();
        Constructor con = c.getDeclaredConstructor(double.class);
        System.out.println(con.getModifiers());
        System.out.println(con.getName());
        System.out.println(Arrays.toString(con.getParameterTypes()));
        System.out.println(Arrays.toString(con.getExceptionTypes()));

6)反射中的常用操作
    public class Student{
        private long id;
        private String name;

        private static int age;
        
        get/set

        public static void say(){
            System.out.println("say..");
        }

    }
    1.使用反射的方式调用构造器创建类的对象
        默认方式:必须调用无参构造器
        Class c = Student.class;
        Student s = (Student)c.newInstance();

        通用方式:获得构造器对象,并调用该构造器

        注:getConstructor方法和newInstance方法的参数都是可变参数
        例如:获得无参构造器并调用创建对象
        Class c = Student.class;
        Constructor constructor = c.getConstructor();
        Student o = (Student)constructor.newInstance();
        System.out.println(o);

        例如:获得有参构造器并调用创建对象
        Class c = Student.class;
        Constructor constructor = c.getConstructor(long.class,String.class);
        Student o = (Student)constructor.newInstance(1L,"tom");
        System.out.println(o);


    2.使用反射的方式访问对象中的属性
        例如:
        Student s = new Student();
        Class c = s.getClass();
        Field[] declaredFields = c.getDeclaredFields();
        for(Field f:declaredFields){

            //设置私有属性可以被访问
            f.setAccessible(true);

            //判断属性是否为static,静态属性的访问不需要对象
            if(Modifier.isStatic(f.getModifiers())){
                System.out.println(f.getName() +" = "+f.get(null));
            }else{
                System.out.println(f.getName() +" = "+f.get(s));
            }
        }

        注:Field类中的get方法可以获得属性值,set方法可以给属性设置值。
    

    3.使用反射的方式调用对象中的方法
        例如:
        Student s = new Student();
        Class c = s.getClass();
        
        Method m1 = c.getMethod("setName",String.class);
        //m1表示Student中的setName方法
        //调用对象s中的m1方法,并且传参"tom"
        //s.setName("tom");
        m1.invoke(s, "tom");
        
        Method m2 = c.getMethod("getName");
        String name = (String)m2.invoke(s);
        System.out.println("name = "+name);
        
        //调用静态方法 不需要对象
        Method m3 = c.getMethod("say");
        m3.invoke(null);

    4.使用反射的方式动态操作数组
        
        public static Object arrayCopy(Object obj){
            //代码
        }

        实现:
        public static Object arrayCopy(Object obj){
            Class c = obj.getClass();
            Object newArray = null;
            if(c.isArray()){
                int len = Array.getLength(obj);
                Class<?> type = c.getComponentType();
                newArray = Array.newInstance(type, len*2);
                for(int i=0;i<len;i++){
                    Object value = Array.get(obj, i);
                    Array.set(newArray, i, value);
                }
            }
            return newArray;
        }

猜你喜欢

转载自blog.csdn.net/bifuguo/article/details/81748079