Java基础学习:反射篇

1.什么是反射?

  Reflection(反射)是被视为动态语言的关键,反射机制允许程序做执行期间借助于ReflectionAPI取得任何类的内部信息,并能直接操作任意对象内部属性及方法

2.反射相关的主要API

      java.lang.Class:代表一个类

  java.lang.reflect.Method:代表类的方法

  java.lang.reflect.Field:代表类的成员变量

  java.lang.reflect.Constructor:代表类的构造方法

 3.简单入门示例代码

package day01.code;

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

import org.junit.Test;

public class TestReflection {

    // 有了反射,可以通过反射创建一个类的对象,并调用其中的结构
    @Test
    public void test2() throws Exception{
        Class clazz=Person.class;
        // 1.创建clazz对应的运行时类Person类的对象
        Person person= (Person)clazz.newInstance();
        System.out.println(person);
        // 2.通过反射调用运行时类的指定的属性
        //     2.1 调用public的属性
        Field f1=clazz.getField("name");
        f1.set(person, "lisi");
        System.out.println(person);
        //     2.2 调用非public的属性
        Field f2= clazz.getDeclaredField("age");
        f2.setAccessible(true);
        f2.set(person, 20);
        System.out.println(person);
        // 3.通过反射调用运行时类的指定的方法
        //    3.1 调用无参方法
        Method m1=clazz.getMethod("show");
        m1.invoke(person);
        //     3.2 调用有参方法
        Method m2=clazz.getMethod("display",String.class);
        m2.invoke(person, "CHN");
    }
    
    // 在有反射以前,如何创建一个类的对象,并调用其中的方法,属性
    @Test
    public void test1(){
        Person person=new Person();
        person.setAge(10);
        person.setName("zhangsan");
        System.out.println(person);
        person.show();
        person.display("CN");
    }
}

