我们来看看 Class 的重要方法, 为了方便起见, 我们先创建一些类和接口.
- package com.byron4j.hightLevel.reflection;
- public interface BaseInterface {
- public int interfaceInt=0;
- void method1();
- int method2(String str);
- }
- package com.byron4j.hightLevel.reflection;
- public class BaseClass {
- public int baseInt;
- private static void method3(){
- System.out.println("Method3");
- }
- public int method4(){
- System.out.println("Method4");
- return 0;
- }
- public static int method5(){
- System.out.println("Method5");
- return 0;
- }
- void method6(){
- System.out.println("Method6");
- }
- // piblic 的内部类
- public class BaseClassInnerClass{}
- // public 的枚举
- public enum BaseClassMemberEnum{}
- }
- package com.byron4j.hightLevel.reflection;
- public class ConcreteClass extends BaseClass implements BaseInterface{
- public int publicInt;
- private String privateString="private string";
- protected boolean protectedBoolean;
- Object defaultObject;
- public ConcreteClass(int i){
- this.publicInt=i;
- }
- @Override
- public void method1() {
- System.out.println("Method1 impl.");
- }
- @Override
- public int method2(String str) {
- System.out.println("Method2 impl.");
- return 0;
- }
- @Override
- public int method4(){
- System.out.println("Method4 overriden.");
- return 0;
- }
- public int method5(int i){
- System.out.println("Method4 overriden.");
- return 0;
- }
- // inner classes
- public class ConcreteClassPublicClass{}
- private class ConcreteClassPrivateClass{}
- protected class ConcreteClassProtectedClass{}
- class ConcreteClassDefaultClass{}
- //member enum
- enum ConcreteClassDefaultEnum{}
- public enum ConcreteClassPublicEnum{}
- //member interface
- public interface ConcreteClassPublicInterface{}
- }
下面来看看使用反射的常用方法.
获得 Class 对象
我们可以通过三种方式获取对象的 Class 实例:
通过静态变量 class
使用示例的 getClass()方法
java.lang.Class.forName(String 完整的类名), 完整的类名包含包名.
原始类型的 class, 包装类型的 TYPE 均可以获得 Class 对象.
- package com.byron4j.hightLevel.reflection;
- public class ReflectionDemo {
- public static void main(String[] args) throws Exception{
- // 方式一: 通过累的静态变量 class 获取 Class 对象
- Class concreteClass = ConcreteClass.class;
- // 方式二: 通过实例的 getClass()方法获取 Class 对象
- concreteClass = new ConcreteClass(7).getClass();
- // 方式三:
- concreteClass = Class.forName("com.byron4j.hightLevel.reflection.ConcreteClass");
- // 打印类相关信息
- System.out.println(concreteClass.getCanonicalName());
- System.out.println(concreteClass.getName());
- /*++++++++++++++++++++++++++++++++++++++++++++++++
- * 原始类型的 class, 包装类型的 TYPE
- * +++++++++++++++++++++++++++++++++++++++++++++++
- */
- Class primative = boolean.class;
- System.out.println(primative.getCanonicalName());
- Class doubleClass = Double.TYPE;
- System.out.println(doubleClass.getName());
- // 数组类型的 class 示例
- Class<?> arrayClass = Class.forName("[D");
- System.out.println(arrayClass.getCanonicalName());
- arrayClass = Class.forName("[B");
- System.out.println(arrayClass.getCanonicalName());
- arrayClass = Class.forName("[S");
- System.out.println(arrayClass.getCanonicalName());
- arrayClass = Class.forName("[C");
- System.out.println(arrayClass.getCanonicalName());
- arrayClass = Class.forName("[F");
- System.out.println(arrayClass.getCanonicalName());
- }
- }
输出如下所示:
- com.byron4j.hightLevel.reflection.ConcreteClass
- com.byron4j.hightLevel.reflection.ConcreteClass
- boolean
- double
- double[]
- byte[]
- short[]
- char[]
- float[]
Class 的 getCanonicalName()方法返回类的名称. 在泛型中使用 java.lang.Class, 可以帮助框架获取子类.
获取超类 Super Class
getSuperclass()方法, 返回类的超类 (基类, 父类) 的 class 实例, 如果该类是 java.lang.Object, 原始类型, 接口则返回 null. 如果该 class 是数组形式, 则该方法返回 java.lang.Object.
- Class<?> superClass = Class.forName("com.byron4j.hightLevel.reflection.ConcreteClass").getSuperclass();
- System.out.println(superClass);
- System.out.println(Object.class.getSuperclass());
- System.out.println(String[][].class.getSuperclass());
输入如下:
- class com.byron4j.hightLevel.reflection.BaseClass
- null
- class java.lang.Object
获取公有的 class
Class 的 getClasses()方法可以获取 class 的所有继承的超类, 接口和自己定义的公有类, 接口, 枚举等的数组形式.
- Class[] classARR = concreteClass.getClasses();
- System.out.println(Arrays.toString(classARR));
输出:
- [class com.byron4j.hightLevel.reflection.ConcreteClass$ConcreteClassPublicClass,
- class com.byron4j.hightLevel.reflection.ConcreteClass$ConcreteClassPublicEnum,
- interface com.byron4j.hightLevel.reflection.ConcreteClass$ConcreteClassPublicInterface,
- class com.byron4j.hightLevel.reflection.BaseClass$BaseClassInnerClass,
- class com.byron4j.hightLevel.reflection.BaseClass$BaseClassMemberEnum]
获取自身声明的类
getDeclaredClasses()获取当前类型自身定义的所有类, 接口, 并不包含从父类继承过来的来, 接口.
- Class[] declareClassARR = concreteClass.getDeclaredClasses();
- System.out.println("Arrays.toString(declareClassARR));
输出:
- [class com.byron4j.hightLevel.reflection.ConcreteClass$ConcreteClassDefaultClass,
- class com.byron4j.hightLevel.reflection.ConcreteClass$ConcreteClassDefaultEnum,
- class com.byron4j.hightLevel.reflection.ConcreteClass$ConcreteClassPrivateClass,
- class com.byron4j.hightLevel.reflection.ConcreteClass$ConcreteClassProtectedClass,
- class com.byron4j.hightLevel.reflection.ConcreteClass$ConcreteClassPublicClass,
- class com.byron4j.hightLevel.reflection.ConcreteClass$ConcreteClassPublicEnum,
- interface com.byron4j.hightLevel.reflection.ConcreteClass$ConcreteClassPublicInterface]
获取定义该 class 的类
class.getDeclaringClass()获取定义 class 的类. 如果该类不是任何类或接口的成员, 则返回 null.
- /**================================================
- * getDeclaringClass
- * ================================================
- */
- System.out.println(BaseClassInnerClass.class.getDeclaringClass());
- System.out.println(Double.TYPE.getDeclaringClass());
该类 BaseClassInnerClass 是在 BaseClass 中定义的, 于是输出:
- class com.byron4j.hightLevel.reflection.BaseClass
- null
获取包名
getPackage()方法获取包的 class 实例.
- /*===========================================
- * getPackage()
- * ==========================================
- */
- System.out.println(concreteClass.getPackage().getName());
输出:
com.byron4j.hightLevel.reflection
获取类的修饰符
getModifiers()方法可以获取 class 实例的访问修饰符的个数. java.lang.reflect.Modifier.toString()可以获取 class 的修饰符的字符串形式.
- /*===========================================
- * getModifiers(),Modifier.toString()
- * ==========================================
- */
- System.out.println(concreteClass.getModifiers());
- System.out.println(Modifier.toString(concreteClass.getModifiers()));
输出:
1
public
获取类型参数
getTypeParameters()方法获取 class 的类型声明参数, 如果有的话. 比如集合框架的接口均制定了泛型.
- Arrays.asList(Class.forName("java.util.Map").getTypeParameters()).forEach(
- s -> { System.out.println(s); }
- );
输出:
K V
获取 class 实现的接口
getGenericInterfaces()可以获取 class 已经实现的接口的数组形式, 并包含泛型接口. getInterfaces()方法会返回所有实现的接口, 但是不包含泛型接口.
- /**=============================================
- * getGenericInterfaces(),getInterfaces()
- * =============================================
- */
- Arrays.asList(concreteClass.getInterfaces()).forEach(
- s -> { System.out.println("com.byron4j.hightLevel.reflection.ConcreteClass 实现的接口:" + s); }
- );
- System.out.println("========================================");
- Arrays.asList(concreteClass.getGenericInterfaces()).forEach(
- s -> { System.out.println("com.byron4j.hightLevel.reflection.ConcreteClass 实现的接口:" + s); }
- );
- System.out.println("========================================");
- System.out.println("========================================");
- Arrays.asList(Class.forName("java.util.ArrayList").getInterfaces()).forEach(
- s -> { System.out.println("java.util.ArrayList 实现的接口:" + s); }
- );
- System.out.println("========================================");
- Arrays.asList(Class.forName("java.util.ArrayList").getGenericInterfaces()).forEach(
- s -> { System.out.println("java.util.ArrayList 实现的接口:" + s); }
- );
输出:
com.byron4j.hightLevel.reflection.ConcreteClass 实现的接口: interface com.byron4j.hightLevel.reflection.BaseInterface
========================================
com.byron4j.hightLevel.reflection.ConcreteClass 实现的接口: interface com.byron4j.hightLevel.reflection.BaseInterface
- ========================================
- ========================================
java.util.ArrayList 实现的接口: interface java.util.List
java.util.ArrayList 实现的接口: interface java.util.RandomAccess
java.util.ArrayList 实现的接口: interface java.lang.Cloneable
java.util.ArrayList 实现的接口: interface java.io.Serializable
========================================
java.util.ArrayList 实现的接口: java.util.List<E>
java.util.ArrayList 实现的接口: interface java.util.RandomAccess
java.util.ArrayList 实现的接口: interface java.lang.Cloneable
java.util.ArrayList 实现的接口: interface java.io.Serializable
获取所有的 public 方法
getMethods()方法可以获取所有的 public 方法, 包含父类, 接口中继承来的 public 方法.
- /**=============================================
- * getMethods()
- * =============================================
- */
- System.out.println("========================================");
- Arrays.asList(concreteClass.getMethods()).forEach(
- s -> { System.out.println("public 类型的方法:" + s); }
- );
输出:
public 类型的方法: public void com.byron4j.hightLevel.reflection.ConcreteClass.method1()
public 类型的方法: public int com.byron4j.hightLevel.reflection.ConcreteClass.method2(java.lang.String)
public 类型的方法: public int com.byron4j.hightLevel.reflection.ConcreteClass.method4()
public 类型的方法: public int com.byron4j.hightLevel.reflection.ConcreteClass.method5(int)
public 类型的方法: public static int com.byron4j.hightLevel.reflection.BaseClass.method5()
public 类型的方法: public final void java.lang.Object.wait() throws java.lang.InterruptedException
public 类型的方法: public final void java.lang.Object.wait(long,int) throws java.lang.InterruptedException
public 类型的方法: public final native void java.lang.Object.wait(long) throws java.lang.InterruptedException
public 类型的方法: public boolean java.lang.Object.equals(java.lang.Object)
public 类型的方法: public java.lang.String java.lang.Object.toString()
public 类型的方法: public native int java.lang.Object.hashCode()
public 类型的方法: public final native java.lang.Class java.lang.Object.getClass()
public 类型的方法: public final native void java.lang.Object.notify()
public 类型的方法: public final native void java.lang.Object.notifyAll()
获取 class 的所有 public 构造器
getConstructors()方法能够获取所有的 public 类型构造器
- /**=============================================
- * getConstructors()
- * =============================================
- */
- System.out.println("========================================");
- Arrays.asList(concreteClass.getConstructors()).forEach(
- s -> { System.out.println("public 类型的构造器:" + s); }
- );
输出:
public 类型的构造器: public com.byron4j.hightLevel.reflection.ConcreteClass(int)
获取所有的 public 属性(成员变量)
getFields()方法可以获取所有的 public 属性. 包含父类, 接口中的属性.
- /**=============================================
- * getFields()
- * =============================================
- */
- System.out.println("========================================");
- Arrays.asList(concreteClass.getFields()).forEach(
- s -> { System.out.println("public 类型的属性:" + s); }
- );
输出:
public 类型的属性: public int com.byron4j.hightLevel.reflection.ConcreteClass.publicInt
public 类型的属性: public static final int com.byron4j.hightLevel.reflection.BaseInterface.interfaceInt
public 类型的属性: public int com.byron4j.hightLevel.reflection.BaseClass.baseInt
获取所有的注解
getAnnotations()方法可以获取所有的注解. 但是只有保留策略为 RUNTIME 的注解.
我们给 类加上注解 @Deprecated.
- @Deprecated
- public class ConcreteClass extends BaseClass implements BaseInterface{...}
- /////////////////////////////////////
- /**=============================================
- * getAnnotations()
- * =============================================
- */
- System.out.println("========================================");
- Arrays.asList(concreteClass.getAnnotations()).forEach(
- s -> { System.out.println("注解:" + s); }
- );
输出:
注解:@java.lang.Deprecated()
反射在属性 (成员变量) 中的应用
反射 API 提供了几个方法可以在运行时分解类的成员变量以及设置其值.
获取 public 属性
除了前面的 getFields()方法能获取全部 public 属性之外, 还提供了一个获取指定属性名称的方法 getField(). 这个方法会在该 class-->接口 -->父类的顺序寻找指定的属性.
场景一: 我们在 ConcreteClass 类, BaseClass 类, BaseInterface 接口分别增加一个属性: public String name = "currClass---NAME";
- public String name = "superClass---NAME";
- public String name = "superInterface---NAME";
- System.out.println(concreteClass.getField("name"));
输出为:
public java.lang.String com.byron4j.hightLevel.reflection.ConcreteClass.name
场景二: 我们在 BaseClass 类, BaseInterface 接口分别增加一个属性: public String name = "superClass---NAME";
public String name = "superInterface---NAME";
这时候获取的属性 name 是接口中的属性:
public static final java.lang.String com.byron4j.hightLevel.reflection.BaseInterface.name
场景三: 我们仅仅在 BaseClass 类增加一个属性: public String name = "superClass---NAME";
这时候获取的属性 name 是父类中的属性:
public java.lang.String com.byron4j.hightLevel.reflection.BaseClass.name
如果是获取不存在的属性, 则出现异常:
System.out.println(concreteClass.getField("hello"));
输出:
java.lang.NoSuchFieldException: hello
获取声明属性的类型
- try {
- System.out.println( concreteClass.getField("interfaceInt").getDeclaringClass() );
- } catch (NoSuchFieldException | SecurityException e) {
- e.printStackTrace();
- }
输出:
interface com.byron4j.hightLevel.reflection.BaseInterface
获取属性的类型
getType()方法返回属性的类型的 class 实例.
System.out.println(concreteClass.getField("interfaceInt").getType().getCanonicalName());
输出:
int
Get/Set public 类型的属性值
Field.get(Object) 获取该属性的值.
- Field field = concreteClass.getField("publicInt");
- System.out.println("属性的类型:"+field.getType());
- ConcreteClass obj= new ConcreteClass(7);
- System.out.println("获取属性值:" + field.get(obj));
- field.set(obj, 77);
- System.out.println("获取属性值:" + field.get(obj));
输出:
属性的类型: int 获取属性值: 7 获取属性值: 77
Field.get()返回的是一个 Object 类型, 如果是原始类型则返回其包装类型. 如果是 final 属性, set() 方法抛出 java.lang.IllegalAccessException.
Get/Set private 类型的属性值
java 中在类之外是不能访问 private 变量的. 但是通过反射可以关闭检查访问修饰符的机制.
- Field privateField = concreteClass.getDeclaredField("privateString");
- System.out.println(privateField.get(obj));
输出, 不能访问 private 的属性:
java.lang.IllegalAccessException: Class com.byron4j.hightLevel.reflection.ReflectionDemo2 can not access a member of class com.byron4j.hightLevel.reflection.ConcreteClass with modifiers "private"
设置可访问机制 Field.setAccessible(true);:
- Field privateField = concreteClass.getDeclaredField("privateString");
- privateField.setAccessible(true);
- System.out.println(privateField.get(obj));
- privateField.set(obj, "新的私有属性值[value]");
- System.out.println(privateField.get(obj));
输出:
private string 新的私有属性值[value]
与方法相关的反射方法
使用反射技术可以获得方法的信息以及调用执行它. 我们来学习获得方法, 调用方法并访问私有方法.
获得 public 方法
我们可以使用 getMethod()方法获的 public class 的方法, 需要提供方法的名称, 参数类型. 如果 class 找不到指定的方法, 则会继续向上从其父类中查找.
下面我们以一个获取 HashMap 的 put 方法的例子来展示如何方法的参数类型, 方法访问修饰符和返回类型.
- /*=========================================
- * 方法
- * ========================================
- */
- Class mapClass = HashMap.class;
- Method mapPut = mapClass.getMethod("put", Object.class, Object.class);
- // 获取参数类型
- System.out.println(Arrays.toString(mapPut.getParameterTypes()));
- // 获取返回类型
- System.out.println(mapPut.getReturnType());
- // 访问修饰符
- System.out.println(Modifier.toString(mapPut.getModifiers()));
输出:
[class java.lang.Object, class java.lang.Object] class java.lang.Object public
调用 public 方法
可以利用 Method.invoke()方法调用指定的方法.
- // 调用方法
- Map<String, String> map = new HashMap<String, String>();
- mapPut.invoke(map, "key", "val");
- System.out.println(map);
输出:
{key=val}
调用 private 方法
我们可以使用 getDeclaredMethod()方法获取私有方法, 然后关闭访问限制, 即可调用.
- /**
- * 访问私有方法
- */
- Method method3 = BaseClass.class.getDeclaredMethod("method3", null);
- method3.setAccessible(true);
- // 静态方法的调用对象可以传入 null
- method3.invoke(null, null);
输出:
Method3
反射在构造器中的使用
我们可以使用 getConstructor()方法获取指定的 public 构造器.
- /**
- * 反射在构造器中的使用
- */
- Constructor<?> constructor = ConcreteClass.class.getConstructor(int.class);
- System.out.println(Arrays.toString(constructor.getParameterTypes()));
- Constructor<?> hashMapConstructor = HashMap.class.getConstructor(null);
- System.out.println(Arrays.toString(hashMapConstructor.getParameterTypes()));
输出:
[int] []
利用构造器初始化对象实例
我们可以利用 constructor 实例的 newInstance()方法获初始化实例.
- /**
- * 初始化实例
- */
- Object myObj = constructor.newInstance(10);
- Method myObjMethod = myObj.getClass().getMethod("method1", null);
- myObjMethod.invoke(myObj, null); //prints "Method1 impl."
- HashMap<String,String> myMap = (HashMap<String,String>)hashMapConstructor.newInstance(null);
来源: https://juejin.im/post/5c80d0a2e51d4566211326ba