本篇關(guān)注:初始化(第5章),訪(fǎng)問(wèn)控制(第6章)
初始化 Initialization
構(gòu)造器 constructor
創(chuàng)建對(duì)象時(shí)被自動(dòng)調(diào)用鼓蜒,名稱(chēng)與類(lèi)名完全相同的特殊方法痹换,用來(lái)執(zhí)行初始化,沒(méi)有返回值
Java中都弹,創(chuàng)建和初始化是捆綁的娇豫。
new創(chuàng)造對(duì)象時(shí),會(huì)為對(duì)象分配空間畅厢,并調(diào)用相應(yīng)構(gòu)造器冯痢。
默認(rèn)構(gòu)造器
又叫無(wú)參構(gòu)造器。如果類(lèi)中沒(méi)有寫(xiě),則編譯器會(huì)自動(dòng)創(chuàng)建浦楣。
class Rock {
Rock() { // 默認(rèn)構(gòu)造器
...
}
}
可以修改為有參數(shù)
重載 Oveloading
用多種方式創(chuàng)建一個(gè)對(duì)象袖肥。參數(shù)列表必須獨(dú)一無(wú)二。以返回值區(qū)分重載方法是行不通的振劳。
class Tree {
int height;
Tree() {
System.out.println("Planting a seed");
height = 0;
}
Tree(int initialHeight) {
height = initialHeight;
System.out.println("The new tree is " + height + " feet tall");
}
void info() {
System.out.println("Tree is " + height + " feet tall");
}
void info(String string) {
System.out.println(string + ": Tree is " + height + " feet tall");
}
}
- 如果傳入的數(shù)據(jù)類(lèi)型(實(shí)際參數(shù)類(lèi)型)小于方法中聲明的形式參數(shù)類(lèi)型椎组,實(shí)際數(shù)據(jù)類(lèi)型就會(huì)被提升。char型不同历恐,如果無(wú)法找到接受char參數(shù)的方法寸癌,就會(huì)把char提升至int。
- 如果傳入的實(shí)際參數(shù)較大弱贼,就得通過(guò)類(lèi)型轉(zhuǎn)換來(lái)執(zhí)行窄化轉(zhuǎn)換熊经。
this
this關(guān)鍵字只能在方法內(nèi)部使用长豁,表示對(duì)“調(diào)用方法的那個(gè)對(duì)象”的引用
很容易在一條語(yǔ)句里對(duì)同一個(gè)對(duì)象執(zhí)行多次操作疚脐∑季ǎ或者將其自身傳遞給外部方法。
在構(gòu)造器中調(diào)用構(gòu)造器
this加上參數(shù)列表庇勃,可以調(diào)用符合的構(gòu)造器檬嘀。
public class Flower {
int petalCount = 0;
String s = "initial value";
Flower(int petals) {
petalCount = petals;
System.out.println("Constructor with int arg only");
}
Flower(String s, int petals) {
this(petals);//call constructor <Flower(int petals)>
//! this(s);//can't call two
this.s = s;
System.out.println("Constructor with int & String args");
}
Flower() {
this("hi", 47);
System.out.println("Default constructor with no arg");
}
}
這種調(diào)用必須處在構(gòu)造器塊中的起始處。
不可以同時(shí)調(diào)用兩個(gè)構(gòu)造器匪凉。
this.s 可以指代數(shù)據(jù)成員枪眉。
其他方法中不可以調(diào)用構(gòu)造器。
成員初始化
基本數(shù)據(jù)類(lèi)型都有默認(rèn)的初值再层。對(duì)象引用的默認(rèn)值是null贸铜。
聲明變量的時(shí)候直接賦值,或者調(diào)用某方法為它賦值聂受。
類(lèi)的內(nèi)部蒿秦,變量定義的先后順序決定了初始化的順序。
變量定義于任意位置蛋济,它們?nèi)耘f會(huì)在任何方法(包括構(gòu)造器)被調(diào)用之前得到初始化棍鳖。
靜態(tài)初始化只在必要時(shí)刻(靜態(tài)對(duì)象被創(chuàng)建/靜態(tài)數(shù)據(jù)被訪(fǎng)問(wèn)),在class對(duì)象首次加載的時(shí)候進(jìn)行一次碗旅。
可以使用靜態(tài)塊組合多個(gè)靜態(tài)初始化
static int a渡处;
static int b;
static{
a = 3祟辟;
b = 4医瘫;
}
初始化順序:先是靜態(tài)對(duì)象,再是非靜態(tài)對(duì)象旧困。
構(gòu)造器也屬于靜態(tài)方法醇份。
對(duì)象創(chuàng)建過(guò)程:假設(shè)有個(gè)Dog類(lèi)
- 首次創(chuàng)建Dog對(duì)象稼锅,或者首次訪(fǎng)問(wèn)Dog類(lèi)的靜態(tài)方法/數(shù)據(jù)時(shí),定位Dog.class文件
- 載入Dog.class(創(chuàng)建Dog.class對(duì)象)僚纷。執(zhí)行靜態(tài)初始化矩距,之后不會(huì)執(zhí)行第二次。
- 用new Dog()創(chuàng)建對(duì)象時(shí)怖竭,在heap上分配內(nèi)存空間
- 內(nèi)存空間清零锥债,Dog對(duì)象所有基本數(shù)據(jù)類(lèi)型和引用變?yōu)槟J(rèn)值
- 執(zhí)行程序中定義的初始化
- 執(zhí)行構(gòu)造器
可變參數(shù)列表
參數(shù)個(gè)數(shù)或類(lèi)型不確定時(shí)
顯式地創(chuàng)建以O(shè)bject數(shù)組為參數(shù)的方法:
class A {}
public void printArray(Object[] args) {
for(Object obj : args)
System.out.print(obj + " ");
System.out.println();
}
printArray(new Object[]{new Integer(47), new Float(3.14), new Double(11.11)});
printArray(new Object[]{"one", "two", "three"});
printArray(new Object[]{new A(), new A(), new A()});
定義可變參數(shù)列表:
public void printArray(Object... args) {
for(Object obj : args)
System.out.print(obj + " ");
System.out.println();
}
類(lèi)型確定:
public void printArray(int i, String... args) {}
適用于參數(shù)個(gè)數(shù)不確定的情況侵状,java把可變參數(shù)當(dāng)做數(shù)組處理赞弥。
- 只支持有一個(gè)可變參數(shù),只能出現(xiàn)在參數(shù)列表的最后趣兄;
- ...前后有無(wú)空格都可以,args名字自定義悼嫉。
- 方法中以數(shù)組的形式訪(fǎng)問(wèn)可變參數(shù)艇潭。
- 把0個(gè)參數(shù)傳給可變參數(shù)列表也可以。
枚舉類(lèi)型 Enumerated types
public enum Spiciness {
NOT, MILD, MEDIUM, HOT, FLAMING
}
public class SimpleEnum {
public static void main(String[] args) {
Spiciness spiciness = Spiciness.MEDIUM;
System.out.println(spiciness);
for(Spiciness s : Spiciness.values())
System.out.println(s + ", ordinal " + s.ordinal());
}
}
可以把enum看成是一個(gè)類(lèi)戏蔑。一個(gè)數(shù)據(jù)類(lèi)型蹋凝。
通常枚舉的元素命名全都大寫(xiě),多個(gè)單詞用_隔開(kāi)总棵。
但是enum不能使用extends繼承其他類(lèi)鳍寂,因?yàn)閑num已經(jīng)繼承了java.lang.Enum(Java是單一繼承)
枚舉類(lèi)中每個(gè)值都被映射到protected Enum(String name, int ordinal)
ordinal():獲取枚舉常量的聲明順序
values():獲取一個(gè)數(shù)組,按聲明順序
與switch組合絕佳情龄,因?yàn)閟witch是在有限的可能值集合中選擇
switch(degree) {
case NOT:
System.out.println("not spicy at all");
break;
case MILD:
case MEDIUM:
System.out.println("a little hot");
break;
case HOT:
case FLAMING:
default:
System.out.println("may be to hot");
break;
}
EnumSet
提供了Set接口的實(shí)現(xiàn)
EnumSet allSpiciness = EnumSet.allOf(Spiciness.class);
EnumSet partSpiciness = EnumSet.of(Spiciness.NOT, Spiciness.MEDIUM);
EnumMap
提供了Map接口的實(shí)現(xiàn)迄汛。鍵(key)是一個(gè)枚舉類(lèi)型
EnumMap<Spiciness, String> enumMap = new EnumMap<>(Spiciness.class);
enumMap.put(Spiciness.NOT, "not spicy at all");
enumMap.put(Spiciness.MILD, "a little hot");
enumMap.put(Spiciness.HOT, "maybe too hot");
for(Spiciness s : Spiciness.values())
System.out.println(s + " represents " + enumMap.get(s));
訪(fǎng)問(wèn)控制 Access control
.java文件被稱(chēng)為編譯單元 compilation unit,或轉(zhuǎn)譯單元 translation unit
每個(gè)編譯單元只能有一個(gè)public類(lèi)
編譯后產(chǎn)生同名的.class文件骤视。Java的可運(yùn)行程序就是一組.class文件(可打包為JAR)
package:聲明一個(gè)包鞍爱。位于除了注釋外的第一行。
import:導(dǎo)入一個(gè)包专酗。
包名:全部小寫(xiě)睹逃。通常是把自己的域名反過(guò)來(lái)〉豢希或者是機(jī)器上的class文件路徑沉填。
處于同路徑且沒(méi)有聲明包名的class文件,會(huì)被看作隸屬于該目錄的默認(rèn)包中佑笋。
如果import兩個(gè)包翼闹,包含相同的類(lèi)名。創(chuàng)建時(shí)就必須明確指明:
java.util.Vector v = new java.util.Vector()
類(lèi)中成員(變量/方法)訪(fǎng)問(wèn)權(quán)限:
類(lèi)內(nèi)部 | 本包其他類(lèi) | 外部包子類(lèi) | 外部包其他類(lèi) | ||
---|---|---|---|---|---|
public | √ | √ | √ | √ | |
protected | √ | √ | √ | ||
default | √ | √ | |||
private | √ |
default:默認(rèn)的包訪(fǎng)問(wèn)權(quán)限允青,不需要寫(xiě)出來(lái)橄碾。class Abc{ }
類(lèi)的修飾:不可以是private和protected的卵沉。內(nèi)部類(lèi)可以。
不希望別人訪(fǎng)問(wèn)該類(lèi)法牲,可以把構(gòu)造器設(shè)為private史汗。但是public static成員可以被訪(fǎng)問(wèn)。
通常最好是把域保持為private拒垃,通過(guò)protected方法控制類(lèi)的繼承者的訪(fǎng)問(wèn)權(quán)限停撞。
封裝 encapsulation:把數(shù)據(jù)和方法包裝進(jìn)類(lèi)中,隱藏具體實(shí)現(xiàn)悼瓮。得到一個(gè)數(shù)據(jù)類(lèi)型戈毒。