無師自通學程式設計之Java基礎(二):構造器以及許可權修飾
一. 構造器
什麼是構造器
所謂構造器就是在一個類的例項化之前必須要呼叫的方法,它和類的名字是一樣的,每個類都有一個預設的無參的構造器。
public class Demo1 {
public Demo1(){}
}
注意,當類中已經有了構造器後,那麼預設構造器會自動失效。
構造器的過載
當想用不同的方法去建立一個方法時,就需要用到構造器的過載
public class Demo1 {
int a;
public Demo1(){
System.out.println("無參構造器");
};
public Demo1(int a){
System.out.println("有參構造器");
this.a=a;
}
}
如何區分過載方法呢?
區分過載方法很簡單,即每一個過載方法都有一個獨一無二的引數列表
引數列表的不同體現在:
1. 宣告的引數的個數不同
2. 宣告的引數型別不同
3. 宣告的引數順序不同
4. 返回值不同也可(只在特定的語境下才可以)
注意,基本資料型別會在傳入一個較小的資料型別的時候自動將它的的和資料型別提升一些,如byte轉為short,short轉為int,但是char有所不同,如果無法找到正好接受char的方法,那麼就會直接將char提升到int型別。
如果傳入的引數比較大的話,那麼必須要通過強轉來降低型別。
This關鍵字
使用this關鍵字的必要性
this關鍵字只可以使用在方法的內部,表示“呼叫方法的那個物件”的引用,也可以返回當前物件的引用,也可以將當前的物件傳遞給其他的方法。
class Demo2{
int i=0;
Demo2 incremnet(){
i++;
return this;
}
void print(){
System.out.println(this.i);
}
public static void main(String[] args) {
Demo2 demo2=new Demo2();
demo2.incremnet().incremnet().incremnet().print();
}
}
可以在一個構造器中呼叫另一個構造器
可以在一構造器之中呼叫另一個構造器,但是但是必須要注意兩點:
1. 呼叫的構造器必須處於最頂端,否則會報錯;
2. 除了構造器之外,嚴禁在其他的任何方法中呼叫構造器。
更加了解static關鍵字
將一個成員變數或者方法宣告為靜態變數或者靜態方法,此時這個變數或者方法是屬於類的,而不是屬於某個具體的物件的,可以通過類名就直接去呼叫他們了。當然,一般物件的引用也可以引用他們。
其實,static方法就是在方法內沒有this的方法,在static方法內不可以呼叫非static方法以及非static變數,但是反過來是可以的。
垃圾回收
關於垃圾回收,必須要明確這三點:
1. 物件可能不會被垃圾回收
2. 垃圾回收並不等於析構
3. 垃圾回收只和記憶體有關
構造器的初始化
構造器的最重要的作用就是進行初始化(儘管java已經有了足夠的保障來保證初始化的進行,具體體現在:
1. 成員變數而言,基本資料型別未初始化,每個資料型別都有其自己的初始值。
2. 物件沒有初始化,預設是null。)
對於靜態資料的初始化而言,基本沒什麼不同,但是靜態初始化只會在必須的時刻進行,如果不建立物件,也不引用對應的靜態變數,那麼靜態初始化幾乎不會進行。
這裡,我們總結一下物件的建立過程(以一個dog類為例子)
1. 即使沒有顯示的使用static關鍵字,但是構造器實際上也是靜態方法,因此,當首次建立型別為dog的物件,或者首次訪問dog類的靜態方法或者靜態變數是,java直譯器必須先根據類路徑定位到dog.Class檔案。
2. 然後載入Dog.class,有關靜態初始化的所有操作都會進行,因此,靜態初始化只會在class檔案第一次載入的時候會進行一次。
3. 當用new Dog()建立物件的時候,會在堆上為dog物件分配足夠的儲存空間。
4. 這塊儲存空間會被清零,這樣就會自動的為dog獨享的所有基本的資料型別都設定成預設型別。
5. 執行所有出現在欄位定義處的初始化動作。
6. 執行構造器,這裡面會牽涉道很多動作,尤其是涉及到繼承的時候。
{
將多個靜態程式碼組成一個靜態程式碼塊,static{
int i=0;
System.out.println("靜態初始化");
}
這段程式碼也僅僅只在第一次初始化類的時候執行一次,即第一次誰給生成一個例項化物件或者第一次訪問這個類的靜態資料成員。
既然有靜態程式碼塊,那麼就要顯示的程式碼快,如{
System.out.println("顯示的初始化");
}
這個程式碼塊實在構造器之前執行的。
}
陣列的初始化
陣列在java中是一個特殊的資料物件,它是一些具有相同資料型別的資料的集合,可以是基本資料型別,也可以是引用,定義一個數組的方式有一下三種類型:
1. Int []a=new int[num];//直接指定陣列的大小
2. Int []a=new int[]{1,3,4,5,}//後面的逗號可選
3. Int []a=new int[]{1,2,4};
注意,一但陣列被初始化了,那麼它的長度就不可以改變了,它有一些方法,這裡指出來。
1. Array.toString();//打印出陣列的字串形式;
2. Array.CopyOf()
3. 太多了,不舉例了,自己去jdk文件看。
可變引數列表
class Demo3{
void f(int...num){
for(int o:num){
System.out.print(o+" ");
}
}
public static void main(String[] args) {
new Demo3().f(1,2,4);
}
}
當然,這裡也可以不輸入任何的引數(這樣做有時候會造成誤解),或者在前面加上其他的引數。
列舉型別
簡單來說,就是一種新的新的資料型別,其實是一個類,並且有著自己的獨特的方法而已。
enum spiciness{
ONE,TWO,THREE,FOUR,FIVE,SIX,SEVEN
}
for(spiciness o:spiciness.values()){
System.out.println(o);
}
其實,列舉型別更多的是用在switch語句中。
二、許可權控制
每一個只有一個public類,若還有其他的類的話,對外界來說是不可見的,他們主要是為了主public類服務的。
訪問修飾符
Public,protected,private。
1. 包訪問許可權
沒有加任何訪問修飾符的變數或者方法意味著對當前的包而言,他們是可以訪問的,但是對於對於其他的包而言,他們是private的。
2. 介面訪問許可權
使用了public關鍵字,也就意味著後面緊跟著的成員對自己和每個人都是可用的
3. Private:無法訪問
即除了包涵該成員的類之外,其他任何的類都無法訪問這個成員。
4. Protected :繼承訪問許可權
包含了包訪問許可權的同時,只對自己的子類提供訪問許可權。
修飾符 全域性 子類 包內 本類

