• Java-反射调用类的完整结构,动态代理


    实例class类

    public class Person {
        public String name;
        int age;
    }
    ----------------------------------------------------------------------------------------------
    public class Test {
        public static void main(String[] args) {
            Person p = new Person();
            Class clazz = p.getClass();//clazz对象中就包含对象p所属的Person类的所有的信息
            
            
            Class c0 = Person.class;//通过类名.class创建指定类的Class实例
            
            Class c1 = p.getClass();//通过一个类的实例对象的getClass()方法,获取对应实例对象的类的Class实例
            
            try {
                //通过Class的静态方法forName(String className)来获取一个类的Class实例
                //forName(String className)方法中的参数是你要获取的Class实例的类的全路径(包名.类名)
                Class c2 = Class.forName("day14.Person");//这个是获取Class实例的常用方式
            } catch (ClassNotFoundException e) {
                e.printStackTrace();
            }
            
        }
    }
    

    通过反射调用类的完整结构

    所用到的对象与接口

    public interface Move {
        void moveType();
    }
    ----------------------------------------------------------------------------------------------
    public interface Study {
        void studyInfo();
    }
    ----------------------------------------------------------------------------------------------    
    public class Student extends Person implements Move,Study{
        public Student(){
            System.out.println("调用的是public Student()");
        }
        
        public Student(String school){
            this.school = school;
            System.out.println("调用的是public Student(String school)");
        }
    
        private Student(String name,int age){
            this.name = name;
            this.age = age;
            System.out.println("调用的是private Student(String name,int age)");
        }
        public String school;
        private String privateField;
        
        public void showInfo(){
            System.out.println("学校是:" + this.school);
        }
        
        @Override
        public void studyInfo() {
            System.out.println("学习的中学的知识");
        }
    
        @Override
        public void moveType() {
            System.out.println("骑自行车上学");
        }
        
        private void test(String name){
            System.out.println("这是私有方法private void test(String name)");
        }
        
        public String getSchool(){
            return this.school;
        }
        
        public void setInfo(String name,String school){
            this.name = name;
            this.school = school;
            System.out.println("这个是setInfo(String name,String school)方法");
        }
        
        public void setInfo(int age){
            System.out.println("这个是public void setInfo(int age)方法");
        }
    }
    

    实现的全部接口

    public class Test1 {
        public static void main(String[] args) {
            try {
                Class clazz = Class.forName("day14.Student");//通过包名.类名的字符串,调用Class.forName方法获取指定类的Class实例
                
                 (以上部分省略)
                Class superClazz = clazz.getSuperclass();//获取父类
                System.out.println("父类:" + superClazz.getName());
                (以下部分省略)
                } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }
    

    所继承的父类

    public class Test1 {
        public static void main(String[] args) {
            try {
                Class clazz = Class.forName("day14.Student");//通过包名.类名的字符串,调用Class.forName方法获取指定类的Class实例
                 (以上部分省略)
                Class[] interfaces = clazz.getInterfaces();//获取当前类的所有接口
                for(Class c : interfaces){
                    System.out.println("接口:" + c.getName());
                }
                (以下部分省略)	
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }
    

    全部的构造器

    Constructor[] cons = clazz.getConstructors();//获取到类的公有的构造方法
    
    for(Constructor c : cons){
        System.out.println("构造方法名称:" + c.getName());//取得方法名称
        //getModifiers取得方法的修饰符,返回数组1代表public
        System.out.println("构造方法:" + c.getName() + "的修饰符是:" + c.getModifiers());
        
        Class[] paramClazz = c.getParameterTypes();
        for(Class pc : paramClazz){
            System.out.println("构造方法:" + c.getName() + "的参数类型是:" + pc.getName());
        }
    }
    -------------------------------------------------------------------------------------
    Constructor[] cons1 = clazz.getDeclaredConstructors();//获取类的所有构造方法,包括公有和私有的
    for(Constructor c : cons1){
        
        System.out.println("-------------------------------------");
        
        System.out.println("构造方法名称:" + c.getName());//取得方法名称
        //getModifiers取得方法的修饰符,返回数组1代表public,返回数组2代表是private
        System.out.println("构造方法:" + c.getName() + "的修饰符是:" + c.getModifiers());//getModifiers取得方法的修饰符
        
        Class[] paramClazz = c.getParameterTypes();//获取构造方法的参数类型,有几个参数数组的元素就有几个
        for(Class pc : paramClazz){
            System.out.println("构造方法:" + c.getName() + "的参数类型是:" + pc.getName());
        }
        
        System.out.println("-------------------------------------");
    }
    

    利用反射构造方法创建对象

    Object obj = clazz.newInstance();//相当于调用Student类的无参公有的构造方法
    Student stu = (Student)obj;
    ------------------------------------------------------------
    Constructor c = clazz.getConstructor(String.class);//指定获取有一个参数并且为String类型的公有的构造方法
    Student stu1 = (Student)c.newInstance("第一中学");//newInstance实例化对象,相当于调用public Student(String school)
    System.out.println(stu1.school);
    ------------------------------------------------------------
    //通过反射机制,可以强制的调用私有的构造方法
    Constructor c = clazz.getDeclaredConstructor(String.class,int.class);//指定获取有两个参数(String,int)的构造方法
    c.setAccessible(true);//解除私有的封装,下面就可以对这个私有方法强制调用
    Student stu = (Student)c.newInstance("zhangsan",12);
    

    全部的方法

    <!-- Method[] ms = clazz.getMethods();//获取到类的所有公有的方法 -->
    Method[] ms = clazz.getDeclaredMethods();//获取类所有方法,包含公有和私有
    for(Method m : ms){
        System.out.println("方法名:" + m.getName());
        System.out.println("返回值类型:" + m.getReturnType());
        System.out.println("修饰符:" + m.getModifiers());
        
        Class[] pcs = m.getParameterTypes();//获取方法的参数类型,是一个数组,方法有几个参数,数据就有几个元素
        if(pcs != null && pcs.length > 0){
            for(Class pc : pcs){
                System.out.println("参数类型:" + pc.getName());
            }
        }
        
        System.out.println("==============================================");
    }
    

    全部的Field(即属性)

    <!-- Field[] fs = clazz.getFields();//获取类的公有的属性,包含父类的公有属性			 -->
    Field[] fs = clazz.getDeclaredFields();//获取本类的(不包括父类的属性)所有的属性,包括私有
    
    for(Field f : fs){
        System.out.println("修饰符:" + f.getModifiers());
        System.out.println("属性的类型:" + f.getType());
        System.out.println("属性的名称:" + f.getName());
    }
    

    类所在的包

    Package p = clazz.getPackage();//获取类所在的包
    System.out.println(p.getName());
    

    反射调用公有代码

    Constructor con = clazz.getConstructor();//获取无参构造
    Object obj = con.newInstance();//使用无参构造创建对象
    

    调用公有方法

    Method m = clazz.getMethod("setInfo", String.class,String.class);//得到名称叫setInfo,参数是String,String的方法
    m.invoke(obj, "zhangsan","第一中学");//参数1是需要实例化的对象,后面的参数是调用当前的方法实际参数
    

    调用私有方法

    //如果想要调用一个私有方法
    Method m1 = clazz.getDeclaredMethod("test", String.class);//获取方法名为test,参数为1个String类型的方法
    
    m1.setAccessible(true);//解除私有的封装,下面可以强制调用私有的方法
    
    m1.invoke(obj, "李四");
    

    反射调用重载方法

    Method m2 = clazz.getMethod("setInfo", int.class);//setInfo的重载方法
    m2.invoke(obj, 1);
    

    反射调用有返回值的方法

    //有返回值的方法
    Method m3 = clazz.getMethod("getSchool");//这是获取方法名为getSchool并且没有参数的方法
    String school = (String)m3.invoke(obj);//调用有返回值的但是没有参数的方法
    System.out.println(school);
    

    反射调用公有属性

    Field f = clazz.getField("school");//获取名称为school的属性
    f.set(stu, "第三中学");//对stu对象的school属性设置值"第三中学"
    String school = (String)f.get(stu);//获取stu对象的school属性的值
    System.out.println(school);
    

    反射调用私有属性

    Field f1 = clazz.getDeclaredField("privateField");
    f1.setAccessible(true);//解除私有的封装,下面就可以强制的调用这个属性
    f1.set(stu, "测试私有属性");
    System.out.println(f1.get(stu));
    

    动态代理

    理解:就是很多类绑在一起,同时改变,加入同一方法

    public class TestDemoImpl implements ITestDemo {
    
        @Override
        public void test1() {
            System.out.println("执行test1()方法");
        }
    
        @Override
        public void test2() {
            System.out.println("执行test2()方法");
        }
    }
    ------------------------动态代理类--------------------------------
    public class ProxyDemo implements InvocationHandler{
    
        Object obj;//被代理的对象
        
        public ProxyDemo(Object obj){
            this.obj = obj;
        }
        
        @Override
        public Object invoke(Object proxy, Method method, Object[] args)
                throws Throwable {
            
            System.out.println(method.getName() + " 方法开始执行");
            
            Object result = method.invoke(this.obj, args);//执行的是指定代理对象的指定的方法
            
            System.out.println(method.getName() + " 方法执行完毕");
            return result;
        }
    
    }
    -------------------------------------------------------------------
    public class Test2 {
        public static void main(String[] args) {
            ITestDemo test = new TestDemoImpl();
            /**
            * 注意:如果一个对象想要通过Proxy.newProxyInstance方法被代理,
            * 那么这个对象的类一定要有相应的接口
            * 就像本类中的ITestDemo接口和实现类TestDemoImpl
            */
            test.test1();
            test.test2();
            System.out.println("======================");
            /**
            * 需求:
            * 在执行test1和test2方法时需要加入一些东西
            * 在执行方法前打印test1或test2开始执行
            * 在执行方法后打印test1或test2执行完毕
            * 打印的方法名要和当时调用方法保存一致
            */
            
            InvocationHandler handler = new ProxyDemo(test);
            /**
            * Proxy.newProxyInstance(ClassLoader, interfaces, h)
            * 参数1是代理对象的类加载器
            * 参数2是被代理的对象的接口
            * 参数3是代理对象
            * 
            * 返回的值就成功被代理后对象,返回的是Object类型,需要根据当时的情况去转换类型
            */
            ITestDemo t = (ITestDemo)Proxy.newProxyInstance(handler.getClass().getClassLoader(), test.getClass().getInterfaces(), handler);
            
            t.test1();
            System.out.println("-----------------------");
            t.test2();
            
        }
    }
    -----------------------------执行结果------------------------------------
    执行test1()方法
    执行test2()方法
    ======================
    test1 方法开始执行
    执行test1()方法
    test1 方法执行完毕
    -----------------------
    test2 方法开始执行
    执行test2()方法
    test2 方法执行完毕
  • 相关阅读:
    修改Tomcat可支持get形式url长度
    UTF-8 带签名和不带签名的区别
    注册asp.net 4.0版本到IIS服务器中
    C#计算字符串长度,汉字算两个字符
    高德地图Javascript API设置域名白名单
    金三银四招聘季,这些BAT以及独角兽互联网公司官方招聘网站值得关注。(个人梳理备用:附BAT以及独角兽公司官方招聘网址)
    【转载】 C#工具类:Csv文件转换类
    【转载】ASP.NET生成图片的缩略图
    【转载】IIS报错不是有效的Win32应用程序
    【转载】C#工具类:FTP操作辅助类FTPHelper
  • 原文地址:https://www.cnblogs.com/dongxuelove/p/13031521.html
Copyright © 2020-2023  润新知