枚舉
- 如果一個變量的取值只可能是固定的幾個值痕鳍,可以考慮使用枚舉
- 枚舉由一組預定義的常量構(gòu)成
public enum Season {
SPRING, SUMMER, FALL, WINTER
}
public class Main {
public static void main(String[] args) {
Season s = Season.WINTER;
// 打印名稱
System.out.println(s.name());// WINTER
// 打印下標
System.out.println(s.ordinal());// 3
}
}
枚舉本質(zhì)上還是一個類硫豆,所有的枚舉類型最終都隱式的繼承自java.lang.Enum
枚舉定義完常量之后可以再定義成員變量,方法等內(nèi)容(也間接說明了枚舉本質(zhì)上確實是一個類)
public enum Season {
SPRING, SUMMER, FALL, WINTER;
int age = 0;
public void test(){
System.out.println(age);
}
}
枚舉的構(gòu)造方法的權(quán)限必須是無修飾或者private
的笼呆。
Java會自動為每一個枚舉添加構(gòu)造函數(shù)熊响,外界不能調(diào)用,枚舉在初始化常量的時候會調(diào)用構(gòu)造方法诗赌。也就是枚舉的構(gòu)造方法并不是提供給外部使用的汗茄,而是給內(nèi)部使用的
包裝類(Wrapper Class)
在講述包裝類之前,先看看基本類型的缺陷
- 無法表示不存在的值(null)
- 不能利用面向?qū)ο蟮姆绞饺ゲ僮骰绢愋停ū热缰苯邮褂没绢愋驼{(diào)用方法)
- 當方法參數(shù)是引用類型時铭若,基本類型無法傳遞
為了解決這些缺陷洪碳,可以將基本類型包裝為引用類型
public class IntObject {
private final int value;
public IntObject(int v) {
this.value = v;
}
public int getValue() {
return this.value;
}
}
IntObject[] money = {
new IntObject(10),
new IntObject(23),
null,
new IntObject(-100),
new IntObject(150),
};
這樣就可以解決上述的缺陷
Java已經(jīng)內(nèi)置了基本類型的包裝類(都在java.lang包中),其中叼屠,數(shù)字類型的基本類型最終都繼承自java.lang.Number
基本類型 | 包裝類 |
---|---|
byte | Byte |
char | Character |
short | Short |
int | Integer |
long | Long |
float | Float |
double | Double |
boolean | Boolean |
Integer[] money2 = {
new Integer(10),
new Integer(23),
null,
new Integer(-100),
new Integer(150)
};
自動裝箱瞳腌、拆箱(Autoboxing and Unboxing)
自動裝箱:java編譯器會自動調(diào)用valueOf
方法,將基本類型轉(zhuǎn)換為包裝類型
Integer[] money2 = {
Integer.valueOf(10),
Integer.valueOf(100),
Integer.valueOf(110),
Integer.valueOf(120),
};
// 自動裝箱
// 數(shù)組里存儲的并不是基本類型 而是Integer
Integer[] money3 = {
10, // 等同于 Integer.valueOf(10)
100,
110,
120,
};
// 這里也是對的
// java編譯器會自動裝箱成Integer類型
Object num = 10;
自動拆箱: java編譯器會自動調(diào)用xxxValue
方法环鲤,將包裝類轉(zhuǎn)為基本類型
Integer i1 = 10;
int i2 = i1;
// 上面等同于下面的代碼
// int i2 = i1.intValue();
包裝類的判等
包裝類的判等纯趋,不要使用==
、!=
運算符冷离,應該使用equals
方法
包裝類是一個類吵冒,所以在使用==
時比較的不是包裝的值,而是對象的內(nèi)存地址西剥。
Integer i1 = 88; // 等價于 Integer.valueOf(88);
Integer i2 = 88;
Integer i3 = 888;
Integer i4 = 888;
// 不推薦
System.out.println(i1 == i2); // true
System.out.println(i3 == i4); // false 888 超出了緩存范圍 所以每次都是新創(chuàng)建的對象
// 推薦
System.out.println(i1.equals(i2)); // true
System.out.println(i3.equals(i4)); // true
在Integer類中有一個IntegerCache
嵌套類痹栖,會緩存-128到127之間的值,在使用valueOf
方法時瞭空,會先從該緩存類中檢查是否有緩存揪阿,有的話直接返回而不是新創(chuàng)建一個Integer對象。 所以i1 == i2
返回true
,而i3 == i4
返回false
,
Integer i5 = 88;
Integer i6 = Integer.valueOf(88);
Integer i7 = new Integer(88); // 這里是新創(chuàng)建了Integer對象 而沒有從緩存取 所以地址不同了
System.out.println(i5 == i6);// true
System.out.println(i5 == i7);// false
使用注意
【基本類型數(shù)組】與【包裝類數(shù)組】之間是不能自動裝箱咆畏、拆箱的南捂。
比如int數(shù)組不能直接賦值給Integer數(shù)組
字符串
Java中用java.lang.String類代表字符串
低層使用char[]存儲字符數(shù)據(jù),從java9開始旧找,低層使用byte[]存儲字符數(shù)據(jù)
所有字符串字面亮都是String類的實例
String對象一旦創(chuàng)建完畢溺健,它的字符內(nèi)容是不可以修改的
字符串常量池(String Constant Pool)
- java中有個字符串常量池(String Constant Pool,簡稱SCP)
- 從java 7開始屬于堆空間的一部分(之前屬于方法區(qū))
當遇到字符串字面量時,回去查看SCP钮蛛,如果SCP中有與字面量內(nèi)容一樣的字符串對象A時鞭缭,就會返回A剖膳,如果沒有,就創(chuàng)建一個新的字符串對象岭辣,并加入到SCP吱晒,然后返回
String s1 = "lwy"; // 會從scp中查找 沒有 然后創(chuàng)建字符串對象返回
String s2 = "lwy"; // 從scp中查找 找到并返回
System.out.println(s1 == s2); // true 所以s1與s2是同一個對象
String s1 = "wy";
String s2 = new String("wy");//
String s3 = new String(s1);
String s4 = new String(s2);
char[] cs = {'w','y'};
String s5 = new String(cs);
String s6 = new String(s5);
上述字符串的內(nèi)存分布大致如下
前面說過,字符串的底層是通過數(shù)組來存放字符的沦童,
@Stable
private final byte[] value;
每次調(diào)用String的構(gòu)造方法都會創(chuàng)建一個新的String對象仑濒,存放在堆區(qū)。
public String(String original) {
this.value = original.value;
this.coder = original.coder;
this.hash = original.hash;
}
但是點開查看String的構(gòu)造方法查看搞动,當初始化傳遞一個String對象的時候躏精,會把傳遞的String的value直接賦值給新對象的value渣刷,也就是說s1,s2,s3,s4的value都是同一個鹦肿。同理,s5辅柴,s6也是同一個value
intern的用法
String s = new String("wy");
s.intern();
A.intern
方法的作用: 如果SCP中存在與A內(nèi)容一樣的字符串對象C時箩溃,就返回C,如果沒有碌嘀,就將A添加進SCP涣旨,并返回A