欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Hibernate延遲加載技術詳解

 更新時間:2016年03月24日 12:10:48   作者:xc635960736  
這篇文章主要介紹了Hibernate延遲加載技術,結(jié)合實例形式詳細分析了Hibernate延遲加載所涉及的各種常用技巧,需要的朋友可以參考下

本文實例講述了Hibernate延遲加載技術。分享給大家供大家參考,具體如下:

Hibernae 的延遲加載是一個非常常用的技術,實體的集合屬性默認會被延遲加載,實體所關聯(lián)的實體默認也會被延遲加載。Hibernate 通過這種延遲加載來降低系統(tǒng)的內(nèi)存開銷,從而保證 Hibernate 的運行性能。

下面先來剖析 Hibernate 延遲加載的“秘密”。

集合屬性的延遲加載

當 Hibernate 從數(shù)據(jù)庫中初始化某個持久化實體時,該實體的集合屬性是否隨持久化類一起初始化呢?如果集合屬性里包含十萬,甚至百萬的記錄,在初始化持久化實體的同時,完成所有集合屬性的抓取,將導致性能急劇下降。完全有可能系統(tǒng)只需要使用持久化類集合屬性中的部分記錄,而完全不是集合屬性的全部,這樣,沒有必要一次加載所有的集合屬性。

對于集合屬性,通常推薦使用延遲加載策略。所謂延遲加載就是等系統(tǒng)需要使用集合屬性時才從數(shù)據(jù)庫裝載關聯(lián)的數(shù)據(jù)。

例如下面 Person 類持有一個集合屬性,該集合屬性里的元素的類型為 Address,該 Person 類的代碼片段如下:

清單 1. Person.java

public class Person
{
 // 標識屬性
 private Integer id;
 // Person 的 name 屬性
 private String name;
 // 保留 Person 的 age 屬性
 private int age;
 // 使用 Set 來保存集合屬性
 private Set<Address> addresses = new HashSet<Address>();
 // 下面省略了各屬性的 setter 和 getter 方法
 ...
}

為了讓 Hibernate 能管理該持久化類的集合屬性,程序為該持久化類提供如下映射文件:

清單 2. Person.hbm.xml

<?xml version="1.0" encoding="GBK"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="org.crazyit.app.domain">
<!-- 映射 Person 持久化類 -->
<class name="Person" table="person_inf">
<!-- 映射標識屬性 id -->
<id name="id" column="person_id">
<!-- 定義主鍵生成器策略 -->
<generator class="identity"/>
</id>
<!-- 用于映射普通屬性 -->
<property name="name" type="string"/>
<property name="age" type="int"/>
<!-- 映射集合屬性 -->
<set name="addresses" table="person_address" lazy="true">
<!-- 指定關聯(lián)的外鍵列 -->
<key column="person_id"/>
<composite-element class="Address">
<!-- 映射普通屬性 detail -->
<property name="detail"/>
<!-- 映射普通屬性 zip -->
<property name="zip"/>
</composite-element>
</set>
</class>
</hibernate-mapping>

從上面映射文件的代碼可以看出,Person 的集合屬性中的 Address 類只是一個普通的 POJO。該 Address 類里包含 detail、zip 兩個屬性。由于 Address 類代碼非常簡單,故此處不再給出該類的代碼。

上面映射文件中 <set.../> 元素里的代碼指定了 lazy="true"(對于 <set.../> 元素來說,lazy="true"是默認值),它指定 Hibernate 會延遲加載集合屬性里 Address 對象。

例如通過如下代碼來加載 ID 為 1 的 Person 實體:

Session session = sf.getCurrentSession();
Transaction tx = session.beginTransaction();
Person p = (Person) session.get(Person.class, 1); //<1>
System.out.println(p.getName());

上面代碼只是需要訪問 ID 為 1 的 Person 實體,并不想訪問這個 Person 實體所關聯(lián)的 Address 對象。此時有兩種情況:

1. 如果不延遲加載,Hibernate 就會在加載 Person 實體對應的數(shù)據(jù)記錄時立即抓取它關聯(lián)的 Address 對象。

2. 如果采用延遲加載,Hibernate 就只加載 Person 實體對應的數(shù)據(jù)記錄。

