zoukankan      html  css  js  c++  java
  • Java-反射机制

    一、Java反射机制概述

    Reflection(反射)是被视为动态语言的关键,反射机制允许程序在执行期借助于Reflection API取得任何类的内部信息,并能直接操作任意对象的内部属性及方法。
    ●加载完类之后,在堆内存的方法区中就产生了一个Class类型的对象(一个类只有一个Class对象),这个对象就包含了完整的类的结构信息。我们可以通过这个对象看到类的结构。这个对象就像一面镜子,透过这个镜子看到类的结构,所以,我们形象的称之为:反射

    ●加载到内存中的类,我们就称为运行时类,此运行时类,就作为Class的一个实例。换句话说,Class的实例就对应着一个运行时类。

    Java反射机制提供的功能

    ➢在运行时判断任意一个对象所属的类
    ➢在运行时构造任意一个类的对象
    ➢在运行时判断任意一个类所具有的成员变量和方法
    ➢在运行时获取泛型信息
    ➢在运行时调用任意一个对象的成员变量和方法
    ➢在运行时处理注解
    ➢生成动态代理

    反射相关的主要API

    java.lang.Class:代表一个类
    java.lang.reflect.Method:代表类的方法
    java.lang.reflect.Field:代表类的成员变量
    java.lang.reflect.Constructor:代表类的构造器

    二、类的加载过程

    当程序主动使用某个类时,如果该类还未被加载到内存中,则系统会通过如下三个步骤对该类进行初始化

    类加载器ClassLoader

    类加载器作用时用来把类(class)装载进内存。JVM规范定义了如下类型的加载器:

    package com.xudong.java;
    
    import org.junit.Test;
    
    import java.io.FileInputStream;
    import java.io.IOException;
    import java.io.InputStream;
    import java.util.Properties;
    
    public class ReflectionTest {
        @Test
        //获取Class的实例的方式
        public void test1() throws ClassNotFoundException {
            //方式一:调用运行时类的属性:.class
            Class clazz1 = Person.class;
            //方式二:通过运行时类的对象,调用getClass()
            Person p1 = new Person();
            Class clazz2 = p1.getClass();
            //方式三:调用Class的静态方法:forName(String classPath)。使用频率多
            Class clazz3 = Class.forName("com.xudong.java.Person");
            //方式四:使用类的加载器 ClassLoader。使用比较少
            ClassLoader classLoader = ReflectionTest.class.getClassLoader();
            Class clazz4 = classLoader.loadClass("com.xudong.java.Person");
    
        }
        @Test
        //读取配置文件
        public void test2() throws IOException {
    
            Properties pros = new Properties();
            //读取配置文件的方式一:
            FileInputStream fis = new FileInputStream("jdbc.properties");
            pros.load(fis);
            //读取配置文件的方式二:
            ClassLoader classLoader = ReflectionTest.class.getClassLoader();
            InputStream is = classLoader.getResourceAsStream("jdbc.properties");
            pros.load(is);
            //获取文件内容
            String user = pros.getProperty("user");
            String password = pros.getProperty("password");
            System.out.println("user =" + user + ",password = " + password);
    
        }
    }
    

    三、创建运行时类的对象

    package com.xudong.java;
    
    import org.junit.Test;
    
    //通过反射创建对应的运行时类的对象
    public class NewInstanceTest {
        @Test
        public void test1() throws IllegalAccessException, InstantiationException {
            Class<Person> clazz = Person.class;
            //newInstance():创建对应的运行时类的对象。只有构造器可以造对象,运行时调用了空参构造器
            //空参的构造器访问权限得够,一般为public
            //便于子类继承此运行时类,默认调用super()时,保证父类有此构造器
            Person obj = clazz.newInstance();
        }
    }
    

    四、调用运行时类的指定的结构

    getFields():获取当前运行时类及其父类中声明为public访问权限的属性
    getDeclaredFields():获取当前运行时类中声明的所有属性(不包含父类)
    getModifiers():获取权限修饰符。使用:Modifier.toString(f.getModifiers)
    getName():获取属性名
    getMethod():获取当前类以及父类中声明为public的方法
    getDeclaredMethod():获取当前运行时类中声明的所有方法(不包含父类)
    getAnnotations():获取当前运行时类中方法声明的注解
    getReturnType().getName():获取当前运行时类中返回值类型
    getParameterTypes():获取当前运行时类中形参列表
    getExceptionTypes():获取当前运行时类中异常
    getConstructors():获取当前运行时类中声明为public的构造器
    getDeclaredConstructors():获取当前运行时类中声明的所有构造器
    getSuperclass():获取当前运行时类的父类
    getGenericSuperclass():获取当前运行时类带泛型的父类
    getInterface():获取运行时类实现的接口
    getPackage():获取当前运行时类所在的包
    setAccessible(true);设置可访问

    五、代理模式

    代理设计模式的原理:
    使用一个代理将对象包装起来,然后用该代理对象取代原始对象。任何对原始对象的调用都要通过代理。代理对象决定是否以及何时将方法调用转到原始对象上。
    ●代理机制的操作,属于静态代理,特征是代理类和目标.对象的类都是在编译期间确定下来,不利于程序的扩展。同时,每一个代理类只能为一个接口服务,这样一来程序开发中必然产生过多的代理。最好可以通过一个代理类完成全部的代理功能
    ●动态代理是指客户通过代理类来调用其它对象的方法,并且是在程序运行时根据需要动态创建目标类的代理对象。
    动态代理使用场合:

    ➢调试
    ➢远程方法调用

    动态代理相比于静态代理的优点:

    抽象角色中(接口)声明的所有方法都被转移到调用处理器一个集中的方法中处理,这样,我们可以更加灵活和统一的处理众多的方法。

    1.静态代理

    代理类和被代理类在编译期间,就确定下来了

    package com.xudong.java;
    
    interface ClothFactory{
        void produceCloth();
    }
    //代理类
    class ProxyClothFactory implements ClothFactory{
    
        private ClothFactory factory;//用被代理类对象进行实例化
    
        public ProxyClothFactory(ClothFactory factory){
            this.factory = factory;
        }
        @Override
        public void produceCloth() {
            System.out.println("代理工厂做一些准备工作");
    
            factory.produceCloth();
    
            System.out.println("代理工厂做一些后续的收尾工作");
    
        }
    }
    //被代理类
    class NikeClothFactory implements ClothFactory{
    
        @Override
        public void produceCloth() {
            System.out.println("Nike工厂生成一批运动服");
        }
    }
    
    public class StaticProxyTest {
        //创建被代理类的对象
        public static void main(String[] args) {
            ClothFactory nike = new NikeClothFactory();
            //创建代理类的对象
            ClothFactory proxyClothFactory = new ProxyClothFactory(nike);
    
            proxyClothFactory.produceCloth();
        }
    }
    

    2.动态代理

    package com.xudong.java;
    
    import java.lang.reflect.InvocationHandler;
    import java.lang.reflect.Method;
    import java.lang.reflect.Proxy;
    
    interface Human{
    
        String getBelief();
    
        void eat(String food);
    
    }
    //被代理类
    class SuperMan implements Human{
    
        @Override
        public String getBelief() {
            return "I believe I can fly!";
        }
    
        @Override
        public void eat(String food) {
            System.out.println("我喜欢吃" + food);
        }
    }
    
    //根据加载到内存中的被代理类,动态的创建一个代理类及其对象。
    class ProxyFactory{
        //调用此方法,返回一个代理类的对象。
        public static Object getProxyInstance(Object obj){//obj:被代理类的对象
            MyInvocationHandler handler = new MyInvocationHandler();
    
            handler.bind(obj);
    
            return Proxy.newProxyInstance(obj.getClass().getClassLoader(),obj.getClass().getInterfaces(),handler);
        }
    }
    
    class MyInvocationHandler implements InvocationHandler{
    
        private Object obj;//需要使用被代理类的对象进行赋值
        public void bind(Object obj){
            this.obj = obj;
        }
    
    
        //当通过代理类的对象,调用方法a时,就会自动的调用如下的方法:invoke()
        //将被代理类要执行的方法a的功能声明在invoke()中
        @Override
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            //method:即为代理类对象调用的方法,此方法也就作为了被代理类对象要调用的方法
            //obj:被代理类的对象
            Object returnValue = method.invoke(obj, args);
            //上述方法返回值就作为当前类中的invoke()的返回值
            return returnValue;
        }
    }
    public class ProxyTest {
        public static void main(String[] args) {
            SuperMan superMan = new SuperMan();
            //proxyInstance:代理类的对象
            Human proxyInstance = (Human) ProxyFactory.getProxyInstance(superMan);
            //当通过代理类对象调用的方法时,会自动的调用被代理类中同名的方法
            String belief = proxyInstance.getBelief();
            System.out.println(belief);
            proxyInstance.eat("火锅");
    
            System.out.println("********************");
    
            NikeClothFactory nikeClothFactory = new NikeClothFactory();
    
            ClothFactory proxyClothFactory = (ClothFactory) ProxyFactory.getProxyInstance(nikeClothFactory);
    
            proxyClothFactory.produceCloth();
        }
    }
    

  • 相关阅读:
    Java安全之JNDI注入
    Visual Studio 2019 升级16.8之后(升级.Net 5),RazorTagHelper任务意外失败
    .Net Core 3.1升级 .Net 5后出现代码错误 rzc generate exited with code 1.
    重走py 之路 ——普通操作与函数(三)
    重走py 之路 ——字典和集合(二)
    设计模式结(完结篇)
    重走py 之路 ——列表(一)
    RestfulApi 学习笔记——分页和排序(五)
    RestfulApi 学习笔记——查询与过滤还有搜索(五)
    Android开发 Error:The number of method references in a .dex file cannot exceed 64K.Android开发 Error:The number of method references in a .dex file cannot exceed 64K
  • 原文地址:https://www.cnblogs.com/nnadd/p/13396871.html
Copyright © 2011-2022 走看看