Java反射详解

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

内容简介: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


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

查看所有标签

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

Big Java Late Objects

Big Java Late Objects

Horstmann, Cay S. / 2012-2 / 896.00元

The introductory programming course is difficult. Many students fail to succeed or have trouble in the course because they don't understand the material and do not practice programming sufficiently. ......一起来看看 《Big Java Late Objects》 这本书的介绍吧!

JS 压缩/解压工具
JS 压缩/解压工具

在线压缩/解压 JS 代码

XML、JSON 在线转换
XML、JSON 在线转换

在线XML、JSON转换工具

HEX HSV 转换工具
HEX HSV 转换工具

HEX HSV 互换工具