反射抽取的点


 * 面试题:
 *      如何获取类的字节码文件对象,并且有几种方式呢?
 * 
 *1)Object类中的getClass()方法,表示正在运行的那个类:Class类
 *2)数据类型的class属性  举例:String.class,Student.class
 *3)Class类中的特有方法:forName(String className):(重点,数据库加载驱动:Drivers)
 *  public static Class<?> forName(String className):获取字节码文件对象
 *
 *  开发中常使用的方式,因为第三种里面的参数是一个字符串...,字符串的内容是一个类的全路径名称
 *  
 package myReflect;

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

public class MyReflect1 {

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

        Person p1=new Person("黛黛",21,"女");
        //第一种方式通过具体类对象使用Object中的getClas方法获取
        Class c1=p1.getClass();
        System.out.println(c1);//class myReflect.Person

        //第二种:通过类获取
        Class c11=p1.getClass();
        System.out.println(c11);//class myReflect.Person

        //第三种,通过Class.forName(String calssName)获取
        Class c12=Class.forName("myReflect.Person");
        System.out.println(c11);//class myReflect.Person


        //获取构造方法,方法略,看API
        //通过反射获取私有的构造方法,并使用
        Constructor con=c1.getDeclaredConstructor(String.class);
        //由于是私有方法,所以先要取消访问检查,否则会出现java.lang.IllegalAccessException
        con.setAccessible(true);
        Object obj=con.newInstance("小馒头");
        System.out.println(obj);//Person [name=小馒头, age=0, sex=null]
        //通过反射获取成员变量并使用
        Field agef=c1.getDeclaredField("age");
        agef.set(obj,21);
        Field sexf=c1.getDeclaredField("sex");
        sexf.set(obj,"女");
        System.out.println(obj);//Person [name=小馒头, age=21, sex=女]

        //通过反射获取成员方法并使用
        Class c2=Class.forName("myReflect.Person");
        Constructor con2=c2.getDeclaredConstructor(String.class);
        con2.setAccessible(true);
        Object obj2=con2.newInstance("煎饼果果");
        Method mAge=c2.getMethod("setAge",int.class);
        Object obj3=mAge.invoke(obj2,22);
        System.out.println(obj3);//null
        Method mSex=c2.getDeclaredMethod("setSex",String.class);
        mSex.invoke(obj2,"男");
        System.out.println(obj2);//Person [name=煎饼果果, age=22, sex=男]
    }
}

应用:
1)设置动态代理
package org.westos.reflect_handler2;

import java.lang.reflect.Proxy;

/**
 *测试类
 * @author Apple
 */
public class Test {

    public static void main(String[] args) {
        //创建用户操作的对象
        UserDao ud = new UserDaoImpl() ;
        ud.add() ;
        ud.delete();
        ud.update() ;
        ud.serach() ;

        System.out.println("------------------");
        //给ud对象设置代理对象
        //Proxy类中的方法创建动态代理类对象
        //public static Object newProxyInstance
        //(ClassLoader loader,Class<?>[] interfaces,InvocationHandler h)
        //InvocationHandler是代理对象需要实现的接口---->需要自定义一个类实现这个接口
        //创建代理对象
        MyInvocationHandler handler = new MyInvocationHandler(ud) ;
        UserDao proxy = (UserDao) Proxy.newProxyInstance(ud.getClass().getClassLoader(), 
                ud.getClass().getInterfaces(),handler) ;
        //参数1:需要类加载器:首先获取当前目标对象的字节码文件对象,在去调用getClassLoser()
        //参数2:获取目标的字节码文件对象,调用方法得到给目标对象提供一组接口

        proxy.add();
        proxy.delete() ;
        proxy.update() ;
        proxy.serach() ;

        //登录注册,增删改查 等等...

    }
}
package org.westos.reflect_handler2;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;

public class MyInvocationHandler implements InvocationHandler {

    //目标对象(需要给哪一个对象设置这个代理呢?)
    private Object target ; 

    //无参构造
    public MyInvocationHandler(Object target){
        this.target = target ;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args)
            throws Throwable {
        //权限校验
        System.out.println("权限校验");
        Object result = method.invoke(target, args) ;
        //日志记录
        System.out.println("日志记录");
        return result; //返回值就是代理对象
    }
}
package org.westos.reflect_handler2;
/**
 * 用户操作的接口
 * @author Apple
 */
public interface UserDao {

    //增
    public abstract void add() ;
    //删
    public abstract void delete() ;
    //update:修改
    public abstract void update() ;
    //查
    public abstract void serach() ;
}
package org.westos.reflect_handler2;

public class UserDaoImpl implements UserDao {

    @Override
    public void add() {
        System.out.println("增加功能");
    }

    @Override
    public void delete() {
        System.out.println("删除功能");
    }

    @Override
    public void update() {
        System.out.println("修改功能");
    }

