java高级开发--反射详解

实例化对象: 通过类的构造方法实例化对象(正向)
获取Class : 通过实例化对象获取创建该对象的类(反向)

Object 类中 getClass() 返回一个Class类型的对象

Class : 类型

类: 现实事物的抽象
对象: 现实的具体事物(你所关注的事物对象)

一丶三种实例化对象

1丶通过构造方法实例化对象

2丶通过反射创建类的实例化对象
类的Class对象的newinstance()方法获取实例化对象(前提是类有无参数的构造方法)
类的Class对象获取构造方法的Constructor对象,通过Constructor的newInstance(…)实例化对象

3丶通过反序列化创建对象

getName() 获得全限定名
getsimpleName() 获得父类名

import java.util.Date;

public class TestReflect {

    public static void mai1(String[] args) {
        //Date
        //java.util.Date   API
        Date date = new Date();
        //类型
        //class 关键字
        //Class 类型
        //Class toString()
        //1丶一个类的实例化对象的getClass()获取
        Class aClass = date.getClass();
        System.out.println(aClass);//java.util.Date

        //2丶类型名称class  eg: Date.class
        //如果date是Date类 返回 true  否则 false
        System.out.println(date instanceof  Date);
        Class classz = Date.class;
        System.out.println(classz);

        //3丶Class.forName(类的全限定名)
        //Class.forName
        //java.util.Date => "java.util.Date"
        //className  => 类的全限定名   packageName.className
        try {
            Class classzz = Class.forName("java.util.Date");
            System.out.println(classzz);

            System.out.println("---------------");
            //3 种方式

            // 当前三个Class对象 都是描述 java.util.Date
            System.out.println(aClass == classz);
            System.out.println(classz == classzz);
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
    }

    public static void main(String[] args) {

        Class dateClass = Date.class;
        try {
            //object 是 java.util.Date
            Object object = dateClass.newInstance();
            Date date = (Date)object;
            System.out.println(object);
            System.out.println(object instanceof Date);
            System.out.println(object.getClass());
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }
    }
}


**二丶反射工厂模式**

public class TestFactory {

public static void main(String[] args) {
    Fruit fruit = FruitFactory.getFruitInstance("com.changehyh.github.reflect.Orange");
    fruit.eat();
}

}

interface Fruit {
void eat();
}

class Apple implements Fruit {
@Override
public void eat() {
System.out.println(“吃苹果”);
}
}

class Orange implements Fruit {
@Override
public void eat() {
System.out.println(“吃橘子”);

}

}

class FruitFactory {
private FruitFactory() {
}

public static Fruit getFruitInstance(String className) {
    //new  -> 具体类型耦合
    try {
        Class classz = Class.forName(className);
        return (Fruit) classz.newInstance();
    } catch (ClassNotFoundException e) {
        e.printStackTrace();
    } catch (IllegalAccessException e) {
        e.printStackTrace();
    } catch (InstantiationException e) {
        e.printStackTrace();
    }
    //
    throw new RuntimeException(" Factory 生产不了 " + className);
}
}

反射调用

获取Class类的三种方式:
1丶一个类的实例化对象的getClass()获取
2丶类型名称.class eg: Date.class
3丶Class.forName(类的全限定名)
同一个类加载其中一个类的Class对象只有一个

在这里插入图片描述

取得父类信息

public class TestClass {
    public static void main(String[] args) {
        //1. new Test().getClass();
        //2. Test.class
        //3. Class.forName("com.bittech.reflect.Test")
        Class cls = Test.class;

        System.out.println("包名:" + cls.getPackage());
        System.out.println("父类:" + cls.getSuperclass().getName());//类的全限名  包名.类名
        System.out.println("父类:" + cls.getSuperclass().getSimpleName());//类名
        System.out.println("接口:" );
        //实例化
        Class[] interfaces = cls.getInterfaces();
        for (Class clsz:interfaces){
            System.out.println(clsz.getName());
            System.out.println(clsz.getSimpleName());
        }

    }
}

2丶反射调用构造

⼀个类中可以存在多个构造⽅法,如果要想取得类中构造的调用,就可以使用Class类中提供的两个方法:
1、取得指定参数类型的构造 getParameterTypes()
2、取得类中的所有构造 getConstructors()

Class类通过反射实例例化类对象的时候,只能够调用类中的无参构造。如果现在类中没有⽆参构造则⽆法使用Class类调用,只能够通过明确的构造调⽤实例化处理

class Test implements Fruit,Message{
    public Test(Integer a,Integer b){

    }
    public Test(Integer a,String b){

    }
    public Test(Integer a){

    }
    public Test(){
        
    }
}

取得指定参数类型的构造 getParameterTypes()

