反射

package reflect;


public class Car {  
    public String brand;  
    private String color;  
    private int maxSpeed;  
      
     //①默认构造函数  
    public Car(){}  
       
     //②带参构造函数  
    public Car(String brand,String color,int maxSpeed){   
        this.brand = brand;  
        this.color = color;  
        this.maxSpeed = maxSpeed;  
    }  
  
     //③未带参的方法  
    public void introduce() {   
       System.out.println("brand:"+brand+";color:"+color+";maxSpeed:" +maxSpeed);  
    }

    public String getBrand() {
        return brand;
    }

    public void setBrand(String brand) {
        this.brand = brand;
    }

    public String getColor() {
        return color;
    }

    public void setColor(String color) {
        this.color = color;
    }

    public int getMaxSpeed() {
        return maxSpeed;
    }

    public void setMaxSpeed(int maxSpeed) {
        this.maxSpeed = maxSpeed;
    }  
    
}  
package reflect;

import java.lang.reflect.AccessibleObject;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;

public class ReflectTest {
    
    /** 
     *验证所有的类都是Class类的实例对象 
     * @throws ClassNotFoundException  
     */  
    public static void verifyIns() throws ClassNotFoundException{  
        System.out.println("-----验证所有的类都是Class类的实例对象 -----");
        //定义两个类型都未知的Class , 设置初值为null, 看看如何给它们赋值成Person类  
        Class<?> class1 = null;  
        Class<?> class2 = null;  
          
        //写法1, 可能抛出 ClassNotFoundException [多用这个写法]  
        class1 = Class.forName("reflect.Car");  
        System.out.println("(写法1) 包名: " + class1.getPackage().getName() + ","   
                + "完整类名: " + class1.getName());  
          
        //写法2  
//        class2 = Car.class;  
//        System.out.println("(写法2) 包名: " + class2.getPackage().getName() + ","   
//                + "完整类名: " + class2.getName());  
    } 

    /**
     * 通过获取类的默认构造器创建实例
     * @throws Throwable
     */
    public static void initByDefaultConst() throws Throwable {
        System.out.println("-----通过获取类的默认构造器创建实例-----");
        //写法1
        //通过类加载器获取car对象
        ClassLoader loader = Thread.currentThread().getContextClassLoader();//获取当前线程的ClassLoader
        Class clazz = loader.loadClass("reflect.Car");//通过指定的全限定类“reflect.Car”装载Car类对应的反射实例
        
        //获取类的默认构造器对象并通过它实例化car
        Constructor  cons = clazz.getDeclaredConstructor((Class[]) null);//通过Car的反射类对象获取Car的构造函数对象cons
        Car car = (Car) cons.newInstance();//通过构造函数对象的newInstrance()方法实例化Car对象,其效果等同于new Car()
        System.out.println("包名:"+car.getClass().getPackage().getName()+",完整类名:"+car.getClass().getName());
        //通过反射方法设置属性
        Method  setBrand = clazz.getMethod("setBrand", String.class);//通过Car的反射类对象的getMethod(String methodName,Class paramClass)获取属性的Setter方法对象,第一个参数是目标Class的方法名;第二个参数是方法入参的对象类型
        setBrand.invoke(car, "红旗");//获取方法反射对象后,即可通过invoke(Object obj,Object param)方法调用目标类的方法,该方法的第一个参数是操作的目标类对象实例;第二个参数是目标方法的入参。
        Method  setColor = clazz.getMethod("setColor", String.class);
        setColor.invoke(car, "红色");
        Method setMaxSpeed = clazz.getMethod("setMaxSpeed", int.class);
        setMaxSpeed.invoke(car, 200);
        Method introduce = clazz.getMethod("introduce",null);
        introduce.invoke(car, null);
        
        //写法2
//        Class clazz = Class.forName("reflect.Car");
//        Car car = (Car)clazz.newInstance();
//        System.out.println("包名:"+car.getClass().getPackage().getName()+",完整类名:"+car.getClass().getName());
    }
    /**
     * 通过获取类的指定构造器创建实例
     * @throws Throwable 
     */
    public static void  initBySpecifiedConst() throws Throwable {
        System.out.println("-----通过获取类的指定构造器创建实例-----");
        ClassLoader loader = Thread.currentThread().getContextClassLoader();//获取当前线程的ClassLoader
        Class clazz = loader.loadClass("reflect.Car");//通过指定的全限定类“reflect.Car”装载Car类对应的反射实例
        Constructor c = clazz.getConstructor(String.class,String.class,int.class);
        Car car = (Car) c.newInstance("Benz","黑色",100);
        Method introduce = clazz.getMethod("introduce",null);
        introduce.invoke(car, null);
    }
 
