zoukankan      html  css  js  c++  java
  • Java反射---Java基础宋红康学习笔记

    一、Java反射机制概述

    1、Java反射机制研究及应用

    • Java反射机制提供的功能

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

    2、反射相关的主要API

    • java.lang.class:代表一个类
    • java.lang.reflect.Method:代表类的方法
    • java.lang.reflect.Field:代表类的成员变量
    • java.lang.reflect.Constructor:代表类的构造器
    public class RefletionTest {
    
        //反射之前,对于Person的操作
        @Test
        public void test1(){
            // 1、创建Person对象
            Person person1 = new Person("Tom",12);
    
            //2、通过对象,调用其内部的属性、方法
            person1.age = 10;
            System.out.println(person1.toString());
    
            person1.show();
    
            //在Person类的外部,不可以通过Person类的对象调用其内部私有结构
            //比如:私有属性 name  私有方法   私有构造器
        }
    
        //反射之后,对Person的操作
        @Test
        public void test2() throws IllegalAccessException, InvocationTargetException, InstantiationException, NoSuchMethodException, NoSuchFieldException {
            Class clazz = Person.class;
            //1、通过反射,创建Person类的对象
            Constructor constructor = clazz.getConstructor(String.class, int.class);
    
            Object ton = constructor.newInstance("Ton", 50);
            Person p = (Person) ton;
            System.out.println(ton.toString());
            //2、通过单设,调用对象指定的属性和方法
            //调用属性
            Field age = clazz.getDeclaredField("age");
            age.set(p,10);
            System.out.println(p.toString());
    
            //调用方法
            Method show = clazz.getDeclaredMethod("show");
            show.invoke(p);
    
            //通过反射,可以调用Person类中的室友结构。比如:私有的构造器、方法、属性
            //调用私有的构造器
            Constructor cons1 = clazz.getDeclaredConstructor(String.class);
            cons1.setAccessible(true);
            Person p1 = (Person) cons1.newInstance("jreey");
            System.out.println(p1);
    
            //调用私有的属性
            Field name = clazz.getDeclaredField("name");
            name.setAccessible(true);
            name.set(p1,"hanmeiemi");
            System.out.println(p1);
    
            //调用私有的方法
            Method showNation = clazz.getDeclaredMethod("showNation", String.class);
            showNation.setAccessible(true);
            String nation = (String) showNation.invoke(p1, "阿拉伯");
            System.out.println(nation);
    
        }
        /*
        * 疑问:通过直接new的方式或反射的凡是都可以调用公共结构,开发中到底用哪个?
        * 建议:直接用new方式
        * 什么时候会使用:反射的方式。反射的特征:动态性
        *
        * 疑问:反射机制与面向对象中的封装性是不是矛盾的?如何看待两个技术?
        * 不矛盾。
        * */
    
        /*
        * 关于java.lang.Class类的理解
        * 1、类的加载过程:
        * 程序经过javac.exe命令以后,会生成一个或多个字节码文件(.class结尾),
        * 接着我们使用java.exe命令对某个字节码文件进行解释运行。相当于将某个字节码文件加载到内存中
        * 此过程就称为类的加载。加载到内存中的类,我们就称为运行时类,此运行时类,就作为Class的一个实例
        *
        * 2、换句话说,Class的实例就对应着一个运行时类。
        *
     	* 3、加载到内存中的运行时类,会缓存一定时间。再此时间之内,我们可以通过不同的方式来获取此运行时类
         *
         * */
    
    }
    
    
    

    二、理解Class类并获取Class的实例

    1、获取Class实例的四种方式

        @Test
        public void test3() throws ClassNotFoundException {
            //方式一:调用运行时类的属性:.class
            Class class1 = Person.class;
            System.out.println(class1);
    
            //方式二:通过运行时类的对象,调用getClass()
            Person p1 = new Person();
            Class class2 = p1.getClass();
            System.out.println(class2);
    
            //方式三、调用Class的静态方法:forName(String classPath)
            Class class3 = Class.forName("com.java反射机制.Person");
            System.out.println(class3);
    
            System.out.println(class1 == class2);//true
            System.out.println(class1 == class3);//true
    
            //方式四、使用类的加载器:ClassLoader(了解)
            ClassLoader classLoader = RefletionTest.class.getClassLoader();
            Class<?> clazz4 = classLoader.loadClass("com.java反射机制.Person");
            System.out.println(clazz4);
    
            System.out.println(class1 == clazz4);
        }
    

    2、Class实例对应的结构说明

    Class c1 = Object.class;

    Class c2 = Comparable.class;

    Class c3 = String[].class;

    Class c4 = int[][].class;

    Class c5 = ElementType.class;

    Class c6 = Override.class;

    Class c7 = int.class;

    Class c8 = void.class;

    Class c9 = Class.class;

    int[] a = new int[10];

    int[] b = new int[100];

    Class c10 = a.getClass();

    Class c11 = b.getClass();

    // 只要元素类型与维度一样,就是同一个Class

    System.out.println(**c10 **== c11);//true

    三、类加载与ClassLoader的理解

    1、ClassLoder的理解

        @Test
        public void test1(){
            //对于自定义类,使用系统类加载器进行加载
            ClassLoader classLoader = ClassLoaderTest.class.getClassLoader();
            System.out.println(classLoader);
    
            //调用系统类加载器的getParent():获取扩展类加载器
            ClassLoader classLoader1 = classLoader.getParent();
            System.out.println(classLoader1);
            //调用扩展类加载器的getParent():无法获取引导类加载器
            //引导类加载器只要负责加载java的核心类库,无法加载自定义类的
            ClassLoader classLoader2 = classLoader1.getParent();
            System.out.println(classLoader2);
        }
    

    2、使用ClassLoder加载配置文件

        /*
        * Properties:用来读取配置文件
        * */
        @Test
        public void test2() throws IOException {
            Properties pros = new Properties();
            //此时的文件的默认在当前的model下
            //读取配置文件的方式一
    //        FileInputStream fis = new FileInputStream("jdbc.properties");
    //        pros.load(fis);
    
            //读取配置文件的方式二
            //此时的文件的默认在当前的model的src下
            ClassLoader classLoader = ClassLoaderTest.class.getClassLoader();
            InputStream is = classLoader.getResourceAsStream("jdbc1.properties");
            pros.load(is);
    
    
    
            String name = pros.getProperty("name");
            String password = pros.getProperty("password");
            System.out.println(name);
            System.out.println(password);
        }
    

    四、创建运行时类的对象

    /*
    *通过反射创建对应的运行时类的对象
    * */
    public class NewInstanceTest {
    
       @Test
       public void test1() throws IllegalAccessException, InstantiationException {
           Class clazz = Person.class;
    
           /*
           * newInstance():调用此方法,创建对应的运行时类的对象
           *   内部调用了运行时类的空参构造期
           *
           * 要想此方法正常的创建运行时类的对象,要求:
           * 1、运行时类必须提供空参构造期
           * 2、空参构造期的访问权限得够。通常设置为public
           *
           * 通常在javabean中要求提供一个public的空参构造器,原因:
           * 1、便于通过反射,创建运行时类的对象
           * 2、便于子类继承此运行时类,默认调用super()时,保证父类有此构造器
           *
           * */
           Person o = (Person) clazz.newInstance();
           System.out.println(o);
    
    
       }
    
       //体会反射的动态性
       @Test
       public void test2(){
           int num = new Random().nextInt(3);//0,1,2
           String classPath = "";
           switch(num){
               case 0:
                   classPath = "java.util.Date";
                   break;
               case 1:
                   classPath = "java.sql.Date";
                   break;
               case 2:
                   classPath = "com.java反射机制.Person";
           }
           try {
               Object instance = getInstance(classPath);
               System.out.println(instance);
           } catch (ClassNotFoundException e) {
               e.printStackTrace();
           } catch (IllegalAccessException e) {
               e.printStackTrace();
           } catch (InstantiationException e) {
               e.printStackTrace();
           }
       }
       /*
       * 创建一个指定类的对象
       * classPath:指定类的全类名
       * */
       public Object getInstance(String classPath) throws ClassNotFoundException, IllegalAccessException, InstantiationException {
           Class clazz = Class.forName(classPath);
           return clazz.newInstance();
       }
    
       @Test
       public void test3(){
           File file = new File("校准壁纸.png");
           System.out.println(file.getPath());
       }
    
    }
    
    

    五、获取运行时类的完整结构

    1、获取运行时类属性

    public class FieldTest {
    
        /*
        * 获取运行时类的属性结构
        * */
        @Test
        public void test1(){
            Class clazz = Creat.class;
    
            //获取属性机构
            //getFields():获取当前运行时类及其父类中声明为public访问权限的属性
            Field[] fields = clazz.getFields();
            for(Field f:fields){
                System.out.println(f);
            }
    
            System.out.println();
    
            //getDeclaredFields():获取当前运行时类中声明的所有属性(不包含父类中声明的属性)
            Field[] declaredFields = clazz.getDeclaredFields();
            for(Field f:declaredFields){
                System.out.println(f);
            }
        }
    
        //权限修饰符 数据类型 变量名
        @Test
        public void test2(){
            Class clazz = Creat.class;
            Field[] declaredFields = clazz.getDeclaredFields();
    
            for(Field f:declaredFields){
                //1、权限修饰符
                int modifiers = f.getModifiers();
                System.out.print(modifiers+"---");
                System.out.print(Modifier.toString(modifiers)+"	");
                //2、数据类型
                Class type = f.getType();
                System.out.print(type.getName()+"	");
                //3、变量名
                String name = f.getName();
                System.out.println(name+"	");
            }
    
        }
    }
    
    

    2、获取运行时类方法

    public class MothodTest {
    
        @Test
        public void test1(){
            Class clazz = Creat.class;
    
            //getMethods():获取当前运行时类及其所有父类中声明为public权限的方法
            Method[] methods = clazz.getMethods();
            for(Method mothod : methods) {
                System.out.println(mothod);
            }
    
            System.out.println();
    
            //getDeclaredMethods():获取当前运行时类中声明的所有方法(不包含父类中的方法)
            Method[] declaredMethods = clazz.getDeclaredMethods();
            for(Method mothod : declaredMethods) {
                System.out.println(mothod);
            }
        }
    
        //权限修饰符  返回值类型  方法名(参数类型1 形参1,...) throws XxxException{}
        @Test
        public void test2(){
            Class clazz = Creat.class;
            Method[] declaredMethods = clazz.getDeclaredMethods();
            for(Method mothod : declaredMethods) {
                //1、获取方法名
                System.out.print(mothod.getName()+"	");
                //2、获取形参列表
                System.out.print("(");
                Class[] parameterTypes = mothod.getParameterTypes();
                if(!(parameterTypes == null && parameterTypes.length == 0)){
                    for(int i = 0; i < parameterTypes.length; i++){
                        System.out.print("形参:"+parameterTypes[i].getName()+" _args_"+i+",");
                        System.out.print("	");
                    }
                }
                System.out.print(")");
    
                //3、、获取方法声明的注解
                Annotation[] annotations = mothod.getAnnotations();
                for(Annotation a:annotations){
                    System.out.print("获取注解;"+a +"	");
                }
    
                //4、权限修饰符
                System.out.print("获取修饰符:"+Modifier.toString(mothod.getModifiers())+"	");
    
                //5、返回值类型
                System.out.print(mothod.getReturnType().getName()+"	");
    
                //6、抛出的异常
                Class[] exceptionTypes = mothod.getExceptionTypes();
                if(!(exceptionTypes == null && exceptionTypes.length == 0)){
                    System.out.print("throws ");
                    for(int i = 0; i < exceptionTypes.length; i++){
                        System.out.print(exceptionTypes[i].getName()+",");
                    }
                }
    
                System.out.println();
    
            }
        }
    }
    

    3、获取运行时类构造器

     /*
        * 获取构造器
        * */
        @Test
        public void test1(){
            Class clazz = Creat.class;
            //getConstructors():获取当前运行时类中声明为public的构造器
            Constructor[] constructors = clazz.getConstructors();
            for(Constructor c :constructors){
                System.out.println(c);
    
            }
    
            System.out.println();
    
            //getDeclaredConstructors():获取运行时类中声明的所有构造器
            Constructor[] declaredConstructors = clazz.getDeclaredConstructors();
            for(Constructor c :declaredConstructors){
                System.out.println(c);
            }
    
        }
    

    4、获取运行时类父类

        /*
        * 获取运行时类的父类
        * */
        @Test
        public void test2(){
            Class clazz = Creat.class;
    
            Class superclass = clazz.getSuperclass();
            System.out.println(superclass);
        }
        /*
        * 获取运行时类带泛型的父类
        * */
        @Test
        public void test3(){
            Class clazz = Creat.class;
    
            Type type = clazz.getGenericSuperclass();
            System.out.println(type);
        }
        /*
         * 获取运行时类带泛型的父类的泛型
         * */
        @Test
        public void test4(){
            Class clazz = Creat.class;
    
            Type type = clazz.getGenericSuperclass();
            ParameterizedType parameterizedType = (ParameterizedType) type;
            //获取泛型类型
            Type[] actualTypeArguments = parameterizedType.getActualTypeArguments();
            for(Type t:actualTypeArguments){
                System.out.println(t.getTypeName());
            }
    
            System.out.println(type);
    
        }
    

    5、获取运行时类接口

        /*
        * 获取运行时类的接口
        * */
        @Test
        public void test5(){
            Class clazz = Creat.class;
            //获取运行时类的接口
            Class[] interfaces = clazz.getInterfaces();
            for(Class c:interfaces){
                System.out.println(c);
            }
    
            System.out.println();
            //获取运行时类父类的接口
            Class[] interfaces1 = clazz.getSuperclass().getInterfaces();
            for(Class c:interfaces1){
                System.out.println(c);
            }
        }
    

    6、获取运行时类所在包

        /*
        * 获取运行时类所在的包
        * */
        @Test
        public void test6(){
            Class clazz = Creat.class;
    
            Package pack = clazz.getPackage();
    
            System.out.println(pack);
        }
    

    7、获取运行时类声明的注解

        /*
        * 获取运行时类声明的注解
        * */
        @Test
        public void test7(){
            Class clazz = Creat.class;
    
            Annotation[] annotations = clazz.getAnnotations();
            for(Annotation a : annotations){
                System.out.println(a);
            }
        }
    

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

    1、调用运行时类指定的属性

    /*
    * 调用运行时类指定的结构:属性、方法、构造器
    * */
    public class ReflectionTest {
    
        @Test
        public void testField() throws NoSuchFieldException, IllegalAccessException, InstantiationException {
            Class clazz = Creat.class;
    
            //创建运行时类的对象
            Creat creat = (Creat) clazz.newInstance();
    
            //获取指定的属性 要求运行时类中声明的属性为public
            //通常不采用此方法
            Field id = clazz.getField("id");
            /*
            *设置当前属性的值
            * set():参数1:指明设置哪个对象的属性  参数2:将此属性设置为多少
            * */
            id.set(creat,12);
    
            //获取当前属性的值
            int str= (int) id.get(creat);
            System.out.println(str);
    
        }
    /*
    * 如何操作运行时类中指定的属性--需要掌握
    * */
        @Test
        public void test2() throws NoSuchFieldException, IllegalAccessException, InstantiationException {
            Class clazz = Creat.class;
    
            //创建运行时类的对象
            Creat creat = (Creat) clazz.newInstance();
    
            //1、getDeclaredField(String fieldName):获取运行时类中指定变量名的属性
            Field name = clazz.getDeclaredField("name");
    
            //2、保证当前属性可访问
            name.setAccessible(true);
    
            //3、获取、设置指定对象的此属性
            name.set(creat,"jdioasjd");
    
            String str = (String) name.get(creat);
    
            System.out.println(str);
        }
    
    }
    

    2、调用运行时类指定的方法

     /*
        * 如何操作运行时类中指定的方法
        * */
        @Test
        public void test3() throws IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException {
            Class clazz = Creat.class;
    
            //创建运行时类的对象
            Creat creat = (Creat) clazz.newInstance();
    
            //1、获取指定的某个方法
            //getDeclaredMethod():
            //  参数1:指明获取方法的名称
            //  参数2:指明获取方法的形参列表
            Method show = clazz.getDeclaredMethod("show", String.class);
            //2、保证当前方法是可执行的
            show.setAccessible(true);
            /*
            * invoke():参数1:方法的调用者  参数2:方法形参赋值的实参
            * invoke()方法的返回值即为对应类中调用的方法的返回值
            * */
            Object returnValue = show.invoke(creat, "guojia");
            System.out.println(returnValue);
    
            System.out.println("********如何调用静态犯法********");
    //        private static String abc(String name){
            Method declaredMethod = clazz.getDeclaredMethod("abc", String.class);
            declaredMethod.setAccessible(true);
            //如果调用运行时类中的方法没有返回值,则此invoke返回null
            Object o = declaredMethod.invoke(Creat.class, "调用静态方法");
            System.out.println(o);
        }
    

    7、调用运行时类指定的构造器

        /*
        * 如何调用运行时类中的指定构造器
        * */
        @Test
        public void test5() throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
            Class clazz = Creat.class;
    
            //    private Creat(String name) 调用此构造器
            /*1、获取指定的构造器
            * getDeclaredConstructor():参数:指明构造器的参数列表
            * */
            Constructor constructor = clazz.getDeclaredConstructor(String.class);
    
            //2、保证此构造器是可访问的
            constructor.setAccessible(true);
    
            //3、调用此构造器创建运行时类的对象
            Object o = constructor.newInstance("我的那么");
            System.out.println(o);
        }
    

    七、反射的应用:动态代理

    1、静态代理

    package com.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) {
            //创建被代理类对象
            NikeClothFactory nike = new NikeClothFactory();
            //创建代理类对象
            ProxyClothFactory factory = new ProxyClothFactory(nike);
    
            factory.produceCloth();
    
        }
    }
    
    

    2、动态代理

    package com.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 superMan";
        }
    
        @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 invoke = method.invoke(obj, args);
            //上述方法的返回值就作为当
            return invoke;
        }
    }
    public class ProxyTest {
        public static void main(String[] args) {
            SuperMan superMan = new SuperMan();
            //proxyInstance:代理类的对象
            Human proxyInstance = (Human) ProxyFactory.getProxyInstance(superMan);
            //当通过代理了i对象调用方法时,会自动地调用被代理类中同名的方法
            String belief = proxyInstance.getBelief();
            System.out.println(belief);
            proxyInstance.eat("四川麻辣烫");
    
    
    
        }
    
    }
    
    
  • 相关阅读:
    python之enumerate枚举 第二篇(六):enumerate枚举
    git使用学习
    Git安装
    eclipse对项目整理分类
    Java基础学习总结——Java对象的序列化和反序列化
    工作代码实例
    substring与substr
    第一个jave程序-helloworld
    UI自动化
    sikuli实例
  • 原文地址:https://www.cnblogs.com/13490-/p/15399268.html
Copyright © 2011-2022 走看看