    public static void main(String[] args) {
        //Test1(int a, int b);    => Test1(int, int) => Test1(int.class, int.class)
        //Test1(int a, String b); => Test1(int,String)
        //Test1(int a);           => Test1(int)
        Class clz = Test.class;
        Constructor[] constructors = clz.getConstructors();
        System.out.println("获取所有的构造方法");
        for (Constructor constructor:constructors){
            Class [] parameterCls= constructor.getParameterTypes();
            String parameter = Arrays.toString(parameterCls);
            System.out.println(
                    constructor.getName() + "("+parameter+")"
            );
        }
 }

取得构造方法

public static void main(String[] args) {
  System.out.println("获取指定的构造方法");
        try {
            /*
            Constructor constructor = clz.getConstructor(Integer.class,String.class);
            System.out.println(constructor);

            //通过Constructor实例化对象
            //new Test(...)
                Object object = constructor.newInstance(20,"java");
                System.out.println(object.getClass());
            */
            Constructor constructor =clz.getConstructor(Integer.class,Integer.class);
            System.out.println(constructor);

            //通过Constructor实例化对象
            //new Test(...)
            Object object = constructor.newInstance(20,22);
            System.out.println(object.getClass());
            } catch (InstantiationException e) {
                e.printStackTrace();
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            } catch (InvocationTargetException e) {
                e.printStackTrace();
            } catch (NoSuchMethodException e) {
            e.printStackTrace();
        }
}

反射调用类中属性
类中的所有属性一定在类对象实例化之后才会进行空间分配,所以此时如果要想调用类的属性,必须保证有实例化对象。通过反射的newInstance()可以直接取得实例化对象(Object类型);
1、 获取类中的全部属性:
2、获取指定属性

class Student extends Person{
    private String school;
    private String skill;
    private LocalDateTime birthday;

    public String getSchool() {
        return school;
    }

    public void setSchool(String school) {
        this.school = school;
    }

    public String getSkill() {
        return skill;
    }

    public void setSkill(String skill) {
        this.skill = skill;
    }

    public LocalDateTime getBirthday() {
        return birthday;
    }

    public void setBirthday(LocalDateTime birthday) {
        this.birthday = birthday;
    }

    @Override
    public String toString() {
        return "Student{" +
                "school='" + school + '\'' +
                ", skill='" + skill + '\'' +
                ", birthday=" + birthday +
                '}';
    }
}

1丶获取类中全部属性

public static void main(String[] args) {
        Class cls = Student.class;
        //子类继承父类的所有结构,是否能否访问取决于访问修饰符
        System.out.println("获取全部属性");
        //Field[] fields = cls.getFields();//返回父类和子类的公开属性
        Field[] fields = cls.getDeclaredFields();//返回子类的所以属性
        for (Field field:fields){
            System.out.println(field.getType() + " " +field.getName());
            System.out.println(field);
        }
    }

2、获取指定属性

 public static void main(String[] args) {
 //自己
        System.out.println("获取指定属性");
        try {
            Field skillField = cls.getDeclaredField("skill");
            System.out.println(skillField);

            //使用属性
            Student student = new Student();
            student.setSkill("Java,PHP,Python,JavaScript");
//            student.getSkill()
            //true 表示可以访问私有的属性
            skillField.setAccessible(true);
            //get 获取
            Object skillValue = skillField.get(student);
            System.out.println(skillValue);
            //set 修改
            skillField.set(student,"C++");
            System.out.println(student);
        } catch (NoSuchFieldException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }
    }
}

