導航:首頁 > 源碼編譯 > java反編譯查看常量池

java反編譯查看常量池

發布時間:2023-03-29 05:38:43

❶ 如何防止java程序源代碼被反編譯

我們都知道JAVA是一種解析型語言,這就決定JAVA文件編譯後不是機器碼,而是一個位元組碼文件,也就是CLASS文件。而這樣的文件是存在規律的,經過反編譯工具是可以還原回來的。例如Decafe、FrontEnd,YingJAD和Jode等等軟體。下面是《Nokia中Short數組轉換演算法
類中Main函數的ByteCode:0 ldc #162 invokestatic #185 astore_16 return其源代碼是:short [] pixels = parseImage("/ef1s.png");
我們通過反編譯工具是可以還原出以上源代碼的。而通過簡單的分析,我們也能自己寫出源代碼的。
第一行:ldc #16
ldc為虛擬機的指令,作用是:壓入常量池的項,形式如下ldc index這個index就是上面的16,也就是在常量池中的有效索引,當我們去看常量池的時候,我們就會找到index為16的值為String_info,裡面存了/ef1s.png.
所以這行的意思就是把/ef1s.pn作為一個String存在常量池中,其有效索引為16。
第二行:2 invokestatic #18
invokestatic為虛擬機指令,作用是:調用類(static)方法,形式如下
invokestatic indexbyte1 indexbyte2
其中indexbyte1和indexbyte2必須是在常量池中的有效索引,而是指向的類型必須有Methodref標記,對類名,方法名和方法的描述符的引用。
所以當我們看常量池中索引為18的地方,我們就會得到以下信息:
Class Name : cp_info#1
Name Type : cp_info#19
1 和19都是常量池中的有效索引,值就是右邊<中的值,再往下跟蹤我就不多說了,有興趣的朋友可以去JAVA虛擬機規范。
這里我簡單介紹一下parseImage(Ljava/lang/String;)[S 的意思。
這就是parseImage這個函數的運行,我們反過來看看parseImage的原型就明白了
short [] parseImage(String)
那麼Ljava/lang/String;就是說需要傳入一個String對象,而為什麼前面要有一個L呢,這是JAVA虛擬機用來表示這是一個Object。如果是基本類型,這里就不需要有L了。然後返回為short的一維數組,也就是對應的[S。是不是很有意思,S對應著Short類型,而「[」對應一維數組,那有些朋友要問了,兩維呢,那就「[[」,呵呵,是不是很有意思。
好了,調用了函數,返回的值要保存下來吧。那麼就是第三行要做的事情了。

❷ java中字元串常量放在哪裡

str1和str2分別
創建兩個對象 Hello對象和str引用對象
兩個必須存放在堆中
str指向堆中的Hello對象
也就是說 兩個對象和str的地址全部存放在堆中

String str="abc"; * 引用數據類型肯定存放在堆中 棧中放置的是參數變數而不能放對象 對象只能放在堆中

它只創建一個對象 在堆中創建一個對String類的對象引用變數str(引用變數肯定是存放在堆里的),然後查找棧中是否有"abc",若沒有則將"abc"存放進棧,並令str指向"abc"鬧猜,若已經存在則直接令str指向"abc".(也就是說引用變數本身只能存放在堆中 它的值是所指向的字元串abc 它的地址存放在棧中) 它創建多個"abc"字元串在內存中其實只存在一個對象而已,這樣有利於節省內存空間同時在一定程度上提高程序運行速度

String str=new String("abc");* 所以通過new操作符的操作都是在堆完成的

它創建兩個對象 abc對鬧滾象和str引用對象 兩個必須存放在堆中 str指向堆中的abc對象 也就是說 兩個對象和str的地址全部存放在堆中 因為使用了new操作符 所以下面的例子里str2,str3和str4即使是值都為abc因為str2的地址在棧中 str3和str4的地址各自開辟空間 所以他們的地址肯定不一樣了
但是它們的值是一樣的 那就是abc

String str2 = "abc";
String str3=new String ("abc");
String str4 =new String ("abc");

equals:equals就是比較值 ==在基本類型里也是比較值 在引用類型里是比較地址 注意這個區別就OK了!

表示堆中的引用變數的值是否相同(引用類型變數比較的是他們本身的值,本身的值液彎余是通過引用變數地址指向的對象或字元串來得到的,不管這個被指向的字元串或者對象是在棧中還是堆中)
==:表示堆中或者棧中的基本類型的值或者引用變數的地址是否相同(基本類型比較的是他們本身的值,引用類型變數比較的是地址)

當equals為true時,==不一定為true;

❸ java方法區中包含哪些內容,常量池中包含哪些內容

方法區里存儲著class文件的信息和動態常量池,class文件的信息包括類信息和靜態常量池。可以將類的信息是對class文件內容的一個框架,裡面具體的內容通過常量池來存儲。
動態常量池裡的內容除了是靜態常量池裡的內容外,還將靜態常量池裡的符號引用轉變為直接引用,而且動態常量池裡的內容是能動態添加的。例如調用String的intern方法就能將string的值添加到String常量池中,這里String常量池是包含在動態常量池裡的,但在jdk1.8後,將String常量池放到了堆中。

❹ String 類

String 是不可變類,不可變的意思是 String 類型變數初始化後,其引用指向內存內容不能改變,變數引用可以指向其他內存。

定義一個 String 變數 str,引用指向內存字元串 abc。
變數賦值時,新開辟內存 def 字元串,str 引用指向新對象,原內存內容 abc 不變。

String 類是一個字元串數組的封裝類(內部一個 char[] 數組)。數組類型 final private,引用 value 值不可變,外部無法訪問。

因此,String 對象本質是指向一個 char 數組內存的引用,設計成 final 不可變類型,一旦 String 對象創建,value 值初始化,指向一塊字元數組內存,char[] 引用不可變,String 對象即不可改變。

替換字元串中的某個字元,String 類 replace() 方法,不直接更改 char[] 引用指向內存,而是開辟一塊新內存。

創建新 char[] 數組,分配內存,長度和老數組一致,復制,替換,new 一個新 String 類對象,在構造方法,新 char[] 數組賦值 String 類內部 value,返回新 String 引用。

class 文件常量池,在文件中,編譯器編伏手譯生成字面量和符號引用,未載入內存,字面量是文本字元串,(如 String str = "abc" 中的 abc)。
符號引用是類/介面全限定名,(如 java/lang/String ),變數名稱( str ),方法名稱和描述符(參數和返回值)。
類載入內存後,class 文件常量池(字面量和符號引用),進入方法區運行時常量池,該常量池區全局共享。
字面量(字元串常量池), jdk1.7 後不再方法區,移到堆中,符號引用如方法名、類備耐全限定名仍然在方法區。

定義一個 String 變數 a,編譯後 hello2 是文本字元串,在 class 文件常量池,編譯階段確定 a 的值。
兩個字元串字面值,編譯時會進行優化(拼接),解析成一個,所以 a2 在編譯期由編譯器直接解析為 hello2。
反編譯 javap -verbose StrClass.class 命令,查看 class 文件常量池。

編譯時會檢查常量池是否已存在 hello2 字元串,只有一個 #2,String,對應 #22,即 hello2。

此過程會查找字元串常量池是仿廳春否存在 hello2,若不存在,在堆創建 char[] 數組,創建 String 對象關聯 char[] 數組,保存到字元串常量池,最後將a指向這個對象。

編譯階段,不能確定 a3 的值,定義 final 變數 c,位元組碼替換掉 a4 中的 c 變數,場景和 a2 一致。

(運行時)對象變數初始化,new 一個 StringBuilder 對象,a3 引用指向 toString() 方法在堆內存 new 的 String 對象。a==a4,指向字元串常量池,a3 指向堆內存 new 的 String 對象。

類載入時,在常量池創建對象 hello2,變數 a5,運行時堆內存 new一個 String 對象,字元串 hello2 已經在常量池,#2項,a 引用指向字元串常量池,a5 引用指向堆內存新對象,(a!=a5)。

class 文件常量池,hello2 文本字元。

類載入內存時,在字元串常量池創建一個 hello2 字元串對象。

對象初始化時,new 指令,在堆中再次創建一個對象,變數 a6 引用指向它。

class 文件常量池只有 hello 和 2 字元串,沒有 hello2 字元串,當類載入時,在字元串常量池不存在 hello2 對象。
初始化時,new 指令在堆創建兩個 String 對象( hello和2 ),通過 StringBuffer 類 append() 方法,toString() 方法在堆內存中 new 一個 String 對象 (hello2),a7 引用指向它。

前一節的變數 a3=b+2 賦值時,class 位元組碼中定義了一個 StringBuilder 類,調用兩次 append() 方法,依次添加 b 和 2 ,即 hello 和 2,一次 toString() 方法,堆內存創建對象。
StringBuffer 和 StringBuilder 區別是線程安全。

StringBuffer 通過 char[] 數組保存數據,每一個 append() 方法的新增數據在 char[] 數組保存,支持不同類型,boolean 類型保存4或5個字元 (true/false),字元串將每個字元保存,StringBuffer 類可以對字元串進行修改,進行字元串拼接時,不會產生新對象,直接對 char[] 數組進行操作更改。

幾乎所有的字元操作方法都 synchronized 同步,該類線程安全。

toString() 方法,創建一個 String 對象,關聯 char[] 數組。

任重而道遠

❺ Java運行時常量池是什麼

在class文件中,「常量池」是最復雜也最值得關注的內容。
Java是一種動態連接的語言,常量池的作用非常重要,常量池中除了包含代碼中所定義的各種基本類型(如int、long等等)和對象型(如String及數組)的常量值還,還包含一些以文本形式出現的符號引用,比如:
類和介面的全限定名;
欄位的名稱和描述符;
方法和名稱和描述符。
在C語言中,如果一個程序要調用其它庫中的函數,在連接時,該函數在庫中的位置(即相對於庫文件開頭的偏移量)會被寫在程序中,在運行時,直接去這個地址調用函數;
而在Java語言中不是這樣,一切都是動態的。編譯時,如果發現對其它類方法的調用或者對其它類欄位的引用的話,記錄進class文件中的,只能是一個文本形式的符號引用,在連接過程中,虛擬機根據這個文本信息去查找對應的方法或欄位。
所以,與Java語言中的所謂「常量」不同,class文件中的「常量」內容很非富,這些常量集中在class中的一個區域存放,一個緊接著一個,這里就稱為「常量池」。
java中的常量池技術,是為了方便快捷地創建某些對象而出現的,當需要一個對象時,就可以從池中取一個出來(如果池中沒有則創建一個),則在需要重復重復創建相等變數時節省了很多時間。常量池其實也就是一個內存空間,不同於使用new關鍵字創建的對象所在的堆空間。本文只從java使用者的角度來探討java常量池技術,並不涉及常量池的原理及實現方法。個人認為,如果是真的專注java,就必須對這些細節方面有一定的了解。但知道它的原理和具體的實現方法則不是必須的。
常量池中對象和堆中的對象

[java] view plain
public class Test{

Integer i1=new Integer(1);
Integer i2=new Integer(1);
//i1,i2分別位於堆中不同的內存空間

System.out.println(i1==i2);//輸出false

Integer i3=1;
Integer i4=1;
//i3,i4指向常量池中同一個內存空間

System.out.println(i3==i4);//輸出true

//很顯然,i1,i3位於不同的內存空間

System.out.println(i1==i3);//輸出false

}

8種基本類型的包裝類和對象池

java中基本類型的包裝類的大部分都實現了常量池技術,這些類是Byte,Short,Integer,Long,Character,Boolean,另外兩種浮點數類型的包裝類則沒有實現。另外Byte,Short,Integer,Long,Character這5種整型的包裝類也只是在對應值小於等於127時才可使用對象池,也即對象不負責創建和管理大於127的這些類的對象。以下是一些對應的測試代碼:

[java] view plain
public class Test{

public static void main(String[] args){

//5種整形的包裝類Byte,Short,Integer,Long,Character的對象,

//在值小於127時可以使用常量池

Integer i1=127;

Integer i2=127;

System.out.println(i1==i2)//輸出true

//值大於127時,不會從常量池中取對象

Integer i3=128;

Integer i4=128;

System.out.println(i3==i4)//輸出false

//Boolean類也實現了常量池技術

Boolean bool1=true;

Boolean bool2=true;

System.out.println(bool1==bool2);//輸出true

//浮點類型的包裝類沒有實現常量池技術

Double d1=1.0;

Double d2=1.0;

System.out.println(d1==d2)//輸出false

}

}

String也實現了常量池技術

String類也是java中用得多的類,同樣為了創建String對象的方便,也實現了常量池的技術,測試代碼如下:
[java] view plain
public class Test{

public static void main(String[] args){

//s1,s2分別位於堆中不同空間

String s1=new String("hello");

String s2=new String("hello");

System.out.println(s1==s2)//輸出false

//s3,s4位於池中同一空間

String s3="hello";

String s4="hello";

System.out.println(s3==s4);//輸出true

}

}
最後
細節決定成敗,寫代碼更是如此。
在JDK5.0之前是不允許直接將基本數據類型的數據直接賦值給其對應地包裝類的,如:Integer i = 5;

但是在JDK5.0中支持這種寫法,因為編譯器會自動將上面的代碼轉換成如下代碼:Integer i=Integer.valueOf(5);

這就是Java的裝箱.JDK5.0也提供了自動拆箱. Integer i =5; int j = i;

Integer的封裝:

[java] view plain
public static Integer valueOf(int i) {
final int offset = 128;
if (i >= -128 && i <= 127) { // must cache
return IntegerCache.cache[i + offset];
}
return new Integer(i);
}

private static class IntegerCache {

private IntegerCache(){}
static final Integer cache[] = new Integer[-(-128) + 127 + 1];
static {
for(int i = 0; i < cache.length; i++)
cache[i] = new Integer(i - 128);
}
}

由於cache[]在IntegerCache類中是靜態數組,也就是只需要初始化一次,即static{......}部分,所以,如果Integer對象初始化時是-128~127的范圍,就不需要再重新定義申請空間,都是同一個對象---在IntegerCache.cache中,這樣可以在一定程度上提高效率。

❻ 反編譯報錯invalidconstantpool

"invalid constant pool" 錯誤通常表示反編譯器無法解析 Java 類文件中的常量池。Java 類文件的常量池包含了類、方法、變數等元素的常量信息,反編譯器需要解析常量池才能生成有效的源代碼。
這種錯誤通常是由於 Java 類文件已經損壞或被篡改導致的。如果你正在嘗試反編譯一個來自第三方庫的 Java 類文件,那麼這種錯誤可能是由於該類文件已經被混淆或加密。在這種情況下,你可能需要使用其他工具或技術來解密或還原鎮伍該類文件。
如果你確定 Java 類文件沒有被損壞或篡改,那麼你可以嘗試使用其他反編譯器來查看是否能夠成功反編譯該類文件。常用的 Java 反編譯器包括 JD-GUI、Jad、FernFlower 等。
總之,"源派invalid constant pool" 錯誤通常是由於 Java 類文件已經損壞或被篡改導致的。如果你無法解決這個問題,可以考慮使用其他反編譯器或其他方法來雹旅賀還原該類文件。

❼ 幾種java反編譯軟體的安裝以及使用總結

下面是在網上找的幾種反編譯軟體的安裝以及使用:
一、JD-JUI
官網下載鏈接:http://jd.benow.ca/
下載之後解壓
點擊「jd-gui.exe」運行:
直接將".jar"文件拖入進去即可查看里邊的「.class」文件,如上圖所示。
二:Luyten
官網下載鏈接:https://github.com/deathmarine/Luyten/releases/tag/v0.5.3
點擊「luyten-0.5.3.exe」下載,下載之後點擊運行,運行後的界面如圖所示,同樣也是講「.jar」文件拖入進入即可。
三、在eclipse中安裝反編譯工具
准備工作:
「jad.exe」下載:https://varaneckas.com/jad/
「net.sf.jadclipse_3.3.0.jar」下載:https://sourceforge.net/projects/jadclipse/files/
jad.exe」下載:
「net.sf.jadclipse_3.3.0.jar」下載:
然後將「net.sf.jadclipse_3.3.0.jar」拷貝到eclipse的plugins目錄下,再刪除eclipse的configuration目錄下「org.eclipse.update」文件,這一步很重要!
重啟eclipse,點擊window->Preference->Java,你會發現里邊多了一個插件「JadClipse」,
選中這個插件,將下圖中紅圈圈的地方的地址填寫為你 「jad.exe」文件的地址
還沒有配置完,先不要close,
點擊General->Editors->File Associations 後,進入下邊的界面
設置.class 文件默認打開方式:
設置.class without source文件的默認打開方式,
需要注意的是,「JadClipse Class File Viewer」這個一開始是沒有的,需用添加,如下圖所示:
接下來在eclipse中查看反編譯後的代碼:(這種方法可能不合適,但是能夠查看)
新建一個EJB project,右鍵「import」,選中"EJB JAR file",導入你的jar包,Finish
在項目下找你要查看的反編譯的文件即可,如果你遇到了下邊的這種情況
關閉這個文件後再次打開,就可以查看了(我的是這樣,所以我感覺這個方法不太好,但別的方法又不知道怎麼查看):
有錯誤或者有更好的方法,希望大家在下邊留言指出

❽ java反編譯器怎麼用

目前最好的反編譯工具,是小穎JAVA源代碼反編譯超級引摯,Google一下就有下的,很好用

❾ Java中的幾種常量池

❿ Java class位元組碼方法都是返回null

如果在 Java 類中,所有方法的位元組碼都返回 null,那麼這很可能是因為你的類沒有實洞衡肢現任何方法,或者所有方法都是抽象方法。

在 Java 中納世,抽象方法是指沒有方法體的方法。抽象方法只有聲明,而沒有攔者實現。抽象方法必須在抽象類中聲明,並且必須由子類實現。例如:

Copy code

public abstract class MyClass { public abstract void myMethod(); }

如果你的類實現了抽象方法,那麼可能是你的實現沒有返回任何值。例如:

Copy code

public class MyClass { public void myMethod() { // 沒有返回值 } }

如果你的類中的方法都是抽象方法或者沒有返回值,那麼在位元組碼中它們都將返回 null。

建議你檢查你的類定義,確保你的類是非抽象的,並且所有的方法都實現了返回值。

閱讀全文

與java反編譯查看常量池相關的資料

熱點內容
高並發處理方案php 瀏覽:145
梯形迭代式演算法 瀏覽:437
ppt轉pdf破解 瀏覽:1002
如何給股票賬號加密碼 瀏覽:105
新鄭java程序員 瀏覽:912
為什麼王者榮耀安卓和蘋果玩不了 瀏覽:774
山西百信恆山伺服器雲主機 瀏覽:843
ssh連接linux伺服器 瀏覽:384
怎麼架設mu伺服器 瀏覽:700
pythonorgdownload 瀏覽:918
選股入門公式源碼小寫怎麼編寫 瀏覽:290
解壓瀏覽器哪個好 瀏覽:449
棍法PDF 瀏覽:663
電腦文件夾怎麼後退一步 瀏覽:166
單片機高速ad 瀏覽:534
androidhttp獲取json 瀏覽:163
紅魔手機怎麼加密應用 瀏覽:234
排班問題演算法 瀏覽:390
建築雲學院app在哪裡下載 瀏覽:803
51單片機定時器0 瀏覽:241