亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

java設(shè)計模式原型模式與享元模式調(diào)優(yōu)系統(tǒng)性能詳解

 更新時間:2023年05月28日 09:15:48   作者:架構(gòu)狂人  
這篇文章主要為大家介紹了java設(shè)計模式原型模式與享元模式調(diào)優(yōu)系統(tǒng)性能方法詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪

原型模式與享元模式

原型模式和享元模式,前者是在創(chuàng)建多個實例時,對創(chuàng)建過程的性能進行調(diào)優(yōu);后者是用減少創(chuàng)建實例的方式,來調(diào)優(yōu)系統(tǒng)性能。這么看,你會不會覺得兩個模式有點相互矛盾呢?

其實不然,它們的使用是分場景的。在有些場景下,我們需要重復(fù)創(chuàng)建多個實例,例如在循環(huán)體中賦值一個對象,此時我們就可以采用原型模式來優(yōu)化對象的創(chuàng)建過程;而在有些場景下,我們則可以避免重復(fù)創(chuàng)建多個實例,在內(nèi)存中共享對象就好了。

今天我們就來看看這兩種模式的適用場景,看看如何使用它們來提升系統(tǒng)性能。

原型模式

原型模式是通過給出一個原型對象來指明所創(chuàng)建的對象的類型,然后使用自身實現(xiàn)的克隆接口來復(fù)制這個原型對象,該模式就是用這種方式來創(chuàng)建出更多同類型的對象。

使用這種方式創(chuàng)建新的對象的話,就無需再通過new實例化來創(chuàng)建對象了。這是因為Object類的clone方法是一個本地方法,它可以直接操作內(nèi)存中的二進制流,所以性能相對new實例化來說,更佳。

實現(xiàn)原型模式

我們現(xiàn)在通過一個簡單的例子來實現(xiàn)一個原型模式:

//實現(xiàn)Cloneable 接口的原型抽象類Prototype
   class Prototype implements Cloneable {
        //重寫clone方法
        public Prototype clone(){
            Prototype prototype = null;
            try{
                prototype = (Prototype)super.clone();
            }catch(CloneNotSupportedException e){
                e.printStackTrace();
            }
            return prototype;
        }
    }
    //實現(xiàn)原型類
    class ConcretePrototype extends Prototype{
        public void show(){
            System.out.println("原型模式實現(xiàn)類");
        }
    }
    public class Client {
        public static void main(String[] args){
            ConcretePrototype cp = new ConcretePrototype();
            for(int i=0; i< 10; i++){
                ConcretePrototype clonecp = (ConcretePrototype)cp.clone();
                clonecp.show();
            }
        }
    }

要實現(xiàn)一個原型類,需要具備三個條件:

  • 實現(xiàn)Cloneable接口:Cloneable接口與序列化接口的作用類似,它只是告訴虛擬機可以安全地在實現(xiàn)了這個接口的類上使用clone方法。在JVM中,只有實現(xiàn)了Cloneable接口的類才可以被拷貝,否則會拋出CloneNotSupportedException異常。
  • 重寫Object類中的clone方法:在Java中,所有類的父類都是Object類,而Object類中有一個clone方法,作用是返回對象的一個拷貝。
  • 在重寫的clone方法中調(diào)用super.clone():默認情況下,類不具備復(fù)制對象的能力,需要調(diào)用super.clone()來實現(xiàn)。

從上面我們可以看出,原型模式的主要特征就是使用clone方法復(fù)制一個對象。通常,有些人會誤以為 Object a=new Object();Object b=a; 這種形式就是一種對象復(fù)制的過程,然而這種復(fù)制只是對象引用的復(fù)制,也就是a和b對象指向了同一個內(nèi)存地址,如果b修改了,a的值也就跟著被修改了。

我們可以通過一個簡單的例子來看看普通的對象復(fù)制問題:

class Student {
    private String name;
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name= name;
    }
}
public class Test {
    public static void main(String args[]) {
        Student stu1 = new Student();
        stu1.setName("test1");
        Student stu2 = stu1;
        stu2.setName("test2");
        System.out.println("學(xué)生1:" + stu1.getName());
        System.out.println("學(xué)生2:" + stu2.getName());
    }
}

如果是復(fù)制對象,此時打印的日志應(yīng)該為:

學(xué)生1:test1
學(xué)生2:test2

然而,實際上是:

學(xué)生1:test2
學(xué)生2:test2

通過clone方法復(fù)制的對象才是真正的對象復(fù)制,clone方法賦值的對象完全是一個獨立的對象。剛剛講過了,Object類的clone方法是一個本地方法,它直接操作內(nèi)存中的二進制流,特別是復(fù)制大對象時,性能的差別非常明顯。我們可以用 clone 方法再實現(xiàn)一遍以上例子。