不加 skillField.setAccessible(true); 不能访问 private 的属性
true 表示可以访问私有的属性

**

ClassLoader类加载器

**

Class类描述的是整个类的信息,在Class类中提供的forName()⽅法,这个⽅法根据ClassPath配置的路径进行类的加载,如果说现在你的类的加载路径可能是网络、文件,这个时候就必须实现类加载器,也就是ClassLoader类的主要作⽤。

Bootstrap(启动类加载器):这个类加载器使用C++实现,是虚拟机⾃身的一部分;其他的类加载器都由Java语⾔言实现,独立于JVM外部并且都继承于java.lang.ClassLoader.BootStrap类加载器负责将存放于<Java_HOME>\lib目录中(或者被-Xbootclasspath参数指定路径中)能被虚拟机识别的(仅按照文件名识别,如rt.jar,名字不符合的类库即使放在lib目录中也不会被加载)类库加载到JVM内存中。启动类加载
器无法被Java程序直接引⽤。

ExtClassLoader(扩展类加载器):它负责加载<Java_HOME>\lib\ext目录中,或者被java.ext.dirs系统变量指定的路径中的类库。开发者可以直接使用扩展类加载器。

AppClassLoader(应用程序类加载器):负责加载用户类径(ClassPath)上指定的类库,如果应⽤程序中没有自定义自己的类加载器,则此加载器就是程序中默认的类加载器。

public class TestClassLoader {
    public static void main(String[] args) {
        Class memberCls = Member.class;
        //获取ClassLoader
        //AppClassLoader(应用程序类加载器)
        System.out.println(memberCls.getClassLoader());
        //ExtClassLoader(扩展类加载器)
        System.out.println(memberCls.getClassLoader()
                .getParent());
        //null ->Bootstrap(启动类加载器) ClassLoader
        System.out.println(memberCls.getClassLoader()
        .getParent().getParent());
    }
}

//1. com.changehyh.github.classloader
//2. com.changehyh.github.classloader.Member
//3. %classpath%/com/changehyh/github/classloader/Member.class
//4. Member.class对象
class Member{

}


双亲委派模型

在这里插入图片描述
上图加载器的关系就是双亲委派模型

双亲委派模型的工作流程是:如果⼀个类加载器收到了类加载请求,它⾸先不会自⼰己去尝试加载这个类,而是把这个请求委托给⽗类加载器去完成,每⼀个层次的类加载器都是如此。因此,所有的加载请求都应当传送到顶层的BootStrap加载器中,只有当⽗加载器反馈无法完成这个加载请求时(在自己搜索范围中没有找到此类),子加载器才会尝试⾃己去加载。
双亲委派模式对于保证Java程序的稳定运行很重要,Java类随着它的类加载器⼀一起具备了一种带有优先级的层次关系。

Object类在程序的各种类加载器环境中都是同⼀个类

import java.lang.reflect.Method;

public class TestObject {

    public static void main(String[] args) {
        Class cls = Object.class;
        System.out.println(cls);
        Method[] methods = cls.getDeclaredMethods();
        for (Method method : methods){
            System.out.println(method);
        }
    }
}

在这里插入图片描述

自定义类加载器:

用户自定义的类加载器
com.changehyh.github.classloader.Member1

public class Member1 {
    @Override
    public String toString() {
        return "这是本地F盘的class文件";
    }
}

MyClassLoader类继承ClassLoader类

import java.io.ByteArrayOutputStream;
import java.io.FileInputStream;
import java.io.IOException;

public class MyClassLoader extends ClassLoader {

    //用户自定义的类加载器
    //com.changehyh.github.classloader.Member1
    public Class loadClasses(String className){
        byte[] byteCodeData = loadData(className);
        //Class类 -> Class文件 -> ByteCode二进制流
        return super.defineClass(className,byteCodeData,0,byteCodeData.length);
    }