很明顯,第二種做法既能減少與數(shù)據(jù)庫的交互,而且避免了裝載 Address 實體帶來的內(nèi)存開銷——這也是 Hibernate 默認啟用延遲加載的原因。

現(xiàn)在的問題是,延遲加載到底是如何實現(xiàn)的呢? Hibernate 在加載 Person 實體時,Person 實體的 addresses 屬性值是什么呢?

為了解決這個問題,我們在 <1>號代碼處設置一個斷點,在 Eclipse 中進行 Debug,此時可以看到 Eclipse 的 Console 窗口有如圖 1 所示的輸出:

圖 1. 延遲加載集合屬性的 Console 輸出

正如圖 1 輸出所看到的,此時 Hibernate 只從 Person 實體對應的數(shù)據(jù)表中抓取數(shù)據(jù),并未從 Address 對象對應的數(shù)據(jù)表中抓取數(shù)據(jù),這就是延遲加載。

那么 Person 實體的 addresses 屬性是什么呢?此時可以從 Eclipse 的 Variables 窗口看到如圖 2 所示的結(jié)果:

圖 2. 延遲加載的集合屬性值

從圖 2 的方框里的內(nèi)容可以看出,這個 addresses 屬性并不是我們熟悉的 HashSet、TreeSet 等實現(xiàn)類,而是一個 PersistentSet 實現(xiàn)類,這是 Hibernate 為 Set 接口提供的一個實現(xiàn)類。

PersistentSet 集合對象并未真正抓取底層數(shù)據(jù)表的數(shù)據(jù),因此自然也無法真正去初始化集合里的 Address 對象。不過 PersistentSet 集合里持有一個 session 屬性,這個 session 屬性就是 Hibernate Session,當程序需要訪問 PersistentSet 集合元素時,PersistentSet 就會利用這個 session 屬性去抓取實際的 Address 對象對應的數(shù)據(jù)記錄。

那么到底抓取那些 Address 實體對應的數(shù)據(jù)記錄呢?這也難不倒 PersistentSet,因為 PersistentSet 集合里還有一個 owner 屬性,該屬性就說明了 Address 對象所屬的 Person 實體,Hibernate 就會去查找 Address 對應數(shù)據(jù)表中外鍵值參照到該 Person 實體的數(shù)據(jù)。

例如我們單擊圖 2 所示窗口中 addresses 行,也就是告訴 Eclipse 要調(diào)試、輸出 addresses 屬性,這就是要訪問 addresses 屬性了,此時就可以在 Eclipse 的 Console 窗口看到輸出如下 SQL 語句:

select
    addresses0_.person_id as person1_0_0_,
    addresses0_.detail as detail0_,
    addresses0_.zip as zip0_
from
    person_address addresses0_
where
    addresses0_.person_id=?

這就是 PersistentSet 集合跟據(jù) owner 屬性去抓取特定 Address 記錄的 SQL 語句。此時可以從 Eclipse 的 Variables 窗口看到圖 3 所示的輸出:

圖 3. 已加載的集合屬性值

從圖 3 可以看出,此時的 addresses 屬性已經(jīng)被初始化了,集合里包含了 2 個 Address 對象,這正是 Person 實體所關聯(lián)的兩個 Address 對象。

通過上面介紹可以看出,Hibernate 對于 Set 屬性延遲加載關鍵就在于 PersistentSet 實現(xiàn)類。在延遲加載時,開始 PersistentSet 集合里并不持有任何元素。但 PersistentSet 會持有一個 Hibernate Session,它可以保證當程序需要訪問該集合時“立即”去加載數(shù)據(jù)記錄,并裝入集合元素。

與 PersistentSet 實現(xiàn)類類似的是,Hibernate 還提供了 PersistentList、PersistentMap、PersistentSortedMap、PersistentSortedSet 等實現(xiàn)類,它們的功能與 PersistentSet 的功能大致類似。

熟悉 Hibernate 集合屬性讀者應該記得:Hibernate 要求聲明集合屬性只能用 Set、List、Map、SortedSet、SortedMap 等接口,而不能用 HashSet、ArrayList、HashMap、TreeSet、TreeMap 等實現(xiàn)類,其原因就是因為 Hibernate 需要對集合屬性進行延遲加載,而 Hibernate 的延遲加載是依靠 PersistentSet、PersistentList、PersistentMap、PersistentSortedMap、PersistentSortedSet 來完成的——也就是說,Hibernate 底層需要使用自己的集合實現(xiàn)類來完成延遲加載,因此它要求開發(fā)者必須用集合接口、而不是集合實現(xiàn)類來聲明集合屬性。

