ProGuard基礎(chǔ)

引言

很早就想寫篇關(guān)于proguard的文章,但是CSDN翠胰、簡(jiǎn)書、博客園等等網(wǎng)站上面已經(jīng)有大量關(guān)于proguard的文章自脯,并且很多都寫得很好之景。我再寫似乎也是重復(fù)而已,而且很有可能還沒(méi)有前輩們寫得好膏潮。思來(lái)想去锻狗,我覺(jué)得對(duì)我來(lái)說(shuō)超不超越前人并不重要,記錄自己的知識(shí)最重要焕参,由此便有了本文轻纪。寫著寫著發(fā)現(xiàn)自己大部分是在翻譯英文文檔,實(shí)在沒(méi)有什么自己的東西龟糕,但實(shí)戰(zhàn)是要有理論基礎(chǔ)的桐磁,為了下一篇《ProGuard實(shí)戰(zhàn)》能更容易理解悔耘,我還是決定即使是純翻譯也要把它寫完讲岁。如果你英語(yǔ)還不錯(cuò),建議你跳過(guò)本文衬以,直接閱讀原汁原味的英文文檔:$SDK/tools/proguard/docs/manual/usage.html($SDK表示android sdk路徑)缓艳。
看完你還有興趣的話,歡迎再回來(lái)看《ProGuard實(shí)戰(zhàn)》看峻。如果你英語(yǔ)一般般阶淘,那建議至少將本文簡(jiǎn)單過(guò)一遍,再看《ProGuard實(shí)戰(zhàn)》互妓。

1. proguard簡(jiǎn)介

proguard是一個(gè)能夠?qū)ava 代碼進(jìn)行壓縮(Shrink)溪窒,優(yōu)化(Optimize),混淆(Obfuscate)冯勉,預(yù)檢(Preveirfy)的工具澈蚌。 proguard已集成到Android SDK中,路徑為$SDK\tools\proguard灼狰,其中包含可執(zhí)行文件宛瞄、jar、文檔交胚、使用例子及默認(rèn)的混淆配置文件等等:


proguard目錄結(jié)構(gòu).png

簡(jiǎn)單介紹一下proguard的主要文件:
(1) bin目錄下是可執(zhí)行文件份汗,包括:
proguard.bat : 用于對(duì)代碼進(jìn)行壓縮盈电、優(yōu)化、混淆杯活、預(yù)檢的可執(zhí)行文件匆帚。
retrace.bat : 用于對(duì)混淆后的代碼出現(xiàn)的異常或者錯(cuò)誤日志進(jìn)行堆棧還原的可執(zhí)行文件旁钧。
proguardgui.bat: 一個(gè)GUI工具卷扮,它集成了proguard.bat和retrace.bat,在可視化界面中提供了處理過(guò)程的各個(gè)步驟的配置項(xiàng)均践,比在命令行使用更加方便晤锹。

(2) lib目錄下是jar文件,與可執(zhí)行文件相對(duì)應(yīng)也有三個(gè):
proguard.jar
retrace.jar
proguardgui.jar
(3) docs目錄下是使用文檔彤委,里面有使用手冊(cè)鞭铆,不熟悉時(shí)可查看其中的文檔。
(4) exmaples是使用例子焦影,可結(jié)合例子學(xué)習(xí)和理解proguard的使用车遂。
(5) proguard-android.txt、proguard-android-optimize.txt斯辰、proguard-project.txt 是默認(rèn)的proguard配置文件舶担。

2. proguard處理流程

proguard處理流程圖如下圖所示:


proguard處理流程.png
  • 壓縮(Shrink): 檢測(cè)并刪除未使用的類,字段彬呻,方法和屬性衣陶。
  • 優(yōu)化(Optimize): 分析并優(yōu)化方法的字節(jié)碼。
  • 混淆(Obfuscate): 使用簡(jiǎn)短的無(wú)意義名稱例如a,b,c等闸氮,重命名類剪况,字段和方法。
  • 預(yù)檢(Preveirfy): 主要是在Java平臺(tái)上對(duì)處理后的代碼進(jìn)行預(yù)檢蒲跨。

前面三步使代碼庫(kù)占用空間更小译断,執(zhí)行更高效,并且更難以逆向工程或悲, 最后的預(yù)驗(yàn)證步驟將預(yù)驗(yàn)證信息添加到類中孙咪,這對(duì)于JavaME是必需的,也可以縮短啟動(dòng)時(shí)間巡语。這些步驟都是可選的翎蹈。 例如,proguard可以僅用于列出應(yīng)用程序中的無(wú)效代碼捌臊,或預(yù)驗(yàn)證類文件杨蛋,以便高效的在Java 使用。

3. proguard入口點(diǎn)

3.1 入口點(diǎn)

為了確定哪些代碼必須保留,哪些代碼可以丟棄或混淆逞力,我們必須為代碼指定一個(gè)或多個(gè)入口點(diǎn)曙寡,入口點(diǎn)通常是含有main方法的類。

  • 在壓縮(Shrink)步驟中寇荧,從入口點(diǎn)開始遞歸確定已使用的類和類成員举庶,未使用的類和類成員將被丟棄。
  • 在優(yōu)化(Optimize)步驟中揩抡,進(jìn)一步優(yōu)化代碼户侥,非入口點(diǎn)的類和方法可能被設(shè)為private,static或final的峦嗤,未使用的參數(shù)可能被刪除蕊唐,某些方法可能被設(shè)為inlined。
  • 在混淆(Obfuscate)步驟中烁设,重命名不是入口點(diǎn)的類和類成員替梨。在整個(gè)過(guò)程中將保留入口點(diǎn),確弊昂冢混淆后仍可以使用其原名稱來(lái)訪問(wèn)它們副瀑。
  • 預(yù)檢(Preveirfy)步驟是唯一不必知道入口點(diǎn)的步驟。

3.2 反射

值得注意的是恋谭,如代碼中使用了反射需要特殊處理糠睡。例如,Class.forName()構(gòu)造可以在運(yùn)行時(shí)引用任何類疚颊,通常情況下狈孔,我們無(wú)法預(yù)見(jiàn)哪些類的類名必須保留。因此串稀,必須將反射動(dòng)態(tài)創(chuàng)建或調(diào)用的類或類成員也指定為入口點(diǎn)除抛。我們必須在proguard配置文件中使用-keep選項(xiàng)來(lái)保留它們的類名。但是母截,proguard會(huì)自動(dòng)檢測(cè)并處理以下情況:

Class.forName("SomeClass")
SomeClass.class
SomeClass.class.getField("someField")
SomeClass.class.getDeclaredField("someField")
SomeClass.class.getMethod("someMethod", new Class[] {})
SomeClass.class.getMethod("someMethod", new Class[] { A.class })
SomeClass.class.getMethod("someMethod", new Class[] { A.class, B.class })
SomeClass.class.getDeclaredMethod("someMethod", new Class[] {})
SomeClass.class.getDeclaredMethod("someMethod", new Class[] { A.class })
SomeClass.class.getDeclaredMethod("someMethod", new Class[] { A.class, B.class })
AtomicIntegerFieldUpdater.newUpdater(SomeClass.class, "someField")
AtomicLongFieldUpdater.newUpdater(SomeClass.class, "someField")
AtomicReferenceFieldUpdater.newUpdater(SomeClass.class, SomeType.class, "someField")

當(dāng)然,類和類成員的名稱可能會(huì)有所不同橄教,但實(shí)際上類的所有構(gòu)造方法在字面上是相同的清寇,proguard可以識(shí)別它們。被引用的類和類成員在壓縮階段被保留护蝶,并且字符串參數(shù)在混淆階段被適當(dāng)?shù)馗隆?br> 此外华烟,如果出現(xiàn)某些類或類成員需要保留,proguard會(huì)提供一些建議持灰。例如盔夜,proguard會(huì)注意類似“(SomeClass)Class.forName(variable).newInstance()”的構(gòu)造。這些可能表明該類或接口SomeClass或其實(shí)現(xiàn)類可能需要保留。然后喂链,我們可以根據(jù)建議相應(yīng)地調(diào)整配置返十。
為了能夠正確的混淆,我們需要對(duì)正在處理的代碼有所了解椭微《纯樱混淆大量使用反射的代碼可能會(huì)出現(xiàn)錯(cuò)誤,需要反復(fù)試驗(yàn)蝇率,尤其是在沒(méi)有關(guān)于代碼內(nèi)部的必要信息的情況下迟杂。

4. proguard的使用

要使用proguard,只需在命令行鍵入:
java -jar proguard.jar options ...

第1節(jié)中我們提到過(guò)proguard.jar本慕,它的路徑為$SDK/tools/proguard/lib/proguard.jar排拷。當(dāng)然我們也可以選擇使用$SDK/tools/proguard/bin/proguard.bat,用文本編輯器打開proguard.bat可以看到它只是一個(gè)腳本锅尘,實(shí)際上還是用java指令來(lái)執(zhí)行的攻泼。通常,我們會(huì)將proguard的大多數(shù)選項(xiàng)都放在配置文件中鉴象,然后運(yùn)行proguard忙菠,例如配置文件為myconfig.pro:
java -jar proguard.jar @myconfig.pro

我們還可以組合命令行選項(xiàng)和配置文件中的選項(xiàng)。例如:
java -jar proguard.jar @myconfig.pro -verbose

proguard 選項(xiàng)參數(shù)和配置文件的說(shuō)明:

  • proguard配置文件中可以添加注釋纺弊,注釋以#字符開始牛欢,一直持續(xù)到該行的末尾。
  • 單詞和限定符之間的多余空格將被忽略淆游。帶有空格或特殊字符的文件名應(yīng)使用單引號(hào)或雙引號(hào)引起來(lái)傍睹。
  • 選項(xiàng)可以在命令行中的參數(shù)和配置文件中的行中任意分組,這意味著可以引用命令行選項(xiàng)的任意部分犹菱,例如拾稳,以避免特殊字符的shell擴(kuò)展。
  • 選項(xiàng)通常是與順序無(wú)關(guān)的腊脱。為了使用方便访得,可以將其縮寫為第一個(gè)唯一字符。

5. proguard選項(xiàng)

參考:$SDK/tools/proguard/docs/manual/usage.html

5.1 輸入/輸出選項(xiàng)(Input/Output Options)

  • -include filename陕凹,使用時(shí)也可以縮寫成@filename悍抑,從給定的文件中遞歸讀取配置選項(xiàng)。

  • -basedirectory directoryname杜耙,為配置參數(shù)或此配置文件中的相對(duì)文件名指定基本目錄搜骡。

  • -injars class_path,指定輸入jar的路徑(或war佑女,ears记靡,zip或目錄)谈竿。這些jar中的類文件將被處理并寫入輸出jar。默認(rèn)情況下摸吠,所有非類文件都將被復(fù)制而不會(huì)更改空凸。直接從目錄中讀取輸入文件時(shí),可以過(guò)濾掉臨時(shí)文件的路徑(例如由IDE創(chuàng)建的臨時(shí)文件)蜕便,在過(guò)濾器小節(jié)會(huì)進(jìn)一步解釋劫恒。為了提高可讀性,可以使用多個(gè)-injars選項(xiàng)指定類路徑條目轿腺。

  • -outjars class_path两嘴, 指定輸出jar的路徑(或wars,ears族壳,zips或目錄)憔辫。-injars選項(xiàng)指定的jar處理后將被寫入-outjars指定的jar。我們可以將一組輸入jar的內(nèi)容處理后輸出到對(duì)應(yīng)的一組輸出jar中仿荆。與-injars選項(xiàng)一樣贰您,可以過(guò)濾輸出條目,在過(guò)濾器小節(jié)會(huì)進(jìn)一步解釋拢操。然后锦亦,將每個(gè)已處理的類文件或資源文件通過(guò)匹配的過(guò)濾器寫入輸出jar組中的第一個(gè)輸出條目。我們必須避免讓輸出文件覆蓋任何輸入文件令境。為了提高可讀性杠园,可以使用多個(gè)-outjars選項(xiàng)指定類路徑條目。如果沒(méi)有任何-outjars選項(xiàng)舔庶,則不會(huì)寫入任何jar抛蚁。

  • -libraryjars class_path, 指定依庫(kù)jar(或war惕橙,ears瞧甩,zip或目錄)。依賴庫(kù)jar中的文件將不會(huì)包含進(jìn)outjars中弥鹦。盡管依賴庫(kù)jar的類的存在可以改善優(yōu)化步驟的結(jié)果肚逸,但是它們只需要被調(diào)用,不需要存在于outjars中惶凝『鸹ⅲ可以過(guò)濾整個(gè)依賴庫(kù)jar的路徑,在過(guò)濾器小節(jié)會(huì)進(jìn)一步解釋苍鲜。為了提高可讀性,可以使用多個(gè)-libraryjars選項(xiàng)指定類路徑條目玷犹。請(qǐng)注意混滔,在查找?guī)祛悤r(shí)洒疚,proguard不考慮boot path和class path,所以必須明確指定代碼將使用的運(yùn)行時(shí)jar坯屿。

  • -skipnonpubliclibraryclasses油湖,指定在讀取依賴庫(kù)jar時(shí)跳過(guò)非公共類,以加快處理速度并減少proguard的內(nèi)存使用量领跛。默認(rèn)情況下乏德,proguard會(huì)讀取非公共和公共庫(kù)類。非公用類通常不相關(guān)吠昭,不影響輸入jar中的實(shí)際程序代碼喊括,忽略它們可以加快proguard的速度,而不會(huì)影響輸出矢棚。某些庫(kù)中可能包含了由公共庫(kù)類擴(kuò)展的非公共庫(kù)類郑什,這種情況我們就不能使用此選項(xiàng)。如果由于設(shè)置了此選項(xiàng)而出現(xiàn)can't find classes錯(cuò)誤蒲肋,則proguard將打印警告蘑拯。

  • -dontskipnonpubliclibraryclasses, 指定不跳過(guò)非公共庫(kù)類兜粘。從4.5版開始申窘,這是默認(rèn)設(shè)置。Android SDK中的是4.7孔轴,因此這個(gè)是默認(rèn)設(shè)置剃法。

  • -dontskipnonpubliclibraryclassmembers, 指定不跳過(guò)包可見(jiàn)的庫(kù)類成員(字段和方法)距糖。默認(rèn)情況下玄窝,proguard在解析庫(kù)類時(shí)會(huì)跳過(guò)包可見(jiàn)的庫(kù)類成員。當(dāng)我們確實(shí)引用了包可見(jiàn)的類成員時(shí)悍引,需要設(shè)置此項(xiàng)恩脂。

  • -keepdirectories [directory_filter], 指定要保留在輸出jar中的目錄(或wars趣斤,ears或directory)俩块。默認(rèn)情況下,目錄條目被刪除浓领。這樣可以減小jar的大小玉凯,但是如果程序代碼嘗試使用“ MyClass.class.getResource(“”)“”之類的結(jié)構(gòu)來(lái)查找它們,則可能會(huì)找不到的联贩。如果指定的選項(xiàng)沒(méi)有過(guò)濾器漫仆,則保留所有目錄。使用過(guò)濾器時(shí)泪幌,僅保留匹配的目錄盲厌。

  • -target version署照,指定要在已處理的類文件中設(shè)置的版本號(hào)。默認(rèn)情況下吗浩,類文件的版本號(hào)保持不變建芙。例如,版本號(hào)可以是1.0懂扼、1.1禁荸、1.2、1.3阀湿、1.4赶熟、1.5(或僅5),1.6(或僅6)或1.7(或僅7)之一炕倘。某些情況下钧大,可能通過(guò)更改類文件的版本號(hào)并對(duì)其進(jìn)行預(yù)先驗(yàn)證。

  • -forceprocessing罩旋, 強(qiáng)制重新處理啊央,即使輸出看起來(lái)是最新的也是如此。最新的檢測(cè)機(jī)制是比較指定輸入涨醋,輸出和配置文件或目錄的日期戳瓜饥。

