Android开发者必知的Java知识(一):Java反射机制
最近重新温习了一下java的反射机制,终结了一些东西,供大家参考
转载请注明出处:http://blog.csdn.net/qinjunni2014/article/details/44106243
1. 获取函数
getMethod
获取所有继承的方法,以及自己声明的public方法,
getDclaredMethod
获取所有自己单独声明的方法,不论处于什么访问状态
代码为证:
class MethodsDisplay {
public static void displayMethods(Class clazz) throws Throwable {
System.out.println("getMethods拿到的方法: ");
Method[] methods = clazz.getMethods();
for (int i = 0; i < methods.length; i++) {
Method method = methods[i];
System.out.println("方法名称 " + method.getName());
// System.out.println("param type " +
// method.getParameterTypes().toString());
}
}
public static void displayDeclaredMethods(Class clazz) throws Throwable {
System.out.println("getDeclaredMethods拿到的方法: ");
Method[] methods = clazz.getDeclaredMethods();
for (int i = 0; i < methods.length; i++) {
Method method = methods[i];
System.out.println("方法名称 " + method.getName());
// System.out.println("param type " +
// method.getParameterTypes().toString());
}
}
}
getDeclaredMethods拿到的方法:
方法名称 name
方法名称 hello
方法名称 printh
方法名称 smile
getMethods拿到的方法:
方法名称 smile
方法名称 wait
方法名称 wait
方法名称 wait
方法名称 equals
方法名称 toString
方法名称 hashCode
方法名称 getClass
方法名称 notify
方法名称 notifyAll
调用私有函数
调用私有函数必须先调用getDeclaredMethod拿到函数, 而且必须在调用前,设置函数accessible
MyObject myObject = new MyObject();
Method method = MyObject.class.getDeclaredMethod("printh");
method.setAccessible(true);
method.invoke(myObject);
调用构造函数
调用构造函数较为特殊,必须使用getDelcaredConstructor获得 一个类型为Constructor的实例,并调用newInstance构造对象
class Person {
private String name;
private int age;
public Person() {
System.out.println("default constructor");
}
public Person(String _name, int _age) {
name = _name;
age = _age;
System.out.println("Constructor with two int params");
}
private void printh() {
System.out.println("invoke private method");
}
protected void name() {
System.out.println(name);
}
void hello(){
System.out.println("hello");
}
public void smile() {
System.out.println("Smiling...");
}
}
try {
Class[] paramTypes = {String.class, int.class};
Constructor con = Person.class.getDeclaredConstructor(paramTypes);
Person person = (Person) con.newInstance("LiLi",18);
person.name();
} catch (InstantiationException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
Class.newInstance
创建对象,除了使用Constructor.newInstance方法外,还可使用Class.newInstance方法,但只限于无参默认构造函数:
Person p = Person.class.newInstance();
p.smile();
如果我们注释掉Person中得无参构造函数, 则在运行上述代码时,会抛出Exception:
Exception in thread "main" java.lang.InstantiationException: Person
at java.lang.Class.newInstance(Class.java:364)
at ReflectMain.main(ReflectMain.java:47)
2. 获取变量
对于Field, 同样有两种获取的函数,getDeclaredField, getField…, 与获取函数一样,两种函数的区别在于 是否包含 继承的field以及private field
- getField: 获取继承的field以及声明的public field
- getDeclaredField: 获取自身声明的field
代码为证:
class Person {
public static final String FEMALE = "female";
public static final String MALE = "male";
private String gender;
public String name;
private int age;
}
class Student extends Person{
public int level;
private int score;
}
class FieldDisplay{
public static void displayFields(Class clazz) throws Throwable{
System.out.println("display getFields:");
Field[] fields = clazz.getFields();
for(int i=0;i< fields.length;i++){
Field field = fields[i];
System.out.println(field.getType()+ ": "+field.getName());
}
}
public static void displayDeclaredFields(Class clazz) throws Throwable{
System.out.println("display getDeclaredFields:");
Field[] fields = clazz.getDeclaredFields();
for(int i=0;i< fields.length;i++){
Field field = fields[i];
System.out.println(field.getType()+ ": "+field.getName());
}
}
}
FieldDisplay.displayFields(Student.class);
FieldDisplay.displayDeclaredFields(Student.class);
输出为:
display getFields:
int: level
class java.lang.String: FEMALE
class java.lang.String: MALE
class java.lang.String: name
display getDeclaredFields:
int: level
int: score
访问私有变量只需对Field调用setAccessible(true)
获取Class
获取Class对象,有两种方法:
- 当我们能访问到该类时,例如Person类,我们可以直接调用Person.class 或者 Person类的对象person的getClass 方法
- 但我们无法访问该类时,我们如果知道该类的完整名称(包括包名),可以直接调用Class.forName进行类的加载
Class.forName
Class.forName有两种重载形式:
- Class.forName(String className)
- forName(String name, boolean initialize, ClassLoader loader) loader指定使用某个类加载器,initialize决定是否初始化
关于类加载器,我们在此不深究,有兴趣的可以参考Java官方文档.
好了,讲了这些Java 反射中最常用到的API,其实只是在为下一步讲解Java 中得annotation作铺垫,小哥即将下篇关于Annotation的介绍,敬请期待。