java -- 标记接口

打印 上一主题 下一主题

主题 913|帖子 913|积分 2739

标记接口

标记接口(Marker Interface),又称标签接口(Tag Interface)
仅代表一个标记 不包含任何方法
标记接口是用来判断某个类是否具有某种能力
Cloneable标记接口

此类实现了 Cloneable 接口,以指示 Object.clone 方法可以合法地对该类实例进行按字段复制
如果在没有实现 Cloneable 接口的实例上调用 Object 的 clone 方法, 则会导致抛出 CloneNotSupportedException 异常
  1. // Cloneable源码:
  2. public interface Cloneable { }
  3. // 仅代表一个标记
  4. // 克隆的前提条件:
  5.     // 被克隆的对象必须实现Cloneable接口
  6.     // 必须重写clone方法
复制代码
基本使用
  1. public class CloneableDemo {
  2.     public static void main(String[] args) throws CloneNotSupportedException {
  3.         // ArrayList类实现了Cloneable接口
  4.         ArrayList<String> list = new ArrayList<String>();
  5.         list.add("张三");
  6.         list.add("李四");
  7.         list.add("王五");
  8.         ArrayList<String> listClone = (ArrayList<String>) list.clone();
  9.         System.out.println(list == listClone);
  10.         System.out.println(listClone);
  11.     }
  12. }
复制代码
Clone案例:将一个学生的数据复制到另一个学生对象中,并且两个对象不受任何的影响.
传统方式:
  1. public class CloneTest {
  2.     public static void main(String[] args) {
  3.         //传统方式:
  4.         Student stu1 = new Student("张三", 12);
  5.         //再次创建一个新的学生对象
  6.         Student stu2 = new Student();
  7.         //把stu1对象name的值取出来赋值给stu2对象的name
  8.         stu2.setName(stu1.getName());
  9.         //把stu1对象age的值取出来赋值给stu2对象的age
  10.         stu2.setAge(stu1.getAge());
  11.         System.out.println(stu1 == stu2);
  12.         System.out.println(stu1);
  13.         System.out.println(stu2);
  14.         System.out.println("================");
  15.         stu1.setName("李四");
  16.         System.out.println(stu1);
  17.         System.out.println(stu2);
  18.     }
  19. }
  20. class Student {
  21.     private String name;
  22.     private int age;
  23.     public String getName() {
  24.         return name;
  25.     }
  26.     public void setName(String name) {
  27.         this.name = name;
  28.     }
  29.     public int getAge() {
  30.         return age;
  31.     }
  32.     public void setAge(int age) {
  33.         this.age = age;
  34.     }
  35.     public Student(String name, int age) {
  36.         this.name = name;
  37.         this.age = age;
  38.     }
  39.     public Student() {
  40.     }
  41.     @Override
  42.     public String toString() {
  43.         return "Student{" +
  44.                 "name='" + name + '\'' +
  45.                 ", age=" + age +
  46.                 '}';
  47.     }
  48. }
复制代码
此时修改对象1的姓名与对象2的姓名无关
克隆方式(浅拷贝):
  1. /*
  2. 实现Cloneable接口
  3. 重写clone方法 将访问权限改为public 并将返回值类型改为Student
  4. */
  5. class Student implements Cloneable{
  6.     private String name;
  7.     private int age;
  8.     public Student(String name, int age) {
  9.         this.name = name;
  10.         this.age = age;
  11.     }
  12.     @Override
  13.     public Student clone() throws CloneNotSupportedException {
  14.         return (Student) super.clone();
  15.     }
  16. }
复制代码
  1. class CloneTest01 {
  2.     public static void main(String[] args) throws CloneNotSupportedException {
  3.         //克隆方式
  4.         //创建学生对象
  5.         Student stu1 = new Student("张三",12);
  6.         //通过克隆获得一个student对象
  7.         Student stu2 = stu1.clone();
  8.         System.out.println(stu1 == stu2);
  9.         System.out.println(stu1);
  10.         System.out.println(stu2);
  11.         stu1.setName("李四");
  12.         System.out.println(stu1);
  13.         System.out.println(stu2);
  14.     }
  15. }