5.2 保留選項(xiàng)(Keep Options)

  • keep [,modifier浴骂,...] class_specification乓土,指定要保留的類和類成員(字段和方法)。例如溯警,為了保留應(yīng)用程序趣苏,我們需要保留包含main方法的主類。為了處理庫(kù)梯轻,我們應(yīng)該保留所有可公開訪問(wèn)的元素食磕。

  • -keepclassmembers [,modifier喳挑,...] class_specification彬伦,指定要保留的類成員(如果它們的類也被保留)。例如伊诵,我們可能想要保留所有實(shí)現(xiàn)Serializable接口的類的序列化字段和方法单绑。

  • -keepclasseswithmembers [,modifier曹宴,...] class_specification搂橙,指定保留滿足條件的類和類成員。例如笛坦,我們可能希望保留所有具有main方法的類份氧,但是又不想一一列出它們唯袄。

  • -keepnames class_specification弯屈,-keep,allowshrinking class_specification的縮寫蜗帜,指定要保留名稱的類和類成員。例如资厉,我們可能希望保留實(shí)現(xiàn)Serializable接口的類的所有類名厅缺,以便處理后的代碼與任何原始序列化的類保持兼容。注意宴偿,這個(gè)選項(xiàng)僅在混淆時(shí)適用湘捎,因此僅對(duì)壓縮階段未刪除的類和類成員有效,完全未使用的類在壓縮階段仍可以刪除窄刘。

  • -keepclassmembernames class_specification窥妇,-keepclassmembers,allowshrinking class_specification的縮寫。指定要保留名稱的類成員娩践。同樣的活翩,這個(gè)選項(xiàng)僅在混淆時(shí)適用。

  • -keepclasseswithmembernames class_specification翻伺, -keepclasseswithmembers,allowshrinking class_specification的縮寫材泄。指定保留滿足條件的類和類成員的名稱。例如吨岭,我們可能希望保留所有native方法名稱及其類的名稱拉宗,以便處理后的代碼仍可以與so代碼鏈接。如果一個(gè)類文件被使用了辣辫,但是它不包含native方法旦事,則其名稱仍將被混淆。同樣的急灭,這個(gè)選項(xiàng)僅在混淆時(shí)適用姐浮。

  • -printseeds [filename],詳細(xì)列出與各種-keep選項(xiàng)匹配的類和類成員化戳,將列表打印到標(biāo)準(zhǔn)輸出或給定文件单料。該列表對(duì)于驗(yàn)證是否確實(shí)找到了預(yù)期的類成員很有用,尤其是在使用通配符的情況下点楼。例如扫尖,您可能要列出所有應(yīng)用程序或保留的所有小程序。

-keep可以用于壓縮和混淆掠廓,各種-keep選項(xiàng)可能看起來(lái)有些混亂换怖,但是實(shí)際上它們背后有一個(gè)模式。 下表總結(jié)了它們之間的關(guān)系:


proguard的keep規(guī)律.png

如果不確定所需要的選項(xiàng)蟀瞧,則應(yīng)該只使用-keep沉颂。 這樣可以保證在壓縮步驟中不刪除指定的類和類成員条摸,并且在混淆步驟中不將其重命名。
注意:
(1)指定類而不指定該類的成員只會(huì)將類保留為入口點(diǎn)铸屉,它的類成員仍然可以被刪除钉蒲,優(yōu)化或混淆。
(2)指定類成員僅將類成員保留為入口點(diǎn)彻坛,相關(guān)的代碼仍可以被優(yōu)化和調(diào)整顷啼。

5.3 壓縮選項(xiàng)(Shrinking Options)

  • -dontshrink,指定不壓縮的類文件昌屉,默認(rèn)壓縮钙蒙。除各種-keep選項(xiàng)列出的類以及它們直接或間接依賴的類之外,所有類和類成員都將被刪除间驮。在每個(gè)優(yōu)化步驟之后也會(huì)壓縮躬厌,因?yàn)槟承﹥?yōu)化后可能會(huì)有更多類和類成員可以被刪除。

  • -printusage [filename]竞帽,列出未使用的代碼扛施。該列表將打印到標(biāo)準(zhǔn)輸出或給定文件。例如抢呆,您可以列出應(yīng)用程序的未使用代碼煮嫌。僅在壓縮時(shí)適用。

  • -whyareyoukeeping class_specification抱虐, 打印為什么在壓縮步驟中保留給定類和類成員的詳細(xì)信息昌阿。對(duì)于每個(gè)指定的類和類成員,此選項(xiàng)將最短的方法鏈打印到指定的種子或入口點(diǎn)恳邀。打印出的最短鏈有時(shí)可能包含循環(huán)扣除懦冰,這些未反映實(shí)際的壓縮過(guò)程。如果指定了-verbose選項(xiàng)谣沸,則跟蹤將包括完整的字段和方法簽名刷钢。僅在壓縮時(shí)適用。如果我們想知道為什么輸出中存在某些給定的元素乳附,這可能會(huì)很有用内地。

