java Reflection(反射)基础知识讲解

Posted IBIT程序猿

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了java Reflection(反射)基础知识讲解相关的知识,希望对你有一定的参考价值。

原文链接:小ben马java Reflection(反射)基础知识讲解

1.获取Class对象的方式

1.1 Class#forName

public static Class<?> forName(String className) throws ClassNotFoundException;

如果没有获取到Class对象,则抛出异常ClassNotFoundException;

eg:

Class<?> customerClazz = Class.forName("cn.xiaobenma.demo.core.reflection.VipCustomer");

1.2 某个类的.class,eg:

Class<?> customerClazz = VipCustomer.class;

1.3 某个对象的getClass(),eg:

VipCustomer customer = new VipCustomer("001", "小ben马", "10086", VipCustomer.VIP_ADVANCED);
Class<?> customerClazz = customer.getClass();

2.判断是否为某个类的实例

我们通常使用instanceof来判断对象是否为某个类的实例。同样,可以使用Class#isInstance()来判断

public native boolean isInstance(Object obj);

例子:

boolean isCustomer = customer instanceof VipCustomer;

isCustomer = VipCustomer.class.isInstance(customer);

如果person为null, 上述例子都返回false。

3. 创建实例

3.1 Class#newInstance(): 要保证能访问类的无参构造方法

public T newInstance() throws InstantiationException, IllegalAccessException;

3.2 通过Constructor#newInstance(Object ... initargs)

public T newInstance(Object ... initargs)
    throws InstantiationException, IllegalAccessException,
           IllegalArgumentException, InvocationTargetException

eg:

Constructor<VipCustomer> constructor = getVipCustomerClass().getConstructor(String.class, String.class, String.class, int.class);
        VipCustomer customer = constructor.newInstance("001", "小ben马", "10086", VipCustomer.VIP_ADVANCED);

4. 获取方法(类方法、成员方法)

4.1 Class#getMethods()

获取当前类及其父类,所有public类方法和成员方法

4.2 Class#getMethod(String name, Class<?>... parameterTypes)

通过方法名、参数类型,获取单个public类方法或者成员方法(当前类或父类定义的)

4.3 Class#getDeclaredMethods()

获取当前类(不包括超类)定义的所有类方法和成员方法

4.4 Class#getDeclaredMethod(String name, Class<?>... parameterTypes)

通过方法名、参数类型,获取单个当前类(不包括超类)定义的类方法或成员方法

5. 获取构造方法

5.1 Class#getConstructors()

获取当前类所有public构造方法

5.2 Class#getConstructor(Class<?>... parameterTypes)

根据参数类型,获取当前类单个public构造方法

5.3 Class#getDeclaredConstructors()

获取当前类所有构造方法

5.4 Class#getDeclaredConstructor(Class<?>... parameterTypes)

根据参数类型,获取当前类单个构造方法

6. 获取变量(类变量、成员变量)

6.1 Class#getFields()

获取当前类及其超类,所有public类变量和成员变量

6.2 Class#getField(String name)

通过名称,获取当前类或超类,单个public类变量或者成员变量

6.3 Class#getDeclaredFields()

获取当前类(不包括超类),所有类变量和成员变量

6.4 Class#getDeclaredField(String name)

通过名称,获取当前类(不包括超类),单个类变量或成员变量

7. 通过Method#invoke(Object obj, Object... args),调用对象的方法

eg:

Method setRank = getVipCustomerClass().getDeclaredMethod("setRank", int.class);
setRank.invoke(customer, VipCustomer.VIP_NORMAL);

8.获取和修改类变量或者成员变量的值

8.1 Field#set(Object obj, Object value)

通过对象和变量值,设置变量,eg:

Field field = getVipCustomerClass().getDeclaredField("rank");
field.set(customer, VipCustomer.VIP_ADVANCED);

8.2 Field#get(Object obj)

通过对象获取变量值,eg:

Field field = getVipCustomerClass().getDeclaredField("rank");
int rank = (int) field.get(customer);

