有关Java反射的使用看这一篇就够了
2018-09-14 20:02
295 查看
1. 简介
本篇文章不探讨反射的实现机制或者说实现原理,仅仅从使用的角度去讲解我们常用的一些API接口,方便自己以后需要使用时信手拈来,同时也方便广大博友能够快速了解API的使用。
什么是反射?
反射是java语言的一个特性,它允许一个java的类获取他所有的成员变量和方法并且显示出来,这样说起来有些抽象,例如我们可以通过反射去实例化一个对象,并不非得使用new这个关键字来实例化,同时我们也可以通过反射知道Java类中有哪些变量、哪些方法等等,这些特性在C或者C++语言中是不存在的。
反射中,我们会常用到三个类,分别为Class、Method和Field,通过类名相信大家已经能够知道大概意思,分别代表类、方法和变量,本篇文章将会用大量的Demo来讲解这三个类中的部分常用重要API的作用,Demo中用到的一个实体类如下:
-
public class Person {
-
private String name;
-
public Person() {
-
System.out.println("Person()...");
-
}
-
public Person(String name) {
-
this.name = name;
-
System.out.println("Person(String name)...");
-
}
-
private void privateMethod(){
-
System.out.println("privateMethod-->name="+this.name);
-
}
-
protected void protectedMethod(){
-
System.out.println("protectedMethod-->name="+this.name);
-
}
-
void defaultMethod(){
-
System.out.println("defaultMethod-->name="+this.name);
-
}
-
public void setName(String name) {
-
this.name = name;
-
System.out.println("setName()...");
-
}
-
public String getName() {
-
System.out.println("getName()...");
-
return name;
-
}
-
@Override
-
public String toString() {
-
return "name: "+this.name;
-
}
-
}
2. Class 类
2.1 获取Class实例
-
// 方法一 forName函数
-
Class c= Class.forName("Person");
-
// 方法二 getClass()函数
-
Person person = new Person();
-
Class c = person.getClass();
-
// 方法三 使用类字面常量
-
Class c=Person.class;
2.2 通过反射来实例化对象
-
// 方法一
-
try {
-
Class c = Person.class;
-
Person person = (Person) c.newInstance();
-
System.out.println(person instanceof Person); // true
-
} catch (InstantiationException e) {
-
e.printStackTrace();
-
} catch (IllegalAccessException e) {
-
e.printStackTrace();
-
}
-
// 方法二
-
try {
-
Class c = Class.forName("reflect.demo.Person");
-
Person person = (Person) c.newInstance();
-
System.out.println(person instanceof Person); // true
-
} catch (ClassNotFoundException e) {
-
e.printStackTrace();
-
} catch (IllegalAccessException e) {
-
e.printStackTrace();
-
} catch (InstantiationException e) {
-
e.printStackTrace();
-
}
以上方式都是调用的Person类无参构造,如果需要调用Person(String name),改如何呢?
-
// 首先获取到Person类中的有参构造,通过构造函数实例化对象
-
try {
-
Class c = Person.class;
-
Constructor constructor = c.getConstructor(new Class[]{String.class});
-
// 调用的是有参构造
-
Person person = (Person) constructor.newInstance("jack");
-
System.out.println(person.toString()); // name: jack
-
} catch (NoSuchMethodException e) {
-
e.printStackTrace();
-
} catch (IllegalAccessException e) {
-
e.printStackTrace();
-
} catch (InstantiationException e) {
-
e.printStackTrace();
-
} catch (InvocationTargetException e) {
-
e.printStackTrace();
-
}
2.3 获取类中所有的方法对象
-
try {
-
Class c = Person.class;
-
// 方式一
-
Method [] methods = c.getMethods(); // 获取所有公共方法,且包括父类的共有方法
-
for (Method method:methods) {
-
System.out.print(method.getName()+", ");
-
}
-
System.out.println("");
-
// 方式二
-
methods = c.getDeclaredMethods(); // 获取所有方法,包括私有、共有等,但是只定义在该类中
-
for (Method method:methods) {
-
System.out.print(method.getName()+", ");
-
}
-
} catch (Exception e) {
-
e.printStackTrace();
-
}
-
输出:
-
toString, getName, setName, wait, wait, wait, equals, hashCode, getClass, notify, notifyAll,
-
toString, getName, setName, protectedMethod, privateMethod, defaultMethod,
-
// 其他
-
Method getMethod(String name, Class<?>... parameterTypes) // 获取某个方法对象,只能是共有的
-
Method getDeclaredMethod(String name, Class<?>... parameterTypes) // 获取获取某个方法对象,只能是当前类的,可以是private、public等
2.4 获取类中字段对象
-
try {
-
Class c = Person.class;
-
Field[] fields = c.getFields(); // 同 getMethods
-
for (Field field : fields) {
-
System.out.print(field.getName() + ", ");
-
}
-
System.out.println("5***************");
-
fields = c.getDeclaredFields(); // 同 getDeclaredMethods
-
for (Field field : fields) {
-
System.out.print(field.getName() + ", ");
-
}
-
} catch (Exception e) {
-
e.printStackTrace();
-
}
2.5 其他方法
- getName : 返回类名,包括包名
- getSimpleName: 返回类名,不包含包名
- cast(Object obj):将obj类型对象转化为当前class类型对象
-
Class cc = Person.class;
-
// getName: reflect.demo.Person getSimpleName: Person
-
System.out.println("getName: "+cc.getName()+" getSimpleName: "+cc.getSimpleName());
3. Method类
- getName() 获取方法名
- invoke(Object obj, Object... args) 执行obj中该方法
- Parameter[] getParameters() 获取方法中的参数
- setAccessible(boolean flag) 设置访问权限
-
Person per = new Person();
-
Class c = Person.class;
-
Method method;
-
try {
-
method = c.getDeclaredMethod("setName", String.class);
-
System.out.println(method.getName()); // 输出: setName
-
method.invoke(per, "hello reflect"); // 调用了 setName方法
-
System.out.println(per); // 输出 name: hello reflect
-
Parameter[] parameters = method.getParameters();
-
for (Parameter parameter:parameters) {
-
System.out.print(parameter.getName()+", "); // 输出:arg0
-
}
-
} catch (Exception e) {
-
e.printStackTrace();
-
}
-
// 如何反射调用私有方法
-
try {
-
method = c.getDeclaredMethod("privateMethod");
-
method.setAccessible(true); // 私有方法必须设置访问权限为true
-
method.invoke(per); // 调用privateMethod方法
-
} catch (Exception e) {
-
e.printStackTrace();
-
}
4. Field API
- String getName() 获取变量名
- setAccessible(boolean flag) 设置访问权限
- Object get(Object obj) 获取obj对象中改变量值
- set(Object obj, Object value) 将obj对象中的改变量值设置为value
-
Class c = Person.class;
-
Person person = new Person("lvjie");
-
try {
-
// Field field = c.getField("name"); // 只能获取到共有变量,包括父类
-
Field field = c.getDeclaredField("name"); // 可以获取当前类中定义的任何变量,包括private、public等
-
System.out.println(field.getName()); // name
-
field.setAccessible(true); // 私有变量必须设置访问权限为true
-
System.out.println(field.get(person)); // 获取该对象中的变量值,私有变量需要添加访问权限
-
System.out.println(person); // name: lvjie
-
field.set(person, "jack"); // 对该对象的变量设置值, 私有变量需要添加访问权限
-
System.out.println(person); // name: jack
-
} catch (Exception e) {
-
e.printStackTrace();
-
}
以上相关API在使用反射过程中是经常遇见的,当然还有其他相关API,例如获取该类、方法和变量上使用到的注解等等,这些在注解的使用上会做讲解。反射配合注解,会产生巨大的功能,目前许多开源库也是基于这两点技术来实现,例如Android中的 EventBus、ButterKnife、DBFlow等等。
如果对Java注解感兴趣,请看下一篇Java注解全面总结
阅读更多相关文章推荐
- 有关Java中数组和反射的使用
- java 反射的一些使用总结
- 使用Java5特性来简化反射编程
- 使用Java5特性来简化反射编程
- 通过反射动态使用Java类(转)
- 有关使用和部署 Java 持久性体系结构 (JPA) 的案例研究
- 在Java中使用反射分析类结构
- JAVA反射使用手记
- 使用反射简化ajax中的处理代码(Java版)
- 转帖一篇 牛文。。教父人物Bruce Ecke:Thinking in Java和 Thinking in C++ 的作者 谈论有关 java ,ajax 和 flex 的。
- JAVA反射使用手记
- 转一篇有关Java的内存泄露的文章(受益哦)
- 转载一篇有关ramdisk 的使用的文章
- 使用Java5特性来简化反射编程
- 一篇有关《JAVA的未来和发展》 B 转载
- 使用java反射操作类的构造函数,成员变量和成员方法
- JAVA反射使用手记
- 使用 java 的反射 和 comparator 实现java bean 的简单排序
- 使用Java 5特性来简化反射编程
- 使用Java5特性来简化反射编程