java反射
JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性;这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制。
一般情况下,我们不应该在正常编程中使用反射,因为存在以下缺点:
- 性能低-因为java反射动态地解析类型,它涉及处理像扫描类路径找到要加载的类,导致性能降低。
- 安全限制-反射需要运行时权限,可能不适用于在安全管理器下运行的系统。这可能会导致应用程序在运行时由于安全管理器而失败。
- 安全问题-使用反射,我们可以访问我们不应该访问的部分代码,例如,我们可以访问类的私有字段并更改它的值。这可能是一个严重的安全威胁,并导致您的应用程序的行为异常。
- 高维护-反射代码很难理解和调试,在编译时也无法找到代码的任何问题,因为类可能不可用,使得它不太灵活和难以维护。
API简介
— java.lang.Class; 代表一个类
— java.lang.reflect.Constructor; 代表类的构造方法
— java.lang.reflect.Field; 代表类的成员变量(成员变量也称为类的属性)
— java.lang.reflect.Method; 代表类的方法
— java.lang.reflect.Array; 提供了动态创建数组,以及访问数组的元素的静态方法
定义类
public interface BaseInterface { public int interfaceInt=0; void method1(); int method2(String str); }
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"); } // inner public class public class BaseClassInnerClass{} //member public enum public enum BaseClassMemberEnum{} }
@Deprecated 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 - 通过静态变量类,使用对象的getClass()方法和java.lang.Class.forName(String fullyClassifiedClassName)。
1)、使用Class类的forName(String className)静态方法。改方法需要传入字符串参数,改字符串参数的值是某个类的全限定类名(必须添加完整的包名)。
Class.forName("java.lang.String");
2)、调用某个类的class属性来获取该类对应的class对象
如
String.class
3)、调用某个对象的getClass方法。
String s = "aa";
Class<?> clazz = s.getClass();
对于基本类型和数组,我们可以使用静态变量类。包装器类提供另一个静态变量TYPE来获取类。
// Get Class using reflection Class<?> concreteClass = ConcreteClass.class; concreteClass = new ConcreteClass(5).getClass(); try { // below method is used most of the times in frameworks like JUnit //Spring dependency injection, Tomcat web container //Eclipse auto completion of method names, hibernate, Struts2 etc. //because ConcreteClass is not available at compile time concreteClass = Class.forName("com.journaldev.reflection.ConcreteClass"); } catch (ClassNotFoundException e) { e.printStackTrace(); } System.out.println(concreteClass.getCanonicalName()); // prints com.journaldev.reflection.ConcreteClass //for primitive types, wrapper classes and arrays Class<?> booleanClass = boolean.class; System.out.println(booleanClass.getCanonicalName()); // prints boolean Class<?> cDouble = Double.TYPE; System.out.println(cDouble.getCanonicalName()); // prints double Class<?> cDoubleArray = Class.forName("[D"); System.out.println(cDoubleArray.getCanonicalName()); //prints double[] Class<?> twoDStringArray = String[][].class; System.out.println(twoDStringArray.getCanonicalName()); // prints java.lang.String[][]
获取Super Class
如果此类表示Object类,接口,原始类型或void,则getSuperclass() 返回null。
Class<?> superClass = Class.forName("com.journaldev.reflection.ConcreteClass").getSuperclass(); System.out.println(superClass); // prints "class com.journaldev.reflection.BaseClass" System.out.println(Object.class.getSuperclass()); // prints "null" System.out.println(String[][].class.getSuperclass());// prints "class java.lang.Object"
获取Declared类
getDeclaredClasses()方法返回一个Class对象数组,反射所有被声明为由此Class对象表示的类的成员的类和接口。返回的数组不包括在继承的类和接口中声明的类。
//getting all of the classes, interfaces, and enums that are explicitly declared in ConcreteClass Class<?>[] explicitClasses = Class.forName("com.journaldev.reflection.ConcreteClass").getDeclaredClasses(); //prints [class com.journaldev.reflection.ConcreteClass$ConcreteClassDefaultClass, //class com.journaldev.reflection.ConcreteClass$ConcreteClassDefaultEnum, //class com.journaldev.reflection.ConcreteClass$ConcreteClassPrivateClass, //class com.journaldev.reflection.ConcreteClass$ConcreteClassProtectedClass, //class com.journaldev.reflection.ConcreteClass$ConcreteClassPublicClass, //class com.journaldev.reflection.ConcreteClass$ConcreteClassPublicEnum, //interface com.journaldev.reflection.ConcreteClass$ConcreteClassPublicInterface] System.out.println(Arrays.toString(explicitClasses));
获取Package名字
//prints "com.journaldev.reflection" System.out.println(Class.forName("com.journaldev.reflection.BaseInterface").getPackage().getName());
获取类的Modifiers
System.out.println(Modifier.toString(concreteClass.getModifiers())); //prints "public" //prints "public abstract interface" System.out.println(Modifier.toString(Class.forName("com.journaldev.reflection.BaseInterface").getModifiers()));
获取Type Parameters
//Get Type parameters (generics) TypeVariable<?>[] typeParameters = Class.forName("java.util.HashMap").getTypeParameters(); for(TypeVariable<?> t : typeParameters) System.out.print(t.getName()+",");
获取Implemented Interfaces
Type[] interfaces = Class.forName("java.util.HashMap").getGenericInterfaces(); //prints "[java.util.Map<K, V>, interface java.lang.Cloneable, interface java.io.Serializable]" System.out.println(Arrays.toString(interfaces)); //prints "[interface java.util.Map, interface java.lang.Cloneable, interface java.io.Serializable]" System.out.println(Arrays.toString(Class.forName("java.util.HashMap").getInterfaces()));
获取所有的public Methods
getMethods()方法返回类的公共方法数组,包括它的超类和超级接口的公共方法。
Method[] publicMethods = Class.forName("com.journaldev.reflection.ConcreteClass").getMethods(); //prints public methods of ConcreteClass, BaseClass, Object System.out.println(Arrays.toString(publicMethods));
获取所有public Constructors
//Get All public constructors Constructor<?>[] publicConstructors = Class.forName("com.journaldev.reflection.ConcreteClass").getConstructors(); //prints public constructors of ConcreteClass System.out.println(Arrays.toString(publicConstructors));
获取所有public Fields
getFields()方法返回类的公共字段数组,包括它的超级类和超级接口的公共字段。
//Get All public fields Field[] publicFields = Class.forName("com.journaldev.reflection.ConcreteClass").getFields(); //prints public fields of ConcreteClass, it's superclass and super interfaces System.out.println(Arrays.toString(publicFields));
获取所有Annotations
java.lang.annotation.Annotation[] annotations = Class.forName("com.journaldev.reflection.ConcreteClass").getAnnotations(); //prints [@java.lang.Deprecated()] System.out.println(Arrays.toString(annotations));
获取指定的Public Field
getField()
方法在指定的类引用中查找字段,然后在超级接口中,然后在超类中。
Field field = Class.forName("com.journaldev.reflection.ConcreteClass").getField("interfaceInt");
通过属性获取类
try { Field field = Class.forName("com.journaldev.reflection.ConcreteClass").getField("interfaceInt"); Class<?> fieldClass = field.getDeclaringClass(); System.out.println(fieldClass.getCanonicalName()); //prints com.journaldev.reflection.BaseInterface } catch (NoSuchFieldException | SecurityException e) { e.printStackTrace(); }
获取Field Type
Field field = Class.forName("com.journaldev.reflection.ConcreteClass").getField("publicInt"); Class<?> fieldType = field.getType(); System.out.println(fieldType.getCanonicalName()); //prints int
Get/Set Public Field Value
Field field = Class.forName("com.journaldev.reflection.ConcreteClass").getField("publicInt"); ConcreteClass obj = new ConcreteClass(5); System.out.println(field.get(obj)); //prints 5 field.setInt(obj, 10); //setting field value to 10 in object System.out.println(field.get(obj)); //prints 10
获取指定的Public Method
Method method = Class.forName("java.util.HashMap").getMethod("put", Object.class, Object.class); //get method parameter types, prints "[class java.lang.Object, class java.lang.Object]" System.out.println(Arrays.toString(method.getParameterTypes())); //get method return type, return "class java.lang.Object", class reference for void System.out.println(method.getReturnType()); //get method modifiers System.out.println(Modifier.toString(method.getModifiers())); //prints "public"
调用Public Method
如果方法是静态的,我们可以传递NULL作为对象参数。
Method method = Class.forName("java.util.HashMap").getMethod("put", Object.class, Object.class); Map<String, String> hm = new HashMap<>(); method.invoke(hm, "key", "value"); System.out.println(hm); // prints {key=value}
调用Private Methods
//invoking private method Method method = Class.forName("com.journaldev.reflection.BaseClass").getDeclaredMethod("method3", null); method.setAccessible(true); method.invoke(null, null); //prints "Method3"
获取指定的Public Constructor
Constructor<?> constructor = Class.forName("com.journaldev.reflection.ConcreteClass").getConstructor(int.class); //getting constructor parameters System.out.println(Arrays.toString(constructor.getParameterTypes())); // prints "[int]" Constructor<?> hashMapConstructor = Class.forName("java.util.HashMap").getConstructor(null); System.out.println(Arrays.toString(hashMapConstructor.getParameterTypes())); // prints "[]"
实例化对象使用Constructor
Constructor<?> constructor = Class.forName("com.journaldev.reflection.ConcreteClass").getConstructor(int.class); //getting constructor parameters System.out.println(Arrays.toString(constructor.getParameterTypes())); // prints "[int]" Object myObj = constructor.newInstance(10); Method myObjMethod = myObj.getClass().getMethod("method1", null); myObjMethod.invoke(myObj, null); //prints "Method1 impl." Constructor<?> hashMapConstructor = Class.forName("java.util.HashMap").getConstructor(null); System.out.println(Arrays.toString(hashMapConstructor.getParameterTypes())); // prints "[]" HashMap<String,String> myMap = (HashMap<String,String>) hashMapConstructor.newInstance(null);