12 反射

12.1  反射的概念

12.1.1 反射机制

  Java反射机制是在运行状态中,对于任意一个类,都能够知道这个类中的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性;这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制。简单的说反射就是动态获取类中信息,对类进行解刨。

  理解反射首先要明确一个概念:那就是动态语言!因为我在学习时对“动态获取类中信息”很困惑。

  动态语言:程序运行时,允许改变程序结构或变量类型,这种语言称为动态语言。

  从这个观点出发Java语言不是动态语言,所以Java有了一个非常突出的动态相关机制--Reflection,可以在运行时加载,探知,使用编译时期完全未知的classes,也就是说Java可以加载一个运行时才知道名称的class。也就是说Java反射机制是在运行状态中,对于任意一个类(class文件<字节码文件>),都能知道这个类的属性和方法。对于任意一个对象,都能调用它的属性和方法。这种动态获取类的信息以及动态调用对象的方法的功能成为Java语言的反射机制。简单的说:反射就是把Java类中的各种成分映射成相应的java类。

12.1.2 反射的好处:

反射极大的增强了程序的扩展性。

12.1.3 反射是使用步骤

步骤:

1,获得Class对象,就是获得指定名称的字节码文件对象。

2,实例化对象,获类的属性,方法和构造函数。

3,调用构造函数创建对象,访问属性,调用方法。

12.2 Class类

1字节码

     当源程序中用到类时,首先要从硬盘把这个类的那些二进制代码,一个类编译成class文件放在硬盘上以后,就是一些二进制代码,要把这些二进制代码加载到内存中里面来,再用这些字节码去复制出一个一个对象来。

2 Class类的由来

  所有的类文件都有共同属性,所以可以向上抽取,把这些共性内容封装成一个类,这个类就叫Class(描述字节码文件的对象)。Class类中包含属性有field(字段)、method(方法)、construction(构造函数)。要想对一个类进行内容的获取,必须要先获取该字节码文件的对象。该对象是Class类型。Class类描述的信息:类的名字,类的访问属性,类所属于的包名,字段名称的列表,方法名称的列表等。每一个字节码就是class的实例对象。如:classcls=Data.class;

3 Class和class的区别

        1)class:Java中的类用于描述一类事物的共性,该类事物有什么属性,没有什么属性,至于这个属性的值是什么,则由此类的实例对象确定,不同的实例对象有不同的属性值。

        2)Class:指的是Java程序中的各个Java类是属于同一类事物,都是Java程序的类,这些类称为Class。例如人对应的是Person类,Java类对应的就是Class。Class是Java程序中各个Java类的总称;它是反射的基石,通过Class类来使用反射。

4 获取Class对象的三种方式

        加载XX.class文件进内存时就被封装成了对象,该对象就是字节码文件对象

1).通过对象的getClass方法进行获取。

        如:Class clazz=new Person().getClass();//Person是一个类名

        弊端:每次都需要具体的类和该类的对象,以及调用getClass方法。

2).任何数据类型都具备着一个静态的属性class,这个属性直接获取到该类型的对应 Class对象。

        如:Class clazz=Person.class;//Person是一个类名

        弊端:还是要使用具体的类,和该类中的一个静态属性class完成。

3). 这种方式较为简单,只要知道类的名称即可。不需要使用该类,也不需要去调用具 体的属性和行为。就可以获取到Class对象了。

        如:String className=”Person”;

Class clazz=Class.forName(className);//Person是一个类名

        这种方式仅知道类名就可以获取到该类字节码对象的方式,利于扩展。

package reflect;