复制代码
浅拷贝的局限性:基本数据类型(包括String)可以达到完全复制,引用数据类型则不可以;
  1. class Student implements Cloneable{
  2.     private String name;
  3.     private int age;
  4.     private Car car;
  5.     @Override
  6.     public Student clone() throws CloneNotSupportedException {
  7.         return (Student) super.clone();
  8.     }
  9. }
  10. class Car {
  11.     private String brand;
  12.     public Car() {
  13.     }
  14.     public Car(String brand) {
  15.         this.brand = brand;
  16.     }
  17.     public String getBrand() {
  18.         return brand;
  19.     }
  20.     public void setBrand(String brand) {
  21.         this.brand = brand;
  22.     }
  23.     @Override
  24.     public String toString() {
  25.         return "Car{" +
  26.                 "brand='" + brand + '\'' +
  27.                 '}';
  28.     }
  29. }
  30. class CloneTest02 {
  31.     public static void main(String[] args) throws CloneNotSupportedException {
  32.         //克隆方式
  33.         //创建学生对象
  34.         Student stu1 = new Student("张三",12,new Car("宝马"));
  35.         //通过克隆获得一个student对象
  36.         Student stu2 = stu1.clone();
  37.         System.out.println(stu1 == stu2);
  38.         System.out.println(stu1);
  39.         System.out.println(stu2);
  40.         stu1.setName("李四");
  41.         //stu1获得了Car修改Car的品牌
  42.         stu1.getCar().setBrand("奔驰");
  43.         //浅拷贝的局限性 引用类型只是拷贝了地址值 修改一个对象的的属性 另一个也改变了
  44.         System.out.println(stu1);
  45.         System.out.println(stu2);
  46.     }
  47. }
复制代码
使用深拷贝解决上述问题
  1. //首先 Car类实现克隆接口 重写clone方法
  2. class Car implements Cloneable {
  3.     private String brand;
  4.     public Car() {
  5.     }
  6.     public Car(String brand) {
  7.         this.brand = brand;
  8.     }
  9.     public String getBrand() {
  10.         return brand;
  11.     }
  12.     public void setBrand(String brand) {
  13.         this.brand = brand;
  14.     }
  15.     @Override
  16.     public String toString() {
  17.         return "Car{" +
  18.                 "brand='" + brand + '\'' +
  19.                 '}';
  20.     }
  21.     @Override
  22.     protected Car clone() throws CloneNotSupportedException {
  23.         return (Car) super.clone();
  24.     }
  25. }
  26. //修改Student的clone方法
  27. class Student implements Cloneable {
  28.     private String name;
  29.     private int age;
  30.     private Car car;
  31.     public String getName() {
  32.         return name;
  33.     }
  34.     public void setName(String name) {
  35.         this.name = name;
  36.     }
  37.     public Student(String name, int age, Car car) {
  38.         this.name = name;
  39.         this.age = age;
  40.         this.car = car;
  41.     }
  42.     public Car getCar() {
  43.         return car;
  44.     }
  45.     public void setCar(Car car) {
  46.         this.car = car;
  47.     }
  48.     public int getAge() {
  49.         return age;
  50.     }
  51.     public void setAge(int age) {
  52.         this.age = age;
  53.     }
  54.     public Student(String name, int age) {
  55.         this.name = name;
  56.         this.age = age;
  57.     }
  58.     public Student() {
  59.     }
  60.     @Override
  61.     public String toString() {
  62.         return "Student{" +
  63.                 "name='" + name + '\'' +
  64.                 ", age=" + age +
  65.                 ", car=" + car +
  66.                 '}';
  67.     }
  68.     @Override
  69.     public Student clone() throws CloneNotSupportedException {
  70. //        return (Student) super.clone();
  71.         Student student = (Student) super.clone();
  72.         Car car = this.car.clone();
  73.         student.setCar(car);
  74.         return student;
  75.     }
  76. }