4.反射的源头Class

  4.1 getClass()详解,此方法中Object类中被定义,会被所有的子类继承,调用此方法返回值的类型是一个Class类,此类的反射的源头,实际上所谓反射从程序的运行结果来看也很好理解,即:可以通过对象反射出类的名称

  @Test
    public void test3(){
        Person person=new Person();
        Class calzz= person.getClass(); // 通过运行时类的对象,调用其getClass(),返回其运行时类
        System.out.println(calzz);
    }

  4.2 反射原理解析

    我们创建了一个类,通过编译(javac.exe),生成对应的.class文件,之后我们使用java.exe加载(JVM的类加载器完成的)此.class文件,此.class文件加载到内存以后,就是一个运行时类,存放在缓存区。那么这个运行时类本身就是一个Class的实例!

    4.2.1 每一个运行时类只加载一次

    4.2.2 有了Class的实例以后,我们才可以进行如下操作

        1)创建对应的运行时类的对象

        2)获取对应的运行时类的完整结构(属性,方法,构造器,内部类,父类,所在的包,异常,注解........)

        3) 调用对应的运行时类的指定的结构(属性,方法,构造器)

        4)反射的应用,动态代理

    正常方式:引入需要的“包类”名称->通过new实例化->取得实例化对象

    反射方式:实例化对象->getClass()方法->得到完整的“包类”名称

  4.3 获取Class的实例

    4.3.1 调用运行时类本身的.class属性

    @Test
    public void test4(){
        // 1.调用运行时类本身的.class属性
        Class clazz=Person.class;
        System.out.println(clazz.getName());
    }

    4.3.2 通过运行时类的对象获取

  @Test
    public void test5(){
        // 通过运行时类的对象获取
        Person person=new Person();
        Class clazz= person.getClass();
        System.out.println(clazz.getName());
    }

    4.3.3 通过Class的静态方法获取

  @Test
    public void Test6() throws Exception{
        // 通过Class的静态方法获取
        String className="day01.code.Person";
        Class clazz= Class.forName(className);
        System.out.println(clazz.getName());
    }

     4.3.4 通过类的加载器

  @Test
    public void test7() throws Exception{
        // 通过类的加载器
        String className="day01.code.Person";
        ClassLoader classLoader=this.getClass().getClassLoader();
        Class clazz= classLoader.loadClass(className);
        System.out.println(clazz.getName());
    }

   4.4 什么是类的加载器?(ClassLoader)

     解释:类加载器是用来把类(class)装载进内存的。JVM 规范定义了两种类型的类加载器:启动类加载器(bootstrap)和用户自定义加载器(user-defined class loader)

    4.4.1 Bootstap Classloader 引导类加载器:用C++编写的,是JVM自带的类加载器,负责Java平台核心库,用来加载核心类库,该加载器无法直接获取

    4.4.2 Extension Classloader 扩展类加载器:负责jre/lib/ext目录下的jar包或 –D java.ext.dirs 指定目录下的jar包装入工作库 .

    4.4.3 System Classloader 系统类加载器:负责java –classpath 或 –D java.class.path所指的目录下的类与jar包装入工作 ,是最常用的加载器

  4.5 有了Class对象,能做什么?

    4.5.1 newInstance() 作用: 创建对应的运行时类的对象,实际上就是调用类运行时类的空参的构造器。注:要想创建成功,1.要求对应的运行时类要有空参的构造器 2.构造器的权限修饰符的权限要足够(经验证同一个包下大于 private 即可) 

  @Test
    public void test1() throws Exception{
        String className="day01.code.Person";
        Class clazz= Class.forName(className);
        // 创建运行时对象
        Object obj=clazz.newInstance();
        Person person=(Person)obj;
        System.out.println(person);
    }

     4.5.2 通过反射调用类的完整结构(实现的全部接口,所继承的父类,全部的构造器,全部的方法,全部的Field)

      4.5.2.1 Field

  // 获取对应的运行时类的属性
    @Test
    public void test1(){
        Class clazz= Person.class;
        // 1.getFields():只能获取到运行时类及其父类中声明为public的属性
        Field[] fields=clazz.getFields();
        for(int i=0;i<fields.length;i++){
            System.out.println(fields[i]);
        }
        System.out.println();
        // 2.getDeclaredFields():获取到运行时类本身声明的所有的属性
        Field[] fields1=clazz.getDeclaredFields();
        for (Field field : fields1) {
            System.out.println(field.getName());
        }
    }
    
    // 权限修饰符 变量类型 变量名,获取属性的各个部分的内容
    @Test
    public void test2(){
        Class clazz= Person.class;
        Field[] fields1=clazz.getDeclaredFields();
        for (Field field : fields1) {
            // 1.获取每个属性的权限修饰符
            int i= field.getModifiers();
            String modifier= Modifier.toString(i);
            System.out.print(modifier+" ");
            // 2.获取属性的变量类型
            Class type=field.getType();
            System.out.print(type.getName()+" ");
            // 3.获取属性名
            System.out.println(field.getName());
        }
    }

       4.5.2.2 Method

  // 1.获取运行时类的方法
    @Test
    public void test1(){
        Class clazz=Person.class;
        // 1.getMethods():获取运行时类及其父类中所有声明为public的方法
        Method[]m1=clazz.getMethods();
        for (Method method : m1) {
            System.out.println(method);
        }
        System.out.println();
        // 2.getDeclaredMethods():获取运行时类本身声明的所有的方法
        Method[]m2=clazz.getDeclaredMethods();
        for (Method method : m2) {
            System.out.println(method);
        }
    }
    
    // 注解 权限修饰符 返回值类型 方法名 形参列表 异常
    @Test
    public void test2(){
        Class clazz=Person.class;
        Method[]m2=clazz.getDeclaredMethods();
        for (Method method : m2) {
            // 1.注解
            Annotation[] ann= method.getAnnotations();
            for (Annotation annotation : ann) {
                System.out.print(annotation+" ");
            }
            // 2.权限修饰符
            String str= Modifier.toString(method.getModifiers());
            System.out.print(str+" ");
            // 3.返回值类型
            Class returnType=method.getReturnType();
            System.out.print(returnType.getName()+" ");
            // 4.方法名
            System.out.print(method.getName()+" ");
            // 5.形参列表
            System.out.print("(");
            Class[]params=method.getParameterTypes();
            for (Class p : params) {
                System.out.print(p.getName());
            }
            System.out.print(")");
            // 6.异常类型
            Class[]exps= method.getExceptionTypes();
            for (Class exp : exps) {
                System.out.print(exp.getName()+" ");
            }
            System.out.println();
        }
    }

        4.5.2.3 构造器

  // 获取运行时类的构造器
    @Test
    public void test2()throws Exception{
        String className="day01.code.Person";
        Class clazz= Class.forName(className);
        Constructor[]cons=clazz.getDeclaredConstructors();
        for (Constructor constructor : cons) {
            System.out.println(constructor);
        }
    }

        4.5.2.4 其他结构

  // 6.获取注解
    @Test
    public void test6(){
        Class clazz=Person.class;
        Annotation[]anns=clazz.getAnnotations();
        for (Annotation annotation : anns) {
            System.out.println(annotation);
        }
    }
    
    // 5.获取所在的包
    @Test
    public void test5(){
        Class clazz=Person.class;
        Package package1=clazz.getPackage();
        System.out.println(package1);
    }
    
    // 4.获取实现的接口
    @Test
    public void test4(){
        Class clazz=Person.class;
        Class[] interfaces=clazz.getInterfaces();
        for (Class class1 : interfaces) {
            System.out.println(class1);
        }
    }
    
    // 3.获取父类的泛型
    @Test
    public void test3(){
        Class clazz=Person.class;
        Type type=clazz.getGenericSuperclass();
        ParameterizedType param=(ParameterizedType) type;
        Type[]ars=param.getActualTypeArguments();
        System.out.println(((Class)ars[0]).getName());
    }
    
    // 2.获取带泛型的父类
    @Test
    public void test2(){
        Class clazz=Person.class;
        Type type=clazz.getGenericSuperclass();
        System.out.println(type);
    }
    
    // 1.获取运行时类的父类
    @Test
    public void test1(){
         Class clazz= Person.class;
         Class superClass=clazz.getSuperclass();
         System.out.println(superClass);
    }

     4.5.3 反射的各种操作

      4.5.3.1 调用运行时类指定的属性

  // 调用运行时类中指定的属性
    @Test
    public void test3() throws Exception{
        Class clazz=Person.class;
        // 1.获取指定的属性,属性权限是public的
        Field name=clazz.getField("name");
        // 2.创建运行时类的对象
        Person p=(Person)clazz.newInstance();
        System.out.println(p);
        // 3.将运行时类的指定的属性赋值
        name.set(p, "Jerry");
        System.out.println(p);
        System.out.println();
        Field age= clazz.getDeclaredField("age");
        // 由于属性权限修饰符的限制,为了保证可以给属性赋值,需要在操作前使得此属性值可以被操作
        age.setAccessible(true);
        age.set(p, 10);
        System.out.println(p);
    }

      4.5.3.2 调用运行时类指定的方法

  // 调用运行时类中指定的方法
    @Test
    public void test3() throws Exception{
        Class clazz=Person.class;
        // getMethod(String methodName,Class...params):获取运行时类中声明为public的方法
        Method m1=clazz.getMethod("show");
        Person person=(Person)clazz.newInstance();
        // 可以获取返回值
        Object returnVal=m1.invoke(person);
        System.out.println(returnVal);
        
        Method m2=clazz.getMethod("toString");
        Object returnVal2=m2.invoke(person);
        System.out.println(returnVal2);
        
        // 获取运行时类的静态方法
        Method m3=clazz.getMethod("info");
        m3.invoke(Person.class);
        // getDeclaredMethod(String methodName,Class...params):获取运行时类中定义的方法
        Method m4=clazz.getDeclaredMethod("display",String.class,Integer.class);
        m4.setAccessible(true);
        Object value= m4.invoke(person,"中国",10);
        System.out.println(value);
    }

      4.5.3.3 调用指定的构造器

  // 调用指定的构造器,创建运行时类的对象
    @Test
    public void test() throws Exception{
        String className="day01.code.Person";
        Class clazz= Class.forName(className);
        Constructor cons= clazz.getDeclaredConstructor(String.class,int.class);
        cons.setAccessible(true);
        Person person=(Person)cons.newInstance("陆虎",10);
        System.out.println(person);
    }

     4.5.4 动态代理vs静态代理

      4.5.4.1 静态代理

