概述
Java的反射机制是指程序在运行时动态获取信息以及动态调用对象方法的功能。它是一种强有力的工具,是面向抽象编程一种实现方式,它能使代码语句更加灵活,极大提高代码的运行时装配能力。
使用反射机制的意义在于:
1.反射机制极大的提高了程序的灵活性和扩展性,降低模块的耦合性,提高自身的适应能力。
2.通过反射机制可以让程序创建和控制任何类的对象,无需提前硬编码目标类。
3.使用反射机制能够在运行时构造一个类的对象,判断一个类所具有的成员变量和方法,调用一个对象的方法并生成动态代理。
4.反射机制是构建框架技术的基础所在,使用反射可以避免将代码写死在框架中。
Class类
java.lang.Class类提供了一些方法可以获取类型的信息,包括成员变量和方法等。无论是基本类型,还是引用类型,每一种类型都有一个对应的Class对象。
获取Class对象的方式有3种:
1.调用Object的getClass()方法获取Class对象。
a.该方式不适于基本类型。
b.该方式获取的Class对象的泛型类型无法确定,只能限制其范围为对象的类型或其子类类型。
2.用“.class”获取Class对象。
a.该方式适用于所有类型。
b.该方式获取的Class对象的泛型类型可以确定。
3.调用Class.forName()方法传入类或接口的完全限定名获取Class对象。
a.该方式不适用于基本类型。
b.该方式获取的Class对象的泛型类型无法确定,且无法限制其范围。
c.使用该方式需要处理异常ClassNotFoundException。
1 @Test 2 void testGetClass1() { 3 // 调用Object的getClass()方法获取Class对象 4 Class<? extends String> c1 = "abc".getClass(); 5 System.out.println(c1); 6 // 用“.class”获取Class对象 7 Class<String> c2 = String.class; 8 System.out.println(c2); 9 // 调用Class.forName()方法获取Class对象 10 Class<?> c3 = null; 11 try { 12 c3 = Class.forName("java.lang.String"); 13 } catch (ClassNotFoundException e) { 14 e.printStackTrace(); 15 } 16 System.out.println(c3); 17 }
输出结果:
对于包装类型,使用“.class”获取到的是包装类型的Class对象,使用“.TYPE”获取到的是对应基本类型的Class对象。只有包装类型才有“.TYPE”语法。
1 @Test 2 void testGetClass2() { 3 // 基本类型的Class对象 4 Class<Integer> c1 = int.class; 5 System.out.println(c1); 6 // 包装类型的Class对象 7 Class<Integer> c2 = Integer.class; 8 System.out.println(c2); 9 // 包装类型对应基本类型的Class对象 10 Class<Integer> c3 = Integer.TYPE; 11 System.out.println(c3); 12 }
输出结果:
可以看到:虽然3种Class对象的类型都为“Class<Integer>”,但是很明显,c1和c3是同一个对象,而c2是另一个对象。
每一种类型对应一个Class对象,所以同一类型的两个实例调用getClass()方法获取到的Class对象是同一个。
1 @Test 2 void testGetClass3() { 3 String s1 = "a", s2 = "b"; 4 Class<? extends String> c1 = s1.getClass(); 5 Class<? extends String> c2 = s2.getClass(); 6 System.out.println(c1 == c2); 7 }
输出结果:
Class类常用方法
Class类中提供了很多方法可以获取一种类型的信息。
获取名字
getName()、getCanonicalName()、getSimpleName()和getTypeName()这四个方法都用于获取名字。区别在于:
1.对于数组来说,getName()方法获取的名字与其他三个方法有所不同,getName()方法获取到的数组的Class对象的名字格式为:通过“[”表示数组嵌套深度,再加上一个编码表示数组元素类型,编码如下:
元素类型 | 编码 |
boolean | Z |
byte | B |
char | C |
double | D |
float | F |
int | I |
long | J |
short | S |
类 | 类名 |
接口 | 接口名 |
2.对于引用类型来说,getSimpleName()方法获取的是类名(接口名),其他三个方法获取的是完全限定名。
1 static void getMessage(Class<?> c) { 2 System.out.println("--------------------"); 3 System.out.println("getName: " + c.getName()); 4 System.out.println("getCanonicalName: " + c.getCanonicalName()); 5 System.out.println("getSimpleName: " + c.getSimpleName()); 6 System.out.println("getTypeName: " + c.getTypeName()); 7 }
1 @Test 2 void testGetMessage() { 3 // 基本类型 4 Class<Integer> c1 = int.class; 5 getMessage(c1); 6 // 数组 7 Class<int[]> c2 = int[].class; 8 getMessage(c2); 9 // 类 10 Class<TestClass> c3 = TestClass.class; 11 getMessage(c3); 12 // 接口 13 Class<TestInterface> c4 = TestInterface.class; 14 getMessage(c4); 15 // 枚举类 16 Class<TestEnum> c5 = TestEnum.class; 17 getMessage(c5); 18 // 注解类 19 Class<TestAnnotation> c6 = TestAnnotation.class; 20 getMessage(c6); 21 }
输出结果:
其中,“[I”表示是一个数组,层数为1层,编码“I”表示的类型为int类型,即“[I”表示的是int[]数组。
判断种类
1.boolean isPrimitive():是否为基本类型。
2.boolean isInterface():是否为接口。
3.boolean isArray():是否为数组。
4.boolean isAnnotation():是否为注解类。
1 static void determineCategory(Class<?> c) { 2 System.out.println("-----" + c.getName() + "-----"); 3 System.out.println("isPrimitive: " + c.isPrimitive()); // 是否为基本类型 4 System.out.println("isInterface: " + c.isInterface()); // 是否为接口 5 System.out.println("isArray: " + c.isArray()); // 是否为数组 6 System.out.println("isAnnotation: " + c.isAnnotation()); // 是否为注解类 7 }
1 @Test 2 void testDetermineCategory() { 3 // 基本类型 4 Class<Integer> c1 = int.class; 5 determineCategory(c1); 6 // 数组 7 Class<int[]> c2 = int[].class; 8 determineCategory(c2); 9 // 类 10 Class<TestClass> c3 = TestClass.class; 11 determineCategory(c3); 12 // 接口 13 Class<TestInterface> c4 = TestInterface.class; 14 determineCategory(c4); 15 // 枚举类 16 Class<TestEnum> c5 = TestEnum.class; 17 determineCategory(c5); 18 // 注解类 19 Class<TestAnnotation> c6 = TestAnnotation.class; 20 determineCategory(c6); 21 }
输出结果:
可以看到:类或者枚举类对于这4种判断的结果都是false,而注解类对于判断是否为接口的结果为true。
转换为字符串
toString()和toGenericString()方法都是将对象转换为一个字符串。相比toString()方法,toGenericString()方法转换的字符串的内容更为精确。
1 static void convertToString(Class<?> c) { 2 System.out.println("-----" + c.getName() + "-----"); 3 System.out.println("toString: " + c.toString()); 4 System.out.println("toGenericString: " + c.toGenericString()); 5 }
1 @Test 2 void testConvertToString() { 3 // 基本类型 4 Class<Integer> c1 = int.class; 5 convertToString(c1); 6 // 数组 7 Class<int[]> c2 = int[].class; 8 convertToString(c2); 9 // 类 10 Class<TestClass> c3 = TestClass.class; 11 convertToString(c3); 12 // 接口 13 Class<TestInterface> c4 = TestInterface.class; 14 convertToString(c4); 15 // 枚举类 16 Class<TestEnum> c5 = TestEnum.class; 17 convertToString(c5); 18 // 注解类 19 Class<TestAnnotation> c6 = TestAnnotation.class; 20 convertToString(c6); 21 }
输出结果:
获取包
Package getPackage():获取所在包的Package对象。
1.如果为基本类型或数组的Class对象,则结果为null。
2.如果为一般类、接口、注解类、枚举类的Class对象,则结果为所在包的Package对象。
testGetPackage输出结果:
String getPackageName():获取所在包的包名。
1.如果为基本类型或数组的Class对象,则结果为java.lang
2.如果为一般类、接口、注解类、枚举类的Class对象,则结果为所在包的包名。
testGetPackageName输出结果:
获取注解
1.<A extends Annotation> A getAnnotation(Class<A> annotationClass):获取标注在类上的指定注解。如果没有指定的注解,则返回null。
2.Annotation[] getAnnotations():获取标注在类上的所有注解。
获取修饰符
int getModifiers():获得修饰类或接口的修饰符编码。
1.如果为基本类型或数组的Class对象,则结果为public、abstract和final。
2.如果为一般类的Class对象,则结果为自身的修饰符。
3.如果为接口或注解类的Class对象,则结果除了自身的修饰符外,还包括abstract和interface。
4.如果为枚举类的Class对象,则结果除了自身的修饰符外,还包括final。
1 @Test 2 void testGetModifiers() { 3 // 基本类型 4 Class<Integer> c1 = int.class; 5 System.out.println(Modifier.toString(c1.getModifiers())); 6 // 数组 7 Class<int[]> c2 = int[].class; 8 System.out.println(Modifier.toString(c2.getModifiers())); 9 // 类 10 Class<TestClass> c3 = TestClass.class; 11 System.out.println(Modifier.toString(c3.getModifiers())); 12 // 接口 13 Class<TestInterface> c4 = TestInterface.class; 14 System.out.println(Modifier.toString(c4.getModifiers())); 15 // 枚举类 16 Class<TestEnum> c5 = TestEnum.class; 17 System.out.println(Modifier.toString(c5.getModifiers())); 18 // 注解类 19 Class<TestAnnotation> c6 = TestAnnotation.class; 20 System.out.println(Modifier.toString(c6.getModifiers())); 21 }
输出结果:
获取父类
1.Class<? super T> getSuperClass():返回当前类的父类的Class对象。
a.如果为基本类型、接口或注解类的Class对象,则结果为null。
b.如果为数组的Class对象,则结果为java.lang.Object的Class对象。
c.如果为枚举类的Class对象,则结果为java.lang.Enum的Class对象。
d.如果为一般类的Class对象,则结果为其父类的Class对象。
1 @Test 2 void testGetSuperClass() { 3 // 基本类型 4 Class<Integer> c1 = int.class; 5 System.out.println(c1.getSuperclass()); 6 // 数组 7 Class<int[]> c2 = int[].class; 8 System.out.println(c2.getSuperclass()); 9 // 类 10 Class<TestClass> c3 = TestClass.class; 11 System.out.println(c3.getSuperclass()); 12 // 接口 13 Class<TestInterface> c4 = TestInterface.class; 14 System.out.println(c4.getSuperclass()); 15 // 枚举类 16 Class<TestEnum> c5 = TestEnum.class; 17 System.out.println(c5.getSuperclass()); 18 // 注解类 19 Class<TestAnnotation> c6 = TestAnnotation.class; 20 System.out.println(c6.getSuperclass()); 21 }
输出结果:
2.Type getGenericSuperclass():返回当前类的父类的Type对象。
a.如果父类带有泛型类型,则为ParameterizedType类型对象。
b.如果父类没有泛型类型,则为Class类型对象。
1 class TestClass1<T> { 2 3 } 4 5 class TestClass2 extends TestClass1<String> { 6 7 } 8 9 class TestClass3 extends TestClass2 { 10 11 }
1 @Test 2 void testGetGenericSuperClass() { 3 Type type1 = TestClass2.class.getGenericSuperclass(); 4 System.out.println(type1); 5 System.out.println(type1 instanceof Class); 6 System.out.println(type1 instanceof ParameterizedType); 7 8 Type type2 = TestClass3.class.getGenericSuperclass(); 9 System.out.println(type2); 10 System.out.println(type2 instanceof Class); 11 System.out.println(type2 instanceof ParameterizedType); 12 }
输出结果:
获取父接口
Class<?>[] getInterfaces():返回当前类的所有父接口的Class对象数组。
1.如果为基本类型或枚举类的Class对象,则结果为空数组。
2.如果为数组的Class对象,则结果为包含java.lang.Cloneable和java.io.Serializable的Class对象的数组。
3.如果为注解类的Class对象,则结果为包含java.lang.annotation.Annotation的Class对象的数组。
4.如果为一般类的Class对象,则结果为包含其实现的所有父接口的Class对象的数组。
5.如果为接口的Class对象,则结果为包含其继承的所有父接口的Class对象的数组。
1 @Test 2 void testGetInterfaces() { 3 // 基本类型 4 Class<Integer> c1 = int.class; 5 System.out.println(Arrays.asList(c1.getInterfaces())); 6 // 数组 7 Class<int[]> c2 = int[].class; 8 System.out.println(Arrays.asList(c2.getInterfaces())); 9 // 类 10 Class<TestClass> c3 = TestClass.class; 11 System.out.println(Arrays.asList(c3.getInterfaces())); 12 // 接口 13 Class<TestInterface> c4 = TestInterface.class; 14 System.out.println(Arrays.asList(c4.getInterfaces())); 15 // 枚举类 16 Class<TestEnum> c5 = TestEnum.class; 17 System.out.println(Arrays.asList(c5.getInterfaces())); 18 // 注解类 19 Class<TestAnnotation> c6 = TestAnnotation.class; 20 System.out.println(Arrays.asList(c6.getInterfaces())); 21 }
输出结果:
获取成员变量
1.Field getField(String name) throws NoSuchFieldException, SecurityException:获取当前类或其父类的指定公共成员变量的Field对象。传入指定公共成员变量的成员变量名。
2.Field[] getFields() throws SecurityException:获取当前类和其父类的所有公共成员变量的Field对象。
3.Field getDeclareField(String name) throws NoSuchFieldException, SecurityException:获取当前类的指定成员变量的Field对象。传入指定成员变量的成员变量名。
4.Field[] getDeclareFields() throws SecurityException:获取当前类的所有成员变量的Field对象。
例如:定义一个TestClass类,该类中有4种访问限制符修饰的成员变量,该类继承了TestSuperClass类,其中也有4种访问限制符修饰的成员变量。
1 class TestSuperClass { 2 3 private boolean field1; 4 protected byte field2; 5 char field3; 6 public double field4; 7 8 }
1 class TestClass extends TestSuperClass { 2 3 private float field5; 4 protected int field6; 5 long field7; 6 public short field8; 7 8 }
1 @Test 2 void testGetFields() { 3 Class<TestClass> c = TestClass.class; 4 System.out.println("-----getFields-----"); 5 System.out.println(Arrays.asList(c.getFields())); 6 System.out.println("-----getDeclareFields-----"); 7 System.out.println(Arrays.asList(c.getDeclaredFields())); 8 }
输出结果:
获取构造方法
1.Constructor<T> getConstructor(Class<?>... parameterTypes) throws NoSuchMethodException, SecurityException:获取当前类的指定公共构造方法的Constructor对象。传入指定公共构造方法参数的Class对象。
2.Constructor<?>[] getConstructors() throws SecurityException:获取当前类的所有公共构造方法的Constructor对象。
3.Constructor<T> getDeclaredConstructor(Class<?>... parameterTypes) throws NoSuchMethodException, SecurityException:获取当前类的指定构造方法的Constructor对象。传入指定构造方法参数的Class对象。
4.Constructor<?>[] getDeclaredConstructors() throws SecurityException:获取当前类的所有构造方法的Constructor对象。
例如:定义一个TestClass类,该类有4种访问限制符修饰的构造方法。
1 class TestClass { 2 3 private TestClass(char c) { 4 5 } 6 7 protected TestClass(float f) { 8 9 } 10 11 TestClass(int i) { 12 13 } 14 15 public TestClass() { 16 17 } 18 19 }
1 @Test 2 void testGetConstructors() { 3 Class<TestClass> c = TestClass.class; 4 System.out.println("-----getConstructors-----"); 5 System.out.println(Arrays.asList(c.getConstructors())); 6 System.out.println("-----getDeclareConstructors-----"); 7 System.out.println(Arrays.asList(c.getDeclaredConstructors())); 8 }
输出结果:
获取方法
1.Method getMethod(String name, Class<?>... parameterTypes) throws NoSuchMethodException, SecurityException:获取当前类或其父类的指定公共方法的Method对象。传入指定公共方法的方法名和方法参数对应的Class对象。
2.Method[] getMethods() throws SecurityException:获取当前类和其父类的所有公共方法的Method对象。
3.Method getDeclaredMethod(String name, Class<?>... parameterTypes) throws NoSuchMethodException, SecurityException:获取当前类的指定方法的Method对象。传入指定方法的方法名和方法参数对应的Class对象。
4.Method[] getDeclaredMethods() throws SecurityException:获取当前类的所有方法的Method对象。
例如:定义一个TestClass类,该类有4种访问限制符修饰的方法,该类继承了TestSuperClass类,其中也有4种访问限制符修饰的方法。
1 class TestSuperClass { 2 3 private void method1() { 4 5 } 6 7 protected void method2() { 8 9 } 10 11 void method3() { 12 13 } 14 15 public void method4() { 16 17 } 18 19 }
1 class TestClass extends TestSuperClass { 2 3 private void method5() { 4 5 } 6 7 protected void method6() { 8 9 } 10 11 void method7() { 12 13 } 14 15 public void method8() { 16 17 } 18 19 }
1 @Test 2 void testGetMethods() { 3 Class<TestClass> c = TestClass.class; 4 System.out.println("-----getMethods-----"); 5 System.out.println(Arrays.asList(c.getMethods())); 6 System.out.println("-----getDeclareMethods-----"); 7 System.out.println(Arrays.asList(c.getDeclaredMethods())); 8 }
输出结果:
ParameterizedType接口
java.lang.reflect.ParameterizedType接口用于存储泛型类型的信息。
ParameterizedType接口常用的方法有:
1.Type[] getActualTypeArguments():获取所有泛型类型的Type对象。
2.Type getRawType():获取原生类型的Type对象。实际上是Class对象。
3.Type getOwnerType():获取所有者类型的Type对象。实际上是Class对象。
1 class TestClass1 { 2 3 static class TestClass2<T> { 4 5 6 7 } 8 9 } 10 11 class TestClass3 extends TestClass2<String> { 12 13 14 15 }
1 @Test 2 void testParameterizedType() { 3 ParameterizedType type = (ParameterizedType) TestClass3.class.getGenericSuperclass(); 4 System.out.println(type); 5 System.out.println(Arrays.asList(type.getActualTypeArguments())); 6 System.out.println(type.getRawType()); 7 System.out.println(type.getOwnerType()); 8 }
输出结果:
Package类
java.lang.Package类用于存储包的信息,每一个包都有一个对应的Package对象。
Package类常用的方法有:
1.String getName():获取包名。
2.<A extends Annotation> A getAnnotation(Class<A> annotationClass):获取标注在包上的指定注解。
3.Annotation[] getAnnotations():获取标注在包上的所有注解。
Annotation注解类
每个注解类都默认继承java.lang.annotation.Annotation注解类。
Annotation注解类常用的方法有:
Class<? extends Annotation> annotationType():获取当前注解的Class对象。
需要注意的是,Annotation是一个注解类,获取到的Annotation对象是一个Java生成的代理对象。通过annotationType()方法获取到的是注解的Class对象,通过getClass()方法获取到的是代理类的Class对象。
1 @Test 2 void testAnnotation() { 3 TestAnnotation testAnnotation = TestClass.class.getAnnotation(TestAnnotation.class); 4 System.out.println(testAnnotation); 5 System.out.println(testAnnotation.getClass()); 6 System.out.println(testAnnotation.annotationType()); 7 }
输出结果:
Modifier类
java.lang.reflect.Modifier类中定义了Java所有修饰符,该类将每一种修饰符用一个数表示:
修饰符 | 编码 | 二进制数 |
public | 1 | 0000 0000 0001 |
private | 2 | 0000 0000 0010 |
protected | 4 | 0000 0000 0100 |
static | 8 | 0000 0000 1000 |
final | 16 | 0000 0001 0000 |
synchronized | 32 | 0000 0010 0000 |
volatile | 64 | 0000 0100 0000 |
transient | 128 | 0000 1000 0000 |
native | 256 | 0001 0000 0000 |
interface | 512 | 0010 0000 0000 |
abstract | 1024 | 0100 0000 0000 |
可以看到,每一个修饰符的编码的二进制数中都只有一个1,而且每一个修饰符编码的二进制数的1的位置都不同。这样,如果某个对象被多个修饰符修饰时,只要把对应二进制位置为1,就可以用修饰符编码表示。
例如:在Modifier类中,public的编码为1(0001),static的编码为8(1000),那么,一个被public和static修饰的方法的修饰符编码为1&8=0001&1000=1001=9。反过来,若已知修饰符编码为9,即1001,有两个1表示有两个修饰符修饰该对象,其中前面的1表示的是static修饰符,后面的1表示的是public修饰符。
Modifier类常用的方法有:
1.static String toString(int mod):将一个修饰符编码解码为修饰符字符串。
2.static int classModifiers():获取可以修饰类的修饰符编码。
3.static int interfaceModifiers():获取可以修饰接口的修饰符编码。
4.static int constructorModifiers():获取可以修饰构造方法的修饰符编码。
5.static int methodModifiers():获取可以修饰方法的修饰符编码。
6.static int fieldModifiers():获取可以修饰成员变量的修饰符编码。
7.static int parameterModifiers():获取可以修饰变量的修饰符编码。
1 @Test 2 void testModifier() { 3 System.out.println("修饰类的修饰符有:" + Modifier.toString(Modifier.classModifiers()).replace(" ", ", ")); 4 System.out.println("修饰接口的修饰符有:" + Modifier.toString(Modifier.interfaceModifiers()).replace(" ", ", ")); 5 System.out.println("修饰构造方法的修饰符有:" + Modifier.toString(Modifier.constructorModifiers()).replace(" ", ", ")); 6 System.out.println("修饰方法的修饰符有:" + Modifier.toString(Modifier.methodModifiers()).replace(" ", ", ")); 7 System.out.println("修饰成员变量的修饰符有:" + Modifier.toString(Modifier.fieldModifiers()).replace(" ", ", ")); 8 System.out.println("修饰变量的修饰符有:" + Modifier.toString(Modifier.parameterModifiers()).replace(" ", ", ")); 9 }
输出结果:
Field类
java.lang.reflect.Field类用于存储成员变量的信息,是AccessibleObject类的子类。每一个成员变量都对应一个Field对象。
Field类常用的方法有:
1.int getModifiers():获取修饰成员变量的修饰符编码。
2.Class<?> getType():获取成员变量的类型的Class对象。
3.String getName():获取成员变量的变量名。
4.Class<?> getDeclaringClass():获取成员变量所在类的Class对象。
5.<T extends Annotation> T getAnnotation(Class<T> annotationClass):获取标注在成员变量上的指定注解。
6.Object get(Object obj) throws IllegalArgumentException, IllegalAccessException:获取指定对象的成员变量的值。
7.void set(Object obj, Object value) throws IllegalArgumentException, IllegalAccessException:为指定变量的成员变量赋值。
1 @Test 2 void testField() { 3 try { 4 Field field = TestClass.class.getField("field"); 5 6 System.out.println(Modifier.toString(field.getModifiers())); // 获取修饰符 7 System.out.println(field.getType()); // 获取类型 8 System.out.println(field.getName()); // 获取变量名 9 System.out.println(field.getDeclaringClass()); // 获取所在类 10 System.out.println(Arrays.asList(field.getAnnotations())); // 获取注解 11 12 TestClass testClass = new TestClass(); 13 field.set(testClass, 10); // 设置值 14 System.out.println(field.get(testClass)); // 获取值 15 } catch (NoSuchFieldException | SecurityException | IllegalArgumentException | IllegalAccessException e) { 16 e.printStackTrace(); 17 } 18 }
输出结果:
Constructor类
java.lang.reflect.Constructor类用于存储构造方法的信息。每一个构造方法都对应一个Constructor对象。
Constructor类常用的方法有:
1.int getModifiers():获取修饰构造方法的修饰符编码。
2.String getName():获取构造方法的方法名。
3.Class<?>[] getParameterTypes():获取构造方法的所有参数类型的Class对象。
4.int getParameterCount():获取构造方法的参数个数。
5.Class<?>[] getExceptionTypes():获取构造方法的所有抛出异常类型的Class对象。
6.<T extends Annotation> T getAnnotation(Class<T> annotationClass):获取标注在构造方法上的指定注解。
7.T newInstance(Object ... initargs) throws InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException:传入参数创建新实例。
1 @Test 2 void testConstructor() { 3 try { 4 Constructor<TestClass> constructor = TestClass.class.getConstructor(int.class); 5 6 System.out.println(Modifier.toString(constructor.getModifiers())); // 获取修饰符 7 System.out.println(constructor.getName()); // 获取构造方法名 8 System.out.println(Arrays.asList(constructor.getParameters())); // 获取参数 9 System.out.println(Arrays.asList(constructor.getParameterTypes())); // 获取参数类型 10 System.out.println(constructor.getParameterCount()); // 获取参数个数 11 System.out.println(Arrays.asList(constructor.getExceptionTypes())); // 获取异常 12 System.out.println(Arrays.asList(constructor.getAnnotations())); // 获取注解 13 14 TestClass testClass = constructor.newInstance(10); // 创建实例 15 System.out.println(testClass.field); 16 } catch (NoSuchMethodException | SecurityException | InstantiationException | IllegalAccessException | IllegalArgumentException | InvocationTargetException e) { 17 e.printStackTrace(); 18 } 19 }
输出结果:
Method类
java.lang.reflect.Method类用于存储方法的信息。每一个方法都对应一个Method对象。
Method类常用的方法有:
1.int getModifiers():获取修饰方法的修饰符编码。
2.Class<?> getReturnType():获取方法返回值类型对应的Class对象。
3.String getName():获取方法的方法名。
4.Class<?>[] getParameterTypes():获取方法的所有参数类型的Class对象。
5.int getParameterCount():获取方法的参数个数。
6.Class<?>[] getExceptionTypes():获取方法的所有抛出异常类型的Class对象。
7.<T extends Annotation> T getAnnotation(Class<T> annotationClass):获取标注在方法上的指定注解。
8.Object invoke(Object obj, Object... args) throws IllegalAccessException, IllegalArgumentException, InvocationTargetException:传入对象和参数执行方法。
1 @Test 2 void testMethod() { 3 try { 4 Method method = TestClass.class.getMethod("divide", int.class, int.class); 5 System.out.println(Modifier.toString(method.getModifiers())); // 获取修饰符 6 System.out.println(method.getReturnType()); // 获取返回值类型 7 System.out.println(method.getName()); // 获取方法名 8 System.out.println(Arrays.asList(method.getParameters())); // 获取参数 9 System.out.println(Arrays.asList(method.getParameterTypes())); // 获取参数类型 10 System.out.println(method.getParameterCount()); // 获取参数个数 11 System.out.println(Arrays.asList(method.getExceptionTypes())); // 获取异常 12 System.out.println(Arrays.asList(method.getAnnotations())); // 获取注解 13 14 System.out.println(method.invoke(new TestClass(), 3, 2)); // 执行方法 15 } catch (NoSuchMethodException | SecurityException | IllegalAccessException | IllegalArgumentException | InvocationTargetException e) { 16 e.printStackTrace(); 17 } 18 }
输出结果:
Executable类
java.lang.reflect.Executable类是一个抽象类。Constructor类和Method类是该类的实现类。该类提供了获取参数的方法。
Executable类常用的方法有:
Parameter[] getParameters():获取所有参数。每一个参数封装为Parameter对象。
AccessibleObject类
java.lang.reflect.AccessibleObject类提供了将反射的对象标记为在使用时是否取消访问控制检查。Field类、Constructor类和Method类都是该类的子类,获取当前访问权限无法访问到的成员变量、构造方法或方法后,需要将访问控制检查能力取消才能使用。而作为Field类、Constructor类和Method类的父类,该类也提供了一些这三个类共有的方法。
AccessibleObject类常用的方法有:
1.void setAccessible(boolean flag):设置是否取消访问控制检查。
2.Annotation[] getAnnotations():获取所有的注解。
1 class TestClass { 2 3 private String field; 4 5 private TestClass() { 6 System.out.println("--私有构造方法--"); 7 } 8 9 private String method() { 10 return "--私有方法--"; 11 } 12 13 }
1 @Test 2 void testAccessibleObject() { 3 try { 4 Class<TestClass> c = TestClass.class; 5 6 Constructor<TestClass> constructor = c.getDeclaredConstructor(); 7 constructor.setAccessible(true); 8 TestClass tc = constructor.newInstance(); 9 10 Field field = c.getDeclaredField("field"); 11 field.setAccessible(true); 12 field.set(tc, "--私有成员变量--"); 13 System.out.println(field.get(tc)); 14 15 Method method = c.getDeclaredMethod("method"); 16 method.setAccessible(true); 17 String result = (String) method.invoke(tc); 18 System.out.println(result); 19 } catch (NoSuchFieldException | SecurityException | NoSuchMethodException | InstantiationException | IllegalAccessException | IllegalArgumentException | InvocationTargetException e) { 20 e.printStackTrace(); 21 } 22 }
输出结果:
如果没有调用setAccessible()方法取消访问控制检查,则无法调用私有构造方法、对私有成员变量设置值和获取值、调用私有方法。
创建对象
定义一个Student类。
1 class Student { 2 3 public String name; 4 public int age; 5 6 public Student() { 7 8 } 9 10 public Student(String name, int age) { 11 this.name = name; 12 this.age = age; 13 } 14 15 public void hello() { 16 System.out.println("My name is " + name + "."); 17 System.out.println("I' m " + age + " years old."); 18 } 19 20 }
1.不使用反射。
1 @Test 2 void testNewInstance1() { 3 Student stu1 = new Student(); 4 stu1.name = "Tom"; 5 stu1.age = 10; 6 stu1.hello(); 7 8 Student stu2 = new Student("Sam", 12); 9 stu2.hello(); 10 }
输出结果:
2.使用反射。
1 @Test 2 void testNewInstance2() { 3 try { 4 Class<Student> clazz = Student.class; 5 Method hello = clazz.getMethod("hello"); 6 7 Constructor<Student> c1 = clazz.getConstructor(); 8 Student stu1 = c1.newInstance(); 9 Field name = clazz.getDeclaredField("name"); 10 name.set(stu1, "Tom"); 11 Field age = clazz.getDeclaredField("age"); 12 age.set(stu1, 10); 13 hello.invoke(stu1); 14 15 Constructor<Student> c2 = clazz.getConstructor(String.class, int.class); 16 Student stu2 = c2.newInstance("Sam", 12); 17 hello.invoke(stu2); 18 } catch (Exception e) { 19 e.printStackTrace(); 20 } 21 }
输出结果:
获取泛型类型
定义泛型类TestClass1和继承该类的TestClass2。
1 class TestClass1<T> { 2 3 4 5 } 6 7 class TestClass2 extends TestClass1<String> { 8 9 10 11 }
获取泛型类型。
1 @Test 2 void testGetGenericClass() { 3 Type type = TestClass2.class.getGenericSuperclass(); 4 if (type instanceof ParameterizedType) { 5 ParameterizedType parameterizedType = (ParameterizedType) type; 6 Type[] types = parameterizedType.getActualTypeArguments(); 7 System.out.println("泛型的个数为:" + types.length); 8 System.out.println("泛型类型:" + Arrays.asList(types)); 9 } 10 }
输出结果:
来源:https://www.cnblogs.com/lqkStudy/p/11141066.html