Java反射详解

栏目: Java · 发布时间: 6年前

内容简介:Java反射详解

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

获得Class对象

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

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

class Item {
    publicstaticvoidmain(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 {

    publicstaticvoidmain(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 {

    publicvoidtest(String string) {
        System.out.println(string);
    }

    publicstaticvoidmain(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 {

    publicvoidtest() {
        System.out.println("Hello World");
    }

    publicstaticvoidmain(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 {

    privatevoidtest(String string) {
        System.out.println(string);
    }
}

public class Main {
    publicstaticvoidmain(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 {
    publicstaticvoidmain(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;
    
    publicstaticvoidmain(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;
    }

    publicstaticvoidmain(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;
    }

    publicstaticvoidmain(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);
            }
        }
    }
}

本文永久更新链接地址 http://www.linuxidc.com/Linux/2018-01/150359.htm


以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

百面机器学习

百面机器学习

诸葛越、葫芦娃 / 人民邮电出版社 / 2018-8-1 / 89.00元

人工智能领域正在以超乎人们想象的速度发展,本书赶在人工智能彻底占领世界之前完成编写,实属万幸。 书中收录了超过100道机器学习算法工程师的面试题目和解答,其中大部分源于Hulu算法研究岗位的真实场景。本书从日常工作、生活中各种有趣的现象出发,不仅囊括了机器学习的基本知识 ,而且还包含了成为出众算法工程师的相关技能,更重要的是凝聚了笔者对人工智能领域的一颗热忱之心,旨在培养读者发现问题、解决问......一起来看看 《百面机器学习》 这本书的介绍吧!

在线进制转换器
在线进制转换器

各进制数互转换器

URL 编码/解码
URL 编码/解码

URL 编码/解码

html转js在线工具
html转js在线工具

html转js在线工具