1、什么是反射?
动态获取类信息以及动态调用对象的方法的功能称为 Java 语言的反射机制。
2、哪里用到了反射?
- JDBC中,利用反射动态加载了数据库驱动程序。
- Web服务器中利用反射调用了Sevlet的服务方法。
- Eclispe等开发工具利用反射动态刨析对象的类型与结构,动态提示对象的属性和方法。
- 很多框架都用到反射机制,注入属性,调用方法,如Spring。
3. Java反射机制的作用
- 在运行时判断任意一个对象所属的类
- 在运行时构造任意一个类的对象
- 在运行时判断任意一个类所具有的成员变量和方法
- 在运行时调用任意一个对象的方法
4、如何使用Java的反射?
1、通过一个全限类名获取类对象
Class.forName(“全限类名”); 例如:com.mysql.jdbc.Driver Driver类已经被加载到 jvm中,并且完成了类的初始化工作就行了
类名.class; 获取Class<?> clz 对象
对象.getClass();
2、获取构造器对象,通过构造器new出一个对象
Clazz.getConstructor([String.class]);
Con.newInstance([参数]);
3、通过class对象创建一个实例对象(就相当与new类名()无参构造器)
Cls.newInstance();
4、通过class对象获得一个属性对象
Field c=cls.getFields():获得某个类的所有的公共(public)的字段,包括父类中的字段。
Field c=cls.getDeclaredFields():获得某个类的所有声明的字段,即包括public、private和proteced,但是不包括父类的声明字段
5、通过class对象获得一个方法对象
Cls.getMethod(“方法名”,class……parameaType);(只能获取公共的)
Cls.getDeclareMethod(“方法名”);(获取任意修饰的方法,不能执行私有)
M.setAccessible(true);(让私有的方法可以执行)
6、让方法执行
1). Method.invoke(obj实例对象,obj可变参数);-----(是有返回值的)
7、如何利用反射实现深拷贝?
利用反射可以对一个 Object 对象进行深度拷贝,具体步骤如下:
-
获取要拷贝的对象的类类型 Class,可以使用
object.getClass()方法获取。 -
创建一个新的实例对象,可以使用
clazz.newInstance()方法创建。 -
获取要拷贝的对象的所有字段,包括私有字段。
-
遍历所有字段,将每个字段的值赋值给新对象的同名字段。对于引用类型的字段,需要递归拷贝。
1 import java.lang.reflect.Field; 2 3 public class DeepCopyUtil { 4 public static <T> T deepCopy(T obj) throws Exception { 5 // 获取对象的类类型 6 Class<?> clazz = obj.getClass(); 7 8 // 创建新的实例对象 9 T newObj = (T) clazz.newInstance(); 10 11 // 获取对象的所有字段,包括私有字段 12 Field[] fields = clazz.getDeclaredFields(); 13 for (Field field : fields) { 14 // 设置可访问私有字段 15 field.setAccessible(true); 16 17 // 如果该字段是引用类型,则递归地拷贝它 18 if (!field.getType().isPrimitive()) { 19 Object fieldValue = field.get(obj); 20 if (fieldValue != null) { 21 field.set(newObj, deepCopy(fieldValue)); 22 } 23 } else { // 否则直接拷贝该字段的值 24 field.set(newObj, field.get(obj)); 25 } 26 } 27 28 return newObj; 29 } 30 }
8、什么是序列化和反序列化?
(1)对象序列化,将对象中的数据编码为字节流的过程。
(2)反序列化;将对象的编码字节流重新反向解码为对象的过程。
JAVA提供了API实现了对象的序列化和反序列化的功能,使用这些API时需要遵守如下约定:
被序列化的对象类型需要实现序列化(Serializable)接口,此接口是标志接口,没有声明任何的抽象方法,JAVA编译器识别这个接口,自动的为这个类添加序列化和反序列化方法。
为了保持序列化过程的稳定,建议在类中添加序列化版本号。
不想让字段放在硬盘上就加transient
以下情况需要使用 Java 序列化:
1、想把的内存中的对象状态保存到一个文件中或者数据库中时候;
2、想用套接字在网络上传送对象的时候;
3、想通过RMI(远程方法调用)传输对象的时候。
声明为static和transient类型的成员数据不能被序列化。因为static代表类的状态,transient代表对象的临时数据。
9、序列化和反序列化实现对 Object 对象的拷贝。
具体步骤如下:
-
将要拷贝的对象进行序列化,得到一个字节流。
-
将字节流反序列化成一个新的对象,即完成了对象的拷贝。
1 import java.io.ByteArrayInputStream; 2 import java.io.ByteArrayOutputStream; 3 import java.io.ObjectInputStream; 4 import java.io.ObjectOutputStream; 5 6 public class DeepCopyUtil { 7 public static <T> T deepCopy(T obj) throws Exception { 8 // 创建字节输出流 9 ByteArrayOutputStream bos = new ByteArrayOutputStream(); 10 11 // 将对象写入字节输出流中 12 ObjectOutputStream oos = new ObjectOutputStream(bos); 13 oos.writeObject(obj); 14 oos.flush(); 15 oos.close(); 16 17 // 从字节数组中读取对象 18 ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray()); 19 ObjectInputStream ois = new ObjectInputStream(bis); 20 T newObj = (T) ois.readObject(); 21 ois.close(); 22 23 return newObj; 24 } 25 }