zoukankan      html  css  js  c++  java
  • Java反射

    反射

    反射概述:

    ​ Java中的反射(Reflection)机制就是指在运行过程中,对于任意一个类,都能够知道这个类的属性和方法,对于任意一个对象都能够调用它的任意一个属性和方法,这种动态获取信息和动态调用方法的功能被称之为Java语言的反射机制。

    反射的使用:

    获取Class对象的三种方式

    一、使用 Class.forName() 的静态方法

    Class.forName(String className)方法可以通过类或接口的名称(一个字符串或完全限定名)来获取对应的Class对象

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

    二、直接获取某个类的Class(最安全,性能最好)

    Class<String> cls = String.class;
    

    三、调用某个对象的getClass()方法

    Class<String> cls = str.getClass();
    

    判断是否为某个类的实例

    instanceof关键字来判断是否为某个类的实例。同时我们也可以借助反射中Class对象的*isInstance()*方法来判断是否为某个类的实例,它是一个Native方法:

    public native boolean isInstance(Object obj);
    

    创建实例

    通过反射来创建对象有两种方式

    使用Class对象的newInstance()方法

    Class<?> c = String.class;
    Object str = c.newInstance();
    

    通过Class对象获取指定的Constructor对象,再调用Constructor对象的newInstance()方法

    // 获取String所对应的Class对象
    Class<?> c = String.class;
    // 获取String类带一个String参数的构造器
    Constructor constructor = c.getConstructor(String.class);
    // 根据构造器创建实例
    Object obj = constructor.newInstance("23333");
    System.out.println(obj);
    

    获取方法

    获取某个Class对象的方法集合,主要有以下几个方法:

    • getDeclaredMethods()方法返回类或接口声明的所有方法,包括公共、保护、默认(包)访问和私有方法,但不包括继承的方法。
    public Method[] getDeclaredMethods() throws SecurityException
    
    • getMethods()方法返回某个类的所有公用(public)方法,包括其继承类的公用方法。
    public Method[] getMethods() throws SecurityException
    
    • getMethod()方法返回一个特定的方法,其中第一个参数为方法名称,后面的参数为方法的参数对应Class的对象。
    public Method getMethod(String name, Class<?>... parameterTypes)
    

    测试:

    public class Test {
        public static void main(String[] args) throws Exception {
            //通过Class.forName来创建反射对象
            Class<?> user = Class.forName("com.ysh.fanshe.User");
            //通过反射对象来获取User实例,调用了无参构造
            Object o = user.newInstance();
            //返回这个类所有的public方法,包括继承类的
            Method[] methods = user.getMethods();
            for (Method method : methods) {
                //获取方法名
                System.out.println(method.getName());
            }
            System.out.println("===========================");
            //获取User类所有方法,不包括继承的
            Method[] declaredMethods = user.getDeclaredMethods();
            for (Method declaredMethod : declaredMethods) {
                //遍历所有方法名
                System.out.println(declaredMethod.getName());
            }
            System.out.println("==========================");
            //根据方法名(第一个参数)获取,后面的参数为参数列表中类的Class对象,是一个可变参数
            Method add = user.getMethod("add", String.class);
            System.out.println(add.getName());
    		//获取私有的
            Method update = user.getDeclaredMethod("update");
            System.out.println(update.getName());
        }
    }
    class User{
        public String add(String name){
            System.out.println("添加成功");
            return name;
        }
        public void delete(){
            System.out.println("删除方法");
        }
        private void update(){
            System.out.println("我是私有方法");
        }
    }
    

    获取类变量

    获取的方法同Method相似,主要是这几个方法,在此不再赘述:

    • Field getField(String name)访问公有的成员变量。
    • Field[] getDeclaredFields():所有已声明的成员变量。但不能得到其父类的成员变量。
    • Field[] getFields()Field[] getDeclaredFields()用法同上。
    		//获取属性,私有的,其他同理
            Field name = user.getDeclaredField("name");
            //getType获取该属性的类型,返回的是一个Class对象
            //SimpleName获取一个类的简单名称,不带包路径的名
            System.out.println(name.getType().getSimpleName());
            //getName获取该属性的变量名,返回String
            System.out.println(name.getName());
            //getModifiers获取属性的修饰符,通过Modifier类的静态方法toString来转换为字符串
            String s = Modifier.toString(name.getModifiers());
            System.out.println(s);
    

    调用方法(重点)

    当我们从类中获取了一个方法后,我们就可以用invoke()方法来调用这个方法。invoke方法的原型为:

    public Object invoke(Object obj, Object... args) throws IllegalAccessException, IllegalArgumentException,
     InvocationTargetException
    
    	   //通过Class.forName来创建反射对象
            Class<?> user = Class.forName("com.ysh.fanshe.User");
            //通过反射对象来获取User实例,调用了无参构造
            Object o = user.newInstance();
    	   //根据方法名(第一个参数)获取,后面的参数为参数列表中类的Class对象,是一个可变参数
            Method add = user.getMethod("add", String.class);
            System.out.println(add.getName());
            //invoke调用方法,第一个参数为对象,第二个参数为传入的参数,返回值为该方法的返回值
            Object a = add.invoke(o, "易水寒");
            System.out.println(a);
    

    利用反射创建数组

    数组在Java里是比较特殊的一种类型,它可以赋值给一个Object Reference。下面我们看一看利用反射创建数组的例子:

    public static void TestArray() throws ClassNotFoundException {
        // 使用`java.lang.reflect.Array`反射创建长度为25的字符串数组.
        Class<?> cls = Class.forName("java.lang.String");
        Object array = Array.newInstance(cls, 25);
        // 往数组里添加内容
        Array.set(array,0, "hello");
        Array.set(array,1, "Java");
        Array.set(array,2, "Go");
        Array.set(array,3, "Scala");
        Array.set(array,4, "Clojure");
        // 获取某一项的内容
        System.out.println(Array.get(array, 3));
    }
    

    使用反射获取信息

    ​ Class类提供了大量的实例方法来获取该Class对象所对应的详细信息,Class类大致包含如下方法,其中每个方法都包含多个重载版本,因此我们只是做简单的介绍,详细请参考JDK文档

    1、获取类内信息

    • 构造器: Constructor<T> getConstructor(Class<?>... parameterTypes)
    • 包含的方法: Method getMethod(String name, Class<?>... parameterTypes)
    • 包含的属性: Field getField(String name)
    • 包含的Annotation: <A extends Annotation> A getAnnotation(Class<A> annotationClass)
    • 内部类: Class<?>[] getDeclaredClasses()
    • 外部类: Class<?> getDeclaringClass()
    • 所实现的接口: Class<?>[] getInterfaces()
    • 修饰符: int getModifiers()
    • 所在包: Package getPackage()
    • 类名: String getName()
    • 简称: String getSimpleName()

    2、判断类本身信息的方法

    • 是否注解类型: boolean isAnnotation()
    • 是否使用了该Annotation修饰: boolean isAnnotationPresent(Class<? extends Annotation> annotationClass)
    • 是否匿名类: boolean isAnonymousClass()
    • 是否数组: boolean isArray()
    • 是否枚举: boolean isEnum()
    • 是否原始类型: boolean isPrimitive()
    • 是否接口: boolean isInterface()
    • obj是否是该Class的实例: boolean isInstance(Object obj)

    3、使用反射获取泛型信息

    ​ 为了通过反射操作泛型以迎合实际开发的需要, Java新增了java.lang.reflect.ParameterizedTypejava.lang.reflect.GenericArrayTypejava.lang.reflect.TypeVariablejava.lang.reflect.WildcardType几种类型来代表不能归一到Class类型但是又和原始类型同样重要的类型。

    • ParameterizedType: 一种参数化类型, 比如Collection
    • GenericArrayType: 一种元素类型是参数化类型或者类型变量的数组类型
    • TypeVariable: 各种类型变量的公共接口
    • WildcardType: 一种通配符类型表达式, 如?? extends Number? super Integer

    代码示例:

    public class Client {
     
        private Map<String, Object> objectMap;
     
        public void test(Map<String, User> map, String string) {
        }
     
        public Map<User, Bean> test() {
            return null;
        }
     
        /**
         * 测试属性类型
         *
         * @throws NoSuchFieldException
         */
        @Test
        public void testFieldType() throws NoSuchFieldException {
            Field field = Client.class.getDeclaredField("objectMap");
            Type gType = field.getGenericType();
            // 打印type与generic type的区别
            System.out.println(field.getType());
            System.out.println(gType);
            System.out.println("**************");
            if (gType instanceof ParameterizedType) {
                ParameterizedType pType = (ParameterizedType) gType;
                Type[] types = pType.getActualTypeArguments();
                for (Type type : types) {
                    System.out.println(type.toString());
                }
            }
        }
     
        /**
         * 测试参数类型
         *
         * @throws NoSuchMethodException
         */
        @Test
        public void testParamType() throws NoSuchMethodException {
            Method testMethod = Client.class.getMethod("test", Map.class, String.class);
            Type[] parameterTypes = testMethod.getGenericParameterTypes();
            for (Type type : parameterTypes) {
                System.out.println("type -> " + type);
                if (type instanceof ParameterizedType) {
                    Type[] actualTypes = ((ParameterizedType) type).getActualTypeArguments();
                    for (Type actualType : actualTypes) {
                        System.out.println("	actual type -> " + actualType);
                    }
                }
            }
        }
     
        /**
         * 测试返回值类型
         *
         * @throws NoSuchMethodException
         */
        @Test
        public void testReturnType() throws NoSuchMethodException {
            Method testMethod = Client.class.getMethod("test");
            Type returnType = testMethod.getGenericReturnType();
            System.out.println("return type -> " + returnType);
            if (returnType instanceof ParameterizedType) {
                Type[] actualTypes = ((ParameterizedType) returnType).getActualTypeArguments();
                for (Type actualType : actualTypes) {
                    System.out.println("	actual type -> " + actualType);
                }
            }
        }
    }
    
    我等的船还不来
  • 相关阅读:
    配置PL/SQL Developer连接Oracle数据库
    解决RPC failed; HTTP 413 curl 22 The requested URL returned error: 413 Request Entity Too Large问题
    解决java.lang.IllegalArgumentException: No converter found for return value of type: class java.util.ArrayList问题
    解决spring mybatis 整合后mapper接口注入失败
    如何解决Failed to start component [StandardEngine[Catalina].StandardHost[127.0.0.1].StandardContext[]]问题
    五毛的cocos2d-x学习笔记05-场景与场景动画,动作
    五毛的cocos2d-x学习笔记04-触摸点
    五毛的cocos2d-x学习笔记03-控件
    五毛的cocos2d-x学习笔记02-基本项目源码分析
    五毛的cocos2d-x学习笔记01-创建项目
  • 原文地址:https://www.cnblogs.com/lxs1204/p/14372656.html
Copyright © 2011-2022 走看看