Hibernate 對集合屬性默認采用延遲加載,在某些特殊的情況下,為 <set.../>、<list.../>、<map.../> 等元素設置 lazy="false"屬性來取消延遲加載。

關聯(lián)實體的延遲加載

默認情況下,Hibernate 也會采用延遲加載來加載關聯(lián)實體,不管是一對多關聯(lián)、還是一對一關聯(lián)、多對多關聯(lián),Hibernate 默認都會采用延遲加載。

對于關聯(lián)實體,可以將其分為兩種情況:

1. 關聯(lián)實體是多個實體時(包括一對多、多對多):此時關聯(lián)實體將以集合的形式存在,Hibernate 將使用 PersistentSet、PersistentList、PersistentMap、PersistentSortedMap、PersistentSortedSet 等集合來管理延遲加載的實體。這就是前面所介紹的情形。

2. 關聯(lián)實體是單個實體時(包括一對一、多對一):當 Hibernate 加載某個實體時,延遲的關聯(lián)實體將是一個動態(tài)生成代理對象。

當關聯(lián)實體是單個實體時,也就是使用 <many-to-one.../> 或 <one-to-one.../> 映射關聯(lián)實體的情形,這兩個元素也可通過 lazy 屬性來指定延遲加載。

下面例子把 Address 類也映射成持久化類,此時 Address 類也變成實體類,Person 實體與 Address 實體形成一對多的雙向關聯(lián)。此時的映射文件代碼如下:

清單 3. Person.hbm.xml

<?xml version="1.0" encoding="GBK"?>
<!-- 指定 Hibernate 的 DTD 信息 -->
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="org.crazyit.app.domain">
<!-- 映射 Person 持久化類 -->
<class name="Person" table="person_inf">
<!-- 映射標識屬性 id -->
<id name="id" column="person_id">
<!-- 定義主鍵生成器策略 -->
<generator class="identity"/>
</id>
<!-- 用于映射普通屬性 -->
<property name="name" type="string"/>
<property name="age" type="int"/>
<!-- 映射集合屬性,集合元素是其他持久化實體
沒有指定 cascade 屬性,指定不控制關聯(lián)關系 -->
<set name="addresses" inverse="true">
<!-- 指定關聯(lián)的外鍵列 -->
<key column="person_id"/>
<!-- 用以映射到關聯(lián)類屬性 -->
<one-to-many class="Address"/>
</set>
</class>
<!-- 映射 Address 持久化類 -->
<class name="Address" table="address_inf">
<!-- 映射標識屬性 addressId -->
<id name="addressId" column="address_id">
<!-- 指定主鍵生成器策略 -->
<generator class="identity"/>
</id>
<!-- 映射普通屬性 detail -->
<property name="detail"/>
<!-- 映射普通屬性 zip -->
<property name="zip"/>
<!-- 必須指定列名為 person_id,
與關聯(lián)實體中 key 元素的 column 屬性值相同 -->
<many-to-one name="person" class="Person"
column="person_id" not-null="true"/>
</class>
</hibernate-mapping>

接下來程序通過如下代碼片段來加載 ID 為 1 的 Person 實體:

// 打開上下文相關的 Session
Session session = sf.getCurrentSession();
Transaction tx = session.beginTransaction();
Address address = (Address) session.get(Address.class , 1); //<1>
System.out.println(address.getDetail());

為了看到 Hibernate 加載 Address 實體時對其關聯(lián)實體的處理,我們在 <1>號代碼處設置一個斷點,在 Eclipse 中進行 Debug,此時可以看到 Eclipse 的 Console 窗口輸出如下 SQL 語句:

select
    address0_.address_id as address1_1_0_,
    address0_.detail as detail1_0_,
    address0_.zip as zip1_0_,
    address0_.person_id as person4_1_0_
from
    address_inf address0_
where
    address0_.address_id=?