    private byte[] loadData(String className) {
        //Class文件的路径:F:\bit daima\20190520\out\production\20190520\com\changehyh\github\classloader\Member1.class
        //Member1的类名:com.changehyh.github.classloader.Member1
        //String classpath = "F:\\bit daima\\20190520\\out\\production\\20190520\\"classpath
        // 环境变量配置,或者系统属性,命令行参数
        String classpath = "F:\\bit daima\\20190520\\out\\production\\20190520\\";
        String classFile = classpath + className.replace(".","\\\\") + ".class";

        try (FileInputStream in = new FileInputStream(classFile);
             ByteArrayOutputStream out = new ByteArrayOutputStream()
        ) {
            byte[] buff = new byte[1024];
            int len = -1;
            while ((len = in.read(buff)) != -1){
                out.write(buff, 0, len);
            }
            byte[] byteCodeData = out.toByteArray();
            return byteCodeData;
        } catch (IOException e) {
           throw new RuntimeException(e);
        }
    }
}

public class TestMyClassLoader {
    public static void main(String[] args) {
        //Member1 -> AppClassLoader  -> Class<Member1> a
        //Member1 -> AppClassLoader  -> Class<Member1> b
        //Member1 -> AppClassLoader  -> Class<Member1> c

        //Member1 -> MyClassLoader  -> Class<Member1>  d
        MyClassLoader myClassLoader = new MyClassLoader();
        //Class
        Class member1Cls1 = myClassLoader.loadClasses("com.changehyh.github.classloader.Member1");
        //Class
        Class member1Cls2 = Member1.class;
        Class member1Cls3 = new Member1().getClass();
        System.out.println(member1Cls1 == member1Cls2); //false 不同的类加载器
        System.out.println(member1Cls2 == member1Cls3);//true 相同的类加载器

    }
}

在这里插入图片描述

反射与代理设计模式

在这里插入图片描述
代理设计模式的核心本质在于:一个接口有两个⼦子类,⼀个负责真实业务,一个负责与真实业务有关的 所有辅助性操作。按照这样的原则,一个基础的代理设计模式如下:

接口如下

package com.bittech.proxy;

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

/**
 * Author: secondriver
 * Created: 2019/5/18
 */
public interface ISubject {
    void eat();
}

//业务类
class RealSubject implements ISubject {
    @Override
    public void eat() {
        System.out.println("饿了要吃饭");
    }
}

class ProxySubject implements ISubject {
    private ISubject subject;
    
    public ProxySubject(ISubject subject) {
        this.subject = subject;
    }
    
    public void prepare() {
        System.out.println("饭前收拾食材");
    }
    
    public void afterEat() {
        System.out.println("洗刷刷");
    }
    
    @Override
    public void eat() {
        this.prepare();
        this.subject.eat(); // 核心吃
        this.afterEat();
    }
}

class Factory {
    
    
    private Factory() {
    }
    
    public static <T> T getInstance(String realClassName) {
        try {
            Class cls = Class.forName(realClassName);
            return (T) cls.newInstance();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InstantiationException e) {
            e.printStackTrace();
        }
        throw new RuntimeException("factory create object failed by class " + realClassName);
    }
    
    
    public static <T> T getInstance(String proxyClassName, Object target) {//target 被代理对象  目标对象  代理对象的构造方法中
        
        try {
            Class cls = Class.forName(proxyClassName);
            //限制:代理类只是实现代理接口
//            Class[] proxyClassInterfaces = cls.getInterfaces();
//            Class[] realClassInterfaces = target.getClass().getInterfaces();
            Constructor constructor = cls.getConstructor(cls.getInterfaces()[0]);
            
            return (T) constructor.newInstance(target);
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        }
        throw new RuntimeException("factory create object failed by class " + proxyClassName);
    }
    
    
    public static <T> T getProxyObject(String realClassName, String proxyClassName) {
        T realObject = Factory.getInstance(realClassName);
        T proxyObject = Factory.getInstance(proxyClassName, realObject);
        return proxyObject;
    }
}

真实业务:

package com.bittech.proxy;

import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;

import java.lang.reflect.Method;