    /**
     *获取构造器列表并用其中一个创建实例
     * @throws Throwable 
     * @throws Exception 
     */
    public static void getAllConstsAndNewInstance() throws Throwable  {
        System.out.println("-----获取构造器列表并用其中一个创建实例-----");
        ClassLoader loader = Thread.currentThread().getContextClassLoader();
        Class clazz = loader.loadClass("reflect.Car");
        Constructor[] constructors = clazz.getConstructors();
        Car car0 = (Car)constructors[0].newInstance();
        System.out.println("包名:"+car0.getClass().getPackage().getName()+",完整类名:"+car0.getClass().getName());
        Object obj = (Car)constructors[1].newInstance("Benz","黑色",100);
        System.out.println("包名:"+obj.getClass().getPackage().getName()+",完整类名:"+obj.getClass().getName());
    }
    
    /**
     * 获取并操作成员变量
     * @throws Throwable
     */
    public static void getAndProcessField() throws Throwable{
        System.out.println("-----获取并操作成员变量-----");
        Class clazz = Class.forName("reflect.Car");
        Object obj = clazz.newInstance();
//        Field[] fields = clazz.getFields();//getFields():获得某个类的所有的公共(public)的字段,包括父类中的字段
        Field[] fields = clazz.getDeclaredFields();//getDeclaredFields():获得某个类的所有声明的字段,即包括public、private和proteced,但是不包括父类的申明字段。
        for(Object o :fields){
            System.out.println(o);
        }
//         AccessibleObject.setAccessible(fields, true); //对所有属性设置访问权限  当类中的成员变量为private时 必须设置此项
         Field fieldBrand = clazz.getField("brand");
         fieldBrand.setAccessible(true);
         fieldBrand.set(obj, "BWM");//对当前属性设置访问权限  当类中的成员变量为private时 必须设置此项
         System.out.println("修改属性之后得到属性变量的值:" + fieldBrand.get(obj));
         Field fieldColor = clazz.getDeclaredField("color");
         fieldColor.setAccessible(true);
         fieldColor.set(obj, "white");//对当前属性设置访问权限  当类中的成员变量为private时 必须设置此项
         System.out.println("修改属性之后得到属性变量的值:" + fieldColor.get(obj));
    }
    /**
     * 获取并操作成员方法
     * @throws Throwable
     */
    public static void getAndProcessMethods() throws Throwable{
        System.out.println("-----获取并操作成员方法-----");
        ClassLoader  loader = Thread.currentThread().getContextClassLoader();
        Class clazz = loader.loadClass("reflect.Car");
//        Method[] methods = clazz.getMethods(); //getMethods()返回某个类的所有公用(public)方法包括其继承类的公用方法,当然也包括它所实现接口的方法。
        Method[] methods = clazz.getDeclaredMethods();//getDeclaredMethods()对象表示的类或接口声明的所有方法,包括公共、保护、默认(包)访问和私有方法,但不包括继承的方法。当然也包括它所实现接口的方法。
        for(Method m :methods){
            System.out.println("方法:"+m);
            System.out.println("方法名:"+m.getName());
            System.out.println("方法返回类型:"+m.getReturnType());
            System.out.println("函数访问修饰符:" + Modifier.toString(m.getModifiers()));  
        }
        Method methodIntroduce = clazz.getMethod("introduce",null);
        methodIntroduce.invoke(clazz.newInstance(), null);
        
        //取得类实现的接口,因为接口类也属于Class 
         Class interfaces[] = clazz.getInterfaces();  
            for (int i = 0; i < interfaces.length; i++) {  
                System.out.println("实现的接口类名: " + interfaces[i].getName() );  
            }  
    }
    
    /**得到类加载器信息
     * @throws Throwable
     */
    public static void getClassLoader() throws Throwable{
        System.out.println("-----得到类加载器信息-----");
        Class clazz = Class.forName("reflect.Car");
        String classLoaderName = clazz.getClassLoader().getClass().getName();
        System.out.println("classLoaderName:"+classLoaderName);
    }
    
    
    public static void main(String args[]) throws Throwable{
         verifyIns();
         initByDefaultConst();
         initBySpecifiedConst();
         getAllConstsAndNewInstance();
         getAndProcessField();
         getAndProcessMethods();
         getClassLoader();
    }
    
}

常用反射的一些地方

https://www.cnblogs.com/ldh-better/p/7148975.html#_label2_1

1.工厂模式:Factory类中用反射的话,添加了一个新的类之后,就不需要再修改工厂类Factory了
2.数据库JDBC中通过Class.forName(Driver).来获得数据库连接驱动
3.分析类文件:毕竟能得到类中的方法等等
4.访问一些不能访问的变量或属性:破解别人代码

 如何优化反射?

一. 善用API

比如,尽量不要getMethods()后再遍历筛选,而直接用getMethod(methodName)来根据方法名获取方法

二、缓存

比如,需要多次动态创建一个类的实例的时候,有缓存的写法会比没有缓存要快很多:

// 1. 没有缓存
void createInstance(String className){
    return Class.forName(className).newInstance();
}

// 2. 缓存forName的结果
void createInstance(String className){
    cachedClass = cache.get(className);
    if (cachedClass == null){
        cachedClass = Class.forName(className);
        cache.set(className, cachedClass);
    }
    return cachedClass.newInstance();
}
为什么?当然是因为forName太耗时了。 

 

posted @ 2017-12-16 16:49  Rainyn  阅读(222)  评论(0编辑  收藏  举报