從這條 SQL 語句不難看出,Hibernate 加載 Address 實體對應的數(shù)據(jù)表抓取記錄,并未從 Person 實體對應的數(shù)據(jù)表中抓取記錄,這是延遲加載發(fā)揮了作用。
從 Eclipse 的 Variables 窗口看到如圖 4 所示的輸出:

圖 4. 延遲加載的實體

從圖 4 可以清楚地看到,此時 Address 實體所關聯(lián)的 Person 實體并不是 Person 對象,而是一個 Person_$$_javassist_0 類的實例,這個類是 Hibernate 使用 Javassist 項目動態(tài)生成的代理類——當 Hibernate 延遲加載關聯(lián)實體時,將會采用 Javassist 生成一個動態(tài)代理對象,這個代理對象將負責代理“暫未加載”的關聯(lián)實體。

只要應用程序需要使用“暫未加載”的關聯(lián)實體,Person_$$_javassist_0 代理對象會負責去加載真正的關聯(lián)實體,并返回實際的關聯(lián)實體——這就是最典型的代理模式。

單擊圖 4 所示 Variables 窗口中的 person 屬性(也就是在調(diào)試模式下強行使用 person 屬性),此時看到 Eclipse 的 Console 窗口輸出如下的 SQL 語句:

select
    person0_.person_id as person1_0_0_,
    person0_.name as name0_0_,
    person0_.age as age0_0_
from
    person_inf person0_
where
    person0_.person_id=?

上面 SQL 語句就是去抓取“延遲加載”的關聯(lián)實體的語句。此時可以看到 Variables 窗口輸出圖 5 所示的結(jié)果:

圖 5. 已加載的實體

Hibernate 采用“延遲加載”管理關聯(lián)實體的模式,其實就在加載主實體時,并未真正去抓取關聯(lián)實體對應數(shù)據(jù),而只是動態(tài)地生成一個對象作為關聯(lián)實體的代理。當應用程序真正需要使用關聯(lián)實體時,代理對象會負責從底層數(shù)據(jù)庫抓取記錄,并初始化真正的關聯(lián)實體。

在 Hibernate 的延遲加載中,客戶端程序開始獲取的只是一個動態(tài)生成的代理對象,而真正的實體則委托給代理對象來管理——這就是典型的代理模式。

代理模式

代理模式是一種應用非常廣泛的設計模式,當客戶端代碼需要調(diào)用某個對象時,客戶端實際上也不關心是否準確得到該對象,它只要一個能提供該功能的對象即可,此時我們就可返回該對象的代理(Proxy)。

在這種設計方式下,系統(tǒng)會為某個對象提供一個代理對象,并由代理對象控制對源對象的引用。代理就是一個 Java 對象代表另一個 Java 對象來采取行動。在某些情況下,客戶端代碼不想或不能夠直接調(diào)用被調(diào)用者,代理對象可以在客戶和目標對象之間起到中介的作用。

對客戶端而言,它不能分辨出代理對象與真實對象的區(qū)別,它也無須分辨代理對象和真實對象的區(qū)別??蛻舳舜a并不知道真正的被代理對象,客戶端代碼面向接口編程,它僅僅持有一個被代理對象的接口。

總而言之,只要客戶端代碼不能或不想直接訪問被調(diào)用對象——這種情況有很多原因,比如需要創(chuàng)建一個系統(tǒng)開銷很大的對象,或者被調(diào)用對象在遠程主機上,或者目標對象的功能還不足以滿足需求……,而是額外創(chuàng)建一個代理對象返回給客戶端使用,那么這種設計方式就是代理模式。

下面示范一個簡單的代理模式,程序首先提供了一個 Image 接口,代表大圖片對象所實現(xiàn)的接口,該接口代碼如下:

清單 3. Image.java

public interface Image
{
void show();
}

該接口提供了一個實現(xiàn)類,該實現(xiàn)類模擬了一個大圖片對象,該實現(xiàn)類的構造器使用 Thread.sleep() 方法來暫停 3s。下面是該 BigImage 的程序代碼。

清單 4. BigImage.java