5.4 優(yōu)化選項(xiàng)(Optimization Options)

  • -dontoptimize,指定不優(yōu)化的類文件赋除。默認(rèn)啟用優(yōu)化阱缓。所有方法都在字節(jié)碼級(jí)別進(jìn)行了優(yōu)化。

  • -optimizations Optimization_filter举农, 在更細(xì)粒度的級(jí)別上指定要啟用和禁用的優(yōu)化荆针。僅在優(yōu)化時(shí)適用。這是一個(gè)專家選項(xiàng)。

  • -optimizationpasses n航背,指定要執(zhí)行的優(yōu)化遍數(shù)喉悴,n的取值范圍為0-7,默認(rèn)為1玖媚,Android項(xiàng)目一般設(shè)置為5箕肃。多次優(yōu)化可能會(huì)導(dǎo)致進(jìn)一步的改進(jìn)。如果在優(yōu)化之后未發(fā)現(xiàn)任何改進(jìn)最盅,則優(yōu)化結(jié)束突雪。僅在優(yōu)化時(shí)適用。

  • -assumenosideeffects class_specification涡贱,指定刪除沒(méi)有任何影響的方法,比如沒(méi)有返回值的且不影響執(zhí)行結(jié)果的方法惹想、有返回值但未使用其返回值且不影響執(zhí)行結(jié)果的方法问词。例如,我們可以指定方法Log.v()嘀粱,用來(lái)優(yōu)化無(wú)用的Log激挪。請(qǐng)注意,該選項(xiàng)將作用于整個(gè)jar锋叨,很容易破壞原有代碼垄分,應(yīng)當(dāng)盡量少用。最好的做法是保持一個(gè)良好的編碼習(xí)慣娃磺,冗余代碼是在寫的時(shí)候就把它刪掉薄湿。僅在優(yōu)化時(shí)適用。

  • -allowaccessmodification偷卧,指定在處理過(guò)程中可以擴(kuò)大類和類成員的訪問(wèn)修飾符豺瘤。這可以改善優(yōu)化步驟的結(jié)果。例如听诸,當(dāng)有一個(gè)public getter時(shí)坐求,可能也必須將訪問(wèn)的字段改成public。大多數(shù)情況下晌梨,不應(yīng)該使用此選項(xiàng)桥嗤,使用后可能導(dǎo)致在API中設(shè)計(jì)為不公開的類和類成員被公開。

  • -mergeinterfacesaggressively仔蝌,指定侵略性的合并接口泛领,即使接口的實(shí)現(xiàn)類未實(shí)現(xiàn)所有接口方法,也可以合并接口掌逛。這樣可以通過(guò)減少類的總數(shù)來(lái)減小輸出的大小师逸。同樣會(huì)破壞原有代碼,如不清楚其影響,應(yīng)當(dāng)不使用該選項(xiàng)篓像。僅在優(yōu)化時(shí)適用动知。

