摘要:不相等的對(duì)象要具有不相等的哈希碼為了哈希表的操作效率,這一點(diǎn)很重要,但不是強(qiáng)制要求,最低要求是不相等的對(duì)象不能共用一個(gè)哈希碼。方法和方法協(xié)同工作,返回對(duì)象的哈希碼。這個(gè)哈希碼基于對(duì)象的身份生成,而不是對(duì)象的相等性。
本文面向
剛學(xué)完Java的新手們。這篇文章不講語(yǔ)法,而是一些除了語(yǔ)法必須了解的概念。
將要去面試的初級(jí)工程師們。查漏補(bǔ)缺,以免遭遇不測(cè)。
目前由于篇幅而被挪出本文的知識(shí)點(diǎn):
淺析JVM之內(nèi)存管理
Java多線(xiàn)程筆記
Java反射學(xué)習(xí)小記
簡(jiǎn)談Java String
JDK,JRE和 JVM 的區(qū)別JVM:java 虛擬機(jī),負(fù)責(zé)將編譯產(chǎn)生的字節(jié)碼轉(zhuǎn)換為特定機(jī)器代碼,實(shí)現(xiàn)一次編譯多處執(zhí)行;
JRE:java運(yùn)行時(shí)環(huán)境,包含了java虛擬機(jī)jvm,java基礎(chǔ)類(lèi)庫(kù)。是使用java語(yǔ)言編寫(xiě)的程序運(yùn)行所需要的軟件環(huán)境;
JDK:java開(kāi)發(fā)工具包,是編寫(xiě)java程序所需的開(kāi)發(fā)工具。JDK包含了JRE,同時(shí)還包含了編譯器javac,調(diào)試和分析工具,JavaDoc。
Java是如何編譯和執(zhí)行的?上圖表示了Java代碼是怎么編譯和加載的
整個(gè)流程從 Java 源碼開(kāi)始,經(jīng)過(guò) javac 程序處理后得到類(lèi)文件,這個(gè)文件中保存的是編譯源碼后得到的 Java 字節(jié)碼。類(lèi)文件是 Java 平臺(tái)能處理的最小功能單位,也是把新代碼傳給運(yùn)行中程序的唯一方式。
新的類(lèi)文件通過(guò)類(lèi)加載機(jī)制載入虛擬機(jī),從而把新類(lèi)型提供給解釋器執(zhí)行。
Object的重要方法所有類(lèi)都直接或間接擴(kuò)展 java.lang.Object 類(lèi)。這個(gè)類(lèi)定義了很多有用的方法,而且你可以根據(jù)需求來(lái)重寫(xiě)這些方法。
toString( )方法toString( ) 方法的作用是返回對(duì)象的文本表示形式。連接字符串或使用 System.out.println( ) 等方法時(shí),會(huì)自動(dòng)在對(duì)象上調(diào)用這個(gè)方法。給對(duì)象提供文本表示形式,十分利于調(diào)試或記錄日志,而且精心編寫(xiě)的 toString( ) 方法還能給報(bào)告生成等任務(wù)提供幫助。
Object 類(lèi)中的 toString( ) 方法返回的字符串由對(duì)象所屬的類(lèi)名和對(duì)象的十六進(jìn)制形式哈希碼(由 hashCode( ) 方法計(jì)算得到,本章節(jié)稍后會(huì)介紹)組成。這個(gè)默認(rèn)的實(shí)現(xiàn)方式提供了對(duì)象的類(lèi)型和標(biāo)識(shí)兩個(gè)基本信息,但一般并沒(méi)什么用。
equals( )方法== 運(yùn)算符測(cè)試兩個(gè)引用是否指向同一個(gè)對(duì)象(比較兩個(gè)內(nèi)存單元的內(nèi)容是否一樣)。如果要測(cè)試兩個(gè)不同的對(duì)象是否相等,必須使用 equals( ) 方法。任何類(lèi)都能覆蓋 equals( ) 方法,定義專(zhuān)用的相等比較方式。Object.equals( ) 方法直接使用 == 運(yùn)算符,只有兩個(gè)對(duì)象是同一個(gè)對(duì)象時(shí),才判定二者相等。
很多類(lèi)以及自定義類(lèi)的equals方法都需要重寫(xiě),是需要根據(jù)場(chǎng)景與需求來(lái)定制的。JDK自帶的許多類(lèi)往往都是:
對(duì)比一些簡(jiǎn)單的屬性值
再對(duì)比復(fù)雜的屬性值or對(duì)比業(yè)務(wù)上最快能區(qū)分對(duì)象的值
再對(duì)比其他的值or對(duì)比地址、長(zhǎng)度
主要為了將那些不匹配的情況盡快排除
hashCode( )方法Java中的hashCode方法就是根據(jù)一定的規(guī)則將與對(duì)象相關(guān)的信息(比如對(duì)象的存儲(chǔ)地址,對(duì)象的字段等)映射成一個(gè)數(shù)值,這個(gè)數(shù)值稱(chēng)作為散列值。 如果集合中已經(jīng)存在一萬(wàn)條數(shù)據(jù)或者更多的數(shù)據(jù),如果采用equals方法去逐一比較,效率必然是一個(gè)問(wèn)題。此時(shí)hashCode方法的作用就體現(xiàn)出來(lái)了,當(dāng)集合要添加新的對(duì)象時(shí),先調(diào)用這個(gè)對(duì)象的hashCode方法,得到對(duì)應(yīng)的hashcode值,實(shí)際上在HashMap的具體實(shí)現(xiàn)中會(huì)用一個(gè)table保存已經(jīng)存進(jìn)去的對(duì)象的hashcode值,如果table中沒(méi)有該hashcode值,它就可以直接存進(jìn)去,不用再進(jìn)行任何比較了;如果存在該hashcode值,就調(diào)用它的equals方法與新元素進(jìn)行比較,相同的話(huà)就不存了,不相同就散列其它的地址,所以這里存在一個(gè)沖突解決的問(wèn)題,這樣一來(lái)實(shí)際調(diào)用equals方法的次數(shù)就大大降低了。
另外注意,默認(rèn)的hashCode會(huì)發(fā)起native調(diào)用,如果用hashCode對(duì)兩個(gè)對(duì)象對(duì)比,會(huì)導(dǎo)致開(kāi)銷(xiāo)增大。
hashcode方法的作用
只要覆蓋了 equals( ) 方法,就必須覆蓋 hashCode( ) 方法。hashCode( ) 方法返回一個(gè)整數(shù),用于哈希表數(shù)據(jù)結(jié)構(gòu)。如果兩個(gè)對(duì)象經(jīng) equals( ) 方法測(cè)試是相等的,它們就要具有相同的哈希碼。不相等的對(duì)象要具有不相等的哈希碼(為了哈希表的操作效率),這一點(diǎn)很重要,但不是強(qiáng)制要求,最低要求是不相等的對(duì)象不能共用一個(gè)哈希碼。為了滿(mǎn)足最低要求,hashCode( ) 方法要使用稍微復(fù)雜的算法或位操作。
Object.hashCode( ) 方法和 Object.equals( ) 方法協(xié)同工作,返回對(duì)象的哈希碼。這個(gè)哈希碼基于對(duì)象的身份生成,而不是對(duì)象的相等性。(如果需要使用基于身份的哈希碼,可以通過(guò)靜態(tài)方法 System.identityHashCode( ) 獲取 Object.hashCode( ) 方法的返回值。)
hashCode和equal方法
hashCode的存在主要是用于查找的快捷性,如Hashtable,HashMap等,hashCode是用來(lái)在散列存儲(chǔ)結(jié)構(gòu)中確定對(duì)象的存儲(chǔ)地址的;
如果兩個(gè)對(duì)象相同,就是適用于equals(java.lang.Object) 方法,那么這兩個(gè)對(duì)象的hashCode一定要相同;
如果對(duì)象的equals方法被重寫(xiě),那么對(duì)象的hashCode也盡量重寫(xiě),并且產(chǎn)生hashCode使用的對(duì)象,一定要和equals方法中使用的一致,否則就會(huì)違反上面提到的第2點(diǎn);
兩個(gè)對(duì)象的hashCode相同,并不一定表示兩個(gè)對(duì)象就相同,也就是不一定適用于equals(java.lang.Object)方法,只能夠說(shuō)明這兩個(gè)對(duì)象在散列存儲(chǔ)結(jié)構(gòu)中,如Hashtable,他們"存放在同一個(gè)籃子里"。
HashCode和equal方法
Comparable::compareTo( )方法如果一個(gè)類(lèi)實(shí)現(xiàn)了 Comparable 接口,就可以比較一個(gè)實(shí)例是小于、大于還是等于另一個(gè)實(shí)例。這也表明,實(shí)現(xiàn) Comparable 接口的類(lèi)可以排序。
因?yàn)?compareTo( ) 方法不在 Object 類(lèi)中聲明,所以由每個(gè)類(lèi)自行決定實(shí)例能否排序。如果能排序就定義 compareTo( ) 方法,實(shí)現(xiàn)實(shí)例排序的方式。
compareTo( ) 方法返回一個(gè) int 類(lèi)型的值,這個(gè)值需要進(jìn)一步說(shuō)明。如果當(dāng)前對(duì)象(this)小于傳入的對(duì)象,compareTo( ) 方法應(yīng)該返回一個(gè)負(fù)數(shù);如果兩個(gè)對(duì)象相等,應(yīng)該返回 0;如果當(dāng)前對(duì)象大于傳入的對(duì)象,應(yīng)該返回一個(gè)正數(shù)。
clone( )方法Object 類(lèi)定義了一個(gè)名為 clone( ) 的方法,這個(gè)方法的作用是返回一個(gè)對(duì)象,并把這個(gè)對(duì)象的字段設(shè)為和當(dāng)前對(duì)象一樣。clone( ) 方法不常用,原因有兩個(gè)。其一,只有類(lèi)實(shí)現(xiàn)了 java.lang.Cloneable 接口,這個(gè)方法才有用。Cloneable 接口沒(méi)有定義任何方法(是個(gè)標(biāo)記接口),因此若想實(shí)現(xiàn)這個(gè)接口,只需在類(lèi)簽名的 implements 子句中列出這個(gè)接口即可。其二,clone( ) 方法聲明為 protected,因此,如果想讓其他類(lèi)復(fù)制你的對(duì)象,你的類(lèi)必須實(shí)現(xiàn) Cloneable 接口,并覆蓋 clone( ) 方法,而且要把 clone( ) 方法聲明為 public。
clone( ) 方法很難正確實(shí)現(xiàn),而副本構(gòu)造方法實(shí)現(xiàn)起來(lái)更容易也更安全。
finalize( )方法一種古老的資源管理技術(shù)叫終結(jié)(finalization),開(kāi)發(fā)者應(yīng)該知道有這么一種技術(shù)。然而,這種技術(shù)幾乎完全廢棄了,任何情況下,大多數(shù) Java 開(kāi)發(fā)者都不應(yīng)該直接使用。
只有少數(shù)應(yīng)用場(chǎng)景適合使用終結(jié),而且只有少數(shù) Java 開(kāi)發(fā)者會(huì)遇到這種場(chǎng)景。如果有任何疑問(wèn),就不要使用終結(jié),處理資源的 try 語(yǔ)句往往是正確的替代品。
終結(jié)機(jī)制的作用是自動(dòng)釋放不再使用的資源。垃圾回收自動(dòng)釋放的是對(duì)象使用的內(nèi)存資源,不過(guò)對(duì)象可能會(huì)保存其他類(lèi)型的資源,例如打開(kāi)的文件和網(wǎng)絡(luò)連接。垃圾回收程序不會(huì)為你釋放這些額外的資源,因此,終結(jié)機(jī)制的作用是讓開(kāi)發(fā)者執(zhí)行清理任務(wù),例如關(guān)閉文件、中斷網(wǎng)絡(luò)連接、刪除臨時(shí)文件,等等。
終結(jié)機(jī)制的工作方式是這樣的:如果對(duì)象有 finalize( ) 方法(一般叫作終結(jié)方法),那么不再使用這個(gè)對(duì)象(或?qū)ο蟛豢蛇_(dá))后的某個(gè)時(shí)間會(huì)調(diào)用這個(gè)方法,但要在垃圾回收程序回收分配給這個(gè)對(duì)象的空間之前調(diào)用。終結(jié)方法用于清理對(duì)象使用的資源。
另外注意,這是一個(gè)實(shí)例方法。而在類(lèi)上,沒(méi)有等效的機(jī)制。
引用類(lèi)型與基本類(lèi)型比較type | which |
---|---|
基礎(chǔ) | byte short int long float double char boolean |
引用 | 數(shù)組 對(duì)象 |
8種基本類(lèi)型對(duì)應(yīng)的包裝類(lèi)也是被final修飾。另外,String類(lèi)和StringBuffer類(lèi)也是被final修飾的。
引用類(lèi)型和對(duì)象與基本類(lèi)型和基本值有本質(zhì)的區(qū)別。
八種基本類(lèi)型由 Java 語(yǔ)言定義,程序員不能定義新基本類(lèi)型。引用類(lèi)型由用戶(hù)定義,因此有無(wú)限多個(gè)。例如,程序可以定義一個(gè)名為 Point 的類(lèi),然后使用這個(gè)新定義類(lèi)型的對(duì)象存儲(chǔ)和處理笛卡兒坐標(biāo)系中的 (x, y) 點(diǎn)。
基本類(lèi)型表示單個(gè)值。引用類(lèi)型是聚合類(lèi)型(aggregate type),可以保存零個(gè)或多個(gè)基本值或?qū)ο?。例如,我們假設(shè)的 Point 類(lèi)可能存儲(chǔ)了兩個(gè) double 類(lèi)型的值,表示點(diǎn)的 x 和 y 坐標(biāo)。char[ ] 和 Point[ ] 數(shù)組類(lèi)型是聚合類(lèi)型,因?yàn)樗鼈儽4嬉恍?char 類(lèi)型的基本值或 Point 對(duì)象。
基本類(lèi)型需要一到八個(gè)字節(jié)的內(nèi)存空間。把基本值存儲(chǔ)到變量中,或者傳入方法時(shí),計(jì)算機(jī)會(huì)復(fù)制表示這個(gè)值的字節(jié)。而對(duì)象基本上需要更多的內(nèi)存。創(chuàng)建對(duì)象時(shí)會(huì)在堆(heap)中動(dòng)態(tài)分配內(nèi)存,存儲(chǔ)這個(gè)對(duì)象;如果不再需要使用這個(gè)對(duì)象了,存儲(chǔ)它的內(nèi)存會(huì)被自動(dòng)垃圾回收。
把對(duì)象賦值給變量或傳入方法時(shí),不會(huì)復(fù)制表示這個(gè)對(duì)象的內(nèi)存,而是把這個(gè)內(nèi)存的引用存儲(chǔ)在變量中或傳入方法。
在 Java 中,引用完全不透明,引用的表示方式由 Java 運(yùn)行時(shí)的實(shí)現(xiàn)細(xì)節(jié)決定。如果你是 C 程序員的話(huà),完全可以把引用看作指針或內(nèi)存地址。不過(guò)要記住,Java 程序無(wú)法使用任何方式處理引用。
似乎看的有點(diǎn)暈?來(lái)點(diǎn)兒代碼吧!
下述代碼處理 int 類(lèi)型基本值:
int x = 42; int y = x;
執(zhí)行這兩行代碼后,變量 y 中保存了變量 x 中所存值的一個(gè)副本。在 Java 虛擬機(jī)內(nèi)部,這個(gè) 32 位整數(shù) 42 有兩個(gè)獨(dú)立的副本。
現(xiàn)在,想象一下把這段代碼中的基本類(lèi)型換成引用類(lèi)型后再運(yùn)行會(huì)發(fā)生什么:
Point p = new Point(1.0, 2.0); Point q = p;
運(yùn)行這段代碼后,變量 q 中保存了一份變量 p 中所存引用的一個(gè)副本。在虛擬機(jī)中,仍然只有一個(gè) Point 對(duì)象的副本,但是這個(gè)對(duì)象的引用有兩個(gè)副本----這一點(diǎn)有重要的含義。假設(shè)上面兩行代碼的后面是下述代碼:
System.out.println(p.x); // 打印p的x坐標(biāo):1.0 q.x = 13.0; // 現(xiàn)在,修改q的x坐標(biāo) System.out.println(p.x); // 再次打印p.x,這次得到的值是13.0
因?yàn)樽兞?p 和 q 保存的引用指向同一個(gè)對(duì)象,所以?xún)蓚€(gè)變量都可以用來(lái)修改這個(gè)對(duì)象,而且一個(gè)變量中的改動(dòng)在另一個(gè)變量中可見(jiàn)。數(shù)組也是一種對(duì)象,所以對(duì)數(shù)組來(lái)說(shuō)也會(huì)發(fā)生同樣的事,如下面的代碼所示:
// greet保存一個(gè)數(shù)組的引用 char[ ] greet = { "h","e","l","l","o" }; char[ ] cuss = greet; // cuss保存的是同一個(gè)數(shù)組的引用 cuss[4] = "!"; // 使用引用修改一個(gè)元素 System.out.println(greet); // 打印“hell!”
把基本類(lèi)型和引用類(lèi)型的參數(shù)傳入方法時(shí)也有類(lèi)似的區(qū)別。假如有下面的方法:
void changePrimitive(int x) { while(x > 0) { System.out.println(x--); } }
調(diào)用這個(gè)方法時(shí),會(huì)把實(shí)參的副本傳給形參 x。在這個(gè)方法的代碼中,x 是循環(huán)計(jì)數(shù)器,向零遞減。因?yàn)?x 是基本類(lèi)型,所以這個(gè)方法有這個(gè)值的私有副本——這是完全合理的做法。
可是,如果把這個(gè)方法的參數(shù)改為引用類(lèi)型,會(huì)發(fā)生什么呢?
void changeReference(Point p) { while(p.x > 0) { System.out.println(p.x--); } }
調(diào)用這個(gè)方法時(shí),傳入的是一個(gè) Point 對(duì)象引用的私有副本,然后使用這個(gè)引用修改對(duì)應(yīng)的 Point 對(duì)象。例如,有下述代碼:
Point q = new Point(3.0, 4.5); // 一個(gè)x坐標(biāo)為3的點(diǎn) changeReference(q); // 打印3,2,1,而且修改了這個(gè)Point對(duì)象 System.out.println(q.x); // 現(xiàn)在,q的x坐標(biāo)是0!
調(diào)用 changeReference( ) 方法時(shí),傳入的是變量 q 中所存引用的副本?,F(xiàn)在,變量 q 和方法的形參 p 保存的引用指向同一個(gè)對(duì)象。這個(gè)方法可以使用它的引用修改對(duì)象的內(nèi)容。但是要注意,這個(gè)方法不能修改變量 q 的內(nèi)容。也就是說(shuō),這個(gè)方法可以隨意修改引用的 Point 對(duì)象,但不能改變變量 q 引用這個(gè)對(duì)象這一事實(shí)。
那么在用運(yùn)算符:==時(shí),也會(huì)有差別。
相等運(yùn)算符(==)比較基本值時(shí),只測(cè)試兩個(gè)值是否一樣(即每一位的值都完全相同)。而 == 比較引用類(lèi)型時(shí),比較的是引用而不是真正的對(duì)象。也就是說(shuō),== 測(cè)試兩個(gè)引用是否指向同一個(gè)對(duì)象,而不測(cè)試兩個(gè)對(duì)象的內(nèi)容是否相同。
Java 的四種引用在 JDK1.2 后,Java 對(duì)引用概念擴(kuò)充,分為強(qiáng)引用、軟引用、弱引用、虛引用。強(qiáng)度漸弱。
在開(kāi)始了解前,最好先稍微了解一下Java Memory Model。我的這篇文章中簡(jiǎn)單的講了一下JMM
強(qiáng)引用就是值在程序代碼之中普遍存在的,類(lèi)似 Object obj = new Object() 這類(lèi)的引用,只要強(qiáng)引用還在,垃圾收集器永遠(yuǎn)不會(huì)回收掉被引用的對(duì)象。
軟引用它關(guān)聯(lián)著的對(duì)象,在系統(tǒng)將要發(fā)生內(nèi)存溢出異常之前,將會(huì)把這些對(duì)象列進(jìn)回收范圍內(nèi)進(jìn)行第二次回收。提供 SoftReference 類(lèi)來(lái)實(shí)現(xiàn)軟引用。
弱引用強(qiáng)度比軟引用更弱一些,被弱引用關(guān)聯(lián)的對(duì)象只能生存到下一次垃圾收集發(fā)生之前。提供 WeakReference 類(lèi)來(lái)實(shí)現(xiàn)軟引用。
虛引用一個(gè)對(duì)象是否有虛引用的存在,完全不會(huì)對(duì)其生存時(shí)間構(gòu)成影響,也無(wú)法通過(guò)虛引用來(lái)去的一個(gè)對(duì)象實(shí)例。為一個(gè)對(duì)象設(shè)置虛引用關(guān)聯(lián)的唯一目的就是能在這個(gè)對(duì)象被收集器回收時(shí)收到一個(gè)系統(tǒng)通知。提供 PhantomReference 類(lèi)來(lái)實(shí)現(xiàn)軟引用。
Java 7之基礎(chǔ) - 強(qiáng)引用、弱引用、軟引用、虛引用
Java垃圾回收機(jī)制與引用類(lèi)型
數(shù)組類(lèi)型不是類(lèi),但數(shù)組實(shí)例是對(duì)象。這意味著,數(shù)組從 java.lang.Object 類(lèi)繼承了方法。數(shù)組實(shí)現(xiàn)了 Cloneable 接口,而且覆蓋了 clone( ) 方法,確保數(shù)組始終能被復(fù)制,而且 clone( ) 方法從不拋出 CloneNotSupportedException 異常。數(shù)組還實(shí)現(xiàn)了 Serializable 接口,所以只要數(shù)組中元素的類(lèi)型能被序列化,數(shù)組就能被序列化。而且,所有數(shù)組都有一個(gè)名為 length 的字段,這個(gè)字段的修飾符是 public final int,表示數(shù)組中元素的數(shù)量。
因?yàn)閿?shù)組擴(kuò)展自 Object 類(lèi),而且實(shí)現(xiàn)了 Cloneable 和 Serializable 接口,所以任何數(shù)組類(lèi)型都能放大轉(zhuǎn)換成這三種類(lèi)型中的任何一種。而且,特定的數(shù)組類(lèi)型還能放大轉(zhuǎn)換成其他數(shù)組類(lèi)型。如果數(shù)組中的元素類(lèi)型是引用類(lèi)型 T,而且 T 能指定給類(lèi)型 S,那么數(shù)組類(lèi)型 T[ ] 就能指定給數(shù)組類(lèi)型 S[ ]。注意,基本類(lèi)型的數(shù)組不能放大轉(zhuǎn)換。例如,下述代碼展示了合法的數(shù)組放大轉(zhuǎn)換:
String[ ] arrayOfStrings; // 創(chuàng)建字符串?dāng)?shù)組 int[ ][ ] arrayOfArraysOfInt; // 創(chuàng)建int二維數(shù)組 Object[ ] oa = arrayOfStrings;// String可以指定給Object,因此String[ ]可以指定給Object[ ] Comparable[ ] ca = arrayOfStrings;// String實(shí)現(xiàn)了Comparable接口,因此String[ ]可以視作Comparable[ ] Object[ ] oa2 = arrayOfArraysOfInt;// int[ ]是Object類(lèi)的對(duì)象,因此int[ ][ ]可以指定給Object[ ] // 所有數(shù)組都是可以復(fù)制和序列化的對(duì)象 Object o = arrayOfStrings; Cloneable c = arrayOfArraysOfInt; Serializable s = arrayOfArraysOfInt[0];
因?yàn)閿?shù)組類(lèi)型可以放大轉(zhuǎn)換成另一種數(shù)組類(lèi)型,所以編譯時(shí)和運(yùn)行時(shí)數(shù)組的類(lèi)型并不總是一樣。這種放大轉(zhuǎn)換叫作"數(shù)組協(xié)變"(array covariance)。
所以在某種意義上,集合框架比數(shù)組好用:
Object [] objectArray = new Long[1]; objectArray[0] = "I dont fit in"; //Throws ArrayStoreException
List
一個(gè)只有在運(yùn)行時(shí)才能拋出異常,一個(gè)在編譯期便可以發(fā)現(xiàn)錯(cuò)誤。
封裝類(lèi) Java中為什么要為基本類(lèi)型提供封裝類(lèi)呢?是為了在各種類(lèi)型間轉(zhuǎn)化,通過(guò)各種方法的調(diào)用。否則你無(wú)法直接通過(guò)變量轉(zhuǎn)化。
比如,現(xiàn)在int要轉(zhuǎn)為String
int a=0; String result=Integer.toString(a);
比如現(xiàn)在要用泛型
Listnums;
這里< >里面就需要指定一個(gè)類(lèi)。如果用int,則報(bào)錯(cuò)。
自動(dòng)裝箱(autoboxing)與拆箱(unboxing)自動(dòng)裝箱是 Java 編譯器在基本數(shù)據(jù)類(lèi)型和對(duì)應(yīng)的對(duì)象包裝類(lèi)型之間做的一個(gè)轉(zhuǎn)化。
基本類(lèi)型和引用類(lèi)型的表現(xiàn)完全不同。有時(shí)需要把基本值當(dāng)成對(duì)象,為此,Java 平臺(tái)為每一種基本類(lèi)型都提供了包裝類(lèi)。Boolean、Byte、Short、Character、Integer、Long、Float 和 Double 是不可變的最終類(lèi),每個(gè)實(shí)例只保存一個(gè)基本值。包裝類(lèi)一般在把基本值存儲(chǔ)在集合中時(shí)使用。 例如
java.util.List: List numbers =newArrayList( );// 創(chuàng)建一個(gè)List集合 numbers.add(newInteger(-1));// 存儲(chǔ)一個(gè)包裝類(lèi)表示的基本值 int i =((Integer)numbers.get(0)).intValue( );// 取出這個(gè)基本值
把 int 轉(zhuǎn)化成 Integer,double 轉(zhuǎn)化成 Double等,反之就是自動(dòng)拆箱。
Integer a=1;//這就是一個(gè)自動(dòng)裝箱,如果沒(méi)有自動(dòng)裝箱的話(huà),需要這樣Integer a=new Integer(1) int b=a;//這就是一個(gè)自動(dòng)拆箱,如果沒(méi)有自動(dòng)拆箱的話(huà),需要這樣:int b=a.intValue( )
這樣就能看出自動(dòng)裝箱和自動(dòng)拆箱是簡(jiǎn)化了基本數(shù)據(jù)類(lèi)型和相對(duì)應(yīng)對(duì)象的轉(zhuǎn)化步驟。
自動(dòng)拆裝箱將會(huì)導(dǎo)致性能問(wèn)題,因?yàn)橛行?shù)字不屬于緩存范圍——意味著會(huì)產(chǎn)生新的對(duì)象,尤其是在集合框架中會(huì)嚴(yán)重導(dǎo)致性能下降。
請(qǐng)運(yùn)行一下下面的代碼,并探究一下:
public static void main(String []args){ Integer a = 1; Integer b = 1; Integer c = 200; Integer d = 200; System.out.println(a==b); System.out.println(c==d); }
Java中的自動(dòng)裝箱與拆箱
關(guān)于異常圖是我自己做的。如果覺(jué)得子類(lèi)父類(lèi)傻傻分不清,可以按照“紅橙黃綠”這個(gè)順序來(lái),最高父類(lèi)是紅。
遇上Error就是跪了,你就別想拯救了。
Exception一般由編碼、環(huán)境、用戶(hù)操作輸入出現(xiàn)問(wèn)題,我們要可以捕捉的也處于這一塊兒。
運(yùn)行時(shí)異常由java虛擬機(jī)由自己捕獲自己拋出。
檢查異常則由自己捕獲自己拋出多重catch,順序是從子類(lèi)到父類(lèi)。
異常拋出throw:將產(chǎn)生的異常拋出。交給上層去處理。異常鏈----A方法拋出異常,B方法嘗試捕獲。main中調(diào)用B,B捕獲的異常中會(huì)有A異常的信息。
throws:聲明將要拋出何種類(lèi)型的異常。
下面是異常類(lèi)族譜
捕捉的異常時(shí),不要僅僅調(diào)用printStackTreace( )去打印輸出,應(yīng)該添加事務(wù)回滾等操作。catch(Exception)可以捕捉遺漏的異常。最后在finally語(yǔ)句里記得釋放資源。
Java異常處理的10個(gè)最佳實(shí)踐這里是我收集的 Java 編程中異常處理的 10 個(gè)最佳實(shí)踐。大家對(duì) Java 中的受檢異常(checked Exception)褒貶不一,這種語(yǔ)言特性要求該異常必須被處理。在本文中,我們盡可能少使用受檢異常,同時(shí)也要學(xué)會(huì)在 Java 編程中,區(qū)別使用受檢和非受檢異常。
1 為可恢復(fù)的錯(cuò)誤使用受檢異常,為編程錯(cuò)誤使用非受檢異常。對(duì) Java 開(kāi)發(fā)者來(lái)說(shuō),選擇受檢還是非受檢異??偸亲屓烁械嚼Щ蟆J軝z異常保證你會(huì)針對(duì)錯(cuò)誤情況提供異常處理代碼,這是一種從語(yǔ)言層面上強(qiáng)制你編寫(xiě)健壯代碼的一種方式,但同時(shí)也引入大量雜亂的代碼并導(dǎo)致其可讀性變差。當(dāng)然,如果你有可替代方式或恢復(fù)策略的話(huà),捕獲異常并做處理看起來(lái)似乎也合情合理。在 Java 編程中選擇受檢異常還是運(yùn)行時(shí)異常的更多信息,請(qǐng)參考 checked vs unchecked exceptions。
2 在 finally 程序塊中關(guān)閉或者釋放資源這是 Java 編程中一個(gè)廣為人知的最佳實(shí)踐和一個(gè)事實(shí)上的標(biāo)準(zhǔn),尤其是在處理網(wǎng)絡(luò)和 IO 操作的時(shí)候。在 finally 塊中關(guān)閉資源能保證無(wú)論是處于正常還是異常執(zhí)行的情況下,資源文件都能被合理釋放,這由 finally 語(yǔ)句塊保證。從 Java7 開(kāi)始,新增加了一項(xiàng)更有趣的功能:自動(dòng)資源管理,或者稱(chēng)之為ARM塊。盡管如此,我們?nèi)匀灰涀≡?finally 塊中關(guān)閉資源,這對(duì)于釋放像 FileDescriptors 這類(lèi)資源至關(guān)重要,因?yàn)樗?socket 和文件操作中都會(huì)被用到。
3 在堆棧信息中包含引起異常的原因Java 庫(kù)和開(kāi)源代碼在很多情況下會(huì)將一種異常包裝成另一種異常。這樣記錄和打印根異常就變得非常重要。Java 異常類(lèi)提供了 getCause() 方法來(lái)獲取導(dǎo)致異常的原因,這可以提供更多有關(guān)異常發(fā)生的根本原因的信息。這條實(shí)踐對(duì)調(diào)試或排除故障大有幫助。在把一個(gè)異常包裝成另一種異常時(shí),記住需要把源異常傳遞給新異常的構(gòu)造器。
4 始終提供異常的有意義的完整信息異常信息是最重要的,在其中,你能找到問(wèn)題產(chǎn)生的原因,因?yàn)檫@是出問(wèn)題后程序員最先看到的地方。記得始終提供精確的真實(shí)的信息。例如,對(duì)比下面兩條 IllegalArgumentException 的異常信息:
message 1: “Incorrect argument for method” message 2: “Illegal value for ${argument}: ${value}
第一條消息僅說(shuō)明了參數(shù)是非法的或不正確的,但第二條消息包括了參數(shù)名和非法值,這對(duì)找到錯(cuò)誤原因很重要。在編寫(xiě)異常處理代碼的時(shí)候,應(yīng)當(dāng)始終遵循該 Java 最佳實(shí)踐。
5 避免過(guò)度使用受檢異常受檢異常的強(qiáng)制性在某種程度上具有一定的優(yōu)勢(shì),但同時(shí)它也使得代碼可讀性變差,混淆了正常的業(yè)務(wù)邏輯代碼。你可以通過(guò)適度使用受檢異常來(lái)最大限度地減少這類(lèi)情況的發(fā)生,這樣可以得到更簡(jiǎn)潔的代碼。你同樣可以使用 Java7 的新功能,比如在一個(gè)catch語(yǔ)句中捕獲多個(gè)異常,以及自動(dòng)管理資源,以此來(lái)移除一些冗余的代碼。
6 將受檢異常轉(zhuǎn)為運(yùn)行時(shí)異常這是在諸如 Spring 之類(lèi)的框架中用來(lái)減少使用受檢異常的方式之一,大部分 JDBC 的受檢異常都被包裝進(jìn) DataAccessException 中,DataAccessException異常是一種非受檢異常。這個(gè)最佳實(shí)踐帶來(lái)的好處是可以將特定的異常限制到特定的模塊中,比如把 SQLException 拋到 DAO 層,把有意義的運(yùn)行時(shí)異常拋到客戶(hù)端層。
7 記住異常的性能代價(jià)高昂需要記住的一件事是異常代價(jià)高昂,同時(shí)讓代碼運(yùn)行緩慢。假如你有一個(gè)方法從 ResultSet 中進(jìn)行讀取,它經(jīng)常會(huì)拋出 SQLException 而不是將 cursor 移到下一元素,這將會(huì)比不拋出異常的正常代碼執(zhí)行的慢的多。因此最大限度的減少不必要的異常捕捉,去修復(fù)真正的根本問(wèn)題。不要僅僅是拋出和捕捉異常,如果你能使用 boolean 變量去表示執(zhí)行結(jié)果,可能會(huì)得到更整潔、更高性能的解決方案。修正錯(cuò)誤的根源,避免不必要的異常捕捉。
8 避免空的 catch 塊沒(méi)有什么比空的 catch 塊更糟糕的了,因?yàn)樗粌H隱藏了錯(cuò)誤和異常,同時(shí)可能導(dǎo)致你的對(duì)象處于不可用狀態(tài)或者臟狀態(tài)??盏?catch 塊沒(méi)有意義,除非你非??隙ó惓2粫?huì)以任何方式影響對(duì)象的狀態(tài),但在程序執(zhí)行期間,用日志記錄錯(cuò)誤依然是最好的方法。這在 Java 異常處理中不僅僅是一個(gè)最佳實(shí)踐,而且是一個(gè)最通用的實(shí)踐。
9 使用標(biāo)準(zhǔn)異常第九條最佳實(shí)踐是建議使用標(biāo)準(zhǔn)和內(nèi)置的 Java 異常。使用標(biāo)準(zhǔn)異常而不是每次創(chuàng)建我們自己的異常,這對(duì)于目前和以后代碼的可維護(hù)性和一致性,都是最好的選擇。重用標(biāo)準(zhǔn)異常使代碼可讀性更好,因?yàn)榇蟛糠?Java 開(kāi)發(fā)人員對(duì)標(biāo)準(zhǔn)的異常更加熟悉,比如 JDK 中的RuntimeException,IllegalStateException,IllegalArgumentException,NullPointerException,他們能立馬知道每種異常的目的,而不是在代碼或文檔里查找用戶(hù)自定義異常的目的。
10 為方法拋出的異常編寫(xiě)文檔Java 提供了 throw 和 throws 關(guān)鍵字來(lái)拋出異常,在 javadoc 中可以用@throw 為任何可能被拋出的異常編寫(xiě)文檔。如果你編寫(xiě) API 或者公共接口,這就變得非常重要。當(dāng)任何方法拋出的異常都有相應(yīng)的文檔記錄時(shí),就能潛在的提醒任何調(diào)用該方法的開(kāi)發(fā)者。
Java 創(chuàng)建對(duì)象的幾種方式用new 語(yǔ)句創(chuàng)建對(duì)象,這是最常見(jiàn)的創(chuàng)建對(duì)象的方法
運(yùn)用反射手段,調(diào)用 java.lang.Class 或者 java.lang.reflect.Constructor 類(lèi)的 newInstance( ) 實(shí)例方法
調(diào)用對(duì)象的 clone( ) 方法
運(yùn)用反序列化手段,調(diào)用 java.io.ObjectInputStream 對(duì)象的 readObject( ) 方法
(1)和(2)都會(huì)明確的顯式的調(diào)用構(gòu)造函數(shù);(3)是在內(nèi)存上對(duì)已有對(duì)象的影印,所以不會(huì)調(diào)用構(gòu)造函數(shù) (4)是從文件中還原類(lèi)的對(duì)象,也不會(huì)調(diào)用構(gòu)造函數(shù)。
序列化(Serializable )與反序列化(Deserialize)對(duì)象序列化(Serializable)是指將對(duì)象轉(zhuǎn)換為字節(jié)序列的過(guò)程,而反序列化則是根據(jù)字節(jié)序列恢復(fù)對(duì)象的過(guò)程。
簡(jiǎn)單的來(lái)說(shuō)就是從object變成了byte,用于傳輸。
序列化一般用于以下場(chǎng)景:
永久性保存對(duì)象,保存對(duì)象的字節(jié)序列到本地文件中;
通過(guò)序列化對(duì)象在網(wǎng)絡(luò)中傳遞對(duì)象;
通過(guò)序列化在進(jìn)程間傳遞對(duì)象。
只有實(shí)現(xiàn)了Serializable和Externalizable接口的類(lèi)的對(duì)象才能被序列化。
小Tips:對(duì)子類(lèi)對(duì)象進(jìn)行反序列化操作時(shí),如果其父類(lèi)沒(méi)有實(shí)現(xiàn)序列化接口,那么其父類(lèi)的構(gòu)造函數(shù)會(huì)被顯式的調(diào)用。
java.io.ObjectOutputStream代表對(duì)象輸出流,它的writeObject(Objectobj)方法可對(duì)參數(shù)指定的obj對(duì)象進(jìn)行序列化,把得到的字節(jié)序列寫(xiě)到一個(gè)目標(biāo)輸出流中。
java.io.ObjectInputStream代表對(duì)象輸入流,它的readObject( )方法從一個(gè)源輸入流中讀取字節(jié)序列,再把它們反序列化為一個(gè)對(duì)象,并將其返回。
覆蓋 (Override) 和重載 (Overload)Override:方法覆蓋是說(shuō)子類(lèi)重新定義了父類(lèi)的方法,方法覆蓋必須有相同的方法名,參數(shù)列表和返回類(lèi)型。一般會(huì)有個(gè)@Override注解。
Overload:Java中的方法重載發(fā)生在同一個(gè)類(lèi)里面兩個(gè)或者是多個(gè)方法的方法名相同但是參數(shù)不同的情況
集合框架對(duì)象存入集合時(shí)會(huì)變成Object類(lèi)型,取出時(shí)需要類(lèi)型轉(zhuǎn)換。所以會(huì)有泛型(這樣也不用考慮取出時(shí)的類(lèi)型轉(zhuǎn)換了)。另外集合里存儲(chǔ)的是引用,所以泛型不能使用基本類(lèi)型。
常見(jiàn)集合
集合概覽
集合家族一覽
Set 是一種 Collection,不過(guò)其中沒(méi)有重復(fù)的對(duì)象;List 也是一種 Collection,其中的元素按順序排列(不過(guò)可能有重復(fù))。
SortedSet 和 SortedMap 是特殊的集和映射,其中的元素按順序排列。
Collection、Set、List、Map、SortedSet 和 SortedMap 都是接口,不過(guò) java.util 包定義了多個(gè)具體實(shí)現(xiàn),例如基于數(shù)組和鏈表的列表,基于哈希表或二叉樹(shù)的映射和集。除此之外,還有兩個(gè)重要的接口:Iterator 和 Iterable,用于遍歷集合中的對(duì)象。
Collection接口Collection
集(set)是無(wú)重復(fù)對(duì)象組成的集合:不能有兩個(gè)引用指向同一個(gè)對(duì)象,或兩個(gè)指向 null 的引用,如果對(duì)象 a 和 b 的引用滿(mǎn)足條件 a.equals(b),那么這兩個(gè)對(duì)象也不能同時(shí)出現(xiàn)在集中。多數(shù)通用的 Set 實(shí)現(xiàn)都不會(huì)對(duì)元素排序,但并不禁止使用有序集(SortedSet 和 LinkedHashSet 就有順序)。而且集與列表等有序集合不同,一般認(rèn)為,集的 contains 方法,不論以常數(shù)時(shí)間還是以對(duì)數(shù)時(shí)間都為1,運(yùn)行效率都高。
List接口List 是一組有序的對(duì)象集合。列表中的每個(gè)元素都有特定的位置,而且 List 接口定義了一些方法,用于查詢(xún)或設(shè)定特定位置(或叫索引)的元素。從這個(gè)角度來(lái)看,List 對(duì)象和數(shù)組類(lèi)似,不過(guò)列表的大小能按需變化,以適應(yīng)其中元素的數(shù)量。和集不同,列表允許出現(xiàn)重復(fù)的元素。
除了基于索引的 get( ) 和 set( ) 方法之外,List 接口還定義了一些方法,用于把元素添加到特定的索引,把元素從特定的索引移除,或者返回指定值在列表中首次出現(xiàn)或最后出現(xiàn)的索引。從 Collection 接口繼承的 add( ) 和 remove( ) 方法,前者把元素添加到列表末尾,后者把指定值從列表中首次出現(xiàn)的位置移除。繼承的 addAll( ) 方法把指定集合中的所有元素添加到列表的末尾,或者插入指定的索引。retainAll( ) 和 removeAll( ) 方法的表現(xiàn)與其他 Collection 對(duì)象一樣,如果需要,會(huì)保留或刪除多個(gè)相同的值。
List 接口沒(méi)有定義操作索引范圍的方法,但是定義了一個(gè) subList( ) 方法。這個(gè)方法返回一個(gè) List 對(duì)象,表示原列表指定范圍內(nèi)的元素。子列表會(huì)回饋父列表,只要修改了子列表,父列表立即就能察覺(jué)到變化。
Map接口映射(map)是一系列鍵值對(duì),一個(gè)鍵對(duì)應(yīng)一個(gè)值。Map 接口定義了用于定義和查詢(xún)映射的 API。Map 接口屬于 Java 集合框架,但沒(méi)有擴(kuò)展 Collection 接口,因此 Map 只是一種集合,而不是 Collection 類(lèi)型。Map 是參數(shù)化類(lèi)型,有兩個(gè)類(lèi)型變量。類(lèi)型變量 K 表示映射中鍵的類(lèi)型,類(lèi)型變量 V 表示鍵對(duì)應(yīng)的值的類(lèi)型。例如,如果有個(gè)映射,其鍵是 String 類(lèi)型,對(duì)應(yīng)的值是 Integer 類(lèi)型,那么這個(gè)映射可以表示為 Map
Map 接口定義了幾個(gè)最有用的方法:put( ) 方法定義映射中的一個(gè)鍵值對(duì),get( ) 方法查詢(xún)指定鍵對(duì)應(yīng)的值,remove( ) 方法把指定的鍵及對(duì)應(yīng)的值從映射中刪除。一般來(lái)說(shuō),實(shí)現(xiàn) Map 接口的類(lèi)都要能高效執(zhí)行這三個(gè)基本方法:一般應(yīng)該運(yùn)行在常數(shù)時(shí)間中,而且絕不能比在對(duì)數(shù)時(shí)間中運(yùn)行的性能差。
Map 的重要特性之一是,可以視作集合。雖然 Map 對(duì)象不是 Collection 類(lèi)型,但映射的鍵可以看成 Set 對(duì)象,映射的值可以看成 Collection 對(duì)象,而映射的鍵值對(duì)可以看成由 Map.Entry 對(duì)象組成的 Set 對(duì)象。(Map.Entry 是 Map 接口中定義的嵌套接口,表示一個(gè)鍵值對(duì)。)
Queue接口和BlockingQueue接口隊(duì)列(queue)是一組有序的元素,提取元素時(shí)按順序從隊(duì)頭讀取。隊(duì)列一般按照插入元素的順序?qū)崿F(xiàn),因此分成兩類(lèi):先進(jìn)先出(first-in, first-out,F(xiàn)IFO)隊(duì)列和后進(jìn)先出(last-in, first-out,LIFO)隊(duì)列。
LIFO 隊(duì)列也叫棧(stack),Java 提供了 Stack 類(lèi),但強(qiáng)烈不建議使用,應(yīng)該使用實(shí)現(xiàn) Deque 接口的類(lèi)。
隊(duì)列也可以使用其他順序:優(yōu)先隊(duì)列(priority queue)根據(jù)外部 Comparator 對(duì)象或 Comparable 類(lèi)型元素的自然順序排序元素。與 Set 不同的是,Queue 的實(shí)現(xiàn)往往允許出現(xiàn)重復(fù)的元素。而與 List 不同的是,Queue 接口沒(méi)有定義處理任意索引位元素的方法,只有隊(duì)列的頭一個(gè)元素能訪(fǎng)問(wèn)。Queue 的所有實(shí)現(xiàn)都要具有一個(gè)固定的容量:隊(duì)列已滿(mǎn)時(shí),不能再添加元素。類(lèi)似地,隊(duì)列為空時(shí),不能再刪除元素。很多基于隊(duì)列的算法都會(huì)用到滿(mǎn)和空這兩個(gè)狀態(tài),所以 Queue 接口定義的方法通過(guò)返回值表明這兩個(gè)狀態(tài),而不會(huì)拋出異常。具體而言,peek( ) 和 poll( ) 方法返回 null 表示隊(duì)列為空。因此,多數(shù) Queue 接口的實(shí)現(xiàn)不允許用 null 作元素。
阻塞式隊(duì)列(blocking queue)是一種定義了阻塞式 put( ) 和 take( ) 方法的隊(duì)列。put( ) 方法的作用是把元素添加到隊(duì)列中,如果需要,這個(gè)方法會(huì)一直等待,直到隊(duì)列中有存儲(chǔ)元素的空間為止。而 take( ) 方法的作用是從隊(duì)頭移除元素,如果需要,這個(gè)方法會(huì)一直等待,直到隊(duì)列中有元素可供移除為止。阻塞式隊(duì)列是很多多線(xiàn)程算法的重要組成部分,因此 BlockingQueue 接口(擴(kuò)展 Queue 接口)在 java.util.concurrent 包中定義。
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/65681.html
摘要:特點(diǎn)高性能且易于使用,旨在實(shí)現(xiàn)簡(jiǎn)單并快速的事務(wù)提交與回滾。大部分項(xiàng)目只需要少量的配置即可地址介紹是開(kāi)源的診斷工具。當(dāng)然,它們的重點(diǎn)是,和。 該文已加入筆主的開(kāi)源項(xiàng)目——JavaGuide(一份涵蓋大部分Java程序員所需要掌握的核心知識(shí)的文檔類(lèi)項(xiàng)目),地址:https://github.com/Snailclimb... 。覺(jué)得不錯(cuò)的話(huà),記得點(diǎn)個(gè)Star。 1. JavaGuide ...
摘要:最近瀏覽,收藏了一些還算不錯(cuò)的面試學(xué)習(xí)相關(guān)的倉(cāng)庫(kù),分享給大家,希望對(duì)你有幫助。除了這九個(gè)倉(cāng)庫(kù),再推薦幾個(gè)不錯(cuò)的學(xué)習(xí)方向的倉(cāng)庫(kù)給大家。數(shù)高達(dá)的筆記后端尤其是程序員的學(xué)習(xí)倉(cāng)庫(kù)兩個(gè)算法相關(guān)的倉(cāng)庫(kù),刷的小伙伴必備 最近瀏覽 Github ,收藏了一些還算不錯(cuò)的 Java面試/學(xué)習(xí)相關(guān)的倉(cāng)庫(kù),分享給大家,希望對(duì)你有幫助。我暫且按照目前的 Star 數(shù)量來(lái)排序。 本文由 SnailClimb 整理...
摘要:為了防止這種現(xiàn)象,我們可以對(duì)字節(jié)碼進(jìn)行混淆。動(dòng)態(tài)鏈接庫(kù)是目標(biāo)文件的集合,目標(biāo)文件在動(dòng)態(tài)鏈接庫(kù)中的組織方式是按照特殊方式形成的。 一、已知防護(hù)策略 1.不可或缺的混淆 Java 是一種跨平臺(tái)、解釋型語(yǔ)言,Java 源代碼編譯成的class文件中有大量包含語(yǔ)義的變量名、方法名的信息,很容易被反編譯為Java 源代碼。為了防止這種現(xiàn)象,我們可以對(duì)Java字節(jié)碼進(jìn)行混淆?;煜粌H能將代碼中的類(lèi)...
摘要:在中,拖放是標(biāo)準(zhǔn)的一部分,任何元素都能夠拖放。如果需要設(shè)置允許放置,我們必須阻止對(duì)元素的默認(rèn)處理方式方法。 系列文章 關(guān)于前端上傳文件全面基礎(chǔ)掃盲貼(零)關(guān)于前端上傳文件全面基礎(chǔ)掃盲貼(一) ----- XMLHttpRequest關(guān)于前端上傳文件全面基礎(chǔ)掃盲貼(二) ----- File關(guān)于前端上傳文件全面基礎(chǔ)掃盲貼(三) ----- FormData關(guān)于前端上傳文件全面基礎(chǔ)掃盲貼(...
摘要:為了解救上面說(shuō)到的問(wèn)題是向提交的一個(gè)草案,旨在推出一套標(biāo)準(zhǔn)的,其基本功能是實(shí)現(xiàn)用對(duì)本地文件進(jìn)行操作。出于安全性的考慮,該只對(duì)本地文件提供有限的訪(fǎng)問(wèn)。 系列文章 關(guān)于前端上傳文件全面基礎(chǔ)掃盲貼(零)關(guān)于前端上傳文件全面基礎(chǔ)掃盲貼(一) ----- XMLHttpRequest關(guān)于前端上傳文件全面基礎(chǔ)掃盲貼(二) ----- File關(guān)于前端上傳文件全面基礎(chǔ)掃盲貼(三) ----- For...
閱讀 2482·2021-11-16 11:45
閱讀 2456·2021-10-11 10:59
閱讀 2259·2021-10-08 10:05
閱讀 3850·2021-09-23 11:30
閱讀 2380·2021-09-07 09:58
閱讀 819·2019-08-30 15:55
閱讀 782·2019-08-30 15:53
閱讀 1931·2019-08-29 17:00