// 使用該 BigImage 模擬一個很大圖片
public class BigImage implements Image
{
public BigImage()
{
try
{
// 程序暫停 3s 模式模擬系統(tǒng)開銷
Thread.sleep(3000);
System.out.println("圖片裝載成功 ...");
}
catch (InterruptedException ex)
{
ex.printStackTrace();
}
}
// 實現(xiàn) Image 里的 show() 方法
public void show()
{
System.out.println("繪制實際的大圖片");
}
}

上面的程序代碼暫停了 3s,這表明創(chuàng)建一個 BigImage 對象需要 3s 的時間開銷——程序使用這種延遲來模擬裝載此圖片所導致的系統(tǒng)開銷。如果不采用代理模式,當程序中創(chuàng)建 BigImage 時,系統(tǒng)將會產(chǎn)生 3s 的延遲。為了避免這種延遲,程序為 BigImage 對象提供一個代理對象,BigImage 類的代理類如下所示。

清單 5. ImageProxy.java

public class ImageProxy implements Image
{
// 組合一個 image 實例,作為被代理的對象
private Image image;
// 使用抽象實體來初始化代理對象
public ImageProxy(Image image)
{
this.image = image;
}
/**
* 重寫 Image 接口的 show() 方法
* 該方法用于控制對被代理對象的訪問,
* 并根據(jù)需要負責創(chuàng)建和刪除被代理對象
*/
public void show()
{
// 只有當真正需要調(diào)用 image 的 show 方法時才創(chuàng)建被代理對象
if (image == null)
{
 image = new BigImage();
}
image.show();
}
}

上面的 ImageProxy 代理類實現(xiàn)了與 BigImage 相同的 show() 方法,這使得客戶端代碼獲取到該代理對象之后,可以將該代理對象當成 BigImage 來使用。

在 ImageProxy 類的 show() 方法中增加了控制邏輯,這段控制邏輯用于控制當系統(tǒng)真正調(diào)用 image 的 show() 時,才會真正創(chuàng)建被代理的 BigImage 對象。下面程序需要使用 BigImage 對象,但程序并不是直接返回 BigImage 實例,而是先返回 BigImage 的代理對象,如下面程序所示。

清單 6. BigImageTest.java

public class BigImageTest
{
public static void main(String[] args)
{
long start = System.currentTimeMillis();
// 程序返回一個 Image 對象,該對象只是 BigImage 的代理對象
Image image = new ImageProxy(null);
System.out.println("系統(tǒng)得到 Image 對象的時間開銷 :" +
(System.currentTimeMillis() - start));
// 只有當實際調(diào)用 image 代理的 show() 方法時,程序才會真正創(chuàng)建被代理對象。
image.show();
}
}

上面程序初始化 image 非???,因為程序并未真正創(chuàng)建 BigImage 對象,只是得到了 ImageProxy 代理對象——直到程序調(diào)用 image.show() 方法時,程序需要真正調(diào)用 BigImage 對象的 show() 方法,程序此時才真正創(chuàng)建 BigImage 對象。運行上面程序,看到如圖 6 所示的結(jié)果。

圖 6. 使用代理模式提高性能

看到如圖 6 所示的運行結(jié)果,讀者應該能認同:使用代理模式提高了獲取 Image 對象的系統(tǒng)性能。但可能有讀者會提出疑問:程序調(diào)用 ImageProxy 對象的 show() 方法時一樣需要創(chuàng)建 BigImage 對象啊,系統(tǒng)開銷并未真正減少啊?只是這種系統(tǒng)開銷延遲了而已啊?

我們可以從如下兩個角度來回答這個問題:

把創(chuàng)建 BigImage 推遲到真正需要它時才創(chuàng)建,這樣能保證前面程序運行的流暢性,而且能減少 BigImage 在內(nèi)存中的存活時間,從宏觀上節(jié)省了系統(tǒng)的內(nèi)存開銷。

有些情況下,也許程序永遠不會真正調(diào)用 ImageProxy 對象的 show() 方法——意味著系統(tǒng)根本無須創(chuàng)建 BigImage 對象。在這種情形下,使用代理模式可以顯著地提高系統(tǒng)運行性能。

與此完全類似的是,Hibernate 也是通過代理模式來“推遲”加載關聯(lián)實體的時間,如果程序并不需要訪問關聯(lián)實體,那程序就不會去抓取關聯(lián)實體了,這樣既可以節(jié)省系統(tǒng)的內(nèi)存開銷,也可以縮短 Hibernate 加載實體的時間。