public class Person {
    private String name;
    private int age;
    private String address;
    public Person() {
        super();
        // TODO Auto-generated constructor stub
    }
    public Person(String name, int age, String address) {
        super();
        this.name = name;
        this.age = age;
        this.address = address;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public int getAge() {
        return age;
    }
    public void setAge(int age) {
        this.age = age;
    }
    public String getAddress() {
        return address;
    }
    public void setAddress(String address) {
        this.address = address;
    }
    
}
package reflect;
/*
 * 反射: 通过class文件的对象,获取构造函数、字段、方法的操作
 * 
 * 学习反射的目的:
 *         有些时候,可能JDK中的方法没有在帮助文档中提供,但是通过查看源代码,却发现有这个方法,不会该方法为private私有,所以JDK的帮助文档没有提供该方法
 *         如果,必须要用这个方法, 我们可以通过反射的方式来获取,进行使用
 * 
 * 构造函数: Constructor
 * 字段:Field
 * 方法:Method
 * 
 * 
 * 如何获取Person类的 字节码文件对象呢?
 * 方式1:  getClass(): 返回进行时的类
 * 方式2: 数据类型.class 静态属性,来获取当前数据类型的字节码文件对象
 * 方式3: public static Class forName(String className) 返回与带有给定字符串名的类或接口相关联的 Class 对象
 * 
 */
public class ReflectDemo {

    public static void main(String[] args) {
        //反射机制获取当前正在运行的类
//        getClassTest1();
        //反射机制获取当前正在运行类的字节码文件
        getClassTest2();
        getClassTest3();

    }
    //通过反射机制,获取当前正在运行的类的字节码文件的对象
    //方式一:对象.getClass()
    public static void getClassTest1(){    
        Person p1 = new Person();
        Person p2 = new Person();
        Class c1 = p1.getClass();
        Class c2 = p2.getClass();
        if (p1==p2) {
            System.out.println("判断获取到的四个对象之间是否为一个对象:"+"p1和p2是一个对象,地址和内容都一致;");
        } else {
            System.out.println("判断获取到的四个对象之间是否为一个对象:"+"p1和p2不是一个对象,地址或内容不一致;");
        }
        if (c1==c2) {
            System.out.println("判断获取到的四个对象之间是否为一个对象:"+"c1和c2是一个对象,地址和内容都一致;");
        } else {
            System.out.println("判断获取到的四个对象之间是否为一个对象:"+"c1和c2不是一个对象,地址或内容不一致;");
        }
    }
    //通过反射机制,获取当前正在运行的类的字节码文件的对象
    //方式一:类名.class   静态属性,来获取当前数据类型的字节码文件对象
    public static void getClassTest2(){
        Class c1 = Person.class;
        Class c2 = Person.class;
        if(c1==c2){
            System.out.println("判断获取到的四个对象之间是否为一个对象:"+"c1和c2是一个对象,地址和内容都一致;");
        }else {
            System.out.println("判断获取到的四个对象之间是否为一个对象:"+"c1和c2不是一个对象,地址或内容不一致;");
        }
    }
    // 方式3: public static Class forName(String className)
    // 返回与带有给定字符串名的类或接口相关联的 Class 对象
    // className : 类的全路径名称 包名.类名
    public static void getClassTest3(){
        try {
            //注意如果不写全路径名,会出现ClassNotFound异常
            Class c1 = Class.forName("reflect.Person");
            Class c2 = Class.forName("reflect.Person");
            if(c1==c2){
                System.out.println("判断获取到的四个对象之间是否为一个对象:"+"c1和c2是一个对象,地址和内容都一致;");
                System.out.println(c1);
            }else {
                System.out.println("判断获取到的四个对象之间是否为一个对象:"+"c1和c2不是一个对象,地址或内容不一致;");
            }
        } catch (ClassNotFoundException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        
    }

}

12.3 常用方法

12.3.1 获取构造函数

package reflect;

public class Student {
    public String name;
    public int age;
    private String address;
    public Student() {
        super();
        // TODO Auto-generated constructor stub
    }
    public Student(String name, int age) {
        super();
        this.name = name;
        this.age = age;
    }
    public Student(String name, String address) {
        super();
        this.name = name;
        this.address = address;
    }
    //私有的构造函数
    private Student(String name, int age, String address) {
        super();
        this.name = name;
        this.age = age;
        this.address = address;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public int getAge() {
        return age;
    }
    public void setAge(int age) {
        this.age = age;
    }
    public String getAddress() {
        return address;
    }
    public void setAddress(String address) {
        this.address = address;
    }
    
}
package reflect;

import java.lang.reflect.Constructor;

/*
 * 反射:
 *         
 * Class类中的方法:
 *         构造函数: Constructor
 * public Constructor getConstructor(Class<?>... parameterTypes) 返回一个 Constructor 对象,它反映此 Class 对象所表示的类的指定公共构造方法。
 *         public Constructor[] getConstructors() : 获取所有的公共的构造函数
 *         public Constructor[] getDeclaredConstructors(): 获取所有的构造函数
 */
public class ReflectConstructorDemo {