//學(xué)生類實現(xiàn)Cloneable接口
class Student implements Cloneable{
    private String name;  //姓名
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name= name;
    }
   //重寫clone方法
   public Student clone() {
        Student student = null;
        try {
            student = (Student) super.clone();
            } catch (CloneNotSupportedException e) {
            e.printStackTrace();
            }
            return student;
   }
}
public class Test {
    public static void main(String args[]) {
        Student stu1 = new Student();  //創(chuàng)建學(xué)生1
        stu1.setName("test1");
        Student stu2 = stu1.clone();  //通過克隆創(chuàng)建學(xué)生2
        stu2.setName("test2");
        System.out.println("學(xué)生1:" + stu1.getName());
        System.out.println("學(xué)生2:" + stu2.getName());
    }
}

運行結(jié)果:

學(xué)生1:test1
學(xué)生2:test2

深拷貝和淺拷貝

在調(diào)用super.clone()方法之后,首先會檢查當(dāng)前對象所屬的類是否支持clone,也就是看該類是否實現(xiàn)了Cloneable接口。

如果支持,則創(chuàng)建當(dāng)前對象所屬類的一個新對象,并對該對象進行初始化,使得新對象的成員變量的值與當(dāng)前對象的成員變量的值一模一樣,但對于其它對象的引用以及List等類型的成員屬性,則只能復(fù)制這些對象的引用了。所以簡單調(diào)用super.clone()這種克隆對象方式,就是一種淺拷貝。

所以,當(dāng)我們在使用clone()方法實現(xiàn)對象的克隆時,就需要注意淺拷貝帶來的問題。我們再通過一個例子來看看淺拷貝。

//定義學(xué)生類
class Student implements Cloneable{
    private String name; //學(xué)生姓名
    private Teacher teacher; //定義老師類
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public Teacher getTeacher() {
        return teacher;
    }
    public void setTeacher(Teacher teacher) {
        this.teacher = teacher;
    }
   //重寫克隆方法
   public Student clone() {
        Student student = null;
        try {
            student = (Student) super.clone();
            } catch (CloneNotSupportedException e) {
            e.printStackTrace();
            }
            return student;
   }
}
//定義老師類
class Teacher implements Cloneable{
    private String name;  //老師姓名
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name= name;
    }
   //重寫克隆方法,對老師類進行克隆
   public Teacher clone() {
        Teacher teacher= null;
        try {
            teacher= (Teacher) super.clone();
            } catch (CloneNotSupportedException e) {
            e.printStackTrace();
            }
            return student;
   }
}
public class Test {
    public static void main(String args[]) {
        Teacher teacher = new Teacher (); //定義老師1
        teacher.setName("劉老師");
        Student stu1 = new Student();  //定義學(xué)生1
        stu1.setName("test1");
        stu1.setTeacher(teacher);
        Student stu2 = stu1.clone(); //定義學(xué)生2
        stu2.setName("test2");
        stu2.getTeacher().setName("王老師");//修改老師
        System.out.println("學(xué)生" + stu1.getName + "的老師是:" + stu1.getTeacher().getName);
        System.out.println("學(xué)生" + stu1.getName + "的老師是:" + stu2.getTeacher().getName);
    }
}

運行結(jié)果:

學(xué)生test1的老師是:王老師
學(xué)生test2的老師是:王老師

觀察以上運行結(jié)果,我們可以發(fā)現(xiàn):在我們給學(xué)生2修改老師的時候,學(xué)生1的老師也跟著被修改了。這就是淺拷貝帶來的問題。

我們可以通過深拷貝來解決這種問題,其實深拷貝就是基于淺拷貝來遞歸實現(xiàn)具體的每個對象,代碼如下:

public Student clone() {
        Student student = null;
        try {
            student = (Student) super.clone();
            Teacher teacher = this.teacher.clone();//克隆teacher對象
            student.setTeacher(teacher);
            } catch (CloneNotSupportedException e) {
            e.printStackTrace();
            }
            return student;
   }

適用場景

前面我詳述了原型模式的實現(xiàn)原理,那到底什么時候我們要用它呢?

在一些重復(fù)創(chuàng)建對象的場景下,我們就可以使用原型模式來提高對象的創(chuàng)建性能。例如,我在開頭提到的,循環(huán)體內(nèi)創(chuàng)建對象時,我們就可以考慮用clone的方式來實現(xiàn)。

例如:

for(int i=0; i&lt;list.size(); i++){
  Student stu = new Student();
  ...
}

我們可以優(yōu)化為:

Student stu = new Student();
for(int i=0; i&lt;list.size(); i++){
 Student stu1 = (Student)stu.clone();
  ...
}

