反射
每个类都有一个 Class 对象,包含了与类有关的信息。当编译一个新类时,会产生一个同名的 .class 文件,该文件内容保存着 Class 对象。
1. Class类
获取一个类的Class对象的三种方式
// 每个类都有一个隐含的静态变量
Class c1 = Apple.class;
// 通过实例化对象的getClass()方法
Apple apple = new Apple();
Class c2 = apple.getClass();
// 通过类的全限定名
Class c3 = Class.forName("com.myf.pojo.Apple");
判断是否是某个类的实例
我们可以借助反射中 Class 对象的 isInstance()
方法来判断是否为某个类的实例,它是一个 native 方法:
public native boolean isInstance(Object obj);
通过反射生成对象
使用Class对象的newInstance()方法来创建Class对象对应类的实例。
下面示例使用的是有参构造,默认调用无参构造orangeClass.getDeclaredConstructor().newInstance()
。Class.newInstance()方法在java9之后被Deprecated不推荐了。
Orange orange = new Orange("莫逸风");
Class<? extends Orange> orangeClass = orange.getClass();
Orange orange1 = orangeClass.getDeclaredConstructor(String.class).newInstance("莫逸风");
示例实体:
class Orange {
String name;
public Orange(String name) {
this.name = name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
2. java.lang.reflect
Class 和 java.lang.reflect 一起对反射提供了支持,java.lang.reflect 类库主要包含了以下三个类:
- Field :可以使用 get() 和 set() 方法读取和修改 Field 对象关联的字段;
- Method :可以使用 invoke() 方法调用与 Method 对象关联的方法;
- Constructor :可以用 Constructor 的 newInstance() 创建新的对象。
3. Class API:
Field[] getFields()
:返回一个包含Field对象的数组,该数组包含这个类或其超类的公有域。Field[] getDeclaredFields()
:返回这个类的全部域。如果类型没有成员变量则返回长度为0的数组。Method[] getMethods()
:返回包含Method对象的数组,该数组包含这个类或其超类的公有方法。Method[] getDeclaredMethods()
:返回这个类或接口的全部方法,但不包括由超类继承的方法(公有方法也没有)。Constructor<?>[] getConstructors()
:类的所有公有有构造器Constructor<?>[] getDeclaredConstructors()
:类的所有构造器
3. Field:
Object get(Object obj)
:获取变量的值,入参为实例对象。Orange orange = orangeClass.getDeclaredConstructor(String.class).newInstance("莫逸风"); Field[] fields = orangeClass.getDeclaredFields(); Object o = fields[0].get(orange); System.out.println(o); //莫逸风
void set(Object obj, Object value)
:设置变量的值。fields[0].set(orange,"莫逸雪"); Object o = fields[0].get(orange); System.out.println(o); //莫逸雪
Class<?> getType()
:返回属性的类型。Class<?> aClass = fields[0].getType(); System.out.println(aClass==String.class); //true
void setAccessible(boolean flag)
:设置属性的访问权限。如果我们将上述示例属性值改为private,则在get,set反射操作变量时会报IllegalAccessException异常。在操作之前设置setAccessible(true)可以解决这个问题。
fields[0].setAccessible(true);
String getName()
:返回变量名称。String name = fields[0].getName(); System.out.println(name); //name
4. Method:
void setAccessible(boolean flag)
:设置方法的访问权限。String getName()
:返回方法名称。<T extends Annotation> T getAnnotation(Class<T> annotationClass)
:如果存在,返回对应的注解没找到合适测试的注解,自定义一个
@Target({ ElementType.TYPE, ElementType.FIELD, ElementType.METHOD }) @Retention(RetentionPolicy.RUNTIME) public @interface Tag { String value(); } // Orange的getName方法添加此注解 @Tag("设置名称") public String getName() { return name; } Method[] methods = orangeClass.getMethods(); Tag annotation = methods[0].getAnnotation(Tag.class); System.out.println(annotation.value()); //设置名称
Annotation[] getAnnotations()
:内部实现是调用getDeclaredAnnotationsAnnotation[] getDeclaredAnnotations()
:返回方法上的注解,忽略继承的注解,如果没有直接存在的注解返回长度为0的注解。Object invoke(Object obj, Object... args)
:执行方法。Orange orange = orangeClass.getDeclaredConstructor(String.class).newInstance("莫逸风"); methods[1].invoke(orange1,"莫逸雪"); Object invoke = methods[0].invoke(orange1); System.out.println(invoke); //莫逸雪
5. Constructor:
T newInstance(Object ... initargs)
:使用构造方法创建对象。Class<T> getDeclaringClass()
:获取所属类的Class对象。Class<? extends Orange> orangeClass = orange.getClass(); Class<?> declaringClass = constructors[0].getDeclaringClass(); System.out.println(declaringClass==orangeClass); // true
void setAccessible(boolean flag)
:设置构造器的访问权限。int getModifiers()
:返回一个用于描述构造器、方法或域的修饰符的整形数值。使用
6. Modifier:
// Orange中添加第二个变量
public static String test;
int modifiers = fields[1].getModifiers();
System.out.println(modifiers); // 9
System.out.println(Modifier.toString(modifiers)); // public static
System.out.println(Modifier.isAbstract(modifiers)); // false
System.out.println(Modifier.isFinal(modifiers)); // false
System.out.println(Modifier.isInterface(modifiers)); // false
System.out.println(Modifier.isNative(modifiers)); // false
System.out.println(Modifier.isPrivate(modifiers)); // false
System.out.println(Modifier.isProtected(modifiers)); // false
System.out.println(Modifier.isPublic(modifiers)); // true
System.out.println(Modifier.isStatic(modifiers)); // true
System.out.println(Modifier.isStrict(modifiers)); // false
System.out.println(Modifier.isSynchronized(modifiers)); // false
System.out.println(Modifier.isVolatile(modifiers)); // false
static String toString(int mod)
:返回对应的修饰符static boolean isAbstract(int modifiers)
:static boolean isFinal(int modifiers)
:static boolean isInterface(int modifiers)
:static boolean isNative(int modifiers)
:static boolean isPrivate(int modifiers)
:static boolean isProtected(int modifiers)
:static boolean isPublic(int modifiers)
:static boolean isStatic(int modifiers)
:static boolean isStrict(int modifiers)
:static boolean isSynchronized(int modifiers)
:static boolean isVolatile(int modifiers)
:
7. 结语
由于反射会额外消耗一定的系统资源,因此如果不需要动态地创建一个对象,那么就不需要用反射。
另外,反射调用方法时可以忽略权限检查,因此可能会破坏封装性而导致安全问题。