[轉]Android 項目的代碼混淆,Android proguard 使用說明

簡介

?

Java代碼是非常容易反編譯的。為了很好的保護Java源代碼,我們往往會對編譯好的class文件進行混淆處理。

?

ProGuard是一個混淆代碼的開源項目。它的主要作用就是混淆,當然它還能對字節碼進行縮減體積、優化等,但那些對于我們來說都算是次要的功能。

官網地址:http://proguard.sourceforge.net/

原理

Java 是一種跨平臺的、解釋型語言,Java 源代碼編譯成中間”字節碼”存儲于 class 文件中。由于跨平臺的需要,Java 字節碼中包括了很多源代碼信息,如變量名、方法名,并且通過這些名稱來訪問變量和方法,這些符號帶有許多語義信息,很容易被反編譯成 Java 源代碼。為了防止這種現象,我們可以使用 Java 混淆器對 Java 字節碼進行混淆。

混淆就是對發布出去的程序進行重新組織和處理,使得處理后的代碼與處理前代碼完成相同的功能,而混淆后的代碼很難被反編譯,即使反編譯成功也很難得出程序的真正語義。被混淆過的程序代碼,仍然遵照原來的檔案格式和指令集,執行結果也與混淆前一樣,只是混淆器將代碼中的所有變量、函數、類的名稱變為簡短的英文字母代號,在缺乏相應的函數名和程序注釋的況下,即使被反編譯,也將難以閱讀。同時混淆是不可逆的,在混淆的過程中一些不影響正常運行的信息將永久丟失,這些信息的丟失使程序變得更加難以理解。

混淆器的作用不僅僅是保護代碼,它也有精簡編譯后程序大小的作用。由于以上介紹的縮短變量和函數名以及丟失部分信息的原因, 編譯后 jar 文件體積大約能減少25% ,這對當前費用較貴的無線網絡傳輸是有一定意義的。

語法


-include {filename}    從給定的文件中讀取配置參數 
-basedirectory {directoryname}    指定基礎目錄為以后相對的檔案名稱 
-injars {class_path}    指定要處理的應用程序jar,war,ear和目錄 
-outjars {class_path}    指定處理完后要輸出的jar,war,ear和目錄的名稱 
-libraryjars {classpath}    指定要處理的應用程序jar,war,ear和目錄所需要的程序庫文件 
-dontskipnonpubliclibraryclasses    指定不去忽略非公共的庫類。 
-dontskipnonpubliclibraryclassmembers    指定不去忽略包可見的庫類的成員。保留選項 
-keep {Modifier} {class_specification}    保護指定的類文件和類的成員 
-keepclassmembers {modifier} {class_specification}    保護指定類的成員,如果此類受到保護他們會保護的更好
-keepclasseswithmembers {class_specification}    保護指定的類和類的成員,但條件是所有指定的類和類成員是要存在。 
-keepnames {class_specification}    保護指定的類和類的成員的名稱(如果他們不會壓縮步驟中刪除) 
-keepclassmembernames {class_specification}    保護指定的類的成員的名稱(如果他們不會壓縮步驟中刪除) 
-keepclasseswithmembernames {class_specification}    保護指定的類和類的成員的名稱,如果所有指定的類成員出席(在壓縮步驟之后) 
-printseeds {filename}    列出類和類的成員-keep選項的清單,標準輸出到給定的文件 壓縮 
-dontshrink    不壓縮輸入的類文件 
-printusage {filename} 
-dontwarn   如果有警告也不終止
-whyareyoukeeping {class_specification}     優化 
-dontoptimize    不優化輸入的類文件 
-assumenosideeffects {class_specification}    優化時假設指定的方法,沒有任何副作用 
-allowaccessmodification    優化時允許訪問并修改有修飾符的類和類的成員 混淆 
-dontobfuscate    不混淆輸入的類文件 
-printmapping {filename} 
-applymapping {filename}    重用映射增加混淆 
-obfuscationdictionary {filename}    使用給定文件中的關鍵字作為要混淆方法的名稱 
-overloadaggressively    混淆時應用侵入式重載 
-useuniqueclassmembernames    確定統一的混淆類的成員名稱來增加混淆 
-flattenpackagehierarchy {package_name}    重新包裝所有重命名的包并放在給定的單一包中 
-repackageclass {package_name}    重新包裝所有重命名的類文件中放在給定的單一包中 
-dontusemixedcaseclassnames    混淆時不會產生形形色色的類名 
-keepattributes {attribute_name,...}    保護給定的可選屬性,例如LineNumberTable, LocalVariableTable, SourceFile, Deprecated, Synthetic, Signature, and InnerClasses. 
-renamesourcefileattribute {string}    設置源文件中給定的字符串常量

