標記介面 標記介面(Marker Interface),又稱標簽介面(Tag Interface) 僅代表一個標記 不包含任何方法 標記介面是用來判斷某個類是否具有某種能力 Cloneable標記介面 此類實現了 Cloneable 介面,以指示 Object.clone 方法可以合法地對該類實例進 ...
標記介面
標記介面(Marker Interface),又稱標簽介面(Tag Interface)
僅代表一個標記 不包含任何方法
標記介面是用來判斷某個類是否具有某種能力
Cloneable標記介面
此類實現了 Cloneable 介面,以指示 Object.clone 方法可以合法地對該類實例進行按欄位複製
如果在沒有實現 Cloneable 介面的實例上調用 Object 的 clone 方法, 則會導致拋出 CloneNotSupportedException 異常
// Cloneable源碼:
public interface Cloneable { }
// 僅代表一個標記
// 克隆的前提條件:
// 被克隆的對象必須實現Cloneable介面
// 必須重寫clone方法
基本使用
public class CloneableDemo {
public static void main(String[] args) throws CloneNotSupportedException {
// ArrayList類實現了Cloneable介面
ArrayList<String> list = new ArrayList<String>();
list.add("張三");
list.add("李四");
list.add("王五");
ArrayList<String> listClone = (ArrayList<String>) list.clone();
System.out.println(list == listClone);
System.out.println(listClone);
}
}
Clone案例:將一個學生的數據複製到另一個學生對象中,並且兩個對象不受任何的影響.
傳統方式:
public class CloneTest {
public static void main(String[] args) {
//傳統方式:
Student stu1 = new Student("張三", 12);
//再次創建一個新的學生對象
Student stu2 = new Student();
//把stu1對象name的值取出來賦值給stu2對象的name
stu2.setName(stu1.getName());
//把stu1對象age的值取出來賦值給stu2對象的age
stu2.setAge(stu1.getAge());
System.out.println(stu1 == stu2);
System.out.println(stu1);
System.out.println(stu2);
System.out.println("================");
stu1.setName("李四");
System.out.println(stu1);
System.out.println(stu2);
}
}
class Student {
private String name;
private int age;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public Student(String name, int age) {
this.name = name;
this.age = age;
}
public Student() {
}
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
此時修改對象1的姓名與對象2的姓名無關
克隆方式(淺拷貝):
/*
實現Cloneable介面
重寫clone方法 將訪問許可權改為public 並將返回值類型改為Student
*/
class Student implements Cloneable{
private String name;
private int age;
public Student(String name, int age) {
this.name = name;
this.age = age;
}
@Override
public Student clone() throws CloneNotSupportedException {
return (Student) super.clone();
}
}
class CloneTest01 {
public static void main(String[] args) throws CloneNotSupportedException {
//克隆方式
//創建學生對象
Student stu1 = new Student("張三",12);
//通過克隆獲得一個student對象
Student stu2 = stu1.clone();
System.out.println(stu1 == stu2);
System.out.println(stu1);
System.out.println(stu2);
stu1.setName("李四");
System.out.println(stu1);
System.out.println(stu2);
}
}
淺拷貝的局限性:基本數據類型(包括String)可以達到完全複製,引用數據類型則不可以;
class Student implements Cloneable{
private String name;
private int age;
private Car car;
@Override
public Student clone() throws CloneNotSupportedException {
return (Student) super.clone();
}
}
class Car {
private String brand;
public Car() {
}
public Car(String brand) {
this.brand = brand;
}
public String getBrand() {
return brand;
}
public void setBrand(String brand) {
this.brand = brand;
}
@Override
public String toString() {
return "Car{" +
"brand='" + brand + '\'' +
'}';
}
}
class CloneTest02 {
public static void main(String[] args) throws CloneNotSupportedException {
//克隆方式
//創建學生對象
Student stu1 = new Student("張三",12,new Car("寶馬"));
//通過克隆獲得一個student對象
Student stu2 = stu1.clone();
System.out.println(stu1 == stu2);
System.out.println(stu1);
System.out.println(stu2);
stu1.setName("李四");
//stu1獲得了Car修改Car的品牌
stu1.getCar().setBrand("賓士");
//淺拷貝的局限性 引用類型只是拷貝了地址值 修改一個對象的的屬性 另一個也改變了
System.out.println(stu1);
System.out.println(stu2);
}
}
使用深拷貝解決上述問題
//首先 Car類實現克隆介面 重寫clone方法
class Car implements Cloneable {
private String brand;
public Car() {
}
public Car(String brand) {
this.brand = brand;
}
public String getBrand() {
return brand;
}
public void setBrand(String brand) {
this.brand = brand;
}
@Override
public String toString() {
return "Car{" +
"brand='" + brand + '\'' +
'}';
}
@Override
protected Car clone() throws CloneNotSupportedException {
return (Car) super.clone();
}
}
//修改Student的clone方法
class Student implements Cloneable {
private String name;
private int age;
private Car car;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Student(String name, int age, Car car) {
this.name = name;
this.age = age;
this.car = car;
}
public Car getCar() {
return car;
}
public void setCar(Car car) {
this.car = car;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public Student(String name, int age) {
this.name = name;
this.age = age;
}
public Student() {
}
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", age=" + age +
", car=" + car +
'}';
}
@Override
public Student clone() throws CloneNotSupportedException {
// return (Student) super.clone();
Student student = (Student) super.clone();
Car car = this.car.clone();
student.setCar(car);
return student;
}
}
RandomAccess標記介面
List
實現所使用的標記介面,用來表明其支持快速(通常是固定時間)隨機訪問。此介面的主要目的是允許一般的演算法更改其行為,從而在將其應用到隨機或連續訪問列表時能提供良好的性能
簡單的來說,如果實現了這個介面,普通for迴圈的速度要優於增強for的速度.
public class ArrayList_Demo01 {
public static void main(String[] args) {
//創建ArrayList集合
List<String> list = new ArrayList<String>();
//添加100W條數據
for (int i = 0; i < 1000000; i++) {
list.add(i+"a");
}
//測試普通迴圈
long startTime = System.currentTimeMillis();
for (int i = 0; i < list.size(); i++) {
//取出集合的每一個元素
list.get(i);
}
long endTime = System.currentTimeMillis();
System.out.println("普通迴圈遍歷: "+(endTime-startTime));
//測試迭代器遍歷
startTime = System.currentTimeMillis();
//獲取迭代器
Iterator<String> it = list.iterator();
while (it.hasNext()){
//取出集合的元素
it.next();
}
endTime = System.currentTimeMillis();
System.out.println("迭代器遍歷: "+(endTime-startTime));
}
}
LinkedList沒有實現此介面,測試:
ublic class LinkedList_Demo01 {
public static void main(String[] args) {
//創建LinkedList集合
List<String> list = new LinkedList<String>();
//添加10W條數據
for (int i = 0; i < 100000; i++) {
list.add(i+"b");
}
//測試普通遍歷時間
long startTime = System.currentTimeMillis();
for (int i = 0; i < list.size(); i++) {
//取出集合的每一個元素
list.get(i);
}
long endTime = System.currentTimeMillis();
System.out.println("普通遍歷時間: "+(endTime-startTime));
//測試迭代器
startTime = System.currentTimeMillis();
//獲取迭代器
Iterator<String> it = list.iterator();
while (it.hasNext()){
//取出集合的每一個元素
it.next();
}
endTime = System.currentTimeMillis();
System.out.println("順序迭代器訪問時間: "+(endTime-startTime));
}
}
實際應用
public class Test {
public static void main(String[] args) {
//我們今後可能有的集合不是直接創建的 可能是別人傳遞的
//我們看到的就是一個List介面
//至於具體的實現類可能不清楚
List<String> list = new ArrayList<>();
//list = new LinkedList<>();
//我們可以判斷以下 這個list集合是否實現了RandomAccess介面
//如果實現了 可以使用隨機訪問的方式來進行遍歷
//如果沒實現 可以使用迭代器的方式來進行遍歷 這樣可以提高效率
if(list instanceof RandomAccess){
for (int i = 0; i < list.size(); i++) {
}
}else {
for (String s : list) {
}
}
}
}