5.5 混淆選項(xiàng)(Obfuscation Options)

  • -dontobfuscate,指定不混淆的類文件员辩,默認(rèn)全部混淆盒粮。除各種-keep選項(xiàng)列出的類和類成員外,其它類和類成員將會(huì)被隨機(jī)重命名成簡(jiǎn)短奠滑、無(wú)意義的名稱丹皱,并且會(huì)刪除對(duì)調(diào)試有用的內(nèi)部屬性,例如源文件名宋税、變量名摊崭、行號(hào)等。

  • -printmapping [filename]杰赛,指定映射文件呢簸。重命名后,重命名后的類和類成員與重命名前的類和類成員有一個(gè)映射關(guān)系乏屯,此選項(xiàng)會(huì)打印這個(gè)映射關(guān)系根时,輸出到標(biāo)準(zhǔn)輸出或指定文件。例如辰晕,混淆后應(yīng)用程序運(yùn)行遇到了異常蛤迎,我們就需要這個(gè)映射關(guān)系文件來(lái)還原異常的堆棧信息,以便定位源代碼中出錯(cuò)的位置含友。僅在混淆時(shí)適用替裆。

  • -applymapping filename,指定重復(fù)使用先前混淆生成的映射文件唱较。映射文件中列出的類和類成員將使用原有名稱扎唾。映射文件中沒(méi)有的類和類成員,即新增的類和類成員將被重命名南缓。映射可以引用輸入類以及庫(kù)類胸遇。此選項(xiàng)在增量混淆時(shí)很有用,在這種情況下汉形,還可以考慮使用-useuniqueclassmembernames選項(xiàng)只允許一個(gè)映射文件纸镊。僅在混淆時(shí)適用。

  • -obfuscationdictionary filename概疆,指定一個(gè)混淆字典逗威。默認(rèn)情況下,短名稱(如“ a”岔冀,“ b”等)用作混淆后的字段和方法的名稱凯旭。指定混淆字典后,混淆字典是一個(gè)文本文件,其中所有有效單詞都將被用作混淆的字段和方法的名稱罐呼,但#符號(hào)后的空格鞠柄,標(biāo)點(diǎn)符號(hào),重復(fù)的單詞和注釋將被忽略嫉柴。我們可以在混淆字典中的輸入一系列保留關(guān)鍵字厌杜、外文字符的標(biāo)識(shí)符。注意计螺,混淆字典幾乎不能改善混淆夯尽。因?yàn)槲谋揪幾g器可以很容易的自動(dòng)替換它們,并且使用混淆字典混淆后登馒,還可以使用更簡(jiǎn)單的名稱再次進(jìn)行混淆匙握。通常,最有用的使用場(chǎng)景是在混淆字典中指定類中已經(jīng)存在的字符串(例如“Code”)作為保留關(guān)鍵字谊娇,這樣可以將類文件的大小減小一點(diǎn)肺孤。僅在混淆時(shí)適用。

  • -classobfuscationdictionary filename济欢,指定一個(gè)文本文件,所有有效單詞都用作混淆的類名小渊。作用類似obfuscationdictionary選項(xiàng)法褥。僅在混淆時(shí)適用。

  • -packageobfuscationdictionary filename酬屉,指定一個(gè)文本文件半等,所有有效單詞都用作混淆的包名。作用類似obfuscationdictionary選項(xiàng)呐萨。僅在混淆時(shí)適用杀饵。

  • -overloadaggressively,指定在混淆時(shí)應(yīng)用侵略性的重載谬擦。多個(gè)字段和方法只要它們的參數(shù)和返回類型不同(不僅是參數(shù))切距,就可以使用相同的名稱。此選項(xiàng)可以使處理后的代碼更小惨远、更難理解谜悟。此選項(xiàng)在某些版本可能會(huì)出現(xiàn)異常,例如北秽,Google的Dalvik VM無(wú)法處理重載的靜態(tài)字段葡幸。如不清楚其影響,應(yīng)當(dāng)不使用該選項(xiàng)贺氓,除非明白處理這種異常蔚叨。僅在混淆時(shí)適用。

  • -useuniqueclassmembernames,指定將相同的混淆名稱分配給具有相同名稱的類成員蔑水,將不同的混淆名稱分配給具有不同名稱的類成員邢锯。如果沒(méi)有該選項(xiàng),則可以將更多的類成員映射到相同的短名稱肤粱,如“ a”弹囚,“ b”等。因此领曼,該選項(xiàng)會(huì)稍微增加結(jié)果代碼的大小鸥鹉,但可以確保保存的混淆名稱映射始終是在后續(xù)的漸進(jìn)混淆步驟中能夠識(shí)別。此選項(xiàng)僅在混淆時(shí)適用庶骄。

  • -dontusemixedcaseclassnames毁渗,指定在混淆時(shí)不生成大小寫混合的類名。默認(rèn)情況下单刁,混淆的類名可以包含大寫字符和小寫字符的混合灸异。這將輸出完全可接受且可用的jars。但僅當(dāng)在不區(qū)分大小寫的文件系統(tǒng)(例如Windows)的平臺(tái)上解壓縮jar時(shí)羔飞,解壓工具才可能會(huì)使名稱相似的類文件相互覆蓋肺樟,這樣解壓縮后相當(dāng)于自己損壞了代碼。想在Windows上解壓縮jar的開發(fā)人員可以使用此選項(xiàng)關(guān)閉此行為逻淌。請(qǐng)注意么伯,混淆的jar將因此變大。僅在混淆時(shí)適用卡儒。

  • -keeppackagenames [package_filter]田柔,指定不混淆指定的包名。package_filter是一系列由逗號(hào)分隔的包名骨望。包名可以包含硬爆?,*和**通配符擎鸠,并且可以在其前面加上诊赊!否定限定符民逼。僅在混淆時(shí)適用。

  • -flattenpackagehierarchy [package_name],指定父包名趾疚,將重命名后的所有包移動(dòng)到指定父包下重新封包缭嫡。不帶參數(shù)或帶空字符串('')的包將被移入根目錄痛侍。此選項(xiàng)可以進(jìn)一步混淆包名钥弯。它可以使處理后的代碼更小,更難理解垂寥。僅在混淆時(shí)適用颠黎。

  • -repackageclasses [package_name]另锋,指定通過(guò)將所有重命名的類文件移動(dòng)到單個(gè)給定的包中來(lái)重新打包它們。不帶參數(shù)或帶空字符串('')的狭归,整個(gè)包將被完全刪除夭坪。該選項(xiàng)將覆蓋-flattenpackagehierarchy選項(xiàng)。這是進(jìn)一步混淆軟件包名稱的另一個(gè)示例过椎。它可以使處理后的代碼更小室梅,更難以理解。它不建議使用的名稱是-defaultpackage疚宇。僅在混淆時(shí)適用亡鼠。如果將類移動(dòng)到其他位置,則在其包目錄中查找資源文件的類將無(wú)法正常工作敷待。有疑問(wèn)的情況下间涵,請(qǐng)不要使用此選項(xiàng),以保持包裝原封不動(dòng)榜揖。

  • -keepattributes [attribute_filter]勾哩,指定要保留的所有可選屬性【儆矗可以使用一個(gè)或多個(gè)-keepattributes指令指定屬性思劳。attribute_filter是一系列由逗號(hào)分隔的屬性名稱。同樣的妨猩,屬性名稱可以包含敢艰?,*和**通配符册赛,并且可以在其前面加上!否定限定符震嫉。典型的可選屬性有:Exceptions森瘪,Signature,Deprecated票堵,SourceFile扼睬,SourceDir,LineNumberTable悴势,LocalVariableTable窗宇,LocalVariableTypeTable,Synthetic特纤,EnclosingMethod军俊,RuntimeVisibleAnnotations,RuntimeInvisibleAnnotations捧存,RuntimeVisibleParameterAnnotations粪躬,RuntimeInvisibleParameterAnnotations担败,AnnotationDefault。還可以將內(nèi)部類的屬性名稱作為源文件的一部分镰官,指定定內(nèi)部類的屬性名稱提前。例如,在處理庫(kù)時(shí)泳唠,至少應(yīng)保留Exceptions狈网,InnerClasses和Signature屬性。還應(yīng)該保留SourceFile和LineNumberTable屬性笨腥,以產(chǎn)生有用的混淆堆棧跟蹤拓哺。最后,如果您的代碼依賴注解扇雕,則可能需要保留注解拓售。僅在混淆時(shí)適用。

  • -keepparameternames镶奉,指定保留參數(shù)名稱和類型的方法础淤。此選項(xiàng)實(shí)際上保留了精簡(jiǎn)版本的調(diào)試屬性LocalVariableTable和LocalVariableTypeTable。在處理庫(kù)時(shí)哨苛,它很有用鸽凶。某些IDE可以使用這些信息來(lái)幫助使用該庫(kù)的開發(fā)人員,例如提供工具提示或自動(dòng)完成功能建峭。僅在混淆時(shí)適用玻侥。

  • -renamesourcefileattribute [string],指定要放入類文件的SourceFile屬性(和SourceDir屬性)中的常量字符串亿蒸。請(qǐng)注意凑兰,必須首先保留該屬性,因此還必須使用-keepattributes指令顯式地保留該屬性边锁。例如姑食,您可能希望處理后的庫(kù)和應(yīng)用程序生成有用的混淆堆棧跟蹤。僅在混淆時(shí)適用茅坛。

  • -adaptclassstrings [class_filter]音半,指定與類名相對(duì)應(yīng)的字符串常量也應(yīng)該被混淆。如果沒(méi)有過(guò)濾器贡蓖,則將修改所有與類名稱相對(duì)應(yīng)的字符串常量曹鸠。使用過(guò)濾器時(shí),僅匹配與過(guò)濾器匹配的類中的字符串常量斥铺。例如彻桃,如果您的代碼包含大量引用類的硬編碼字符串,并且您不想保留其名稱仅父,則可能要使用此選項(xiàng)叛薯。主要適用于混淆時(shí)浑吟,但相應(yīng)的類也會(huì)在壓縮步驟中自動(dòng)保留。

  • -adaptresourcefilenames [file_filter]耗溜,根據(jù)相應(yīng)類文件的混淆名稱指定要重命名的資源文件组力。如果沒(méi)有過(guò)濾器,則將與類文件對(duì)應(yīng)的所有資源文件重命名抖拴。使用過(guò)濾器燎字,僅重命名匹配的文件。僅在混淆時(shí)適用阿宅。

  • -adaptresourcefilecontents [file_filter]候衍,指定要更新其內(nèi)容的資源文件。資源文件中提到的任何類名都將根據(jù)相應(yīng)類的混淆名進(jìn)行重命名洒放。沒(méi)有過(guò)濾器蛉鹿,所有資源文件的內(nèi)容都會(huì)更新。使用過(guò)濾器往湿,僅更新匹配的文件妖异。使用平臺(tái)的默認(rèn)字符集來(lái)解析和寫入資源文件。您可以通過(guò)設(shè)置環(huán)境變量LANG或Java系統(tǒng)屬性file.encoding來(lái)更改此默認(rèn)字符集领追。