?

?

Android Eclipse開發環境與ProGuard

在Android 2.3以前,混淆Android代碼只能手動添加proguard來實現代碼混淆,非常不方便。而2.3以后,Google已經將這個工具加入到了SDK的工具集里。具體路徑:SDK\tools\proguard。當創建一個新的Android工程時,在工程目錄的根路徑下,會出現一個proguard的配置文件proguard.cfg。也就是說,我們可以通過簡單的配置,在我們的elipse工程中直接使用ProGuard混淆Android工程。

?

具體混淆的步驟非常簡單。首先,我們需要在工程描述文件project.properties中,添加一句話,啟用ProGuard。如下所示:

?


# This file is automatically generated by Android Tools.
# Do not modify this file -- YOUR CHANGES WILL BE ERASED!
#
# This file must be checked in Version Control Systems.
#
# To customize properties used by the Ant build system edit
# "ant.properties", and override values to adapt the script to your
# project structure.
#
# To enable ProGuard to shrink and obfuscate your code, uncomment this (available properties: sdk.dir, user.home):
proguard.config=${sdk.dir}/tools/proguard/proguard-android.txt:proguard-project.txt# Project target.
target=android-19

這樣,Proguard就可以使用了。當我們正常通過Android Tools導出Application Package時(或者使用ant執行release打包),Proguard就會自動啟用,優化混淆你的代碼。

?

?

導出成功后,你可以反編譯看看混淆的效果。一些類名、方法名和變量名等,都變成了一些無意義的字母或者數字。證明混淆成功!

?

實例(proguard 文件代碼解讀)

