Java包括Java SDK(JDK),JRE(包括JVM及相关接口)以及相关工具。
我们绝大多数时间接触的是Java SDK(JDK)。
数据类型
不管哪种编程语言,都或多或少提供了基本的数据类型,大多数语言,都有char、short、int、long、float、double这几种基本数据类型。任何一种编程语言,都会有自己的一套类型系统,只不过支持的类型或多或少罢了。
对象
Java编程语言最重要的一个类型就是对象。Java是一种纯对象编程语言,尽管也提供了char、short、int、long、float、double这写基本数据类型,Java也通过语法糖装箱拆箱机制,将这些基本数据类型装箱成对象,和对象一样的方式操作这些类型的数据。
byte
int
long
float
double
char
字符串
操作符
==
public class equaltest {
public static void main(String[] args) {
Object o1 = new Object();
Object o2 = new Object();
if (o1 == o2) {
System.out.println("o1 == o2");
} else {
System.out.println("o1 != o2");
}
}
}
Compiled from "equaltest.java"
public class equaltest extends java.lang.Object
SourceFile: "equaltest.java"
minor version: 0
major version: 50
Constant pool:
const #1 = Method#2.#18;// java/lang/Object."<init>":()V
const #2 = class#19;// java/lang/Object
const #3 = Field#20.#21;// java/lang/System.out:Ljava/io/PrintStream;
const #4 = String#22;// o1 == o2
const #5 = Method#23.#24;// java/io/PrintStream.println:(Ljava/lang/String;)V
const #6 = String#25;// o1 != o2
const #7 = class#26;// equaltest
const #8 = Asciz<init>;
const #9 = Asciz()V;
const #10 = AscizCode;
const #11 = AscizLineNumberTable;
const #12 = Ascizmain;
const #13 = Asciz([Ljava/lang/String;)V;
const #14 = AscizStackMapTable;
const #15 = class#19;// java/lang/Object
const #16 = AscizSourceFile;
const #17 = Ascizequaltest.java;
const #18 = NameAndType#8:#9;// "<init>":()V
const #19 = Ascizjava/lang/Object;
const #20 = class#27;// java/lang/System
const #21 = NameAndType#28:#29;// out:Ljava/io/PrintStream;
const #22 = Ascizo1 == o2;
const #23 = class#30;// java/io/PrintStream
const #24 = NameAndType#31:#32;// println:(Ljava/lang/String;)V
const #25 = Ascizo1 != o2;
const #26 = Ascizequaltest;
const #27 = Ascizjava/lang/System;
const #28 = Ascizout;
const #29 = AscizLjava/io/PrintStream;;
const #30 = Ascizjava/io/PrintStream;
const #31 = Ascizprintln;
const #32 = Asciz(Ljava/lang/String;)V;
{
public equaltest();
Signature: ()V
Code:
Stack=1, Locals=1, Args_size=1
0:aload_0
1:invokespecial#1; //Method java/lang/Object."<init>":()V
4:return
LineNumberTable:
line 1: 0
public static void main(java.lang.String[]);
Signature: ([Ljava/lang/String;)V
Code:
Stack=2, Locals=3, Args_size=1
0:new#2; //class java/lang/Object
3:dup
4:invokespecial#1; //Method java/lang/Object."<init>":()V
7:astore_1
8:new#2; //class java/lang/Object
11:dup
12:invokespecial#1; //Method java/lang/Object."<init>":()V
15:astore_2
16:aload_1
17:aload_2
18:if_acmpne32
21:getstatic#3; //Field java/lang/System.out:Ljava/io/PrintStream;
24:ldc#4; //String o1 == o2
26:invokevirtual#5; //Method java/io/PrintStream.println:(Ljava/lang/String;)V
29:goto40
32:getstatic#3; //Field java/lang/System.out:Ljava/io/PrintStream;
35:ldc#6; //String o1 != o2
37:invokevirtual#5; //Method java/io/PrintStream.println:(Ljava/lang/String;)V
40:return
LineNumberTable:
line 4: 0
line 5: 8
line 6: 16
line 7: 21
line 9: 32
line 11: 40
StackMapTable: number_of_entries = 2
frame_type = 253 /* append */
offset_delta = 32
locals = [ class java/lang/Object, class java/lang/Object ]
frame_type = 7 /* same */
}
字符串
hash计算:
public int hashCode() { int h = hash; if (h == 0) { int off = offset; char val[] = value; int len = count; for (int i = 0; i < len; i++) { h = 31*h + val[off++]; } hash = h; } return h; }
以字符串"abcdef"为例:
String s = "abcdef";
// a
// 31 * a + b
// 31 * (31 * a + b) + c
// 31 * (31 * (31 * a + b) + c) + d
// 31 * (31 * (31 * (31 * a + b) + c) + d) + e
// 31 * (31 * (31 * (31 * (31 * a + b) + c) + d) + e) + f
// 31 * (31 * (31 * (31*31*a + 31*b + c) + d) + e) + f
// 31 * (31 * (31*31*31*a + 31*31*b + 31*c + d) + e) + f
// 31 * (31*31*31*31*a + 31*31*31*b + 31*31*c + 31*d + e) + f
// 31*31*31*31*31*a + 31*31*31*31*b + 31*31*31*c + 31*31*d + 31*e + f
// a*31^5 + b*31^4 + c*31^3 + d*31^2 + e*31^1 + f*31^0
结果就是:
s[0]*31^(n-1) + s[1]*31^(n-2) + ... + s[n-1]
其中31^n表示31的n次幂。
31还真是个神奇的奇质数。
总是听很多傻叉说String s = "abc";和String s = new String("abc");创建了几个对象,创建了哪些对象,还分析得误人子弟。
其实反编译下就清清楚楚了:
String s = "abc";反编译如下:
0: ldc #2 // String abc
2: astore_1
String s = new String("abc");反编译如下:
0: new #2 // class java/lang/String
3: dup
4: ldc #3 // String abc
6: invokespecial #4 // Method java/lang/String."<init>":(Ljava/lang/String;)V
9: astore_1
还有这种:
String s1 = "abc";
String s2 = "def";
String s3 = "g";
String s4 = s1 + s2 + s3;
反编译如下:
0: ldc #2 // String abc
2: astore_1
3: ldc #3 // String def
5: astore_2
6: ldc #4 // String g
8: astore_3
9: new #5 // class java/lang/StringBuilder
12: dup
13: invokespecial #6 // Method java/lang/StringBuilder."<init>":()V
16: aload_1
17: invokevirtual #7 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
20: aload_2
21: invokevirtual #7 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
24: aload_3
25: invokevirtual #7 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
28: invokevirtual #8 // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
31: astore 4
intern
String str = new String("string abc"); long addr1 = location(str); str = str.intern(); long addr2 = location(str); str = str.intern(); long addr3 = location(str); System.out.println("addr1: " + addr1 + ", addr2: " + addr2 + ", addr3: " + addr3);
输出:
addr1: 48404368, addr2: 48404384, addr3: 48404384
从输出结果看出,add2和add3是一样的,但和add1不一样。add1表示"string abc"在堆上分配的对象的地址,add2和add3是"string abc"在运行时常量池(run-time constant pool)的地址。
大家有没有发现"string abc"在堆上分配的对象的地址和在运行时常量池(run-time constant pool)的地址相距不大?
String str = "string abcdef"; long addr1 = location(str); str = str.intern(); long addr2 = location(str); str = str.intern(); long addr3 = location(str); System.out.println("addr1: " + addr1 + ", addr2: " + addr2 + ", addr3: " + addr3);
输出:
addr1: 48402584, addr2: 48402584, addr3: 48402584
从输出结果看出,add1,add2和add3是一样的。表示"string abcdef"在常量池(constant pool)的地址。
变量
原子变量
不可变变量
不可变变量指的是变量具备的不可变性(immutability),也就是它是变量,但这个变量是不可变的(immutable)。
另一个我们可能会想到的一个概念就是字面量。
不可变变量,或者说变量的不可变性,包括这里提到的字面量在函数式编程领域以及在一些比较新的编程语言,设计为支持高并发应用场景,如go语言等比较常见。
不可变变量在多线程领域是非常有优势的,虽然被称为变量,但由于它的不可变性,不会试图去修改它的值,这意味着在多线程领域我们在对它操作时不需要有额外的同步,互斥等,也不会涉及到锁的问题。
Java中,String就是我们常见到的不可变变量。其他的如Integer,Long,Float,Double等都是不可变变量。
在Java多线程中,不可变变量是线程安全的,不需要考虑线程安全性的问题。
关于Java中的不可变变量,这个不可变性的特征是怎么理解的?这个变量的不可变性是指对这种变量操作不会改变变量自身的值。很多支持不可变变量或者变量的不可变性的程序语言中,都是语义范畴上规定的不可变变量。Java虽说也有语义范畴规定,但在Java世界里,一切皆对象,Java提供的不可变变量在jdk标准库中以类的形式实现的,如String等,Java的变量的不可变性更多体现在对应的类实现中。
关于“变量的不可变性是指对这种变量操作不会改变变量自身的值”的理解,以String为例,如下代码:
String s = “abc”;
s = "this is " + abc;
按照变量可变的理解,"this is " + abc只是在“abc”字符串对应的内存地址的起始位置写入“this is ”,同时“abc”向后移动8个字节,也就是说s = "this is " + abc;后的s对应的内存地址和之前的s = “abc”的s的内存地址不变,在这个过程中不会有新的内存空间分配,不会产生新的字符串变量。
而在这里,s = "this is " + abc;实际上会产生一个新的字符串“this is abc”,之前的“abc”并没有变,这期间只是s的引用变了,字符串的内容没有发生改变,s = "this is " + abc;后的s对应的内存地址和之前的s = “abc”的s的内存地址是不一样的。
如String,当字符串构造出来后,该字符串就不可变了。
Java中构造字符串:
String s1 = "abc";
String s2 = new String("abc");
以下这种虽然也是一种构造字符串的方式,但不具备不可变性,Java中字符串的不可变变量体现在String。
char data[] = {'a', 'b', 'c'};
常量
private static void test0() { for (int i = 0; i < 10; i++) { System.out.println(i); } }
0: iconst_0
1: istore_0
2: iload_0
3: bipush 10
5: if_icmpge 21
8: getstatic #2 // Field java/lang/System.out:Ljava/io/PrintStream;
11: iload_0
12: invokevirtual #3 // Method java/io/PrintStream.println:(I)V
15: iinc 0, 1
18: goto 2
21: return
private static void test1(int[] a) { for (int i = 0; i < a.length; i++) { System.out.println(i); } }
0: iconst_0
1: istore_1
2: iload_1
3: aload_0
4: arraylength
5: if_icmpge 21
8: getstatic #2 // Field java/lang/System.out:Ljava/io/PrintStream;
11: iload_1
12: invokevirtual #3 // Method java/io/PrintStream.println:(I)V
15: iinc 1, 1
18: goto 2
21: return
上面两段代码编译后的字节码区别仅仅是将
3: aload_0
4: arraylength
替换为
3: bipush 10
private static void test2(int[] a) { for (int i : a) { System.out.println(i); } }
0: aload_0
1: astore_1
2: aload_1
3: arraylength
4: istore_2
5: iconst_0
6: istore_3
7: iload_3
8: iload_2
9: if_icmpge 31
12: aload_1
13: iload_3
14: iaload
15: istore 4
17: getstatic #2 // Field java/lang/System.out:Ljava/io/PrintStream;
20: iload 4
22: invokevirtual #3 // Method java/io/PrintStream.println:(I)V
25: iinc 3, 1
28: goto 7
31: return
private static void test3(List<Integer> a) { for (int i : a) { System.out.println(i); } }
0: aload_0
1: invokeinterface #4, 1 // InterfaceMethod java/util/List.iterator:()Ljava/util/Iterator;
6: astore_1
7: aload_1
8: invokeinterface #5, 1 // InterfaceMethod java/util/Iterator.hasNext:()Z
13: ifeq 39
16: aload_1
17: invokeinterface #6, 1 // InterfaceMethod java/util/Iterator.next:()Ljava/lang/Object;
22: checkcast #7 // class java/lang/Integer
25: invokevirtual #8 // Method java/lang/Integer.intValue:()I
28: istore_2
29: getstatic #2 // Field java/lang/System.out:Ljava/io/PrintStream;
32: iload_2
33: invokevirtual #3 // Method java/io/PrintStream.println:(I)V
36: goto 7
39: return
和以下代码编译后的字节码是一样的:
private static void test4(List<Integer> a) { Iterator<Integer> iterator = a.iterator(); while (iterator.hasNext()) { int next = iterator.next(); System.out.println(next); } }
0: aload_0
1: invokeinterface #4, 1 // InterfaceMethod java/util/List.iterator:()Ljava/util/Iterator;
6: astore_1
7: aload_1
8: invokeinterface #5, 1 // InterfaceMethod java/util/Iterator.hasNext:()Z
13: ifeq 39
16: aload_1
17: invokeinterface #6, 1 // InterfaceMethod java/util/Iterator.next:()Ljava/lang/Object;
22: checkcast #7 // class java/lang/Integer
25: invokevirtual #8 // Method java/lang/Integer.intValue:()I
28: istore_2
29: getstatic #2 // Field java/lang/System.out:Ljava/io/PrintStream;
32: iload_2
33: invokevirtual #3 // Method java/io/PrintStream.println:(I)V
36: goto 7
39: return
它也等同于下面这种写法:
private static void test5(List<Integer> a) { for (Iterator<Integer> iterator = a.iterator(); iterator.hasNext(); ) { int next = iterator.next(); System.out.println(next); } }
0: aload_0
1: invokeinterface #4, 1 // InterfaceMethod java/util/List.iterator:()Ljava/util/Iterator;
6: astore_1
7: aload_1
8: invokeinterface #5, 1 // InterfaceMethod java/util/Iterator.hasNext:()Z
13: ifeq 39
16: aload_1
17: invokeinterface #6, 1 // InterfaceMethod java/util/Iterator.next:()Ljava/lang/Object;
22: checkcast #7 // class java/lang/Integer
25: invokevirtual #8 // Method java/lang/Integer.intValue:()I
28: istore_2
29: getstatic #2 // Field java/lang/System.out:Ljava/io/PrintStream;
32: iload_2
33: invokevirtual #3 // Method java/io/PrintStream.println:(I)V
36: goto 7
39: return
语法糖
Java中使用到语法糖的地方包括:
1、装箱和拆箱
2、EnhancedForStatement以及EnhancedForStatementNoShortIf
EnhancedForStatement:
for ( {VariableModifier} LocalVariableType VariableDeclaratorId : Expression ) Statement
EnhancedForStatementNoShortIf:
for ( {VariableModifier} LocalVariableType VariableDeclaratorId : Expression ) StatementNoShortIf
类
Java所有对象都有一个基类Object。
抽象类
接口
对象
对象类型
静态类型
关于静态类型
Object obj = new Lock();
这里变量obj的静态类型是Object,它的实际类型为Lock。
实际类型
public interface Ops { void firstOp(); } public class Test implements Ops { public void firstOp() { System.out.println("firstOp."); } } Ops ops = new Test(); if (ops.equals(new Test())) { ... }
静态分派
动态分派
和静态分配对应的,还有一种叫动态分派。
方法
Java中的方法都封装在类中,不像其他语言,如C或者C++存在全局方法。
方法调用
从对象角度看,调用对象的方法,可以理解为调用者对象和被调用者对象之间的通信。
重载
方法名称相同,方法参数和返回类型不同
如下:
void outputType(Output out, Object obj) {
out.write("object");
}
void outputType(Output out, int i) {
out.write("int");
}
void outputType(Output out, char c) {
out.write("char");
}
如果一个方法有多个重载方法,如何决定调用哪一个?
如上,Java根据传入参数对应的数量,顺序以及参数类型来决定调用哪一个重载方法。Java在编译阶段就已经确定调用的目标方法。这是Java中的一种静态分派。
所谓的静态分派。因为它是根据参数的静态类型在编译阶段来确定分派,这从java源代码编译成字节码结果中可以看到。
上面提到的参数类型指的是静态类型,或者叫外观类型,而不是变量或参数的实际类型。
装箱和拆箱
在面向对象语言中,有一种比较重要的特性,那就是装箱和拆箱,这是一种语法糖特性,这种特性不止在面向对象语言中存在,在其他任何语言都基本存在这种特性。
虽然在java中也有定义了很多常用的基本类型,但在Java中,一切皆对象。因此,Java中的基本类型都有一个与之对应的类。在程序中,这些基本类型和类之间可以隐性的通过装箱和拆箱进行类型转换。
举个例子:
int inc(Integer i) {
return ++i;
}
在这个例子中就包括几次装箱和拆箱过程。
char
对应Character, 通过Character#valueOf(char c)和Character#charValue()进行装箱和拆箱。
int
对应Integer, 通过Integer#valueOf(int i)和Integer#intValue()进行装箱和拆箱。
等等。
这种装箱和拆箱的类型转换过程是在编译阶段确定的。
Character c = 'a';
0: bipush 97
2: invokestatic #2 // Method java/lang/Character.valueOf:(C)Ljava/lang/Character;
5: astore_1
char c2 = c;
6: aload_1
7: invokevirtual #3 // Method java/lang/Character.charValue:()C
10: istore_2
Integer i = 10;
0: bipush 10
2: invokestatic #2 // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
5: astore_1
int j = i;
6: aload_1
7: invokevirtual #3 // Method java/lang/Integer.intValue:()I
10: istore_2
Long l = 100L;
0: ldc2_w #6 // long 100l
3: invokestatic #8 // Method java/lang/Long.valueOf:(J)Ljava/lang/Long;
6: astore_1
long l2 = l;
7: aload_1
8: invokevirtual #9 // Method java/lang/Long.longValue:()J
11: lstore_2
Float f = 0.1F;
0: ldc #4 // float 0.1f
2: invokestatic #5 // Method java/lang/Float.valueOf:(F)Ljava/lang/Float;
5: astore_1
float f2 = f;
6: aload_1
7: invokevirtual #6 // Method java/lang/Float.floatValue:()F
10: fstore_2
Double d = 0.1;
0: ldc2_w #13 // double 0.1d
3: invokestatic #15 // Method java/lang/Double.valueOf:(D)Ljava/lang/Double;
6: astore_1
double d2 = d;
7: aload_1
8: invokevirtual #16 // Method java/lang/Double.doubleValue:()D
11: dstore_2
public static void test11() { int i = 10; Integer i2 = 10; if (i == i2) { // i == i2 } else { // i != i2 } }
Code:
0: bipush 10
2: istore_0
3: bipush 10
5: invokestatic #4 // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
8: astore_1
9: iload_0
10: aload_1
11: invokevirtual #5 // Method java/lang/Integer.intValue:()I
14: if_icmpne 17
17: return
public static void test12() { int i = 10; Integer i2 = 10; if (i2.equals(i)) { // i == i2 } else { // i != i2 } }
0: bipush 10
2: istore_0
3: bipush 10
5: invokestatic #4 // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
8: astore_1
9: aload_1
10: iload_0
11: invokestatic #4 // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
14: invokevirtual #17 // Method java/lang/Integer.equals:(Ljava/lang/Object;)Z
17: ifeq 20
20: return
类加载机制
类加载过程
以下是一个最简单的Java程序的类加载过程。
一个最简单的Java程序的类加载至少会有AppClassLoader、ExeClassLoader这两个类加载器参与。
对象
对象哈希
hashCode方法
对象引用
关于引用,几乎在所有的程序语言中都有类似的概念。在不同语言中,对于引用的理解也不尽相同,虽然大体意思都差不多。
在Java中,对引用还有更细的概念划分。根据对对象的引用“强度”还分为强引用,软引用(Soft Reference),弱引用(Weak Reference),幽灵引用(Phantom Reference)4中引用方式。这里的引用”强度”跟GC有关。
1、强引用
2、软引用(Soft Reference)
3、弱引用(Weak Reference)
4、虚引用(Phantom Reference),或者叫“幽灵”引用
我们都知道,对象创建之后,在使用是肯定需要有个引用来对这个对象进行操作,调用它的方法,对它的字段进行操作,这个引用跟我们的变量一样,就像我们在操作某个变量时,有个变量名进行操作。
通常是这样的:
A a = new A();
这种引用方式就是我们说的强引用。也是我们最常见的使用对象的方式。
其他的引用使用方式和强引用不同,通常是这样的:
Object obj = new Object();
SoftReference<Object> sf = new SoftReference<Object>(obj);
在使用时,通过sf来使用被引用的对象。
这些引用都继承了Reference类。
| |----
| |<--|
+------+
| +------+ +------+ +------+ +------+ |
--->| |---->| |---->| |----> ... ---->| |----
| | | | | | | |
+------+ +------+ +------+ +------+
Reference类在加载后会初始化启动一个ReferenceHandler来处理捕获引用。
private static class ReferenceHandler extends Thread { ReferenceHandler(ThreadGroup g, String name) { super(g, name); } public void run() { for (;;) { Reference r; synchronized (lock) { if (pending != null) { r = pending; Reference rn = r.next; pending = (rn == r) ? null : rn; r.next = r; } else { try { lock.wait(); } catch (InterruptedException x) { } continue; } } // Fast path for cleaners if (r instanceof Cleaner) { ((Cleaner)r).clean(); continue; } ReferenceQueue q = r.queue; if (q != ReferenceQueue.NULL) q.enqueue(r); } } }
GC来运行的时候也会收这里的lock同步对象影响。
虚引用
虚引用实现类为PhantomReference。另一个重要的虚引用实现类为Cleaner,Cleaner类继承了PhantomReference。
If the garbage collector determines at a certain point in time that the referent of a phantom reference is phantom reachable, then at that time or at some later time it will enqueue the reference.
In order to ensure that a reclaimable object remains so, the referent of a phantom reference may not be retrieved: The get method of a phantom reference always returns null.
Unlike soft and weak references, phantom references are not automatically cleared by the garbage collector as they are enqueued. An object that is reachable via phantom references will remain so until all such references are cleared or themselves become unreachable.
Cleaner
|
v
+------+ +------+ +------+ +------+
| |---->| |---->| |----> ... ---->| |
| |<----| |<----| |<---- ... <----| |
+------+ +------+ +------+ +------+
调用
调用栈
异常
Checked & Unchecked异常
错误
异常和错误
异常处理
Java通过try来检查可能会产生异常的代码,如果产生异常,通过catch进行捕获异常。
public static void test0() { try { int i = 0; } catch(Exception e) { } }
Code:
0: iconst_0
1: istore_0
2: goto 6
5: astore_0
6: return
Exception table:
from to target type
0 2 5 Class java/lang/Exception
public static void test1() { try { int i = 0; } finally { } }
Code:
0: iconst_0
1: istore_0
2: return
public static void test2() { try { int i = 0; } catch(Exception e) { } finally { } }
Code:
0: iconst_0
1: istore_0
2: goto 12
5: astore_0
6: goto 12
9: astore_1
10: aload_1
11: athrow
12: return
Exception table:
from to target type
0 2 5 Class java/lang/Exception
0 2 9 any
private static void throwOutOfMemoryError1() { byte[] buf = new byte[1024 * 1024 * 1024]; }
Exception in thread "main" java.lang.OutOfMemoryError: Java heap space
at OutOfMemoryTest.throwOutOfMemoryError1(OutOfMemoryTest.java:15)
at OutOfMemoryTest.main(OutOfMemoryTest.java:45)
private static void throwOutOfMemoryError2() { ByteBuffer buf = ByteBuffer.allocate(1024 * 1024 * 1024); }
Exception in thread "main" java.lang.OutOfMemoryError: Java heap space
at java.nio.HeapByteBuffer.<init>(HeapByteBuffer.java:57)
at java.nio.ByteBuffer.allocate(ByteBuffer.java:335)
at OutOfMemoryTest.throwOutOfMemoryError2(OutOfMemoryTest.java:19)
private static void throwOutOfMemoryError3() { ByteBuffer buf = ByteBuffer.allocateDirect(1024 * 1024 * 1024); }
Exception in thread "main" java.lang.OutOfMemoryError: Direct buffer memory
at java.nio.Bits.reserveMemory(Bits.java:693)
at java.nio.DirectByteBuffer.<init>(DirectByteBuffer.java:123)
at java.nio.ByteBuffer.allocateDirect(ByteBuffer.java:311)
at OutOfMemoryTest.throwOutOfMemoryError3(OutOfMemoryTest.java:23)
private static void throwOutOfMemoryError4() throws Throwable { Unsafe unsafe = getUnsafe(); for (;;) { unsafe.allocateMemory(1024 * 1024 * 1024); } }
Exception in thread "main" java.lang.OutOfMemoryError
at sun.misc.Unsafe.allocateMemory(Native Method)
at OutOfMemoryTest.throwOutOfMemoryError4(OutOfMemoryTest.java:29)
异常机制
Java运行时数据区域
方法区
Heap
JVM Stack
本地方法栈
程序计数器
运行时常量池
how to get the constant pool for a class
获取类的常量池:
ConstantPool constantPool = sun.misc.SharedSecrets.getJavaLangAccess().getConstantPool(Class klass);
例如:
ConstantPool constantPool = sun.misc.SharedSecrets.getJavaLangAccess().getConstantPool(String.class);
在SharedSecrets类(sun.misc.SharedSecrets)中, SharedSecrets.java在jdk\src\share\classes\sun\misc目录下,其中有个getJavaLangAccess和setJavaNetAccess方法:
public static JavaLangAccess getJavaLangAccess() {
return javaLangAccess;
}
public static void setJavaNetAccess(JavaNetAccess jna) {
javaNetAccess = jna;
}
在System类(java.lang.System)中,在jdk\src\share\classes\java\lang下,气宗有个initializeSystemClass方法,该方法由JVM调用,其中有如下代码:
// Allow privileged classes outside of java.lang
sun.misc.SharedSecrets.setJavaLangAccess(new sun.misc.JavaLangAccess(){
public sun.reflect.ConstantPool getConstantPool(Class klass) {
return klass.getConstantPool();
}
public boolean casAnnotationType(Class<?> klass, AnnotationType oldType, AnnotationType newType) {
return klass.casAnnotationType(oldType, newType);
}
public AnnotationType getAnnotationType(Class klass) {
return klass.getAnnotationType();
}
public byte[] getRawClassAnnotations(Class<?> klass) {
return klass.getRawAnnotations();
}
public <E extends Enum<E>>
E[] getEnumConstantsShared(Class<E> klass) {
return klass.getEnumConstantsShared();
}
public void blockedOn(Thread t, Interruptible b) {
t.blockedOn(b);
}
public Thread newThreadWithAcc(Runnable target, AccessControlContext acc) {
return new Thread(target, acc);
}
});
ConstantPool
sun.reflect.ConstantPool类在jdk\src\share\classes\sun\reflect目录下。ConstantPool 类通过反射方式来访问类对应的常量池。
public class ConstantPoolClass {
}
16
0: fail: Wrong type at constant pool index
1: getClassAt: class com.alaemall.ConstantPoolClass
2: getUTF8At: com/alaemall/ConstantPoolClass
3: getClassAt: class java.lang.Object
4: getUTF8At: java/lang/Object
5: getUTF8At: <init>
6: getUTF8At: ()V
7: getUTF8At: Code
8: getMethodAt: public java.lang.Object()
9: fail: Wrong type at constant pool index
10: getUTF8At: LineNumberTable
11: getUTF8At: LocalVariableTable
12: getUTF8At: this
13: getUTF8At: Lcom/alaemall/ConstantPoolClass;
14: getUTF8At: SourceFile
15: getUTF8At: ConstantPoolClass.java
直接内存
堆上分配&栈上分配
栈上分配
class K { private int a; private long ts; public int getA() { return a; } public void setA(int a) { this.a = a; } public long getTs() { return ts; } public void setTs(long ts) { this.ts = ts; } } public class JavaTest { public static void main(String[] args) throws Exception { { K k = new K(); System.out.println(k.getA() + ", " + k.getTs()); } int i = 0; for (;;) { try { System.out.println(i++); Thread.sleep(2000); } catch(InterruptedException e) { e.printStackTrace(); } } } }
java -server -XX:+DoEscapeAnalysis -XX:+PrintGC JavaTest
java -server -XX:-DoEscapeAnalysis -XX:+PrintGC JavaTest
对象
对象内存布局
Java内存模型
参考另一篇文章:https://lobin.iteye.com/blog/617507
重排序
编译重排
编译器优化重排序
指令重排
指令级并行重排序
x86手册上call调用时的指令重排:
内存系统重排序
相关推荐
这是本人第一篇java学习笔记,主要记录了学习过程中学习到的知识点以及自己的盲区,供大家参考,不喜欢勿喷,谢谢。
《Java语言程序设计提高篇+进阶篇第十版》是一本深入探讨Java编程技术的权威著作,适合已经掌握Java基础的开发者进一步提升自己的技能。这本书的第十版充分反映了Java语言的最新发展,包括Java 8及更高版本的重要...
理解它们的范围和用法是掌握Java的第一步。此外,还有引用数据类型,如类、接口和数组,它们都是对象的容器。 控制结构是编程中的关键元素,包括条件语句(if-else, switch-case)和循环(for, while, do-while)。...
《Java语言程序设计(基础篇+进阶篇)第六版》是Java学习的重要参考资料,尤其对于初学者和希望深入理解Java编程概念的人来说,这是一本不可多得的教材。本书分为基础篇和进阶篇,涵盖了Java编程的各个方面,旨在帮助...
本书是Java语言的经典教材,中文版分为基础篇和进阶篇,主要介绍程序设计基础、面向对象程序设计、GUI程序设计、数据结构和算法、高级Java程序设计等内容。本书以示例讲解解决问题的技巧,提供大量的程序清单,每章配...
例如,第1题可能是一个简单的数据类型转换或基本运算的题目,作者的代码会展示如何正确地处理这些计算。第2至12题可能逐渐增加难度,涵盖数组、字符串操作、函数的使用等。第15题可能涉及到类的使用,例如创建一个...
第一周,实习生主要适应了公司环境,意识到实习不仅仅是学习新知识,而是需要适应实际工作环境,调整作息习惯。这一阶段,他们熟悉了工作环境和Java编程的环境配置,强调了“多看、多问、多观察、多思考”的学习态度...
Java程序语言设计是Java开发者学习过程中的一本经典教材,梁勇教授的第十版结合了基础篇与进阶篇,深入浅出地讲解了Java编程的核心概念和技术。此压缩包包含了该书的课后习题答案,对于正在学习或已经学过这本书的...
《Java语言程序设计基础篇第十版》是一本深入浅出介绍Java编程的教材,源码rar文件包含了书中各个章节的示例代码,是学习和理解Java编程的重要资源。本压缩包中的源码覆盖了Java语言的基础语法、面向对象特性、异常...
在本资源中,我们聚焦于Java语言设计的基础篇——第八版的第四章编程题解答。这一部分的内容旨在帮助读者深入理解和应用Java编程的基本概念。Java作为一种广泛应用的面向对象的编程语言,其基础知识对于任何想从事...
《Java语言程序设计 基础篇 第10版 梁勇 答案》是一本针对初学者和进阶者的重要参考资料,由知名Java教育专家梁勇编写。本书全面覆盖了Java语言的基础概念、语法和编程技巧,旨在帮助读者深入理解并掌握Java编程的...
《Java语言程序设计基础篇(原书第十版)》是一本深入浅出的Java编程教程,适合初学者和有一定经验的开发者。这本书以其详尽的内容和实用的代码示例深受读者喜爱,尤其对于想要深入了解Java编程的人来说,是一份...
java语言程序设计(基础篇)原书第十版 课后习题答案,自己一个行一行写的代码,不是标准答案,但每个答案都测试过。 从第9章到第13章。 包含的题目有: 第九章:9.1-9.5 9.7-9.9 9.13 第十章:10.1 10.4-10.7 第十...
Java开发基础:初识Java Java,一种广泛使用的高级编程语言,由Sun Microsystems(现为Oracle Corporation的一部分)在...在"初始Java第一讲"的PPT中,通常会涵盖这些基础内容,帮助初学者建立对Java编程的全面认识。
Java语言程序设计与数据结构(基础篇)第11版(黑皮书)第一章节代码jdk18版本 1.1(显示三条消息)编写程序,显示Welcome to Java、Welcome to Computer Science和Programming is fun。 1.2(显示三条消息)编写...
在第一个练习题中,我们定义了一个名为 `TriangleNew` 的类,它继承自 `GeometricObject` 类。这个类具有三个私有变量 `side1`、`side2` 和 `side3`,分别表示三角形的三个边长。类中实现了 `getArea` 方法和 `...
1. **基础语法**:Java的基础语法是学习Java的第一步,包括变量声明、数据类型(基本类型和引用类型)、运算符、流程控制语句(如if、for、while、switch)以及方法的定义和调用。 2. **面向对象编程**:Java是一种...
第6节将聚焦于Java NIO中的Socket通道操作,这是网络编程中的重要一环。SocketChannel是基于TCP协议的,提供了一种可靠的数据传输方式。我们将学习如何创建和配置SocketChannel,以及如何通过它进行数据的读写。此外...
1. **Java简介与环境配置**:第四章可能首先介绍Java的历史、应用领域,以及如何在不同操作系统上安装Java Development Kit (JDK)和设置环境变量。这包括了解`javac`编译器和`java`运行命令的用法。 2. **基本数据...
根据提供的信息,“Java语言程序设计 基础篇 第八版 带目录”这本书主要针对初学者介绍了Java编程的基础知识。尽管提供的具体内容部分只包含了下载链接,我们仍然可以根据书名、描述以及标签来推断出书中可能涵盖的...