9.动态改变方法和变量的可访问性

在使用反射获取被调用类的构造方法、方法或变量,可能对于调用类是不可访问的,如被调用类的private构造方法,private方法, private变量,会抛出IllegalAccessException
java可以通过使用AccessibleObject#setAccessible(boolean flag)改变可访问性。
ConstructorMethodField都是AccessibleObject的子类。

eg:

//在VipCustomer中定义类静态常量PRI_NO=100
Field field = getVipCustomerClass().getDeclaredField("PRI_NO");
field.setAccessible(true);
Assert.assertEquals(100, field.get(null));

//私有构造方法
Constructor<VipCustomer> constructor = getVipCustomerClass().getDeclaredConstructor();
constructor.setAccessible(true);
VipCustomer customer = constructor.newInstance();
Assert.assertNull(customer.getCustomerNo());
Assert.assertNull(customer.getName());
Assert.assertNull(customer.getMobilePhone());

//调用私有类方法
Method method = getVipCustomerClass().getDeclaredMethod("doNothingByVipCustomer");
method.setAccessible(true);
method.invoke(null);

10.利用反射创建数组

数组是比较特殊的类型。

10.1 Array#newInstance(Class<?> componentType, int length)

创建一维数组,eg:

//一维数组
Object array = Array.newInstance(String.class, 2);
Array.set(array, 0, "小ben马");
Array.set(array, 1, "xiaobenma");

Assert.assertEquals("小ben马", Array.get(array, 0));
Assert.assertEquals("xiaobenma", Array.get(array, 1));

10.2 Array#newInstance(Class<?> componentType, int... dimensions)

创建多维数组,eg:

//多维数组
//String[2][1]
Object arrays = Array.newInstance(String.class, 2, 1);

Object array0 = Array.newInstance(String.class, 1);
Array.set(array0, 0, "小ben马");
Array.set(arrays, 0, array0);

Object array1 = Array.newInstance(String.class, 1);
Array.set(array1, 0, "xiaobenma");
Array.set(arrays, 1, array1);

Assert.assertEquals("小ben马", Array.get(Array.get(arrays, 0), 0));
Assert.assertEquals("xiaobenma", Array.get(Array.get(arrays, 1), 0));

10.3 Array#get(Object array, int index)

根据数组和相关索引获取对应的值

10.4 Array#set(Object array, int index, Object value)

根据索引和相关索引,设置对应的值

11.Modifier说明

通常在类中

  • 定义构造方法格式[修饰符列表] 类名([参数列表])
  • 定义变量的格式为[修饰符列表] 返回类型 变量名称
  • 定义方法的格式为[修饰符列表] 返回类型 方法名([参数列表])

Member#getModifiers()返回一个int类型,通过解释int的值,能获取定义的修饰符列表。ConstructorMethodField都是Member的实现类。

修饰符返回的int值,需要通过Modifier解释。

其中,

  • Modifier#toString(int mod): 打印定义的所有修饰符
  • Modifier#isXXX(int mod): 判断修饰符的类型

如果你看过Modifier的源码,你会发现一个有趣的事情,修饰符是按bit位定义的,如:

 /**
 * The {@code int} value representing the {@code public}
 * modifier.
 */
public static final int PUBLIC           = 0x00000001;

/**
 * The {@code int} value representing the {@code private}
 * modifier.
 */
public static final int PRIVATE          = 0x00000002;

/**
 * The {@code int} value representing the {@code protected}
 * modifier.
 */
public static final int PROTECTED        = 0x00000004;

ps说明

  • 反射相关包java.lang.reflect
  • Proxy是反射中比较重要的应用,在后续博客单独更新。
  • 相关demo代码 core-java-learning


以上是关于java Reflection(反射)基础知识讲解的主要内容,如果未能解决你的问题,请参考以下文章

Java进阶之reflection(反射机制)——反射概念与基础

Java进阶之reflection(反射机制)——反射概念与基础

深入解析Java反射 - 基础

java反射机制

java反射

java反射