除此之外,原型模式在開源框架中的應(yīng)用也非常廣泛。例如Spring中,@Service默認都是單例的。用了私有全局變量,若不想影響下次注入或每次上下文獲取bean,就需要用到原型模式,我們可以通過以下注解來實現(xiàn),@Scope(“prototype”)。

享元模式

享元模式是運用共享技術(shù)有效地最大限度地復(fù)用細粒度對象的一種模式。該模式中,以對象的信息狀態(tài)劃分,可以分為內(nèi)部數(shù)據(jù)和外部數(shù)據(jù)。內(nèi)部數(shù)據(jù)是對象可以共享出來的信息,這些信息不會隨著系統(tǒng)的運行而改變;外部數(shù)據(jù)則是在不同運行時被標記了不同的值。

享元模式一般可以分為三個角色,分別為 Flyweight(抽象享元類)、ConcreteFlyweight(具體享元類)和 FlyweightFactory(享元工廠類)。抽象享元類通常是一個接口或抽象類,向外界提供享元對象的內(nèi)部數(shù)據(jù)或外部數(shù)據(jù);具體享元類是指具體實現(xiàn)內(nèi)部數(shù)據(jù)共享的類;享元工廠類則是主要用于創(chuàng)建和管理享元對象的工廠類。

實現(xiàn)享元模式

我們還是通過一個簡單的例子來實現(xiàn)一個享元模式:

//抽象享元類
interface Flyweight {
    //對外狀態(tài)對象
    void operation(String name);
    //對內(nèi)對象
    String getType();
}
//具體享元類
class ConcreteFlyweight implements Flyweight {
    private String type;
    public ConcreteFlyweight(String type) {
        this.type = type;
    }
    @Override
    public void operation(String name) {
        System.out.printf("[類型(內(nèi)在狀態(tài))] - [%s] - [名字(外在狀態(tài))] - [%s]\n", type, name);
    }
    @Override
    public String getType() {
        return type;
    }
}
//享元工廠類
class FlyweightFactory {
    private static final Map&lt;String, Flyweight&gt; FLYWEIGHT_MAP = new HashMap&lt;&gt;();//享元池,用來存儲享元對象
    public static Flyweight getFlyweight(String type) {
        if (FLYWEIGHT_MAP.containsKey(type)) {//如果在享元池中存在對象,則直接獲取
            return FLYWEIGHT_MAP.get(type);
        } else {//在響應(yīng)池不存在,則新創(chuàng)建對象,并放入到享元池
            ConcreteFlyweight flyweight = new ConcreteFlyweight(type);
            FLYWEIGHT_MAP.put(type, flyweight);
            return flyweight;
        }
    }
}
public class Client {
    public static void main(String[] args) {
        Flyweight fw0 = FlyweightFactory.getFlyweight("a");
        Flyweight fw1 = FlyweightFactory.getFlyweight("b");
        Flyweight fw2 = FlyweightFactory.getFlyweight("a");
        Flyweight fw3 = FlyweightFactory.getFlyweight("b");
        fw1.operation("abc");
        System.out.printf("[結(jié)果(對象對比)] - [%s]\n", fw0 == fw2);
        System.out.printf("[結(jié)果(內(nèi)在狀態(tài))] - [%s]\n", fw1.getType());
    }
}

輸出結(jié)果:

[類型(內(nèi)在狀態(tài))] - [b] - [名字(外在狀態(tài))] - [abc]
[結(jié)果(對象對比)] - [true]
[結(jié)果(內(nèi)在狀態(tài))] - [b]

觀察以上代碼運行結(jié)果,我們可以發(fā)現(xiàn):如果對象已經(jīng)存在于享元池中,則不會再創(chuàng)建該對象了,而是共用享元池中內(nèi)部數(shù)據(jù)一致的對象。這樣就減少了對象的創(chuàng)建,同時也節(jié)省了同樣內(nèi)部數(shù)據(jù)的對象所占用的內(nèi)存空間。

適用場景

享元模式在實際開發(fā)中的應(yīng)用也非常廣泛。例如Java的String字符串,在一些字符串常量中,會共享常量池中字符串對象,從而減少重復(fù)創(chuàng)建相同值對象,占用內(nèi)存空間。代碼如下:

String s1 = "hello";
 String s2 = "hello";
 System.out.println(s1==s2);//true

還有,在日常開發(fā)中的應(yīng)用。例如,池化技術(shù)中的線程池就是享元模式的一種實現(xiàn);將商品存儲在應(yīng)用服務(wù)的緩存中,那么每當(dāng)用戶獲取商品信息時,則不需要每次都從redis緩存或者數(shù)據(jù)庫中獲取商品信息,并在內(nèi)存中重復(fù)創(chuàng)建商品信息了。

總結(jié)

