54.13.1簡單的例子 我們首先創建一個長度是10的整型的數組,對其初始化。
#!java
public static void main(String[] args)
{
int a[]=new int[10];
for (int i=0; i<10; i++)
a[i]=i;
dump (a);
}
public static void main(java.lang.String[]);
flags: ACC_PUBLIC, ACC_STATIC
Code:
stack=3, locals=3, args_size=1
0: bipush 10
2: newarray int
4: astore_1
5: iconst_0
6: istore_2
7: iload_2
8: bipush 10
10: if_icmpge 23
13: aload_1
14: iload_2
15: iload_2
16: iastore
17: iinc 2, 1
20: goto 7
23: aload_1
24: invokestatic #4 // Method dump:([?
? I)V
27: return
newarray指令,創建了一個有10個整數元素的數組,數組的大小設置使用bipush指令,然后結果會返回到棧頂。數組類型用newarry指令操作符,進行設定。
newarray被執行后,引用(指針)到新創建的數據,棧頂的槽中,astore_1存儲引用指向到LVA的一號槽,main()函數的第二個部分,是循環的存儲值1到相應的素組元素。 aload_1得到數據的引用并放入到棧中。lastore將integer值從堆中存儲到素組中,引用當前的棧頂。main()函數代用dump()的函數部分,參數是,準備給aload_1指令的(行偏移23)
現在我們進入dump()函數。
#!java
public static void dump(int a[])
{
for (int i=0; i<a.length; i++)
System.out.println(a[i]);
}
#!bash
public static void dump(int[]);
flags: ACC_PUBLIC, ACC_STATIC
Code:
stack=3, locals=2, args_size=1
0: iconst_0
1: istore_1
2: iload_1
3: aload_0
4: arraylength
5: if_icmpge 23
8: getstatic #2 // Field java/?
? lang/System.out:Ljava/io/PrintStream;
11: aload_0
12: iload_1
13: iaload
14: invokevirtual #3 // Method java/io?
? /PrintStream.println:(I)V
17: iinc 1, 1
20: goto 2
23: return
到了引用的數組在0槽,a.length表達式在源代碼中是轉化到arraylength指令,它取得數組的引用,并且數組的大小在棧頂。 iaload在行偏移13被用于裝載數據元素。 它需要在堆棧中的數組引用。用aload_0 11并且索引(用iload_1在行偏移12準備)
無可厚非,指令前綴可能會被錯誤的理解,就像數組指令,那樣不正確,這些指令和對象的引用一起工作的。數組和字符串都是對象。
54.13.2 數組元素的求和
另外的例子
#!java
public class ArraySum
{
public static int f (int[] a)
{
int sum=0;
for (int i=0; i<a.length; i++)
sum=sum+a[i];
return sum;
}
}
public static int f(int[]);
flags: ACC_PUBLIC, ACC_STATIC
Code:
stack=3, locals=3, args_size=1
0: iconst_0
1: istore_1
2: iconst_0
3: istore_2
4: iload_2
5: aload_0
6: arraylength
7: if_icmpge 22
10: iload_1
11: aload_0
12: iload_2
13: iaload
14: iadd
15: istore_1
16: iinc 2, 1
19: goto 4
22: iload_1
23: ireturn
LVA槽0是數組的引用,LVA槽1是本地變量和。
54.13.3 main()函數唯一的數據參數
讓我們使用唯一的main()函數參數,字符串數組。
#!java
public class UseArgument
{
public static void main(String[] args)
{
System.out.print("Hi, ");
System.out.print(args[1]);
System.out.println(". How are you?");
}
}
934 0參(argument)第0個參數是程序(和C/C++類似)
因此第一個參數,而第一參數是擁護提供的。
public static void main(java.lang.String[]);
flags: ACC_PUBLIC, ACC_STATIC
Code:
stack=3, locals=1, args_size=1
0: getstatic #2 // Field java/?
? lang/System.out:Ljava/io/PrintStream;
3: ldc #3 // String Hi,
5: invokevirtual #4 // Method java/io?
? /PrintStream.print:(Ljava/lang/String;)V
8: getstatic #2 // Field java/?
? lang/System.out:Ljava/io/PrintStream;
11: aload_0
12: iconst_1
13: aaload
14: invokevirtual #4 // Method java/io?
? /PrintStream.print:(Ljava/lang/String;)V
17: getstatic #2 // Field java/?
? lang/System.out:Ljava/io/PrintStream;
20: ldc #5 // String . How ?
? are you?
22: invokevirtual #6 // Method java/io?
? /PrintStream.println:(Ljava/lang/String;)V
25: return
aload_0在11行加載,第0個LVA槽的引用(main()函數唯一的參數) iconst_1和aload在行偏移12,13,取得數組第一個元素的引用(從0計數) 字符串對象的引用在棧頂行14行偏移,給println方法。
54.1.34 初始化字符串數組
#!java
class Month
{
public static String[] months =
{
"January",
"February",
"March",
"April",
"May",
"June",
"July",
"August",
"September",
"October",
"November",
"December"
};
public String get_month (int i)
{
return months[i];
};
}
get_month()函數很簡單
public java.lang.String get_month(int);
flags: ACC_PUBLIC
Code:
stack=2, locals=2, args_size=2
0: getstatic #2 // Field months:[?
? Ljava/lang/String;
3: iload_1
4: aaload
5: areturn
aaload操作數組引用,java字符串是一個對象,所以a_instructiong被用于操作他們.areturn返回字符串對象的引用。
month[]數值是如果初始化的?
static {};
flags: ACC_STATIC
Code:
stack=4, locals=0, args_size=0
0: bipush 12
2: anewarray #3 // class java/?
? lang/String
5: dup
6: iconst_0
7: ldc #4 // String January
9: aastore
10: dup
11: iconst_1
12: ldc #5 // String ?
? February
14: aastore
15: dup
16: iconst_2
17: ldc #6 // String March
19: aastore
20: dup
21: iconst_3
22: ldc #7 // String April
24: aastore
25: dup
26: iconst_4
27: ldc #8 // String May
29: aastore
30: dup
31: iconst_5
32: ldc #9 // String June
34: aastore
35: dup
36: bipush 6
38: ldc #10 // String July
40: aastore
41: dup
42: bipush 7
44: ldc #11 // String August
46: aastore
47: dup
48: bipush 8
50: ldc #12 // String ?
? September
52: aastore
53: dup
54: bipush 9
56: ldc #13 // String October
58: aastore
59: dup
60: bipush 10
62: ldc #14 // String ?
? November
64: aastore
65: dup
66: bipush 11
68: ldc #15 // String ?
? December
70: aastore
71: putstatic #2 // Field months:[?
? Ljava/lang/String;
74: return
937 anewarray 創建一個新數組的引用(a是一個前綴)對象的類型被定義在anewarray操作數中,它在這是“java/lang/string”文本字符串,在這之前的bipush 1L是設置數組的大小。 對于我們再這看到一個新指令dup,他是一個眾所周知的堆棧操作的計算機指令。用于復制棧頂的值。(包括了之后的編程語言)它在這是用于復制數組的引用。因為aastore張玲玲 起到彈出堆棧中的數組的作用,但是之后,aastore需要在使用一次,java編譯器,最好同dup代替getstatic指令,用于生成之前的每個數組的存貯操作。例如,月份字段。
54.13.5可變參數 可變參數 變長參數函數,實際上使用的就是數組,實際使用的就是數組。
#!java
public static void f(int... values)
{
for (int i=0; i<values.length; i++)
System.out.println(values[i]);
}
public static void main(String[] args)
{
f (1,2,3,4,5);
}
public static void f(int...);
flags: ACC_PUBLIC, ACC_STATIC, ACC_VARARGS
Code:
stack=3, locals=2, args_size=1
0: iconst_0
1: istore_1
2: iload_1
3: aload_0
4: arraylength
5: if_icmpge 23
8: getstatic #2 // Field java/?
? lang/System.out:Ljava/io/PrintStream;
11: aload_0
12: iload_1
13: iaload
14: invokevirtual #3 // Method java/io?
? /PrintStream.println:(I)V
17: iinc 1, 1
20: goto 2
23: return
f()函數,取得一個整數數組,使用的是aload_0 在行偏移3行。取得到了一個數組的大小,等等。
public static void main(java.lang.String[]);
flags: ACC_PUBLIC, ACC_STATIC
Code:
stack=4, locals=1, args_size=1
0: iconst_5
1: newarray int
3: dup
4: iconst_0
5: iconst_1
6: iastore
7: dup
8: iconst_1
9: iconst_2
10: iastore
11: dup
12: iconst_2
13: iconst_3
14: iastore
15: dup
16: iconst_3
17: iconst_4
18: iastore
19: dup
20: iconst_4
21: iconst_5
22: iastore
23: invokestatic #4 // Method f:([I)V
26: return
素組在main()函數是構造的,使用newarray指令,被填充慢了之后f()被調用。
939 隨便提一句,數組對象并不是在main()中銷毀的,在整個java中也沒有被析構。因為JVM的垃圾收集齊不是自動的,當他感覺需要的時候。 format()方法是做什么的?它用兩個參數作為輸入,字符串和數組對象。
public PrintStream format(String format, Object... args?)
讓我們看一下。
#!java
public static void main(String[] args)
{
int i=123;
double d=123.456;
System.out.format("int: %d double: %f.%n", i, d?? );
}
public static void main(java.lang.String[]);
flags: ACC_PUBLIC, ACC_STATIC
Code:
stack=7, locals=4, args_size=1
0: bipush 123
2: istore_1
3: ldc2_w #2 // double 123.456?
? d
6: dstore_2
7: getstatic #4 // Field java/?
? lang/System.out:Ljava/io/PrintStream;
10: ldc #5 // String int: %d?
? double: %f.%n
12: iconst_2
13: anewarray #6 // class java/?
? lang/Object
16: dup
17: iconst_0
18: iload_1
19: invokestatic #7 // Method java/?
? lang/Integer.valueOf:(I)Ljava/lang/Integer;
22: aastore
23: dup
24: iconst_1
25: dload_2
26: invokestatic #8 // Method java/?
? lang/Double.valueOf:(D)Ljava/lang/Double;
29: aastore
30: invokevirtual #9 // Method java/io?
? /PrintStream.format:(Ljava/lang/String;[Ljava/lang/Object?
? ;)Ljava/io/PrintStream;
33: pop
34: return
所以int和double類型是被首先普生為integer和double 對象,被用于方法的值。。。format()方法需要,對象雷翔的對象作為輸入,因為integer和double類是繼承于根類root。他們適合作為數組輸入的元素, 另一方面,數組總是同質的,例如,同一個數組不能含有兩種不同的數據類型。不能同時都把integer和double類型的數據同時放入的數組。
數組對象的對象在偏移13行,整型對象被添加到在行偏移22. double對象被添加到數組在29行。
倒數第二的pop指令,丟棄了棧頂的元素,因此,這些return執行,堆棧是的空的(平行)
54.13.6 二位數組
二位數組在java 中是一個數組去引用另外一個數組 讓我們來創建二位素組。()
#!java
public static void main(String[] args)
{
int[][] a = new int[5][10];
a[1][2]=3;
}
public static void main(java.lang.String[]);
flags: ACC_PUBLIC, ACC_STATIC
Code:
stack=3, locals=2, args_size=1
0: iconst_5
1: bipush 10
3: multianewarray #2, 2 // class "[[I"
7: astore_1
8: aload_1
9: iconst_1
10: aaload
11: iconst_2
12: iconst_3
13: iastore
14: return
它創建使用的是multianewarry指令:對象類型和維數作為操作數,數組的大小(10*5),返回到棧中。(使用iconst_5和bipush指令)
行引用在行偏移10加載(iconst_1和aaload)列引用是選擇使用iconst_2指令,在行偏移11行。值得寫入和設定在12行,iastore在13 行,寫入數據元素?
#!java
public static int get12 (int[][] in)
{
return in[1][2];
}
public static int get12(int[][]);
flags: ACC_PUBLIC, ACC_STATIC
Code:
stack=2, locals=1, args_size=1
0: aload_0
1: iconst_1
2: aaload
3: iconst_2
4: iaload
5: ireturn
引用數組在行2加載,列的設置是在行3,iaload加載數組。
54.13.7 三維數組 三維數組是,引用一維數組引用一維數組。
#!java
public static void main(String[] args)
{
int[][][] a = new int[5][10][15];
a[1][2][3]=4;
get_elem(a);
}
public static void main(java.lang.String[]);
flags: ACC_PUBLIC, ACC_STATIC
Code:
stack=3, locals=2, args_size=1
0: iconst_5
1: bipush 10
3: bipush 15
5: multianewarray #2, 3 // class "[[[I"
9: astore_1
10: aload_1
11: iconst_1
12: aaload
13: iconst_2
14: aaload
15: iconst_3
16: iconst_4
17: iastore
18: aload_1
19: invokestatic #3 // Method ?
? get_elem:([[[I)I
22: pop
23: return
它是用兩個aaload指令去找right引用。
#!java
public static int get_elem (int[][][] a)
{
return a[1][2][3];
}
public static int get_elem(int[][][]);
flags: ACC_PUBLIC, ACC_STATIC
Code:
stack=2, locals=1, args_size=1
0: aload_0
1: iconst_1
2: aaload
3: iconst_2
4: aaload
5: iconst_3
6: iaload
7: ireturn
53.13.8總結
在java中可能出現棧溢出嗎?不可能,數組長度實際就代表有多少個對象,數組的邊界是可控的,而發生越界訪問的情況時,會拋出異常。
字符串也是對象,和其他對象的構造方式相同。(還有數組)
#!java
public static void main(String[] args)
{
System.out.println("What is your name?");
String input = System.console().readLine();
System.out.println("Hello, "+input);
}
public static void main(java.lang.String[]);
flags: ACC_PUBLIC, ACC_STATIC
Code:
stack=3, locals=2, args_size=1
0: getstatic #2 // Field java/?
? lang/System.out:Ljava/io/PrintStream;
3: ldc #3 // String What is?
? your name?
5: invokevirtual #4 // Method java/io?
? /PrintStream.println:(Ljava/lang/String;)V
8: invokestatic #5 // Method java/?
? lang/System.console:()Ljava/io/Console;
11: invokevirtual #6 // Method java/io?
? /Console.readLine:()Ljava/lang/String;
14: astore_1
15: getstatic #2 // Field java/?
? lang/System.out:Ljava/io/PrintStream;
18: new #7 // class java/?
? lang/StringBuilder
21: dup
22: invokespecial #8 // Method java/?
? lang/StringBuilder."<init>":()V
25: ldc #9 // String Hello,
27: invokevirtual #10 // Method java/?
? lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/?
? StringBuilder;
30: aload_1
31: invokevirtual #10 // Method java/?
? lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/?
? StringBuilder;
34: invokevirtual #11 // Method java/?
? lang/StringBuilder.toString:()Ljava/lang/String;
37: invokevirtual #4 // Method java/io?
? /PrintStream.println:(Ljava/lang/String;)V
40: return
944 在11行偏移調用了readline()方法,字符串引用(由用戶提供)被存儲在棧頂,在14行偏移,字符串引用被存儲在LVA的1號槽中。
用戶輸入的字符串在30行偏移處重新加載并和 “hello”字符進行了鏈接,使用的是StringBulder類,在17行偏移,構造的字符串被pirntln方法打印。
54.14.2 第二個例子 另外一個例子
#!java
public class strings
{
public static char test (String a)
{
return a.charAt(3);
};
public static String concat (String a, String b)
{
return a+b;
}
}
public static char test(java.lang.String);
flags: ACC_PUBLIC, ACC_STATIC
Code:
stack=2, locals=1, args_size=1
0: aload_0
1: iconst_3
2: invokevirtual #2 // Method java/?
? lang/String.charAt:(I)C
5: ireturn
945
字符串的鏈接使用用StringBuilder類完成。
#!java
public static java.lang.String concat(java.lang.String, java.?
? lang.String);
flags: ACC_PUBLIC, ACC_STATIC
Code:
stack=2, locals=2, args_size=2
0: new #3 // class java/?
? lang/StringBuilder
3: dup
4: invokespecial #4 // Method java/?
? lang/StringBuilder."<init>":()V
7: aload_0
8: invokevirtual #5 // Method java/?
? lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/?
? StringBuilder;
11: aload_1
12: invokevirtual #5 // Method java/?
? lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/?
? StringBuilder;
15: invokevirtual #6 // Method java/?
? lang/StringBuilder.toString:()Ljava/lang/String;
18: areturn
另外一個例子
#!java
public static void main(String[] args)
{
String s="Hello!";
int n=123;
System.out.println("s=" + s + " n=" + n);
}
字符串構造用StringBuilder類,和它的添加方法,被構造的字符串被傳遞給println方法。
#!bash
public static void main(java.lang.String[]);
flags: ACC_PUBLIC, ACC_STATIC
Code:
stack=3, locals=3, args_size=1
0: ldc #2 // String Hello!
2: astore_1
3: bipush 123
5: istore_2
6: getstatic #3 // Field java/?
? lang/System.out:Ljava/io/PrintStream;
9: new #4 // class java/?
? lang/StringBuilder
12: dup
13: invokespecial #5 // Method java/?
? lang/StringBuilder."<init>":()V
16: ldc #6 // String s=
18: invokevirtual #7 // Method java/?
? lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/?
? StringBuilder;
21: aload_1
22: invokevirtual #7 // Method java/?
? lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/?
? StringBuilder;
25: ldc #8 // String n=
27: invokevirtual #7 // Method java/?
? lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/?
? StringBuilder;
30: iload_2
31: invokevirtual #9 // Method java/?
? lang/StringBuilder.append:(I)Ljava/lang/StringBuilder;
34: invokevirtual #10 // Method java/?
? lang/StringBuilder.toString:()Ljava/lang/String;
37: invokevirtual #11 // Method java/io?
? /PrintStream.println:(Ljava/lang/String;)V
40: return