复制代码
RandomAccess标记接口

List 实现所使用的标记接口,用来表明其支持快速(通常是固定时间)随机访问。此接口的主要目的是允许一般的算法更改其行为,从而在将其应用到随机或连续访问列表时能提供良好的性能
简单的来说,如果实现了这个接口,普通for循环的速度要优于增强for的速度.
  1. public class ArrayList_Demo01 {
  2.     public static void main(String[] args) {
  3.         //创建ArrayList集合
  4.         List<String> list = new ArrayList<String>();
  5.         //添加100W条数据
  6.         for (int i = 0; i < 1000000; i++) {
  7.             list.add(i+"a");
  8.         }
  9.         //测试普通循环
  10.         long startTime = System.currentTimeMillis();
  11.         for (int i = 0; i < list.size(); i++) {
  12.             //取出集合的每一个元素
  13.             list.get(i);
  14.         }
  15.         long endTime = System.currentTimeMillis();
  16.         System.out.println("普通循环遍历: "+(endTime-startTime));
  17.         //测试迭代器遍历
  18.         startTime = System.currentTimeMillis();
  19.         //获取迭代器
  20.         Iterator<String> it = list.iterator();
  21.         while (it.hasNext()){
  22.             //取出集合的元素
  23.             it.next();
  24.         }
  25.         endTime = System.currentTimeMillis();
  26.         System.out.println("迭代器遍历: "+(endTime-startTime));
  27.     }
  28. }
复制代码
LinkedList没有实现此接口,测试:
  1. ublic class LinkedList_Demo01 {
  2.     public static void main(String[] args) {
  3.         //创建LinkedList集合
  4.         List<String> list = new LinkedList<String>();
  5.         //添加10W条数据
  6.         for (int i = 0; i < 100000; i++) {
  7.             list.add(i+"b");
  8.         }
  9.         //测试普通遍历时间
  10.         long startTime = System.currentTimeMillis();
  11.         for (int i = 0; i < list.size(); i++) {
  12.             //取出集合的每一个元素
  13.             list.get(i);
  14.         }
  15.         long endTime = System.currentTimeMillis();
  16.         System.out.println("普通遍历时间: "+(endTime-startTime));
  17.         //测试迭代器
  18.         startTime = System.currentTimeMillis();
  19.         //获取迭代器
  20.         Iterator<String> it = list.iterator();
  21.         while (it.hasNext()){
  22.             //取出集合的每一个元素
  23.             it.next();
  24.         }
  25.         endTime = System.currentTimeMillis();
  26.         System.out.println("顺序迭代器访问时间: "+(endTime-startTime));
  27.     }
  28. }
复制代码
实际应用
  1. public class Test {
  2.     public static void main(String[] args) {
  3.         //我们今后可能有的集合不是直接创建的 可能是别人传递的
  4.         //我们看到的就是一个List接口
  5.         //至于具体的实现类可能不清楚
  6.         List<String>  list = new ArrayList<>();
  7.         //list = new LinkedList<>();
  8.         //我们可以判断以下 这个list集合是否实现了RandomAccess接口
  9.         //如果实现了 可以使用随机访问的方式来进行遍历
  10.         //如果没实现 可以使用迭代器的方式来进行遍历 这样可以提高效率
  11.         if(list instanceof  RandomAccess){
  12.             for (int i = 0; i < list.size(); i++) {
  13.             }
  14.         }else {
  15.             for (String s : list) {
  16.             }
  17.         }
  18.     }
  19. }
复制代码
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

兜兜零元

金牌会员
这个人很懒什么都没写!

标签云

快速回复 返回顶部 返回列表