-optimizationpasses 7  #指定代碼的壓縮級別 0 - 7
-dontusemixedcaseclassnames  #是否使用大小寫混合
-dontskipnonpubliclibraryclasses  #如果應用程序引入的有jar包,并且想混淆jar包里面的class
-dontpreverify  #混淆時是否做預校驗(可去掉加快混淆速度)
-verbose #混淆時是否記錄日志(混淆后生產映射文件?map?類名 -> 轉化后類名的映射
-optimizations !code/simplification/arithmetic,!field/*,!class/merging/*  #淆采用的算法
-keep public class * extends android.app.Activity  #所有activity的子類不要去混淆
-keep public class * extends android.app.Application
-keep public class * extends android.app.Service
-keep public class * extends android.content.BroadcastReceiver
-keep public class * extends android.content.ContentProvider
-keep public class * extends android.app.backup.BackupAgentHelper
-keep public class * extends android.preference.Preference
-keep public class com.android.vending.licensing.ILicensingService #指定具體類不要去混淆
-keepclasseswithmembernames class * {native <methods>;  #保持 native 的方法不去混淆
}-keepclasseswithmembers class * {public <init>(android.content.Context, android.util.AttributeSet);  #保持自定義控件類不被混淆,指定格式的構造方法不去混淆
}-keepclasseswithmembers class * {public <init>(android.content.Context, android.util.AttributeSet, int);
}-keepclassmembers class * extends android.app.Activity { public void *(android.view.View); #保持指定規則的方法不被混淆(Android layout 布局文件中為控件配置的onClick方法不能混淆)
}-keep public class * extends android.view.View {  #保持自定義控件指定規則的方法不被混淆public <init>(android.content.Context);public <init>(android.content.Context, android.util.AttributeSet);public <init>(android.content.Context, android.util.AttributeSet, int);public void set*(...);
}-keepclassmembers enum * {  #保持枚舉 enum 不被混淆public static **[] values();public static ** valueOf(java.lang.String);
}-keep class * implements android.os.Parcelable {  #保持 Parcelable 不被混淆(aidl文件不能去混淆)public static final android.os.Parcelable$Creator *;
}-keepnames class * implements java.io.Serializable #需要序列化和反序列化的類不能被混淆(注:Java反射用到的類也不能被混淆)
-keepclassmembers class * implements java.io.Serializable { #保護實現接口Serializable的類中,指定規則的類成員不被混淆static final long serialVersionUID;private static final java.io.ObjectStreamField[] serialPersistentFields;!static !transient <fields>;private void writeObject(java.io.ObjectOutputStream);private void readObject(java.io.ObjectInputStream);java.lang.Object writeReplace();java.lang.Object readResolve();
}-keepattributes Signature  #過濾泛型(不寫可能會出現類型轉換錯誤,一般情況把這個加上就是了)-keepattributes *Annotation*  #假如項目中有用到注解,應加入這行配置-keep class **.R$* { *; }  #保持R文件不被混淆,否則,你的反射是獲取不到資源id的-keep class **.Webview2JsInterface { *; }  #保護WebView對HTML頁面的API不被混淆
-keepclassmembers class * extends android.webkit.WebViewClient {  #如果你的項目中用到了webview的復雜操作 ,最好加入public void *(android.webkit.WebView,java.lang.String,android.graphics.Bitmap);public boolean *(android.webkit.WebView,java.lang.String);
}
-keepclassmembers class * extends android.webkit.WebChromeClient {  #如果你的項目中用到了webview的復雜操作 ,最好加入public void *(android.webkit.WebView,java.lang.String);
}
#對WebView的簡單說明下:經過實戰檢驗,做騰訊QQ登錄,如果引用他們提供的jar,若不加防止WebChromeClient混淆的代碼,oauth認證無法回調,反編譯基代碼后可看到他們有用到WebChromeClient,加入此代碼即可。-keepclassmembernames class com.cgv.cn.movie.common.bean.** { *; }  #轉換JSON的JavaBean,類成員名稱保護,使其不被混淆##################################################################
# 下面都是項目中引入的第三方 jar 包。第三方 jar 包中的代碼不是我們的目標和關心的對象,故而對此我們全部忽略不進行混淆。
##################################################################
-libraryjars  libs/android-support-v4.jar
-dontwarn android.support.v4.**
-keep class android.support.v4.** { *; }  
-keep interface android.support.v4.** { *; }
-keep public class * extends android.support.v4.** 
-keep public class * extends android.app.Fragment
-libraryjars libs/gson-2.3.1-sources.jar
-libraryjars libs/gson-2.3.1.jar
-dontwarn com.google.gson.**    
-keep class sun.misc.Unsafe { *; }
-keep class com.google.gson.** { *; }-libraryjars libs/alipaySDK-20150602.jar
-dontwarn com.alipay.**    
-dontwarn com.ta.utdid2.**    
-dontwarn com.ut.device.**    
-keep class com.alipay.** { *; }
-keep class com.ta.utdid2.** { *; }
-keep class com.ut.device.** { *; }-libraryjars libs/android-async-http-1.4.6.jar
-dontwarn com.loopj.android.http.**
-keep class com.loopj.android.http.** { *; }-libraryjars libs/baidumapapi_v2_4_1.jar
-dontwarn com.baidu.**
-keep class com.baidu.** {*; }
-keep class assets.** {*; }
-keep class vi.com.gdi.bgl.** {*; }-libraryjars libs/libammsdk.jar
-dontwarn com.tencent.**
-keep class com.tencent.** { *; }-libraryjars libs/locSDK_4.1.jar
-dontwarn com.baidu.location.**
-keep class com.baidu.location.** { *; }-libraryjars libs/mframework.jar
-dontwarn m.framework.**
-keep class m.framework.** { *; }-libraryjars libs/mta-sdk-1.6.2.jar
-dontwarn com.tencent.stat.**
-keep class com.tencent.stat.** { *; }-libraryjars libs/nineoldandroids-library-2.4.0.jar
-dontwarn com.nineoldandroids.**
-keep class com.nineoldandroids.** { *; }-libraryjars libs/open_sdk_r4889.jar
-dontwarn com.tencent.**
-keep class com.tencent.** { *; } -libraryjars libs/ShareSDK-Core-2.5.9.jar
-dontwarn cn.sharesdk.framework.**
-keep class cn.sharesdk.framework.** { *; } -libraryjars libs/ShareSDK-ShortMessage-2.5.9.jar
-dontwarn cn.sharesdk.system.text.**
-keep class cn.sharesdk.system.text.** { *; } -libraryjars libs/ShareSDK-SinaWeibo-2.5.9.jar
-dontwarn cn.sharesdk.sina.weibo.**
-keep class cn.sharesdk.sina.weibo.** { *; } -libraryjars libs/ShareSDK-Wechat-2.5.9.jar
-dontwarn cn.sharesdk.wechat.friends.**
-keep class cn.sharesdk.wechat.friends.** { *; } -libraryjars libs/ShareSDK-Wechat-Core-2.5.9.jar
-dontwarn cn.sharesdk.wechat.utils.**
-keep class cn.sharesdk.wechat.utils.** { *; } -libraryjars libs/ShareSDK-Wechat-Favorite-2.5.9.jar
-dontwarn cn.sharesdk.wechat.favorite.**
-keep class cn.sharesdk.wechat.favorite.** { *; } -libraryjars libs/ShareSDK-Wechat-Moments-2.5.9.jar
-dontwarn cn.sharesdk.wechat.moments.**
-keep class cn.sharesdk.wechat.moments.** { *; } -libraryjars libs/universal-image-loader-1.9.2-SNAPSHOT-with-sources.jar
-dontwarn com.nostra13.universalimageloader.**
-keep class com.nostra13.universalimageloader.** { *; } -libraryjars libs/weibosdkcore.jar
-dontwarn com.sina.weibo.sdk.**
-keep class com.sina.weibo.sdk.** { *; }

?

關于如何配置忽略第三方jar,附上一個圖進行說明。

?

?

說明一下,第三方jar包中如果有.so文件,不用去理會,引入的第三方jar文件不要混淆,否則可能會報異常。

?

文件

在release模式下打包apk時會自動運行ProGuard,這里的release模式指的是通過ant release命令或eclipse project->android tools->export signed(unsigned)?application package生成apk。
在debug模式下為了更快調試并不會調用proguard。

?

如果是ant命令打包apk,proguard信息文件會保存于工程代碼下的/bin/proguard文件夾內;
如果用eclipse export命令打包,會在/proguard文件夾內。其中包含以下文件:

?


mapping.txt
表示混淆前后代碼的對照表,這個文件非常重要。如果你的代碼混淆后會產生bug的話,log提示中是混淆后的代碼,希望定位到源代碼的話就可以根據mapping.txt反推。
每次發布都要保留它方便該版本出現問題時調出日志進行排查,它可以根據版本號或是發布時間命名來保存或是放進代碼版本控制中。


dump.txt
描述apk內所有class文件的內部結構。

seeds.txt
列出了沒有被混淆的類和成員。

usage.txt
列出了源代碼中被刪除在apk中不存在的代碼。

不能混淆的代碼

?

顧名思義,不能混淆代碼如果被混淆了,就會出現錯誤。

1、需要反射的代碼

2、系統接口

3、Jni接口

4、需要序列號和反序列化的代碼(即實現Serializable接口的JavaBean)

5、與服務端進行元數據交互的JavaBean(JSON、XML中對應的類)

……

常見錯誤

?

1) Proguard returned with error code 1. See console

? > 更新proguard版本
? > android-support-v4 不進行混淆
? > 添加缺少相應的庫

2) 使用gson包解析數據時,出現 missing type parameter 異常

? > 在 proguard-project.txt 中添加
? ? -dontobfuscate
? ? -dontoptimize
? > 在 proguard-project.txt 中添加
? ? # removes such information by default, so configure it to keep all of it.
? ? -keepattributes Signature?
? ? # Gson specific classes
? ? -keep class sun.misc.Unsafe { *; }
? ? #-keep class com.google.gson.stream.** { *; }
? ? # Application classes that will be serialized/deserialized over Gson
? ? -keep class com.google.gson.examples.android.model.** { *; }

3) 類型轉換錯誤

? > 在 proguard-project.txt 中添加
? ? -keepattributes Signature

4) 空指針異常

? > 混淆過濾掉相關類與方法

5) java.lang.reflect.UndeclaredThrowableException

? > -keep interface com.dev.impl.**

6) Error: Unable to access jarfile ..libproguard.jar

? > 路徑問題

7) java.lang.NoSuchMethodError

? > 這也是最常見的問題,因為找不到相關方法,方法被混淆了,混淆過濾掉相關方法便可。

?

?

----------------------

?

?


---------------------

原文:https://yq.aliyun.com/articles/1328

版權聲明:本文為作者原創文章,轉載請附上博文鏈接!
?

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/285140.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/285140.shtml
英文地址,請注明出處:http://en.pswp.cn/news/285140.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

數據結構與算法:終于可以用三種語言(C,C#,JavaScript)把圖的廣度優先遍歷講清楚了(推薦收藏)

文章目錄鄰接矩陣存儲圖的廣度優先遍歷過程分析C語言實現隊列編程程序中加入圖的處理函數結果的再次分析C#語言實現圖的廣度優先遍歷、并顯示廣度優先遍歷生成樹JavaScript語言實現圖的廣度優先遍歷、并顯示廣度優先遍歷生成樹鄰接矩陣存儲圖的廣度優先遍歷過程分析 對圖1這樣…

C語言試題161之求100000以內的自守數

??個人主頁:個人主頁 ??系列專欄:C語言試題200例 ??推薦一款刷算法、筆試、面經、拿大公司offer神器?? 點擊跳轉進入網站 ?作者簡介:大家好,我是碼莎拉蒂,CSDN博客專家(全站排名Top 50),阿里云博客專家、51CTO博客專家、華為云享專家 1、題目 題目:自守數是…

改造.NET遺留應用

淺議.NET遺留應用改造TLDR&#xff1a;本文介紹了遺留應用改造中的一些常見問題&#xff0c;并對改造所能開展的目標、原則、策略進行了概述。一、背景概述1、概述或許僅“遺留應用”這個標題就比較吸睛&#xff0c;因為我聽過太多人吐槽了。Robert Martin在《修改代碼的藝術》…

GitHub的DGit改進了平臺的可靠性、性能以及可用性

GitHub最近悄悄地發布了DGit&#xff0c;全稱為“分布式Git”。這是一種基于Git創建的分布式存儲系統&#xff0c;其目標是改進使用GitHub時的可靠性、可用性以及性能。\\DGit是一個應用層面的協議&#xff0c;它利用了Git分布式的特性&#xff0c;將每個倉庫在三臺不同的、獨立…

用靜態NAT實現外網PC訪問內網服務器

在我們的生產環境中常常處于安全考慮將服務器置于內網環境中&#xff0c;但同時得向外網提供各種服務功能&#xff0c;此時就需要用到NAT技術。下面是我用思科的仿真軟件搭建的一個實驗環境&#xff0c;實現外網PC訪問內網服務器。先說明一下實驗環境&#xff1a;路由器R0左邊為…

[轉]分布式事務之TCC服務設計和實現注意事項

1、TCC簡介 TCC是一種比較成熟的分布式事務解決方案&#xff0c;可用于解決跨庫操作的數據一致性問題&#xff1b; TCC是服務化的兩階段編程模型&#xff0c;其Try、Confirm、Cancel 3個方法均由業務編碼實現&#xff1b; 其中Try操作作為一階段&#xff0c;負責資源的檢查和…

量化投資策略的評估標準及其計算公式

收益率指標&#xff1a;分為策略的總收益率和策略的年化收益率 策略的總收益率&#xff1a; 策略的總收益率是評價一個策略盈利能力的最基本的指標&#xff0c;其計算方法為&#xff1a; 公式中Vt表示策略最終的股票和現金的總價值&#xff0c;V0表示策略最初的股票和現金的總…

.net post xml 數據

var request WebRequest.Create(url);//url 是post 接口的URL request.Method "post";// 請求方法 request.ContentType "text/xml"; //請求類型 request.Headers.Add("charset:utf-8"); //設置文檔類型的編碼格式 var encoding Encoding.Ge…

【ArcGIS微課1000例】0005:空間連接(Spatial Join)

問題描述 現在要根據范圍,怎樣批量統計各個范圍內的湖泊的總面積、各個省份內的鐵路或河流總長度、各個地區的人口綜合等。 空間連接 根據空間關系將一個要素類的屬性連接到另一個要素類的屬性。目標要素和來自連接要素的被連接屬性寫入到輸出要素類。 用法 空間連接是指根…

【微服務專題之】.Net6中集成消息隊列-RabbitMQ中直接路由模式

微信公眾號&#xff1a;趣編程ACE關注可了解更多的.NET日常實戰開發技巧&#xff0c;如需源碼 請公眾號后臺留言 源碼;[如果覺得本公眾號對您有幫助&#xff0c;歡迎關注]前文回顧【微服務專題之】.Net6下集成消息隊列上-RabbitMQ【微服務專題之】.Net6下集成消息隊列2-RabbitM…

C語言試題162之圓周率π

??個人主頁:個人主頁 ??系列專欄:C語言試題200例 ??推薦一款刷算法、筆試、面經、拿大公司offer神器?? 點擊跳轉進入網站 ?作者簡介:大家好,我是碼莎拉蒂,CSDN博客專家(全站排名Top 50),阿里云博客專家、51CTO博客專家、華為云享專家 1、題目 題目:圓周率π…

第14、15教學周作業

要求一 還差一些沒做完。 要求二 USTH_C程序設計&#xff08;基礎&#xff09;14周第一次PTA作業 7-3 將數組中的數逆序存放 1.實驗代碼 #include<stdio.h>int main() {int i,n,t;scanf("%d",&n);int a[n];for(i0;i<n;i){scanf("%d",&t)…

篇三:訪問JSON靜態文件

背景&#xff1a;在定位的時候帶出車牌號的前兩位&#xff0c;這里就有一個地址和車牌號前兩位的映射關系&#xff0c;這個映射關系起初是通過Ajax在頁面加載的時候請求去數據庫里面查出來賦給一個變量&#xff0c;然后去操作&#xff0c;但是這個過程通常需要4~7秒&#xff0c…

代理(Proxy)

2019獨角獸企業重金招聘Python工程師標準>>> 一、代理的概念 動態代理技術是整個java技術中最重要的一個技術&#xff0c;它是學習java框架的基礎&#xff0c;不會動態代理技術&#xff0c;那么在學習Spring這些框架時是學不明白的。 動態代理技術就是用來產生一個對…

【ArcGIS微課1000例】0006:創建隨機點(Create Random Points)

問題描述 在一個給定的范圍內,根據隨機位置,生成指定數量的隨機點。生成的隨機點通常用來提取每個點對應的NDVI,高程,氣溫等值。 ArcGIS創建隨機點 創建指定數量的隨機點要素。可以在范圍窗口中、面要素內、點要素上或線要素沿線生成隨機點。 工具介紹:

C語言試題163之計算某一天是對應年的第幾天,這一年一共多少天;計算兩個日期之間相隔的天數。兩個日期由鍵盤輸入。

??個人主頁:個人主頁 ??系列專欄:C語言試題200例 ??推薦一款刷算法、筆試、面經、拿大公司offer神器?? 點擊跳轉進入網站 ?作者簡介:大家好,我是碼莎拉蒂,CSDN博客專家(全站排名Top 50),阿里云博客專家、51CTO博客專家、華為云享專家 1、題目 題目:計算某一…

[轉]《吐血整理》系列-頂級程序員工具集

你知道的越多&#xff0c;你不知道的越多 點贊再看&#xff0c;養成習慣 GitHub上已經開源 https://github.com/JavaFamily 有一線大廠面試點腦圖、個人聯系方式&#xff0c;歡迎Star和指教 前言 這期是被人才群交流里&#xff0c;還有很多之前網友評論強行頂出來的一期&#x…

跟我做?個高德地圖的 iOS / Android MAUI 控件(前言)

Microsoft Build 2022 ?會上正式發布了 .NET MAUI , 對于 .NET 開發者可以? C# 完成跨平臺的前端應?開發。對?起 MAUI 的前身 Xamarin , MAUI 除了可以?傳統的原?開發模式外&#xff0c;還?持了 Blazor 的混合式開發。這也讓更多?向的開發?員能進?到跨平臺的應?開發…

Valid Number

Valid Number 題解 題目描述 即判斷某個字符串是否合法的數字表達式。如&#xff1a; 2e10&#xff0c;合法。 75.0.&#xff0c;非法。 0e&#xff0c;非法。 0.1 &#xff0c;合法。題解 基于規則與狀態判斷。可利用二維數組模擬狀態轉移圖&#xff0c;又或是利用變量記錄狀…

java.util.ListIterator

列表迭代器并不持有當前元素的引用&#xff0c;其持有的游標是位于列表連個元素之間。可以通過調用next()或者previous()返回列表中的元素。一個擁有n個元素的列表擁有n1個游標位置&#xff0c;示意圖如下&#xff1a; 注意&#xff1a;remove和 set(Object)方法并不是以迭代器…