java-反射
class
class本身是一种数据类型,class/interface的数据类型是Class,JVM为每个加载的类、接口创建唯一的Class实例。
Class实例包含该class的所有信息,通过Class实例获取class信息的方法称为反射(Reflection)。反射的目的是当获得某个Object实例时,我们可以获得该Object的class信息。
获取一个class的Class实例:
Class cls = String.class;
Class cls = "str".getClass();
Class cls = Class.forName("java.lang.String");
Class实例在JVM中是唯一的
-
== 比较两个实例(只能精确的判断数据类型,不能做子类的比较)
Class cls1 = String.class; String s = "Hello"; Class cls2 = s.getClass(); Class cls3 = Class.forName("java.lang.String"); boolean b1 = cls1==cls2; //true boolean b1 = cls1==cls3; //true
-
使用instanceof(不但匹配当前类型,还匹配当前类型的子类)
Integer n = new Integer(123); boolean b3 = n instanceof Integer; //true boolean b4 = n instanceof Number; //true //Integer是Number的子类 boolean b1 = n.getClass() == Integer.class; //true boolean b2 = n.getClass() == Number.class; //false
-
通常情况下我们使用instanceof进行比较。
从Class实例获取class信息:
-
getName()
-
getSimpleName()
-
getPackage()
Class cls = String.class; String name = cls.getName(); //"java.lang.String" String sname = cls.getSimpleName(); //"String" String pkg = cls.getPackage().getName(); //"java.lang"
从Class实例判断class类型:
-
isInterface()
-
isEnum()
-
isArray()
-
isPrimitive()
Runnable.class.isInterface(); //true java.time.Month.class.isEnum(); //true String [].class.isArray(); //true int.class.isprimitive(); //true
创建class实例:
-
cls.newInstance()
Class cls = String.class; //new String(); String s = (String)cs.newInstance(); 这里的局限在于,只能调用String类的public、无参的默认构造方法,带参数的构造方法我们没有办法调用。
JVM总是动态加载class,可以在运行期根据条件控制加载class。
-
利用JVM动态加载class的特性,可以在运行期间跟据条件不同加载不同的实现类。
//Commons logging优先使用Log4j: LogFactory factory; if(isClassPresent("org.apache.logging.log4j.LOgger")){ factory = createLog4j(); }else{ factory = createJDKLog(); } boolean isClassPresent(String name){ try{ Class.forName(name); return true; }catch(Exception e){ return false; } }
访问字段 Field对象封装了字段的所有信息
通过Class实例获取字段field信息:
-
getField(name):获取某个public的field(包括父类)
-
getDeclaredField(name):获取当前类的某个field(不包括父类)
-
getFields():获取所有public的field(包括父类)
-
getDeclaredFields():获取当前类的所有field(不包括父类)
Integer n = new Integer(123); Class cls = n.getClass(); Field []fs = cls.getFields(); for(Field f: fs){ f.getName(); f.getType(); f.getModeifiers(); }
Field对象包含一个field的所有信息:
- getName()
- getType()
- getModifiers() 获得修饰符(private、public、protect)
获取和设置field的值:
-
get(Object obj)
-
set(Object, Object)设置一个实例的该字段的值
Integer n = new Integer(234); Class cls = n.getClass(); Field f = cls.getDeclaredField("value"); f.get(n); //234 相当于n.value f.set(n,123); //相当于n.value=456;
通过反射访问Field需要通过SecurityManager设置的规则。
-
SecurityManager的规则阻止对该Field设置accessible:
例如,规则应用于所有java和javax开头的package的类
通过设置setAccessible(true)来访问非public字段(可能会失败)
f.setAccessible(true);
调用方法 Method
通过Class实例获取方法Method信息:
- getMethod(name, Class...):获取某个public的method(包括父类)
- getDeclaredMethod(name, Class...):获取当前类的某个method(不包括父类)
- getMethods():获取所有public的method(包括父类)
- getDeclaredMethods():获取当前类的所有method(不包括父类)
Method对象包含一个method的所有信息:
- getName()
- getReturnType()
- getParameterTypes()
- getModifiers()
调用Method:
- Object invoke(Object obj, Object... args)
通过设置setAccessible(true)来访问非public方法。
反射调用Method也遵守多态的规则。
调用构造方法 Constructor
调用public无参数构造方法:
- Class.newInstance()
通过Class实例获取Constructor信息:
- getConstructor(Class...):获取某个public的Constructor
- getDeclaredConstructor(Class...):获取某个Constructor
- getConstructors():获取所有public的Constructor
- getDeclaredConstructors():获取所有Constructor
通过Constructor实例可以创建一个实例对象:
- newInstance(Object… parameters)
通过设置setAccessible(true)来访问非public构造方法。
获取继承关系
获取父类的Class:
- Class getSuperclass()
- Object的父类是null
- interface的父类是null
获取当前类直接实现的interface:
- Class[] getInterfaces()
- 不包括间接实现的interface
- 没有interface的class返回空数组
- interface返回继承的interface
判断一个向上转型是否成立:
-
bool isAssignableFrom(Class)
Integer.isAssignableFrom(Number.class); //false Number.isAssignableFrom(Integer.class); //true