/**
 * Author: secondriver
 * Created: 2019/5/18
 */
public class RealSubject1 {
    
    void eat() {
        System.out.println("吃饭");
    }
    
    public static void main(String[] args) {
        //真实业务对象  被代理对象
        RealSubject1 realSubject1 = new RealSubject1();
        //增强的业务对象
        MethodInterceptor interceptor = new RealSubjectAdvance(realSubject1);
        //代理对象
        //enchaner生成代理对象
        Enhancer enhancer = new Enhancer();
        //代理类父类,处理逻辑
        enhancer.setSuperclass(realSubject1.getClass());
        enhancer.setCallback(interceptor);
        RealSubject1 proxyObject = (RealSubject1) enhancer.create();
        proxyObject.eat();
        System.out.println(proxyObject.getClass());
        
    }
    
}

//业务增强
class RealSubjectAdvance implements MethodInterceptor {
    
    private final Object target;
    
    RealSubjectAdvance(Object target) {
        this.target = target;
    }
    
    @Override
    public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
        System.out.println("吃饭前,做饭");
        Object returnValue = method.invoke(this.target, objects);
        System.out.println("吃饭后,洗碗");
        return returnValue;
    }
}

业务辅助类

package com.bittech.proxy;

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

/**
 * 该类:用于增强真实业务类对象的(被代理对象target)
 * <p>
 * Author: secondriver
 * Created: 2019/5/18
 */
public class RealSubjectHandler implements InvocationHandler {
    
    private final Object target;
    
    public RealSubjectHandler(Object target) {
        this.target = target;
    }
    
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        //invoke调用时
        //method :  此时调用代理接口的method
        //args   :  此时调用代理接口的method方法传入的参数
        
        System.out.println("做饭");//code ...
        Object returnValue = method.invoke(this.target, args);
        System.out.println("洗碗");
        
        return returnValue;
    }
}

测试类:

package com.bittech.proxy;

import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.Arrays;

/**
 * Author: secondriver
 * Created: 2019/5/18
 */
public class TestProxy {
    
    public static void main(String[] args) {
        /*
        ISubject realObject= new RealSubject();
        ISubject proxyObject = new ProxySubject(realObject);
        proxyObject.eat();
        */
        /*
        ISubject realObject= Factory.getInstance("com.bittech.proxy.RealSubject");
        ISubject proxyObject = Factory.getInstance("com.bittech.proxy.ProxySubject",realObject);
         */
        /*
        ISubject proxyObject = Factory.getProxyObject(
                "com.bittech.proxy.RealSubject",
                "com.bittech.proxy.ProxySubject"
        );
        proxyObject.eat();
         */
        
        System.out.println("动态代理");
        ISubject realSubject = new RealSubject();
        InvocationHandler handler = new RealSubjectHandler(realSubject);
        //代理对象
        ISubject proxySubject = (ISubject) Proxy.newProxyInstance(
                realSubject.getClass().getClassLoader(),
                //动态生成的代理类的字节码需要类加载器,保证代理类和业务类在同一个类类加载器中
                
                new Class[]{ISubject.class, CharSequence.class},// 动态生成的代理类实现的接口,Proxy.newProxyInstance返回的代理对象(Object)向下转型
                handler//代理类动态生成的,无法动态生成业务增强,传入InvocationHandler接口的实例化对象
        );
        proxySubject.eat();
        
        System.out.println("============");
        System.out.println("类型:" + proxySubject.getClass());
        System.out.println("接口:" + Arrays.toString(proxySubject.getClass().getInterfaces()));
        System.out.println("父类:" + proxySubject.getClass().getSuperclass());
        
        System.out.println("=============");
        Constructor[] constructors = proxySubject.getClass().getConstructors();
        for (Constructor c : constructors) {
            System.out.println(c);
        }
        System.out.println("=============");
        Method[] methods = proxySubject.getClass().getMethods();
        for (Method method : methods) {
            System.out.println(method);
        }
        
        //ByteCode
        //1. .java -> .class
        //2. .class  ASM   API
    }
}

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值