    @Override
    public void serach() {
        System.out.println("查询功能");
    }
}
2)给你ArrayList<Integer>的一个对象,我想在这个集合中添加一个字符串数据
package myReflect;

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

/**
 * 给你ArrayList<Integer>的一个对象,我想在这个集合中添加一个字符串数据,如何实现呢?
 * 
 * 反射的应用:
 *      1)在集合中应用
 *      2)用来反射区读取配置文件来加载里面的内容(MySQL,Oracle等等,SQLServer,MangoDB)
 * @author Apple
 */
public class ArrayListTest {
    public static void main(String[] args) throws Exception {
        ArrayList<Integer> al=new ArrayList<Integer>();
        Class c=al.getClass();

        Method m=c.getDeclaredMethod("add",Object.class);
        m.invoke(al,"不如");
        m.invoke(al,"去死");
        for(Object o:al) {
            System.out.println(o);
            /**
             * 不如 
             * 去死
             */
        }
    }
}
3)写一个方法,
public void setProperty(Object obj, String propertyName, Object value){},
此方法可将obj对象中名为propertyName的属性的值设置为value
package myReflect;

import java.lang.reflect.Field;

public class Tool {

    public void setProperty(Object obj, String propertyName, Object value) throws 
    NoSuchFieldException, 
    SecurityException, 
    IllegalArgumentException,
    IllegalAccessException{

        //获取类的字节码文件对象
        Class c = obj.getClass() ;

        //通过字节码文件对象获取Field对象
        //为了防止可能后有一些私有的成员变量:getDeclaredField("字段名称")
        Field field = c.getDeclaredField(propertyName) ;

        //通过field对象给指定对象obj设置属性值
        //防止出现  IllegalAccessException:设置Java语言取消访问检查
        field.setAccessible(true) ;
        field.set(obj, value) ;
    }
}
package myReflect;

/**
 * 1:写一个方法,
public void setProperty(Object obj, String propertyName, Object value){},
此方法可将obj对象中名为propertyName的属性的值设置为value
 * @author Apple
 */
//测试类
public class ToolDemo {

    public static void main(String[] args) throws NoSuchFieldException, 
    SecurityException, 
    IllegalArgumentException, 
    IllegalAccessException {

        //创建Person类对象
        Person p = new Person() ;
        Tool t = new Tool() ;
        //设置name属性
        t.setProperty(p, "name", "高圆圆") ;
        t.setProperty(p, "age", 27) ;

        System.out.println(p);

        Dog d = new Dog() ;
        t.setProperty(d, "gender",'公' ) ;
        t.setProperty(d, "price", 34.56F) ;
        System.out.println(d);
    }
}

class Dog{
    char gender ;
    float price ;

    @Override
    public String toString() {
        return gender+"---"+price ;
    }
}
4)用作配置文件,需要时修改文件内容即可
package myReflect;

import java.io.FileReader;
import java.io.FileWriter;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
import java.util.Properties;

public class Test {

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

        //反射之前的作用:
//      Student s = new Student() ;
//      s.love() ;
//      Teacher t = new Teacher() ;
//      t.love() ;
//      Worker w = new Worker() ;
//      w.love() ;

        //使用反射的做法:
        //文本文件是一种键值对象的形式...
        //需要将文本文件中的内容加载属性集合类中(键值对都是String类型)
        //创建一个属性集合类
        Properties prop = new Properties() ;
        //编写properties内容
        prop.setProperty("className","myReflect.Worker");
        prop.setProperty("methodName","love");

        //store将properties的内容写入到文件中
        prop.store(new FileWriter("class.txt"),"Content");

        //load将文本文件中的内容加入到properties中
        FileReader fr = new FileReader("class.txt") ;
        prop.load(fr) ;
        //关闭资源
        fr.close() ;

        //通过键获取值,使用它的特有功能getProperty("String key")
        String className = prop.getProperty("className") ;
        String methodName = prop.getProperty("methodName") ;

        //获取字节码文件对象
        Class c = Class.forName(className);

        //通过反射获取构造器对象,并且通过构造器对象创建该类的实例
        Constructor con = c.getConstructor() ;
        Object obj = con.newInstance() ;

        //获取成员方法
        Method m = c.getMethod(methodName) ;

        //调用
        m.invoke(obj) ;
    }
}
---------------------------------------------------------------------------------------------------------------------------------
class.txt
#Content
#Sun Dec 17 16:15:57 CST 2017
methodName=love
className=myReflect.Worker
-----------------------------------------------------------------------------------------------------------------------------------
package myReflect;

public class Student {

    public void love(){
        System.out.println("学生爱学习,爱Java");
    }
}
package myReflect;

public class Worker {

    public void love(){
        System.out.println("工人爱生活,爱老婆");
    }
}

posted @ 2017-12-18 19:27  快乐的内啡肽呀  阅读(43)  评论(0)    收藏  举报