Java 标记接口(Serializable/Cloneable/RandomAccess)
简介:Java中的标记接口(Marker Interface),又称标签接口,是个空接口,对于实现了标记接口的类,可以在运行时通过反射机制去获取元数据,现在Spring中的注解(Annotation)已经成了维护元数据的最好方式。
一、Serializable
1. 作用:实现java.io.Serializable接口,可以将类进行序列化和反序列化;
2. 概念组
A. 序列化:指把对象转换为字节序列的过程;
B. 反序列化:指把字节序列恢复成对象的过程;
3. 为保证serialVersionUID值跨不同Java编译器实现的一致性,序列化类必须声明一个明确的serialVersionUID值。
二、Cloneable
1. 对象创建方式
A. 使用new操作符创建一个对象,但new出来的对象的属性都还是初始化的值;
B. 使用clone方法复制一个对象,而clone的对象包含对象存在的属性值,且clone是通过navtive底层实现,所以比set速度快;
2. 克隆分类:浅拷贝和深拷贝,主要区别在于是否支持引用类的成员变量的复制;
3. 浅拷贝(ShallowClone)
A. 定义:如果原型对象的成员变量是基本数据类型,将复制一份给拷贝对象;如果原型对象的成员变量是引用类型,就将引用对象的地址复制一份给拷贝对象(二者指向相同的内存地址);
B. 实现步骤
第一步:被复制的类需要实现java.lang.Cloneable标记接口,否则调用clone方法会抛出CloneNotSupportedException异常;
第二步:覆盖clone方法,访问修饰符设为public,调用super.clone()方法得到需要的拷贝对象;
C. 示例
package com.ruhuanxingyun.javabasic.clone; import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; /** * @description: 浅克隆 * @author: ruphie * @date: Create in 2020/10/20 21:08 * @company: ruhuanxingyun */ public class ShallowClone { public static void main(String[] args) throws CloneNotSupportedException { Skill skill = new Skill("跳远"); Student student1 = new Student("张三", 19, skill); // 数据拷贝 Object student2 = student1.clone(); System.out.println("是否相等:" + (student1 == student2)); System.out.println("student1:" + student1 + ",student2:" + student2); student1.setName("李四"); skill.setSkillName("拔河"); System.out.println("student1:" + student1 + ",student2:" + student2); } @Data @NoArgsConstructor @AllArgsConstructor private static class Student implements Cloneable { /** * 姓名 */ private String name; /** * 年龄 */ private Integer age; /** * 技能对象 */ private Skill skill; /** * 注:方法的权限修饰符改为public */ @Override public Object clone() throws CloneNotSupportedException { return super.clone(); } } @Data @NoArgsConstructor @AllArgsConstructor private static class Skill { /** * 技能 */ private String skillName; } }
4. 深拷贝(DeepClone)
A. 定义:无论原型对象的成员变量是基本数据类型还是引用类型,都将复制一份给拷贝对象,深克隆将原型对象的所有引用对象也复制一份给拷贝对象;
B. 实现方式
方式一:通过覆盖Object类的clone()方法实现;
方式二:通过序列化(Serialization)方式实现;
C. 多层拷贝问题:指引用类型里面包含很多引用类型,或者内层引用类型的类里面又包含引用类型,需用使用序列化的方式来解决;
D. 示例
package com.ruhuanxingyun.javabasic.clone; import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; /** * @description: 深克隆 * @author: ruphie * @date: Create in 2020/10/20 21:38 * @company: ruhuanxingyun */ public class DeepClone { public static void main(String[] args) throws CloneNotSupportedException { Skill skill = new Skill("跳远"); Student student1 = new Student("张三", 19, skill); // 数据拷贝 Object student2 = student1.clone(); System.out.println("是否相等:" + (student1 == student2)); System.out.println("student1:" + student1 + ",student2:" + student2); student1.setName("李四"); skill.setSkillName("拔河"); System.out.println("student1:" + student1 + ",student2:" + student2); } @Data @NoArgsConstructor @AllArgsConstructor private static class Student implements Cloneable { /** * 姓名 */ private String name; /** * 年龄 */ private Integer age; /** * 技能对象 */ private Skill skill; /** * 注:方法的权限修饰符改为public * 深克隆不能简单的调用父类clone方法 */ @Override public Object clone() throws CloneNotSupportedException { Student student = (Student) super.clone(); Skill skill = (Skill) this.skill.clone(); student.setSkill(skill); return student; } } @Data @NoArgsConstructor @AllArgsConstructor private static class Skill implements Cloneable { /** * 技能 */ private String skillName; @Override public Object clone() throws CloneNotSupportedException { return super.clone(); } } }
三、RandomAccess
1. 作用:实现接口java.util.RandomAccess,用来表明其支持快速(通常是固定时间)随机访问,主要目的是允许一般的算法更改其行为,从而在将其应用到随机或连续访问列表时能提供良好的性能;
2. 应用:如果List实现了该接口,那么使用for循环的方式获取数据的性能会优于用迭代器获取数据。
List<String> list = new ArrayList<>(3);
list.add("aa");
list.add("bb");
list.add("cc);
// 随机访问
for (int i = 0, len = list.size(); i < len; i++) { list.get(i); }
// 顺序访问 for (Iterator it = list.iterator(); it.hasNext(); ) { it.next(); }