• 20220210 Java 反射基础类


    主要的相关类

    • java.lang.Class
    • java.lang.reflect.Method
    • java.lang.reflect.Field
    • java.lang.reflect.Modifier
    • java.lang.reflect.Constructor

    Class 类

    除了int等基本类型外,Java的其他类型全部都是class(包括interface)。

    如何获取一个classClass实例?有三个方法:

    • 直接通过一个class的静态变量class获取:

      Class cls = String.class;
      
    • 如果我们有一个实例变量,可以通过该实例变量提供的getClass()方法获取:

      String s = "Hello";
      Class cls = s.getClass();
      
    • 如果知道一个class的完整类名,可以通过静态方法Class.forName()获取:

      Class cls = Class.forName("java.lang.String");
      

    动态加载:JVM在执行Java程序的时候,并不是一次性把所有用到的class全部加载到内存,而是第一次需要用到class时才加载。

    /**
     * Class 类
     */
    public class ClassMain {
        public static void main(String[] args) {
            // printClassInfo("".getClass());
            // printClassInfo(Runnable.class);
            // printClassInfo(java.time.Month.class);
            // printClassInfo(String[].class);
            // printClassInfo(int.class);
    
            // getParentClassInfo();
    
            // getInterface();
    
    
            getInherit();
        }
    
        /**
         * 继承关系
         * 当我们判断一个实例是否是某个类型时,正常情况下,使用instanceof操作符
         * 如果是两个Class实例,要判断一个向上转型是否成立,可以调用isAssignableFrom():
         *
         *
         * 通过Class对象可以获取继承关系:
         * Class getSuperclass():获取父类类型;
         * Class[] getInterfaces():获取当前类实现的所有接口。
         * 通过Class对象的isAssignableFrom()方法可以判断一个向上转型是否可以实现。
         */
        private static void getInherit() {
            Object n = Integer.valueOf(123);
            boolean isDouble = n instanceof Double; // false
            boolean isInteger = n instanceof Integer; // true
            boolean isNumber = n instanceof Number; // true
            boolean isSerializable = n instanceof java.io.Serializable; // true
    
    
            // Integer i = ?
            Integer.class.isAssignableFrom(Integer.class); // true,因为Integer可以赋值给Integer
            // Number n = ?
            Number.class.isAssignableFrom(Integer.class); // true,因为Integer可以赋值给Number
            // Object o = ?
            Object.class.isAssignableFrom(Integer.class); // true,因为Integer可以赋值给Object
            // Integer i = ?
            Integer.class.isAssignableFrom(Number.class); // false,因为Number不能赋值给Integer
        }
    
    
        /**
         * 获取interface
         * 如果一个类没有实现任何interface,那么getInterfaces()返回空数组。
         */
        private static void getInterface() {
            Class s = Integer.class;
            Class[] is = s.getInterfaces();
            for (Class i : is) {
                System.out.println(i);
            }
            // interface java.lang.Comparable
        }
    
        /**
         * 获取父类的Class
         */
        private static void getParentClassInfo() {
            Class i = Integer.class;
            Class n = i.getSuperclass();
            System.out.println(n);  // class java.lang.Number
            Class o = n.getSuperclass();
            System.out.println(o);  // class java.lang.Object
            System.out.println(o.getSuperclass());  // null
        }
    
    
        static void printClassInfo(Class cls) {
            System.out.println("==============================");
            System.out.println("Class name: " + cls.getName());
            System.out.println("Canonical name: " + cls.getCanonicalName());
            System.out.println("Simple name: " + cls.getSimpleName());
            if (cls.getPackage() != null) {
                System.out.println("Package name: " + cls.getPackage().getName());
            }
            System.out.println("is interface: " + cls.isInterface());
            System.out.println("is enum: " + cls.isEnum());
            System.out.println("is array: " + cls.isArray());
            System.out.println("is primitive: " + cls.isPrimitive());
        }
    }
    

    访问字段 Field

    public class FieldMain {
        public static void main(String[] args) throws Exception {
            getFieldTest();
            getFieldDetailTest();
        }
    
        /**
         * Field getField(name):根据字段名获取某个public的field(包括父类)
         * Field getDeclaredField(name):根据字段名获取当前类的某个field(不包括父类)
         * Field[] getFields():获取所有public的field(包括父类)
         * Field[] getDeclaredFields():获取当前类的所有field(不包括父类)
         */
        private static void getFieldTest() throws Exception {
            System.out.println("=================== getFieldTest ===================");
            Class stdClass = Student.class;
    
            System.out.println(Arrays.toString(stdClass.getFields()));  // score , name
            System.out.println(Arrays.toString(stdClass.getDeclaredFields()));  // score , grade
        }
    
        private static void getFieldDetailTest() throws Exception {
            System.out.println("=================== getFieldDetailTest ===================");
            Field f = String.class.getDeclaredField("value");
            Class<?> type = f.getType();
            int m = f.getModifiers();
    
            System.out.println(f);  // private final char[] java.lang.String.value
            System.out.println(f.toGenericString());
            System.out.println(f.getName());    //
            System.out.println(type.getCanonicalName()); // class [B 表示byte[]类型
            System.out.println(Modifier.isFinal(m)); // true
            System.out.println(Modifier.isPublic(m)); // false
            System.out.println(Modifier.isProtected(m)); // false
            System.out.println(Modifier.isPrivate(m)); // true
            System.out.println(Modifier.isStatic(m)); // false
    
            // 泛型相关
            Field f2 = GenericType.class.getDeclaredField("type");
            System.out.println(f2); // java.lang.Object reflection.FieldMain$GenericType.type
            System.out.println(f2.toGenericString());   // java.lang.Object reflection.FieldMain$GenericType.type
    
            Field f3 = GenericType.class.getDeclaredField("typeList");
            System.out.println(f3); // java.util.List reflection.FieldMain$GenericType.typeList
            System.out.println(f3.toGenericString());   // java.util.List<T> reflection.FieldMain$GenericType.typeList
        }
    
        class GenericType<T>{
            T type;
            List<T> typeList;
        }
    
        class Student extends Person {
            public int score;
            private int grade;
        }
    
        class Person {
            public String name;
            private String age;
        }
    
    }
    
    public class FieldValueMain {
    
        public static void main(String[] args) throws Exception {
            Person p = new Person("Xiao Ming");
            Class c = p.getClass();
            Field f = c.getDeclaredField("name");
            f.setAccessible(true); // private 时需要加上
            Object value = f.get(p);
            System.out.println(value); // "Xiao Ming"
            f.set(p, "Xiao Hong");
            System.out.println(p.getName()); // "Xiao Hong"
        }
    }
    
    class Person {
        private String name;
    
        public Person(String name) {
            this.name = name;
        }
    
        public String getName() {
            return name;
        }
    }
    
    

    调用方法 Method

    /**
     * Method getMethod(name, Class...):获取某个public的Method(包括父类)
     * Method getDeclaredMethod(name, Class...):获取当前类的某个Method(不包括父类)
     * Method[] getMethods():获取所有public的Method(包括父类)
     * Method[] getDeclaredMethods():获取当前类的所有Method(不包括父类)
     */
    public class MethodMain {
        public static void main(String[] args) throws Exception {
            // getMethod();
            // invokeMethod();
            // invokeStaticMethod();
            // invokePrivateMethod();
            invokeMultiMethod();
        }
    
        /**
         * 调用多态方法
         */
        private static void invokeMultiMethod() throws Exception {
            // 获取Person的hello方法:
            Method h = Person.class.getMethod("hello");
            // 对Student实例调用hello方法:
            h.invoke(new Student());    // Student:hello
    
            /*
            相当于:
                Person p = new Student();
                p.hello();
             */
        }
    
        /**
         * 调用非public方法
         *
         * @throws Exception
         */
        private static void invokePrivateMethod() throws Exception {
            Person p = new Person();
            Method m = p.getClass().getDeclaredMethod("setName", String.class);
            m.setAccessible(true);
            m.invoke(p, "Bob");
            System.out.println(p.name);
        }
    
        /**
         * 通过反射调用静态方法
         *
         * @throws Exception
         */
        private static void invokeStaticMethod() throws Exception {
            // 获取Integer.parseInt(String)方法,参数为String:
            Method m = Integer.class.getMethod("parseInt", String.class);
            // 调用该静态方法并获取结果:
            Integer n = (Integer) m.invoke(null, "12345");
            // 打印调用结果:
            System.out.println(n);
        }
    
        /**
         * 通过反射调用类方法
         *
         * @throws Exception
         */
        private static void invokeMethod() throws Exception {
            // String对象:
            String s = "Hello world";
            // 获取String substring(int)方法,参数为int:
            Method m = String.class.getMethod("substring", int.class);
            // 在s对象上调用该方法并获取结果:
            String r = (String) m.invoke(s, 6);
            // 打印调用结果:
            System.out.println(r);
        }
    
        private static void getMethod() throws Exception {
            Class stdClass = Student.class;
            Method method = stdClass.getMethod("getScore", String.class);
    
            System.out.println(Arrays.toString(stdClass.getMethods())); // getScore , getName , Object.wait...
            System.out.println(Arrays.toString(stdClass.getDeclaredMethods())); // getGrade , getScore
    
            // 获取public方法getScore,参数为String:
            System.out.println(method);
            // 获取继承的public方法getName,无参数:
            System.out.println(stdClass.getMethod("getName"));
            // 获取private方法getGrade,参数为int:
            System.out.println(stdClass.getDeclaredMethod("getGrade", int.class));
    
            /**
             * getName():返回方法名称,例如:"getScore";
             * getReturnType():返回方法返回值类型,也是一个Class实例,例如:String.class;
             * getParameterTypes():返回方法的参数类型,是一个Class数组,例如:{String.class, int.class};
             * getModifiers():返回方法的修饰符,它是一个int,不同的bit表示不同的含义。
             */
            System.out.println(method.getName());
            Class<?> returnType = method.getReturnType();
            Class<?>[] parameterTypes = method.getParameterTypes();
            int modifiers = method.getModifiers();
        }
    
        static class Student extends Person {
            public void hello() {
                System.out.println("Student:hello");
            }
    
            public int getScore(String type) {
                return 99;
            }
    
            private int getGrade(int year) {
                return 1;
            }
        }
    
        static class Person {
    
            public void hello() {
                System.out.println("Person:hello");
            }
    
            private String name = "personName";
    
            private void setName(String name) {
                this.name = name;
            }
    
            public String getName() {
                return name;
            }
        }
    }
    

    调用构造方法 Constructor

    /**
     * getConstructor(Class...):获取某个public的Constructor;
     * getDeclaredConstructor(Class...):获取某个Constructor;
     * getConstructors():获取所有public的Constructor;
     * getDeclaredConstructors():获取所有Constructor。
     *
     * Constructor总是当前类定义的构造方法,和父类无关,因此不存在多态的问题
     */
    public class ConstructorMain {
        public static void main(String[] args) throws Exception {
    
            // 调用Class.newInstance()的局限是,它只能调用该类的public无参数构造方法。
            // 如果构造方法带有参数,或者不是public,就无法直接通过Class.newInstance()来调用。
            Integer integer = Integer.class.newInstance();
            System.out.println(integer);
    
            // 获取构造方法Integer(int):
            Constructor cons1 = Integer.class.getConstructor(int.class);
            // 调用构造方法:
            Integer n1 = (Integer) cons1.newInstance(123);
            System.out.println(n1);
    
            // 获取构造方法Integer(String)
            Constructor cons2 = Integer.class.getConstructor(String.class);
            Integer n2 = (Integer) cons2.newInstance("456");
            System.out.println(n2);
        }
    }
    

    动态代理

    public class ProxyMain {
        public static void main(String[] args) {
            /**
             * 在运行期动态创建一个interface实例的方法如下:
             * 1. 定义一个InvocationHandler实例,它负责实现接口的方法调用;
             * 2. 通过Proxy.newProxyInstance()创建interface实例,它需要3个参数:
             * 2.1. 使用的ClassLoader,通常就是接口类的ClassLoader;
             * 2.2. 需要实现的接口数组,至少需要传入一个接口进去;
             * 2.3. 用来处理接口方法调用的InvocationHandler实例。
             * 3. 将返回的Object强制转型为接口。
             */
            InvocationHandler handler = new InvocationHandler() {
                @Override
                public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                    System.out.println(method); // public abstract void reflection.ProxyMain$Hello.morning(java.lang.String)
                    if (method.getName().equals("morning")) {
                        System.out.println("Good morning, " + args[0]); // Good morning, Bob
                    }
                    return null;
                }
            };
            Hello hello = (Hello) Proxy.newProxyInstance(Hello.class.getClassLoader(), // 传入ClassLoader
                    new Class[]{Hello.class}, // 传入要实现的接口
                    handler); // 传入处理调用方法的InvocationHandler
            hello.morning("Bob");
        }
    
        interface Hello {
            void morning(String name);
        }
    
        /**
         * 把上面的动态代理改写为静态实现类大概长这样:
         */
        static class HelloDynamicProxy implements Hello {
            InvocationHandler handler;
    
            public HelloDynamicProxy(InvocationHandler handler) {
                this.handler = handler;
            }
    
            public void morning(String name) {
                try {
                    handler.invoke(this, Hello.class.getMethod("morning", String.class), new Object[]{name});
                } catch (Throwable throwable) {
                    throwable.printStackTrace();
                }
            }
        }
    }
    

    参考资料

  • 相关阅读:
    JS调用WebService
    C# FTP FtpWebRequest UsePassive 属性
    vs2010 rdlc .net4.0 卸载 Appdomain 时出错。 (异常来自 HRESULT:0x80131015) 解决办法
    DotNetBar RibbonControl控件office2007风格
    C# WinForm RDLC报表不预览直接连续打印
    C# 调用 WebService 连接ORACLE 11g
    C# WinForm程序打印条码 Code39码1
    RDLC报表 在WinForm里运行出现 未能加载文件或程序集microsoft.reportviewer.winforms
    C# 使用 SAP NCO3.0 调用SAP RFC函数接口
    在ui自动化中,如果有多个case在不同的class 下,要全部执行并且要求只启动一次浏览器页面,怎么处理?
  • 原文地址:https://www.cnblogs.com/huangwenjie/p/15881126.html
Copyright © 2020-2023  润新知