5.6 預(yù)檢選項(xiàng)(Preverification Options)

  • -dontpreverify他膳,指定不預(yù)先驗(yàn)證已處理的類文件。 默認(rèn)情況下绒窑,如果目標(biāo)版本是Java Micro Edition或Java 6或更高版本棕孙,類文件將進(jìn)行預(yù)驗(yàn)證。 對(duì)于Java Micro Edition些膨,需要進(jìn)行預(yù)驗(yàn)證蟀俊,因此,如果指定此選項(xiàng)订雾,則需要在已處理的代碼上運(yùn)行外部預(yù)驗(yàn)證器欧漱。 對(duì)于Java 6,尚不需要進(jìn)行預(yù)驗(yàn)證葬燎,但可以提高Java虛擬機(jī)中類加載的效率。android項(xiàng)目中一般會(huì)配置此選項(xiàng)缚甩。

  • -microedition谱净,指定已處理的類文件針對(duì)Java Micro Edition。 然后擅威,預(yù)驗(yàn)證器將添加適當(dāng)?shù)腟tackMap屬性壕探,該屬性與Java Standard Edition的默認(rèn)StackMapTable屬性不同。 例如郊丛,如果您正在處理Midlet李请,則將需要此選項(xiàng)瞧筛。

5.7 通用選項(xiàng)(General Options)

  • -verbose,指定在處理期間寫出更多信息导盅。如果程序因異常終止较幌,則此選項(xiàng)將打印出整個(gè)堆棧跟蹤,而不僅僅是異常消息白翻。

  • -dontnote [class_filter]乍炉,指定不打印有關(guān)配置中潛在的錯(cuò)誤或遺漏,例如類名中的錯(cuò)字或缺少可能有用的選項(xiàng)滤馍〉呵恚可選過(guò)濾器是一個(gè)正則表達(dá)式。設(shè)置后巢株,proguard不會(huì)打印匹配有關(guān)名稱的類的注釋槐瑞。

  • -dontwarn [class_filter],指定不警告尚未解決的引用和其他重要問(wèn)題阁苞±ч荩可選過(guò)濾器是一個(gè)正則表達(dá)式; proguard不會(huì)打印匹配有關(guān)名稱的類的警告猬错。忽視警告可能很危險(xiǎn)窗看,如果未處理的類或類成員確實(shí)需要進(jìn)行處理,則處理后的代碼將無(wú)法正常運(yùn)行倦炒。僅當(dāng)我們知道沒(méi)有風(fēng)險(xiǎn)時(shí)才使用此選項(xiàng)显沈,例如,android的默認(rèn)混淆配置中忽略了support包或androidx包中所有類的警告逢唤,因?yàn)閟upport包或androidx包一般不會(huì)出什么問(wèn)題拉讯。

  • -ignorewarnings,指定打印有關(guān)未解決的引用和其他重要問(wèn)題的任何警告鳖藕,但在任何情況下都將繼續(xù)處理魔慷。

  • -printconfiguration [filename],指定打印已解析的整個(gè)配置著恩,包括所包含的文件和替換的變量院尔。結(jié)構(gòu)被打印到標(biāo)準(zhǔn)輸出或給定的文件。有時(shí)這對(duì)于調(diào)試配置或?qū)ML配置轉(zhuǎn)換為更具可讀性的格式很有用喉誊。

  • -dump [filename]邀摆,指定在進(jìn)行任何處理后輸出該類文件的內(nèi)部結(jié)構(gòu)。結(jié)構(gòu)被打印到標(biāo)準(zhǔn)輸出或給定的文件伍茄。例如栋盹,您可能想要輸出給定jar文件的內(nèi)容,但不想進(jìn)行任何處理敷矫。

5.8 類路徑(Class Paths)

proguard接受通用化的類路徑來(lái)指定輸入文件和輸出文件例获。類路徑由許多條目組成汉额,這些條目由傳統(tǒng)的路徑分隔符分隔(例如,在Unix上為“:”榨汤,在Windows平臺(tái)上為“;”)蠕搜。在重復(fù)的情況下,按條目的順序決定優(yōu)先級(jí)件余。
每個(gè)輸入條目可以是:

  • 一個(gè)類文件或資源文件讥脐,
  • 包含以上任何內(nèi)容的jar文件,
  • 包含以上任何內(nèi)容的war文件啼器,
  • 包含以上任何內(nèi)容的ear文件旬渠,
  • 包含以上任何內(nèi)容的zip文件,
  • 包含以上任何內(nèi)容的目錄端壳。

直接指定的多個(gè)類文件和資源文件的路徑將被忽略告丢,因此多個(gè)類文件通常應(yīng)為jar文件,war文件损谦,ear文件岖免,zip文件或目錄的一部分。此外照捡,在歸檔或目錄內(nèi)的類文件的路徑不應(yīng)有任何其他目錄前綴颅湘。

每個(gè)輸出條目可以是:

  • 一個(gè)jar文件,其中將包含了所有已處理的類文件和資源文件栗精。
  • 一個(gè)war文件闯参,包含了以上所有內(nèi)容,
  • 一個(gè)ear文件悲立,包含了以上所有內(nèi)容鹿寨,
  • 一個(gè)zip文件,包含了以上所有內(nèi)容薪夕,
  • 一個(gè)目錄脚草,包含了以上所有內(nèi)容。

指定輸出條目后原献,proguard通常會(huì)以合理的方式打包結(jié)果馏慨,并根據(jù)需要重新構(gòu)造輸入條目。一般是直接將所有輸入內(nèi)容寫入輸出目錄姑隅,輸出目錄將包含輸入條目的完整重構(gòu)熏纯。但是打包過(guò)程是可以自定義的,我們也可以將文檔也打包到輸出目錄粤策,重新生成zip文件,如果有此需要误窖,請(qǐng)參考使用手冊(cè)的restructure output archives.一節(jié)叮盘。