小結(jié)

Hibernate 的延遲加載(lazy load)本質(zhì)上就是代理模式的應用,我們在過去的歲月里就經(jīng)常通過代理模式來降低系統(tǒng)的內(nèi)存開銷、提升應用的運行性能。Hibernate 充分利用了代理模式的這種優(yōu)勢,并結(jié)合了 Javassist 或 CGLIB 來動態(tài)地生成代理對象,這更加增加了代理模式的靈活性,Hibernate 給這種用法一個新名稱:延遲加載。無論怎樣,充分分析、了解這些開源框架的實現(xiàn)可以更好的感受經(jīng)典設計模式的優(yōu)勢所在。

希望本文所述對大家基于Hibernate框架的Java程序設計有所幫助。

相關文章

  • 使用String類型小數(shù)值轉(zhuǎn)換為Long類型

    使用String類型小數(shù)值轉(zhuǎn)換為Long類型

    這篇文章主要介紹了使用String類型小數(shù)值轉(zhuǎn)換為Long類型操作,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2021-09-09
  • 利用consul在spring boot中實現(xiàn)分布式鎖場景分析

    利用consul在spring boot中實現(xiàn)分布式鎖場景分析

    這篇文章通過場景分析給大家介紹如何利用consul在spring boot中實現(xiàn)簡單的分布式鎖功能,代碼簡單易懂,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友參考下吧
    2021-09-09
  • Mybatis-plus4條件構造器使用方式

    Mybatis-plus4條件構造器使用方式

    這篇文章主要介紹了Mybatis-plus4條件構造器使用方式,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2024-02-02
  • java 中模式匹配算法-KMP算法實例詳解

    java 中模式匹配算法-KMP算法實例詳解

    這篇文章主要介紹了java 中模式匹配算法-KMP算法實例詳解的相關資料,需要的朋友可以參考下
    2017-06-06
  • Java開發(fā)SSM框架微信退款的實現(xiàn)

    Java開發(fā)SSM框架微信退款的實現(xiàn)

    這篇文章是Java微信退款的教程,退款之前用戶需要先進行支付,支付之后才可以使用退款,非常具有實用價值,感興趣的小伙伴們可以參考一下
    2018-10-10
  • Java匹配正則表達式匯總

    Java匹配正則表達式匯總

    java匹配字符串表達式在我們數(shù)據(jù)處理方面是及其重要的,現(xiàn)在就把我這幾天數(shù)據(jù)處理比較常用的向大家介紹一下,常規(guī)的一些匹配方式就不介紹了,我們來學習一些特殊的,感興趣的朋友跟隨小編一起看看吧
    2023-03-03
  • Java 語言中Object 類和System 類詳解

    Java 語言中Object 類和System 類詳解

    Object 是 Java 類庫中的一個特殊類,也是所有類的父類。今天通過本文給大家介紹java object類的簡單概念及常用方法,需要的朋友參考下吧
    2021-07-07
  • Java回溯法解決全排列問題流程詳解

    Java回溯法解決全排列問題流程詳解

    從n個不同元素中任取m(m≤n)個元素,按照一定的順序排列起來,叫做從n個不同元素中取出m個元素的一個排列。當m=n時所有的排列情況叫全排列。這篇文章主要介紹了Java回溯法解決全排列問題
    2022-10-10
  • Java實戰(zhàn)之實現(xiàn)一個好用的MybatisPlus代碼生成器

    Java實戰(zhàn)之實現(xiàn)一個好用的MybatisPlus代碼生成器

    這篇文章主要介紹了Java實戰(zhàn)之實現(xiàn)一個好用的MybatisPlus代碼生成器,文中有非常詳細的代碼示例,對正在學習java的小伙伴們有非常好的幫助,需要的朋友可以參考下
    2021-04-04
  • Java多態(tài)用法與注意點實例分析

    Java多態(tài)用法與注意點實例分析

    這篇文章主要介紹了Java多態(tài)用法與注意點,結(jié)合實例形式分析了java多態(tài)相關的向上轉(zhuǎn)型、向下轉(zhuǎn)型、隱藏等相關操作技巧,需要的朋友可以參考下
    2019-08-08

最新評論