在编程时如果不知道jdk默认做的一些事情就很难理解一些东西, 如 Integer 的自动拆封装就会很难受
反编译工具我这里使用的是JDK1.5中的, 在高版本中看不到类的默认继承了
这是一个基础类的源码文件
public class Demo {
public static void main(String[] args) {
System.out.println("HelloWorld!");
}
}
反编译过后的
# javap -c Demo
Compiled from "Demo.java"
public class Demo extends java.lang.Object{
public Demo();
Code:
0: aload_0
1: invokespecial #1; //Method java/lang/Object."<init>":()V
4: return
public static void main(java.lang.String[]);
Code:
0: getstatic #2; //Field java/lang/System.out:Ljava/io/PrintStream;
3: ldc #3; //String helloWorld!
5: invokevirtual #4; //Method java/io/PrintStream.println:(Ljava/lang/String;)V
8: return
}
反编译过后可以看到
- 自定义一个类会默认继承
java.lang.Object
, 这也是 Object 利用多态能接受任意对象的原因 - 一个类中会默认有一个构造方法,他的默认实现是调用到父类的空构造方法
- 当你自定义了一个构造方法后jdk就不会默认给你加空构造了
- 这里要注意构造方法中
super(...)
一定是第一行代码,就算你不写super(...)
她会默认调用父类的空构造
接下来在来看一段源码
import java.util.Arrays;
import java.util.List;
public class Demo {
public static void main(String[] args) {
List<String> list = Arrays.asList("Java", "JavaME", "JavaSE", "JavaEE");
String data = "";
for (String s : list) {
data += s + ",";
}
System.out.println(data);
}
}
反编译后的结果为
# javap -c Demo
Compiled from "Demo.java"
public class Demo extends java.lang.Object{
public Demo();
Code:
0: aload_0
1: invokespecial #1; //Method java/lang/Object."<init>":()V
4: return
public static void main(java.lang.String[]);
Code:
0: iconst_4
1: anewarray #2; //class java/lang/String
4: dup
5: iconst_0
6: ldc #3; //String Java
8: aastore
9: dup
10: iconst_1
11: ldc #4; //String JavaME
13: aastore
14: dup
15: iconst_2
16: ldc #5; //String JavaSE
18: aastore
19: dup
20: iconst_3
21: ldc #6; //String JavaEE
23: aastore
24: invokestatic #7; //Method java/util/Arrays.asList:([Ljava/lang/Object;)Ljava/util/List;
27: astore_1
28: ldc #8; //String
30: astore_2
31: aload_1
32: invokeinterface #9, 1; //InterfaceMethod java/util/List.iterator:()Ljava/util/Iterator;
37: astore_3
38: aload_3
39: invokeinterface #10, 1; //InterfaceMethod java/util/Iterator.hasNext:()Z
44: ifeq 86
47: aload_3
48: invokeinterface #11, 1; //InterfaceMethod java/util/Iterator.next:()Ljava/lang/Object;
53: checkcast #2; //class java/lang/String
56: astore 4
58: new #12; //class java/lang/StringBuilder
61: dup
62: invokespecial #13; //Method java/lang/StringBuilder."<init>":()V
65: aload_2
66: invokevirtual #14; //Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
69: aload 4
71: invokevirtual #14; //Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
74: ldc #15; //String ,
76: invokevirtual #14; //Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
79: invokevirtual #16; //Method java/lang/StringBuilder.toString:()Ljava/lang/String;
82: astore_2
83: goto 38
86: getstatic #17; //Field java/lang/System.out:Ljava/io/PrintStream;
89: aload_2
90: invokevirtual #18; //Method java/io/PrintStream.println:(Ljava/lang/String;)V
93: return
}
从反编译中能看出
- 关于字符串拼接
- 在少量字符串拼接时jdk会默认给我们转成StringBuilder来实现,这也是为什么少量字符串拼接可以使用String对象的原因
- 在使用
for (String s : list) {}
时- 会默认调用到
java.util.Iterator
接口中的方法 - 我们自定义类如果想使用这种迭代方式就需要满足一下两种条件
- 是集合架构中的一员
- 自定义实现
Iterator
中的方法
- 会默认调用到
自定义枚举类
public enum Demo {
SUCCESS(0, "成功"),
ERROR(1, "失败");
private Integer code;
private String msg;
Demo(Integer code, String msg) {
this.code = code;
this.msg = msg;
}
}
反编译枚举后可以看到
# javap Demo
Compiled from "Demo.java"
public final class Demo extends java.lang.Enum{
public static final Demo SUCCESS;
public static final Demo ERROR;
public static final Demo[] values();
public static Demo valueOf(java.lang.String);
static {};
}
从反编译结果中可以看到
- 枚举类实际上是一个加了
final
class 他会默认继承自java.lang.Enum
- 每一个枚举类型都会转成 public static final 的对象
自定义注解
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface Demo {
String value();
}
反编译的结果
# javap Demo
Compiled from "Demo.java"
public interface Demo extends java.lang.annotation.Annotation{
public abstract java.lang.String value();
}
从反编译结果中可以看出
- 可以看出注解会默认继承
java.lang.annotation.Annotation
- 一个属性就是一个抽象方法
还有一些常识
Java
会默认导入java.lang
包- 这个自动导入使得我们在使用
Integer,Object,System
等类的时候不需要手动导包
- 这个自动导入使得我们在使用
System.out.println();
的时候会默认调用到对象中的toString();
方法HashSet
在存储时会默认调用到对象的hashCode()::equals()
方法HashSet
在判断元素重复时借助了hashCode()
的hash算法来筛选掉一批不重复的数据- 在hash值相等的时候在借助
equals()
判断是否重复如果重复就不录入了 - 为什么要使用到两个方法来判断是否重复这里是hash算法的一个特点了, 在
HashMap
中如果hash值相等值不相等就会在hash表中形成一个hash链
TreeSet
在存储时,要求元素实现Comparable
接口TreeSet
使用了树状结构需要使用到java.lang.Comparable#compareTo
方法的返回值- 通过返回来决定元素是否重复: [
0元素重复
,<0左子树
,>0右子树
]
Integer 的自动封装和catch
先来看一段源码代码
Integer val1 = 1;
Integer val2 = 1;
System.out.println(val1 == val2);
Integer val3 = 996;
Integer val4 = 996;
System.out.println(val3 == val4);
反编译结果
# javap -c Demo
Compiled from "Demo.java"
public class Demo {
public Demo();
Code:
0: aload_0
1: invokespecial #1 // Method java/lang/Object."<init>":()V
4: return
public static void main(java.lang.String[]);
Code:
0: iconst_1
1: invokestatic #2 // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
4: astore_1
5: iconst_1
6: invokestatic #2 // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
9: astore_2
10: getstatic #3 // Field java/lang/System.out:Ljava/io/PrintStream;
13: aload_1
14: aload_2
15: if_acmpne 22
18: iconst_1
19: goto 23
22: iconst_0
23: invokevirtual #4 // Method java/io/PrintStream.println:(Z)V
26: sipush 996
29: invokestatic #2 // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
32: astore_3
33: sipush 996
36: invokestatic #2 // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
39: astore 4
41: getstatic #3 // Field java/lang/System.out:Ljava/io/PrintStream;
44: aload_3
45: aload 4
47: if_acmpne 54
50: iconst_1
51: goto 55
54: iconst_0
55: invokevirtual #4 // Method java/io/PrintStream.println:(Z)V
58: return
}
- 在Integer类型自动拆装箱实际上是使用了
Integer.valueOf()
方法 - 我们可以通过了解
valueOf()
的源码来理解 Integer-128~127
缓存
Integer.valueOf() 的实现
public static Integer valueOf(int i) {
if (i >= IntegerCache.low && i <= IntegerCache.high)
return IntegerCache.cache[i + (-IntegerCache.low)];
return new Integer(i);
}
Integer缓存核心实现
private static class IntegerCache {
static final int low = -128;
static final int high;
static final Integer cache[];
static {
// high value may be configured by property
int h = 127;
String integerCacheHighPropValue =
sun.misc.VM.getSavedProperty("java.lang.Integer.IntegerCache.high");
if (integerCacheHighPropValue != null) {
try {
int i = parseInt(integerCacheHighPropValue);
i = Math.max(i, 127);
// Maximum array size is Integer.MAX_VALUE
h = Math.min(i, Integer.MAX_VALUE - (-low) -1);
} catch( NumberFormatException nfe) {
// If the property cannot be parsed into an int, ignore it.
}
}
high = h;
cache = new Integer[(high - low) + 1];
int j = low;
for(int k = 0; k < cache.length; k++)
cache[k] = new Integer(j++);
// range [-128, 127] must be interned (JLS7 5.1.7)
assert IntegerCache.high >= 127;
}
private IntegerCache() {}
}