• Java反射


    反射是指程序在运行时能够获取自身的信息. Java的反射机制将类和方法封装为对象, 允许程序动态的创建对象或调用方法.

    获得Class对象

    java.lang.Class是反射机制的核心封装类, 通常有三种方法可以获得类的Class对象.

    为了便于说明创建一个Item类:

    class Item {
        public static void main(String[] args) {
            Item item = new Item();
        } 
    }
    
    • Class.forName("Item"): 根据目标类的名称获得Class对象的静态方法.

    • Item.class: 通过静态属性获得Class对象

    • item.getClass(): 通过实例方法获得Class对象

    通过Class对象可以访问类的元信息:

    • String getName(): 获得包含包名在内的完整类名
    • String getSimpleName(): 获得不含包名的简单类名
    • Package getPackage(): 获得包的封装对象
    • Class getSuperclass(): 获得父类的Class对象
    • Class[] getInterfaces(): 获得所有实现接口的Class对象

    获得构造器

    通过Class对象调用默认构造器进行实例化:

    public class Main {
    
    	public static void main(String[] args)
    			throws InstantiationException, IllegalAccessException {
    		Class clazz = MyClass.class;
    		MyClass obj = (MyClass) clazz.newInstance();
    		System.out.println(obj.i);
    	}
    }
    

    不过这样只能调用默认构造器, 若要使用其它构造器实例化则需要先获得构造器对象:

    • Constructor clazz.getConstructor(Class[]): 根据参数获得public构造器对象.

    • Constructor clazz.getDeclaredConstructor(Class[]): 根据参数获得构造器对象, 包括public, default, protected, private.

    也可以通过Class对象获得构造器的列表:

    • Constructor[] clazz.getConstructors(): 获得所有public构造器对象.
    • Constructor[] clazz.getDeclaredConstructors(): 获得所有构造器对象, 包括public, default, protected, private.

    Constructor.newInstance()方法可以用于实例化类. 示例:

    Constructor constructor = MyClass.class.getConstructor(String.class);
    MyClass obj = (MyClass)constructor.newInstance("abc");
    

    获得方法

    可以同通过Class对象获得Method对象访问类的方法:

    public class Item {
    
        public  void test(String string) {
            System.out.println(string);
        }
    
        public static void main(String[] args) throws Exception {
            Item item = new Item();
            Method method = Item.class.getMethod("test", String.class);
            method.invoke(item, "Hello World");
        }
    }
    

    getMethod()第一个参数为方法的名称, 后面的可变参数表示目标方法的参数表. 两者共同标记类中的一个方法.

    invoke()方法第一个参数为调用方法的实例, 后面为方法的实参表.

    访问无参数的方法也很简单:

    public class Item {
    
        public  void test() {
            System.out.println("Hello World");
        }
    
        public static void main(String[] args) throws Exception {
            Item item = new Item();
            Method method = Item.class.getMethod("test", null);
            method.invoke(item);
        }
    }
    

    有两个方法用于获得方法:

    • Method getMethod(name, clazz...): 根据名称和参数表获得public方法, 包括继承自父类的方法.

    • Method getDeclaredMethod(name, clazz...): 根据名称和参数表获得方法, 包括继承自父类的方法. 包括public, default, protected, private.

    类似地, 有两个方法用于获得方法列表:

    • Method[] getMethods(): 获得所有public方法
    • Method[] getDeclaredMethods(): 获得所有方法

    int Method.getModifiers()用于获得public, static等修饰符. 修饰符由标志位(BitSet)标示, 被转换成int返回.

    可以使用java.lang.reflect.Modifier检查标志符类型:

    Modifier.isAbstract(int modifiers);
    Modifier.isFinal(int modifiers);
    Modifier.isInterface(int modifiers);
    Modifier.isNative(int modifiers);
    Modifier.isPrivate(int modifiers);
    Modifier.isProtected(int modifiers);
    Modifier.isPublic(int modifiers);
    Modifier.isStatic(int modifiers);
    Modifier.isStrict(int modifiers);
    Modifier.isSynchronized(int modifiers);
    Modifier.isTransient(int modifiers);
    Modifier.isVolatile(int modifiers);
    

    直接调用私有方法Method对象的invoke方法时会抛出IllegalAccessException异常, 需要先调用method.setAccessible(true):

    class Item {
    
        private void test(String string) {
            System.out.println(string);
        }
    }
    
    public class Main {
        public static void main(String[] args) throws Exception {
            Item item = new Item();
            Method method = Item.class.getDeclaredMethod("test", String.class);
            method.setAccessible(true); // 未加此行会抛出IllegalAccessException
            method.invoke(item, "Hello World");
        }
    }
    

    获得域

    访问域与访问方法非常类似:

    • Field getField(name): 根据名称获得域, 包括继承自父类的方法.

    • Field getDeclaredField(name): 根据名称获得域, 包括继承自父类的域. 包括public, default, protected, private.

    • Field[] getFields(): 获得所有public

    • Field[] getDeclaredFields(): 获得所有域

    访问私有域同样需要setAccessible(true).

    Field对象可以访问或修改域:

    class Item {
        private String msg;
    }
    
    public class Main {
        public static void main(String[] args) throws Exception {
            Item item = new Item();
            Field field = Item.class.getDeclaredField("msg");
            field.setAccessible(true);
            field.set(item, "Hello World");
            System.out.println((String)field.get(item));
        }
    }
    

    反射与泛型

    Java的反射机制允许在运行时获得泛型参数, 需要获得泛型参数的场景有:

    • 获得泛型域的类型, 以进行访问或设置

    • 获得泛型方法(构造器)的参数类型, 以进行调用

    • 获得泛型方法的返回值类型

    java.lang.reflect.Type接口用于描述泛型参数, Type接口的唯一实现是Class类.

    获得域的类型:

    public class Item {
    
        public List<String> list;
        
        public static void main(String[] args) throws Exception {
            Field field = Item.class.getField("list");
            Type type = field.getGenericType();
            if (type instanceof ParameterizedType) {
                ParameterizedType paramType = (ParameterizedType) type;
                Type[] typeArgs = paramType.getActualTypeArguments();
                for(Type typeArg : typeArgs){
                    Class typeArgClass = (Class) typeArg;
                    System.out.println(typeArgClass);
                }
            }
        }
    }
    

    获得泛型方法参数类型:

    public class Item {
    
        public List<String> list;
    
        public List<String> getList() {
            return list;
        }
    
        public static void main(String[] args) throws Exception {
            Method method = Item.class.getMethod("getList", null);
            Type type = method.getGenericReturnType();
            if (type instanceof ParameterizedType) {
                ParameterizedType paramType = (ParameterizedType) type;
                Type[] typeArgs = paramType.getActualTypeArguments();
                for(Type typeArg : typeArgs){
                    Class typeArgClass = (Class) typeArg;
                    System.out.println(typeArgClass);
                }
            }
        }
    }
    

    获得泛型方法的返回值类型:

    public class Item {
    
        public List<String> list;
    
        public List<String> getList() {
            return list;
        }
    
        public static void main(String[] args) throws Exception {
            Method method = Item.class.getMethod("getList", null);
            Type type = method.getGenericReturnType();
            if (type instanceof ParameterizedType) {
                ParameterizedType paramType = (ParameterizedType) type;
                Type[] typeArgs = paramType.getActualTypeArguments();
                for(Type typeArg : typeArgs){
                    Class typeArgClass = (Class) typeArg;
                    System.out.println(typeArgClass);
                }
            }
        }
    }
    
  • 相关阅读:
    3.17爸爸要回去了(之十一)
    爸爸丢了 (2013.3.10,确诊五天后,之十)
    Polyline转Polygon
    将一个应用程序添加做成windows服务
    找个输入IPoint在某个FeatureClass上距离最近的要素
    线程间操作无效: 从不是创建控件“label4”的线程访问它。
    删除文件夹下的文件和文件夹
    int组成时间值
    CRONTAB
    NFS
  • 原文地址:https://www.cnblogs.com/Finley/p/7788851.html
Copyright © 2020-2023  润新知