許可權修飾符的範圍
使用許可權修飾符的目的是為了具體實現的隱藏,其實就是為了封裝
科普:單例模式
一、單例模式定義:
單例模式確保某個類只有一個例項,而且自行例項化並向整個系統提供這個例項。在計算機系統中,執行緒池、快取、日誌物件、對話方塊、印表機、顯示卡的驅動程式物件常被設計成單例。這些應用都或多或少具有資源管理器的功能。每臺計算機可以有若干個印表機,但只能有一個Printer Spooler,以避免兩個列印作業同時輸出到印表機中。每臺計算機可以有若干通訊埠,系統應當集中管理這些通訊埠,以避免一個通訊埠同時被兩個請求同時呼叫。總之,選擇單例模式就是為了避免不一致狀態,避免政出多頭。
二、單例模式特點:
1、單例類只能有一個例項。
2、單例類必須自己建立自己的唯一例項。
3、單例類必須給所有其他物件提供這一例項。
單例模式保證了全域性物件的唯一性,比如系統啟動讀取配置檔案就需要單例保證配置的一致性。
三、單例模式的建立。這裡介紹兩種建立方式,
1.餓漢式單例(立即載入方式)
// 餓漢式單例publicclass Singleton1 {
// 私有構造private Singleton1() {}
privatestaticSingleton1 single =new Singleton1();
// 靜態工廠方法publicstatic Singleton1 getInstance() {
return single;
}
}
2.懶漢式單例(延遲載入方式)
publicclass Singleton3 {
// 私有構造private Singleton3() {}
privatestaticSingleton3 single =null;
publicstatic Singleton3 getInstance() {
// 等同於 synchronized public static Singleton3 getInstance()synchronized(Singleton3.class){
// 注意:裡面的判斷是一定要加的,否則出現執行緒安全問題if(single ==null){
single =new Singleton3();
}
}
return single;
}
}