反射的作用
- 程序可以访问, 检测和修改它本身状态或行为的能力, 即自描述和自控制
- 可以在运行时加载, 探知和使用编译期间完全未知的类
- 反射在java.lang.reflect包中,在Java2就有,在Java5得到完善
反射的功能
- 在运行中分析类的能力
- 在运行中查看和操作对象
- 基于反射自由创建对象
- 反射构建出无法直接访问的类
- set或get到无法访问的成员变量
- 调用不可访问的方法
- 实现通用的数组操作代码
- 实现类似函数指针的功能
Java中创建对象的方式
java中常用的接口
- Comparable用于对象比较接口
- Runnable用于对象线程化接口
- Serializable用于对象序列化接口
- Clonable用于对象克隆接口
方法1
public class Demo6 {
public static void main(String[] args) {
A a = new A();
a.hello();
}
}
class A {
public void hello() {
System.out.println("Hello from A");
}
}
方法2
public class Demo6 {
public static void main(String[] args) {
// 注意clone相当于在内存中有两个该对象的副本
B obj2 = new B();
obj2.hello();
B obj3 = null;
try {
obj3 = (B) obj2.clone();
} catch (CloneNotSupportedException e) {
e.printStackTrace();
}
obj3.hello();
}
}
// 使用clone的方法
class B implements Cloneable {
public void hello() {
System.out.println("hello from B");
}
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
}
方法3
public class Demo6 {
public static void main(String[] args) {
C obj = new C();
// 定义文件输出流
try {
// 将对象信息输出到data.obj文件中
ObjectOutputStream out = new ObjectOutputStream(
new FileOutputStream("data.obj"));
out.writeObject(obj);
out.close();
} catch (IOException e) {
e.printStackTrace();
}
// 定义文件输入流
try {
// 读取data.obj文件创建对象
ObjectInputStream in = new ObjectInputStream(
new FileInputStream("data.obj"));
C obj1 = (C) in.readObject();
in.close();
obj1.hello();
} catch (Exception e) {
e.printStackTrace();
}
}
}
// 使用序列化和反序列化
// 由于序列化就引发安全漏洞,可能在JDK未来的版本中移除掉
class C implements Serializable {
private static final long serialVersionUID = -1383000935440370829L;
public void hello() {
System.out.println("hello from C");
}
}
方法4
项目路径
public class Demo1 {
public static void main(String[] args) {
// 使用反射机制创建对象
try {
// 读取A.class文件并创建对象
Object object = Class.forName("exmple.com.demo4.A").newInstance();
// 调用对象中的方法
Method method = Class.forName("exmple.com.demo4.A").getMethod("hello");
method.invoke(object);
} catch (Exception e) {
e.printStackTrace();
}
}
}
反射关键类
- Class:是类型的标识
- JVM为每个对象都保留其类型标识信息
获取类型标识信息
public static void main(String[] args) {
// 方式1
String s1 = "abc";
Class c1 = s1.getClass();
// 获取类型的包全名
System.out.println(c1.getName());// java.lang.String
// 方式2
try {
Class c2 = Class.forName("java.lang.String");
System.out.println(c2.getName());
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
// 方式3
Class c3 = String.class;
System.out.println(c3.getName());
}
getFields() / getDeclareFields() | getFields()返回本类和父类所有的属性,getDeclareFields()返回本类中的属性,不包括父类 |
---|---|
getMethods() / getDeclareMethods() | getMethods()返回本类和父类所有的方法,getDeclareMethods()返回本类中的属性,不包括父类 |
getPackage() | 返回本类所在的包 |
getModifiers() | 返回本类的前缀修饰符,如public等 |
getInterfaces() | 返回本类所继承的接口,以Class的方式显示 |
getSuperClass() | 返回本类的父类 |
getConstructors() | 返回本类的所有构造函数 |
getAnnotation() | 返回本类相应的注解 |
获取成员变量
public class Demo2 {
public static void main(String[] args) {
B obj = new B(20, "Tom");
Class c = obj.getClass();
// 获取本类及父类所有的public字段
Field[] fs = c.getFields();
try {
System.out.println(fs[0].getName() + ":"
+ fs[0].get(obj));
} catch (IllegalAccessException e) {
e.printStackTrace();
}
// 获取本类所有声明的字段
Field[] fs2 = c.getDeclaredFields();
for (Field f : fs2) {
// 将获取到的private属性设置为可以临时访问
f.setAccessible(true);
try {
System.out.println(f.getName() + ":" + f.get(obj));
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
}
}
class B {
public int age;
private String name;
public B(int age, String name) {
this.age = age;
this.name = name;
}
}
获取成员方法
public class Demo2 {
public static void main(String[] args) throws InvocationTargetException, IllegalAccessException {
B obj = new B();
Class c = obj.getClass();
// 获取public方法包括父类及父接口
Method[] ms = c.getMethods();
for (Method m : ms) {
// 调用f1函数
if ("f1".equals(m.getName())) {
m.invoke(obj, null);
}
}
// 获取该类的所有方法
Method[] ms2 = c.getDeclaredMethods();
for (Method m : ms2) {
// 调用f2函数
if ("f2".equals(m.getName())) {
m.setAccessible(true);
String result = (String) m.invoke(obj, "abc");
System.out.println(result);
}
}
}
}
class B {
public void f1() {
System.out.println("B f1 function");
}
public String f2(String s) {
System.out.println("B f2 function");
return s;
}
}
运行结果
B f1 function
B f2 function
abc
获取构造函数
public class Demo2 {
public static void main(String[] args) throws IllegalAccessException, InvocationTargetException, InstantiationException {
D d = new D();
Class c = d.getClass();
Constructor[] cons = c.getConstructors();
for (Constructor con : cons) {
// 调用有参构造
if (con.getParameterCount() > 0) {
D obj = (D) con.newInstance(100);
obj.printNum();
} else {
// 无参构造
D obj = (D) con.newInstance();
obj.printNum();
}
}
}
}
class D {
private int num;
public D() {
this.num = 10;
}
public D(int num) {
this.num = num;
}
public void printNum() {
System.out.println(this.num);
}
}
运行结果:
10
100
反射应用
JDBC
// 构建Java和数据库之间的桥梁
try {
Class.forName("com.mysql.jdbc.Driver");
System.out.prinln("注册成功");
} catch (ClassNotFoundException e) {
System.out.prinln("注册失败");
e.printStackTrace();
return ;
}
数组扩充
- Java的数组一旦创建,其长度是不再更改的
- 新建一个大数组(相同类型),然后将旧数组的内容拷贝过去
public static void main(String[] args) {
int[] a = { 1, 2, 3, 4, 5};
System.out.println(a.length);
a = (int[]) goodCopy(a, 10);
System.out.println(a.length);
}
public static Object goodCopy(Object oldArray, int newLength) {
// Array类型
Class c = oldArray.getClass();
// 获取数组中单个元素的类型
Class componentType = c.getComponentType();
// 获取数组的长度
int oldLength = Array.getLength(oldArray);
// 新数组
Object newArray = Array.newInstance(componentType, newLength);
// 拷贝旧数据
System.arraycopy(oldArray, 0, newArray, 0 , oldLength);
return newArray;
}
运行结果:
5
10
动态执行方法
- 给定类名、方法名、即可执行
- 加上定时器,即可做定时任务执行
public class Demo3 {
public static void main(String[] args) {
// 创建定时器对象
Timer timer = new Timer();
// 获取当前时间对象
Calendar now = Calendar.getInstance();
// 当前时间+1s
now.set(Calendar.SECOND, now.get(Calendar.SECOND) + 1);
Date runDate = now.getTime();
// 定时任务
MyTesk task2 = new MyTesk();
// 每3s执行一次
timer.scheduleAtFixedRate(task2, runDate, 3000);
}
}
class MyTesk extends TimerTask {
@Override
public void run() {
try {
Method m = Class.forName("exmple.com.demo4.Worker")
.getMethod("hello");
// 静态方法不用new对象
m.invoke(null);
} catch (Exception e) {
e.printStackTrace();
}
}
}
Json和Java对象互转
本案例中使用的是第三方库Gson,而Gson底层是使用反射机制来实现的
Gson gson = new Gson();
String str = "{\"name\":\"jo\"" + ",\"email\":\"a@b.com\"}";
Person p = gson.formJson(str, Person.class);
System.out.println(p.getName());
Systen.out.println(p.getEmail());