    public static void main(String[] args) {
        //根据参数类型获取指定公共构造函数
        getConstructorTest();
        //获取所有的公共构造函数
        getConstrnctorsTest();
        //获取指定的构造函数(公有,私有)
        getDeclaredConstructorTest();
        //获取所有的公共构造函数(公有,私有)
        getDeclaredConstructorsTest();

    }
    //获取指定的公共构造函数
    public static void getConstructorTest(){
        Class c = Student.class;
        try {
            Constructor conPub = c.getConstructor(String.class,int.class);
            System.out.println(conPub);
            
        } catch (NoSuchMethodException | SecurityException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        //获取指定的私有构造函数,注意只能获取公共的构造函数,访问私有会报出java.lang.NoSuchMethodException: reflect.Student.<init>(java.lang.String, int, java.lang.String)
//        try {
//            Constructor conPri = c.getConstructor(new Class[] {String.class,int.class,String.class});
//            System.out.println(conPri);
//        } catch (NoSuchMethodException | SecurityException e) {
//            // TODO Auto-generated catch block
//            e.printStackTrace();
//        }
    }
    //获取所有的公共构造函数
    public static void getConstrnctorsTest(){
        Class c = Student.class;
        Constructor[] conPub = c.getConstructors();
        for (Constructor constructor : conPub) {
            System.out.println("获取到的所有的公共的构造函数:"+constructor);
        }
    }
    //获取指定的构造函数(公共和私有都可以获取)
    public static void getDeclaredConstructorTest(){
        Class c = Student.class;
        try {
            Constructor conPub = c.getDeclaredConstructor(new Class[]{String.class,int.class});
            System.out.println("获取公共的构造函数:"+conPub);
        } catch (NoSuchMethodException | SecurityException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        try {
            Constructor conPri = c.getDeclaredConstructor(String.class,int.class,String.class);
            System.out.println("获取私有的构造函数:"+conPri);
        } catch (NoSuchMethodException | SecurityException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }
    //获取所有的构造函数(公共和私有都可以获取)
    public static void getDeclaredConstructorsTest(){
        Class c = Student.class;
        Constructor[] con = c.getDeclaredConstructors();
        for (Constructor constructor : con) {
            System.out.println("获取所有的公共构造函数:"+constructor);
        }
    }

}

12.3.2 获取当前字节码实例

package reflect;

import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;

/*
 * public Constructor getConstructor(Class<?>... parameterTypes)
 * 
 * 通过构造函数, 创建对象
 * public Object newInstance(Object... initargs)
 * 使用此 Constructor 对象表示的构造方法来创建该构造方法的声明类的新实例,并用指定的初始化参数初始化该实例
 */
public class NewInstanceByConstructorDemo {

    public static void main(String[] args) {
        //通过构造函数创建实例对象
        getPublicInstanceByConstructorTest();
        //暴力进入,通过私有构造获取实例
        setAccessibleTest();
    }
    //通过构造函数创建实例对象,注意不能创建私有的构造函数,否则报出错误
    //java.lang.IllegalAccessException: Class reflect.NewInstanceByConstructorDemo can not access a member of class reflect.Student with modifiers "private"
    public static void getPublicInstanceByConstructorTest(){
        Class c = Student.class;
//        try {
//            //创建私有对象
//            Constructor conPri = c.getDeclaredConstructor(String.class,int.class,String.class);
//            Object obj1 = conPri.newInstance("静",27,"河南");
//            Object obj2 = conPri.newInstance("静",27,"河南");
//            if (obj1 == obj2) {
//                System.out.println("获取到的两个对象是同一个地址!");
//            }else {
//                System.out.println("获取到的不是两个对象!");
//            }
//        } catch (NoSuchMethodException | SecurityException e) {
//            // TODO Auto-generated catch block
//            e.printStackTrace();
//        } catch (InstantiationException e) {
//            // TODO Auto-generated catch block
//            e.printStackTrace();
//        } catch (IllegalAccessException e) {
//            // TODO Auto-generated catch block
//            e.printStackTrace();
//        } catch (InvocationTargetException e) {
//            // TODO Auto-generated catch block
//            e.printStackTrace();
//        }
        //创建公共构造函数
        
        try {
            Constructor conPub = c.getConstructor(String.class,int.class);
            Object obj1 = conPub.newInstance("静",27);
            Object obj2 = conPub.newInstance("静",27);
            if (obj1==obj2) {
                System.out.println("创建是同一个对象");
            } else {
                System.out.println("不是同一个对象");
            }
        } catch (InstantiationException | IllegalAccessException
                | IllegalArgumentException | InvocationTargetException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (NoSuchMethodException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (SecurityException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }
    //在上边我们看到私有构造函数创建实例时,报错了,这是java的机制决定的,那么有没有办法让他创建成功呢
    /*
     * 获取Student类中的非public的构造函数,并创建对象
     * 
     * public Constructor<T> getDeclaredConstructor(Class<?>... parameterTypes)
     * 获取指定的构造函数 (包含私有的)
     * 
     * public void setAccessible(boolean flag)
     * 将此对象的 accessible 标志设置为指示的布尔值。值为 true 则指示反射的对象在使用时应该取消 Java 语言访问检查
     * 
     * 步骤:
     *         创建一个Class字节码文件对象
     *         获取指定的构造函数  如果是非public的构造函数,需要 强制访问(暴力访问)
     *         创建对象
     */
    public static void setAccessibleTest(){
        Class c = Student.class;
        try {
            Constructor conPri = c.getDeclaredConstructor(String.class,int.class,String.class);
            //强制访问,暴力进入,(通过私有构造函数获取对象)
            conPri.setAccessible(true);
            Object obj = conPri.newInstance("静",27,"河南");
            System.out.println(obj);
            Object object = conPri.newInstance("静",27,"河南");
            System.out.println(object);
        } catch (NoSuchMethodException | SecurityException | InstantiationException | IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }
}

12.3.3 获取当前字节码中字段

package reflect;

import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;

/*
 * 字段:Field
 * 
 * private String name;
 * int age;
 * public String address;
 *
 * 步骤:
 *     a: 创建class字节码文件对象
 *     b: 获取指定的字段,如果是非public 修饰的字段, 需要 暴力访问
 *     c: 对字段进行操作
 * 
 *  Class中的方法:
 *      public Field[] getFields() : 获取 public 修饰的 所有字段
 *         public Field[] getDeclaredFields(): 获取所有的字段(包含私有)
 *         public Field getDeclaredField(String name):获取指定的字段,包含私有
 *         public Field getField(String name): 获取指定的字段
 * 
 * Field中的方法:
 *         public void set(Object obj, Object value):  为指定对象中的当前字段, 赋值
        
        Person p1;
        Person p2;
        addressField.set( p1,"上海");
 * 
 */
public class ReflectFieldDemo {

    public static void main(String[] args) {
        //获取指定的字段(公共的),操作字段
        getPubFieldTest();
        //获取指定的字段(私有的),操作字段
        getPriFieldTest();
        //获取所有公共字段
        getPubFieldsTest();
        //获取所有字段(含私有)
        getAllFieldsTest();

    }
    //获取指定的字段(公共的)
    public static void getPubFieldTest(){
        //获取字节码对象
        Class c = Student.class;
        //获取指定字段
        try {
            //获取构造函数
            Constructor conPub = c.getConstructor(String.class,int.class);
            //获取实例对象
            Object obj = conPub.newInstance("静",27);
            //获取指定字段
            Field fN = c.getField("name");
            //设置对象字段
            fN.set(obj, "静");
            Field fA = c.getField("age");
            fA.set(obj, 27);
            System.out.println(obj);
            Student stu = (Student) obj;
            System.out.println(stu.getName()+"--"+stu.getAge());
            System.out.println("-------------------------------------");
        } catch (NoSuchFieldException | SecurityException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (IllegalArgumentException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (NoSuchMethodException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (InstantiationException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }
    //获取指定的字段(私有的)
    public static void getPriFieldTest(){
        Class c = Student.class;
        try {
            //获取私有的构造函数
            Constructor conPri = c.getDeclaredConstructor(String.class,int.class,String.class);
            //暴力获取实例
            conPri.setAccessible(true);
            Object obj = conPri.newInstance("静",25,"河北");
            //获取字段
            Field fN = c.getDeclaredField("name");
            Field fA = c.getDeclaredField("age");
            fA.set(obj, 27);
            Field fAdder = c.getDeclaredField("address");
            //java.lang.IllegalAccessException: Class reflect.ReflectFieldDemo can not access a member of class reflect.Student with modifiers "private"
            //不能直接操作私有字段,否则报错上面,
//            fAdder.set(obj, "河南");
            fAdder.setAccessible(true);
            fAdder.set(obj, "河南");
            Student stu = (Student) obj;
            System.out.println(stu.getName()+"--"+stu.getAge()+"--"+stu.getAddress());
            System.out.println("-------------------------------------");
        } catch (NoSuchMethodException | SecurityException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (InstantiationException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (IllegalArgumentException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (NoSuchFieldException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }
    //获取所有的字段(公共)
    public static void getPubFieldsTest(){
        //获取字节码文件
        Class c = Student.class;
        try {
            //获取构造函数
            Constructor conPub = c.getConstructor(String.class,int.class);
            Object obj = conPub.newInstance("静",25);
            //获取所有公共字段
            Field[] f = c.getFields();
            for (Field field : f) {
                System.out.println(field.get(obj));
                System.out.println(field);
                System.out.println("-------------------------------------");
            }
        } catch (NoSuchMethodException | SecurityException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (InstantiationException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (IllegalArgumentException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
                
    }
    //获取所有字段(含私有)
    public static void getAllFieldsTest(){
        Class c = Student.class;
        try {
            Constructor conPri = c.getDeclaredConstructor(String.class,int.class,String.class);
            conPri.setAccessible(true);
            Object obj = conPri.newInstance("静",27,"河南");
            Field[] f = c.getDeclaredFields();
            for (Field field : f) {
                //字段数组中存在私有,要暴力访问
                field.setAccessible(true);
                System.out.println(field.get(obj));
                System.out.println(field);
                System.out.println("-------------------------------------");
            }
        } catch (NoSuchMethodException | SecurityException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (InstantiationException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (IllegalArgumentException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }
}

12.3.4 获取当前字节码中的方法

package reflect;

public class Student {
    public String name;
    public int age;
    private String address;
    public Student() {
        super();
        // TODO Auto-generated constructor stub
    }
    public Student(String name, int age) {
        super();
        this.name = name;
        this.age = age;
    }
    public Student(String name, String address) {
        super();
        this.name = name;
        this.address = address;
    }
    //私有的构造函数
    private Student(String name, int age, String address) {
        super();
        this.name = name;
        this.age = age;
        this.address = address;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public int getAge() {
        return age;
    }
    private void setAge(int age) {
        this.age = age;
    }
    public String getAddress() {
        return address;
    }
    public void setAddress(String address) {
        this.address = address;
    }
    
}
package reflect;

import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

/*
 * 反射方法: Method
 * 
 * 步骤:
 *     a: 创建class 字节码文件对象
 *     b: 获取指定的方法
 *     c: 使用方法(需要前有对象,才能使用方法)
 * 
 * Class类中的方法:
 *         public Method[] getMethods() 获取所有的公共方法(包含父类的)
 *         public Method[] getDeclaredMethods() 获取所有的方法(不包含父类)
 * 
 *         public Method getMethod(String name, Class<?>... parameterTypes) : 获取指定的方法
 *                                 name: 想要获取的方法的名字
 *                                 parameterTypes: 获取的方法的参数列表的数据类型
 * 
 *         public Method getDeclaredMethod(String name, Class<?>... parameterTypes) : 获取指定的方法(包含私有的)
 * 
 * Method类的方法:
 *         public Object invoke(Object obj, Object... args)
 *         调用给定的对象中的当前方法,并且给定方法的参数列表,这个时候就可以确定调用的是具体的哪一个方法了
 *     暴力访问
 *         public void setAccessible(boolean flag)
 * 
 */
public class ReflectMethodDemo {

    public static void main(String[] args) {
        //获取指定方法(公共)
        getPubMethodTest();
        //获取所有的公共方法
        getPubMethodsTest();
        //获取所有方法,含私有
        getAllMethodsTest();
    }
    //获取指定方法(公共),私有
    public static void getPubMethodTest(){
        //获取字节码文件
        Class c = Student.class;
        //获取构造函数,创建该字节码文件对象实例
        try {
            Constructor conPub = c.getConstructor(String.class,int.class);
            Object obj = conPub.newInstance("静",27);
            //获取指定方法,公共
            Method m1 = c.getMethod("setName", String.class);
            //java.lang.NoSuchMethodException: reflect.Student.setAge(int)
//            Method m2 = c.getMethod("setAge", int.class);
            //获取指定方法,私有
            Method m2 = c.getDeclaredMethod("setAge", int.class);
            m1.invoke(obj, "岁月静好");
//java.lang.IllegalAccessException: Class reflect.ReflectMethodDemo can not access a member of class reflect.Student with modifiers "private"
            //暴力调用私有方法
            m2.setAccessible(true);
            m2.invoke(obj, 28);
            Student stu = (Student) obj;
            System.out.println(stu.getName()+"--"+stu.getAge());
            System.out.println("---------------------------------------");
        } catch (NoSuchMethodException | SecurityException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (InstantiationException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (IllegalArgumentException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }
    //获取所有的公共方法
    public static void getPubMethodsTest(){
        Class c = Student.class;
        try {
            Constructor con = c.getConstructor(String.class,int.class);
            Object obj = con.newInstance("静",27);
            Method[] mm = c.getMethods();
            for (Method method : mm) {
                System.out.println("方法名字:"+method.getName());
            }
            System.out.println("---------------------------------------------");
        } catch (NoSuchMethodException | SecurityException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (InstantiationException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (IllegalArgumentException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }
    //获取所有的方法(含私有)
    public static void getAllMethodsTest(){
        Class c = Student.class;
        try {
            Constructor con = c.getConstructor();
            Object obj = c.newInstance();
            Method[] mm = c.getDeclaredMethods();
            for (Method method : mm) {
                System.out.println(method.getName());
            }
        } catch (NoSuchMethodException | SecurityException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (InstantiationException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }
}

12.3.5 通过反射向集合中添加字符串

package reflect;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;

/*
 *  需求: ArrayList<Integer> list = new ArrayList<Integer>();
 *      向集合中 添加3个字符串
 *  
 *      通过反射来解决该问题
 *      
 *      思路: 
 *          a: 获取  ArrayList 的字节码文件对象
 *          b: 获取 add 方法
 *          c: 使用方法
 *      
 *      注意: 当我们的java文件 生成对应的Class文件的时候, 泛型是不会编译到 class文件中的
 */
public class ReflectTest {

    public static void main(String[] args) {
        //通过反射向集合中添加字符串]
        test();

    }
    public static void test(){
        ArrayList<String> al = new ArrayList<>();
        Class c = al.getClass();
        try {
            Method m = c.getMethod("add", Object.class);
            m.invoke(al, "2014");
            m.invoke(al, "2015");
            m.invoke(al, "2016");
            System.out.println("ArrayList:"+al);
        } catch (NoSuchMethodException | SecurityException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (IllegalArgumentException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }
}

 12.4 反射的优点和缺点

  为什么要用反射机制?直接创建对象不就可以了吗,这就涉及到了动态与静态的概念,  

  静态编译:在编译时确定类型,绑定对象,即通过。  

  动态编译:运行时确定类型,绑定对象。动态编译最大限度发挥了java的灵活性,体现了多态的应用,有以降低类之间的藕合性。  

  一句话,反射机制的优点就是可以实现动态创建对象和编译,体现出很大的灵活性,特别是在J2EE的开发。

它的缺点是对性能有影响。使用反射基本上是一种解释操作,我们可以告诉JVM,我们希望做什么并且它满足我们的要求。这类操作总是慢于只直接执行相同的操作。

 

posted @ 2017-05-28 03:20  十月十四  阅读(249)  评论(0编辑  收藏  举报