java -- 標記介面

来源:https://www.cnblogs.com/paopaoT/archive/2023/04/15/17321793.html
-Advertisement-
Play Games

標記介面 標記介面(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) {

            }
        }
    }
}


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • Redis入門 1.初始Redis 1.1認識NoSQL | | SQL(關係型資料庫) | NoSQL(非關係型資料庫) | | | | | | 數據結構 | 結構化(Structured) | 非結構化 | | 數據關聯 | 關聯的(Relational) | 無關聯的 | | 查詢方式 | S ...
  • 1.背景描述 2020年團隊決定對elasticsearch升級。es(elasticsearch縮寫,下同)當前版本為0.9x,升級到5.x版本。es在本公司承載三個部分的業務,站內查詢,訂單數據統計,elk日誌分析。 對於站內查詢和訂單數據統計,當前業務架構是 mysql -> canal -> ...
  • Mysql 中,為什麼 WHERE 使用別名會報錯,而 ORDER BY 不會報錯? 我們先對salary * 12 命名一個別名annual_sal SELECT employee_id,salary,salary * 12 annual_sal FROM employees ORDER BY a ...
  • 1.車系頁佈局渲染現狀 車系頁是重要的車系信息頁面,更新迭代多年,頁面佈局不斷變化,xml佈局文件越寫越複雜。 獲取車系頁佈局文件耗時: startTime = System.currentTimeMillis(); setContentView(R.layout.car_series_revisi ...
  • “我苦心鍛煉了三年,我變禿了,也變強了。” —— 琦玉老師 0x00 大綱 0x01 前言 四個月前,我在《你是來找茬的吧?對自己的博客進行調優》一文中探討了以博客的使用者而不是開發者身份去進行優化,究竟能做到何種程度的問題。當時以 Edge 瀏覽器的開發者工具里的 lighthouse 評分和載入 ...
  • #例子 星巴茲是以擴張速度最快而聞名的咖啡連鎖店。因為擴張速度實在太快,他們著急更新訂單系統,來匹配他們的飲料供應要求。 ##實現1 繼承 購買咖啡時,也可以要求其中加入各種調料,例如:蒸奶,豆漿 很明顯,星巴茲為自己製造了一個維護噩夢,如果牛奶的價錢上揚,怎麼辦?新增一種焦糖調料風味時,怎麼辦 調 ...
  • 說明 使用 VLD 記憶體泄漏檢測工具輔助開發時整理的學習筆記。同系列文章目錄可見 《記憶體泄漏檢測工具》目錄 1. 使用方式 在 VS 中使用 VLD 的方法可以查看另外一篇博客:在 VS 2015 中使用 VLD。 2. 輸出報告 在 VS 中使用 VLD 時的輸出報告,與在 QT 中使用時是一致的 ...
  • 說明 使用 VLD 記憶體泄漏檢測工具輔助開發時整理的學習筆記。本篇介紹在 VS 2015 中使用 VLD。同系列文章目錄可見 《記憶體泄漏檢測工具》目錄 1. 使用前的準備 參考本人另一篇博客 安裝 Visual Leak Detector 下載 vld-2.5.1-setup.exe 並按步驟安裝 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...