package day01.code1;

// 静态代理
// 接口
interface ClothFactory{
    
    void productCloth();
}

// 被代理类
class NikeClothFactory implements ClothFactory{

    @Override
    public void productCloth() {
        System.out.println("Nike工厂生成一批衣服");
    }
    
}

// 代理类
class ProxyFactory implements ClothFactory{

    ClothFactory cf;
    
    public ProxyFactory(ClothFactory cf) {
        this.cf=cf;
    }
    
    @Override
    public void productCloth() {
        System.out.println("代理类开始执行。。。");
        this.cf.productCloth();
    }
    
}

public class TestClothProduct {
    
    public static void main(String[]args){
        NikeClothFactory nikeClothFactory=new NikeClothFactory();
        ProxyFactory proxyFactory=new ProxyFactory(nikeClothFactory);
        proxyFactory.productCloth();
    }
}

      4.5.4.2 动态代理

package day01.code1;

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

interface Subject{
    void action();
}
// 被代理类
class RealSubject implements Subject{

    @Override
    public void action() {
        System.out.println("被代理类方法开始执行");
    }
    
}
class MyInvocationHandler implements InvocationHandler{

    Object obj;// 实现了接口的被代理类的对象的声明
    
    // 1.给被代理的对象实例化 2.返回一个代理类的对象
    public Object blind(Object obj){
        this.obj=obj;
        return Proxy.newProxyInstance(obj.getClass().getClassLoader(),obj.getClass().getInterfaces(), this);
    }
    // 当通过代理类的对象发起对被重写的方法的调用时,都会转换为对如下的invoke方法的调用
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        // method方法的返回值是returnVal
        Object returnVal=method.invoke(obj, args);
        return returnVal;
    }
    
}

public class TestProxy {

    public static void main(String[]args){
        // 1.被代理类的对象
        RealSubject real=new RealSubject();
        // 2.创建一个实现了InvacationHandler接口的类的对象
        MyInvocationHandler handler=new MyInvocationHandler();
        // 3.调用blind()方法,动态的返回一个同样实现了real所在类实现的接口Subject的代理类的对象
        Object object=handler.blind(real);
        // 4.此时subject就是代理类的对象
        Subject subject=(Subject)object;
        // 5.转到对InvocationHandler接口对实现类对invoke()方法的调用
        subject.action();
        
        // 再举一例
        NikeClothFactory nikeClothFactory=new NikeClothFactory();
        // proxyCloth即为代理类的对象
        ClothFactory proxyCloth=(ClothFactory)handler.blind(nikeClothFactory);
        proxyCloth.productCloth();
        
    }
}

 

posted @ 2017-01-13 22:43  东特出猫  阅读(213)  评论(0编辑  收藏  举报