此外秩贰,proguard還可以根據(jù)其完整的相對(duì)文件名來(lái)過(guò)濾類路徑及其內(nèi)容。每個(gè)類路徑后面都可以跟隨多達(dá)5種類型的文件過(guò)濾器柔吼,過(guò)濾器以括號(hào)包涵毒费,不同類型的過(guò)濾器以分號(hào)分隔,相同類型的過(guò)濾器以逗號(hào)分隔:

  • zip名稱過(guò)濾器愈魏,
  • ear名稱過(guò)濾器觅玻,
  • war名稱過(guò)濾器,
  • jar名稱過(guò)濾器培漏,
  • 類文件名和資源文件名的過(guò)濾器溪厘。

如果指定的過(guò)濾器少于5個(gè),則假定它們是后者牌柄。任何空的過(guò)濾器都將被忽略畸悬。類路徑的過(guò)濾格式一般如下所示(方括號(hào)“ []”表示其內(nèi)容是可選的):

classpathentry([[[[zipfilter;]earfilter;]warfilter;]jarfilter;]filefilter)

例如,“ rt.jar(java/**.class珊佣,javax/**.class)”匹配rt jar內(nèi)java和javax目錄中的所有類文件蹋宦。
例如,“ input.jar(!**.gif咒锻,images/**)”匹配input.jar內(nèi)images目錄中的所有文件冷冗,但gif文件除外。
注意惑艇,不同的過(guò)濾器將應(yīng)用于所有相應(yīng)的文件類型蒿辙,而不管其在輸入中的嵌套級(jí)別如何; 它們是正交的敦捧。
例如须板,“ input.war(lib/**.jar,support/**.jar; **.class兢卵,**.gif)”僅考慮input.war中l(wèi)ib和support目錄中的jar文件习瑰,而不考慮 其他jar文件。 然后秽荤,它將匹配所有遇到的類文件和gif文件甜奄。

5.9 文件名(File Names)

proguard接受基于絕對(duì)路徑和相對(duì)路徑的文件名和目錄名,相對(duì)路徑解釋如下:

  • 如果設(shè)置了基準(zhǔn)目錄窃款,則相對(duì)于基本目錄(前面提到的basedirectory選項(xiàng))课兄,否則
  • 如果指定了配置文件的位置,則相對(duì)于指定配置文件的位置晨继,否則
  • 相對(duì)于工作目錄烟阐。

名稱可以包含以'<'和'>'分隔的Java系統(tǒng)屬性。系統(tǒng)屬性將自動(dòng)替換為其各自的值。例如蜒茄,<java.home>/lib/rt.jar將自動(dòng)擴(kuò)展為/usr/local/java/jdk/jre/lib/rt.jar唉擂。同樣,<user.home>將擴(kuò)展到用戶的主目錄檀葛,而<user.dir>將擴(kuò)展到當(dāng)前的工作目錄玩祟。

帶有特殊字符(如空格和括號(hào))的名稱必須用單引號(hào)或雙引號(hào)引起來(lái)。請(qǐng)注意屿聋,名稱列表中的每個(gè)文件名都必須單獨(dú)引用空扎。另請(qǐng)注意,在命令行上使用引號(hào)本身時(shí)可能需要轉(zhuǎn)義润讥。例如转锈,在命令行上,可以使用 '-injars "my program.jar":"/your directory/your program.jar"'.之類的選項(xiàng)象对。

5.10 過(guò)濾器(Filters)

為了配置的處理過(guò)程中的諸多方面黑忱,proguard提供了許多帶有過(guò)濾器的選項(xiàng):文件名,目錄名勒魔,類名甫煞,包名,屬性名冠绢,優(yōu)化名等抚吠。而過(guò)濾器是可以包含通配符的逗號(hào)分隔名稱的列表。 只有與列表中的項(xiàng)目匹配的名稱才能通過(guò)過(guò)濾器弟胀,輸入文件中只有具有匹配文件名的文件才被讀瓤Α;輸出文件中只有具有匹配文件名的文件才被被寫入孵户。 支持的通配符取決于使用過(guò)濾器的名稱的類型萧朝,但是以下通配符是通用的:


proguard通配符.png

5.11 保留選項(xiàng)修飾符(Keep Option Modifiers)

  • allowshrinking,允許壓縮夏哭,指定-keep選項(xiàng)中指定的入口點(diǎn)可以壓縮检柬,即使必須保留這些入口點(diǎn)也可以。 也就是說(shuō)竖配,可以在壓縮步驟中移除入口點(diǎn)何址,但是如果確有必要,可以不對(duì)其進(jìn)行優(yōu)化或混淆进胯。
  • allowoptimization用爪,允許優(yōu)化,指定可以優(yōu)化-keep選項(xiàng)中指定的入口點(diǎn)胁镐,即使必須保留這些入口點(diǎn)也是如此偎血。 也就是說(shuō)诸衔,可以在優(yōu)化步驟中更改入口點(diǎn),但不能將其刪除或混淆颇玷。 該修飾符僅對(duì)實(shí)現(xiàn)不常用要求有用署隘。
  • allowobfuscation,允許混淆亚隙,指定-keep選項(xiàng)中指定的入口點(diǎn)可能會(huì)被混淆,即使必須保留它們也是如此违崇。 也就是說(shuō)阿弃,入口點(diǎn)可以在混淆步驟中重命名,但是它們可能不會(huì)被刪除或優(yōu)化羞延。 該修飾符僅對(duì)達(dá)到不常用要求有用渣淳。

5.12 類規(guī)范(Class Specifications)

類規(guī)范是類和類成員(字段和方法)的模板。 它在各種-keep選項(xiàng)和-assumenosideeffects選項(xiàng)中使用伴箩。 相應(yīng)的選項(xiàng)僅適用于與模板匹配的類和類成員入愧。這種模板看起來(lái)非常像Java代碼,還有一些帶有通配符的擴(kuò)展名嗤谚。 例如:

[@annotationtype] [[!]public|final|abstract|@ ...] [!]interface|class|enum classname
    [extends|implements [@annotationtype] classname]
[{
    [@annotationtype] [[!]public|private|protected|static|volatile|transient ...] <fields> |
                                                                      (fieldtype fieldname);
    [@annotationtype] [[!]public|private|protected|static|synchronized|native|abstract|strictfp ...] <methods> |
                                                                                           <init>(argumenttype,...) |
                                                                                           classname(argumenttype,...) |
                                                                                           (returntype methodname(argumenttype,...));
    [@annotationtype] [[!]public|private|protected|static ... ] *;
    ...
}]
  • 方括號(hào)“ []”表示其內(nèi)容是可選的棺蛛。

  • 省略號(hào)“ ...”表示可以指定任何數(shù)量的前述項(xiàng)目。豎線“ |”分隔兩個(gè)選項(xiàng)巩步。

  • 括號(hào)“()”表示同一分組旁赊。

  • 縮進(jìn)是為了看起來(lái)直觀一些,空格在實(shí)際配置文件中無(wú)關(guān)緊要椅野。

  • class關(guān)鍵字是指任何接口或類终畅。 interface關(guān)鍵字將匹配限制為接口類。 enum關(guān)鍵字將匹配限制為枚舉類竟闪。在接口或枚舉關(guān)鍵字之前加离福!將匹配分別限制為不是接口或枚舉的類。

  • 每個(gè)類別名稱必須完整的類名炼蛤,例如java.lang.String妖爷。但類名可以使用通配符“?”鲸湃,“*”赠涮, “**”、否定限定符 “暗挑!”笋除。

  • extends和implements 通常用于使用通配符限制類。一個(gè)用于類炸裆,一個(gè)用于接口垃它,可以看做是等效的,只能匹配擴(kuò)展或?qū)崿F(xiàn)了指定類的類,即某個(gè)類或接口的子類国拇。請(qǐng)注意洛史,匹配的類不包括該類本身。如果需要酱吝,應(yīng)在單獨(dú)的選項(xiàng)中指定該類也殖。

  • @ specifications可用于將類和類成員限制為使用指定注釋類型進(jìn)行注釋的成員。指定注釋類型就像類名一樣务热。

  • 字段和方法的指定與Java中的指定非常相似忆嗜,除了方法參數(shù)列表不包含參數(shù)名稱(就像在Javadoc和javap等其他工具中一樣)。規(guī)范還可以包含以下所有通配符:
    (1)<init>匹配任何構(gòu)造函數(shù)崎岂。
    (2)<fields>匹配任何字段捆毫。
    (3)<methods>匹配任何方法。
    (4)* 匹配任何字段或方法冲甘。
    請(qǐng)注意绩卤,上述通配符沒(méi)有返回類型。僅<init>通配符具有參數(shù)列表江醇。
    字段和方法也可以使用正則表達(dá)式指定濒憋。名稱可以包含以下通配符:
    (1)?匹配方法名稱中的任何單個(gè)字符嫁审。
    (2)* 匹配方法名稱的任何部分跋炕。
    描述符中的類型可以包含以下通配符:
    (1)% 匹配任何原始類型(“ boolean”,“ int”等律适,但不匹配“ void”)辐烂。
    (2)? 匹配類名稱中的任何單個(gè)字符捂贿。
    (3)* 與不包含包分隔符的類名的任何部分匹配纠修。
    (4)** 匹配類名的任何部分,可能包含任意數(shù)量的包分隔符厂僧。
    (5)*** 匹配任何類型(基本類型或非基本類型扣草,數(shù)組或非數(shù)組)。
    (6)... 匹配任何類型的任意數(shù)量的參數(shù)颜屠。
    請(qǐng)注意辰妙,?甫窟,*和**通配符將永遠(yuǎn)與基本類型不匹配密浑。此外,僅***通配符將匹配任何維度的數(shù)組類型粗井。例如尔破,“ ** get *()”匹配“ java.lang.Object getObject()”街图,但不匹配“ float getFloat()”,也不匹配“ java.lang.Object [] getObjects()”懒构。

  • 也可以使用其簡(jiǎn)短的類名(不帶包名)或使用其完整的類名來(lái)指定構(gòu)造函數(shù)餐济。與Java語(yǔ)言一樣,構(gòu)造函數(shù)規(guī)范具有參數(shù)列表胆剧,但沒(méi)有返回類型絮姆。

  • 類和類成員的訪問(wèn)修飾符通常用于限制通配類和類成員。只有設(shè)置了相同的訪問(wèn)修飾符才能匹配秩霍。前面的滚朵!代表不能設(shè)置該訪問(wèn)修飾符。允許組合多個(gè)修飾符(例如public static)前域。這意味著必須設(shè)置兩個(gè)訪問(wèn)修飾符(例如public和static),除非它們發(fā)生沖突韵吨,否則必須至少設(shè)置其中一個(gè)(例如public或protected)匿垄。

最后,本文翻譯內(nèi)容居多归粉,部分內(nèi)容翻譯之后重新組織了語(yǔ)言進(jìn)行描述椿疗,可能有不正確或者不準(zhǔn)確的地方,歡迎交流糠悼、指正届榄。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市倔喂,隨后出現(xiàn)的幾起案子铝条,更是在濱河造成了極大的恐慌,老刑警劉巖席噩,帶你破解...
    沈念sama閱讀 219,110評(píng)論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件班缰,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡悼枢,警方通過(guò)查閱死者的電腦和手機(jī)埠忘,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,443評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)馒索,“玉大人莹妒,你說(shuō)我怎么就攤上這事〈律希” “怎么了旨怠?”我有些...
    開封第一講書人閱讀 165,474評(píng)論 0 356
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)渔期。 經(jīng)常有香客問(wèn)我运吓,道長(zhǎng)渴邦,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,881評(píng)論 1 295
  • 正文 為了忘掉前任拘哨,我火速辦了婚禮谋梭,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘倦青。我一直安慰自己瓮床,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,902評(píng)論 6 392
  • 文/花漫 我一把揭開白布产镐。 她就那樣靜靜地躺著隘庄,像睡著了一般。 火紅的嫁衣襯著肌膚如雪癣亚。 梳的紋絲不亂的頭發(fā)上丑掺,一...
    開封第一講書人閱讀 51,698評(píng)論 1 305
  • 那天,我揣著相機(jī)與錄音述雾,去河邊找鬼街州。 笑死,一個(gè)胖子當(dāng)著我的面吹牛玻孟,可吹牛的內(nèi)容都是我干的唆缴。 我是一名探鬼主播,決...
    沈念sama閱讀 40,418評(píng)論 3 419
  • 文/蒼蘭香墨 我猛地睜開眼黍翎,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼面徽!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起匣掸,我...
    開封第一講書人閱讀 39,332評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤趟紊,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后碰酝,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體织阳,經(jīng)...
    沈念sama閱讀 45,796評(píng)論 1 316
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,968評(píng)論 3 337
  • 正文 我和宋清朗相戀三年砰粹,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了唧躲。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,110評(píng)論 1 351
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡碱璃,死狀恐怖弄痹,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情嵌器,我是刑警寧澤肛真,帶...
    沈念sama閱讀 35,792評(píng)論 5 346
  • 正文 年R本政府宣布,位于F島的核電站爽航,受9級(jí)特大地震影響蚓让,放射性物質(zhì)發(fā)生泄漏乾忱。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,455評(píng)論 3 331
  • 文/蒙蒙 一历极、第九天 我趴在偏房一處隱蔽的房頂上張望窄瘟。 院中可真熱鬧,春花似錦趟卸、人聲如沸蹄葱。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,003評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)图云。三九已至,卻和暖如春邻邮,著一層夾襖步出監(jiān)牢的瞬間竣况,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,130評(píng)論 1 272
  • 我被黑心中介騙來(lái)泰國(guó)打工筒严, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留帕翻,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,348評(píng)論 3 373
  • 正文 我出身青樓萝风,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親紫岩。 傳聞我的和親對(duì)象是個(gè)殘疾皇子规惰,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,047評(píng)論 2 355