原型模式和享元模式,在開源框架,和實際開發(fā)中,應(yīng)用都十分廣泛。

在不得已需要重復(fù)創(chuàng)建大量同一對象時,我們可以使用原型模式,通過clone方法復(fù)制對象,這種方式比用new和序列化創(chuàng)建對象的效率要高;在創(chuàng)建對象時,如果我們可以共用對象的內(nèi)部數(shù)據(jù),那么通過享元模式共享相同的內(nèi)部數(shù)據(jù)的對象,就可以減少對象的創(chuàng)建,實現(xiàn)系統(tǒng)調(diào)優(yōu)。

以上就是java設(shè)計模式原型模式與享元模式調(diào)優(yōu)系統(tǒng)性能詳解的詳細內(nèi)容,更多關(guān)于java原型模式享元模式的資料請關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • java中的動態(tài)代理與責(zé)任鏈模式詳解

    java中的動態(tài)代理與責(zé)任鏈模式詳解

    這篇文章主要介紹了java中的動態(tài)代理與責(zé)任鏈模式詳解,動態(tài)代理提供了一種靈活且非侵入式的方式,可以對對象的行為進行定制和擴展,它在代碼重用、解耦和業(yè)務(wù)邏輯分離、性能優(yōu)化以及系統(tǒng)架構(gòu)中起到了重要的作用,需要的朋友可以參考下
    2023-08-08
  • Java經(jīng)典排序算法之插入排序

    Java經(jīng)典排序算法之插入排序

    這篇文章主要為大家詳細介紹了Java經(jīng)典排序算法之插入排序,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2017-04-04
  • java實現(xiàn)抖音飛機大作戰(zhàn)

    java實現(xiàn)抖音飛機大作戰(zhàn)

    這篇文章主要為大家詳細介紹了java實現(xiàn)抖音飛機大作戰(zhàn),文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2019-04-04
  • Java線程編程中isAlive()和join()的使用詳解

    Java線程編程中isAlive()和join()的使用詳解

    這篇文章主要介紹了Java線程編程中isAlive()和join()的使用詳解,是Java入門學(xué)習(xí)中的基礎(chǔ)知識,需要的朋友可以參考下
    2015-09-09
  • spring注解之@Valid和@Validated的區(qū)分總結(jié)

    spring注解之@Valid和@Validated的區(qū)分總結(jié)

    @Validated和@Valid在基本驗證功能上沒有太多區(qū)別,但在分組、注解地方、嵌套驗證等功能上有所不同,下面這篇文章主要給大家介紹了關(guān)于spring注解之@Valid和@Validated區(qū)分的相關(guān)資料,需要的朋友可以參考下
    2022-03-03
  • Java Spring MVC獲取請求數(shù)據(jù)詳解操作

    Java Spring MVC獲取請求數(shù)據(jù)詳解操作

    Spring MVC 是 Spring 提供的一個基于 MVC 設(shè)計模式的輕量級 Web 開發(fā)框架,本質(zhì)上相當(dāng)于 Servlet,Spring MVC 角色劃分清晰,分工明細。由于 Spring MVC 本身就是 Spring 框架的一部分,可以說和 Spring 框架是無縫集成
    2021-11-11
  • java根據(jù)模板實現(xiàn)填充word內(nèi)容并轉(zhuǎn)換為pdf

    java根據(jù)模板實現(xiàn)填充word內(nèi)容并轉(zhuǎn)換為pdf

    這篇文章主要為大家詳細介紹了java如何根據(jù)模板實現(xiàn)填充word內(nèi)容并轉(zhuǎn)換為pdf,文中的示例代碼講解詳細,感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下
    2025-04-04
  • SpringBoot-application.yml多環(huán)境配置詳解

    SpringBoot-application.yml多環(huán)境配置詳解

    本文主要介紹了SpringBoot-application.yml多環(huán)境配置詳解,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2022-07-07
  • Java安全編碼:防范Java安全漏洞的最佳實踐

    Java安全編碼:防范Java安全漏洞的最佳實踐

    Java作為一種跨平臺的編程語言,在廣泛應(yīng)用的同時,也會從時至?xí)r出現(xiàn)安全漏洞,這些漏洞可能會對Java應(yīng)用程序的安全性造成嚴重威脅,因此,必須采取必要的措施,以確保Java應(yīng)用程序的安全性,以最佳實踐來防范Java安全漏洞,是應(yīng)對安全威脅的最好方法之一,
    2024-01-01
  • 完美解決IDEA Ctrl+Shift+f快捷鍵突然無效的問題

    完美解決IDEA Ctrl+Shift+f快捷鍵突然無效的問題

    這篇文章主要介紹了完美解決IDEA Ctrl+Shift+f快捷鍵突然無效的問題,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2021-02-02

最新評論