傳智播客-劉意-java深入淺出精華版學習筆記Day07
成員變數和區域性變數的區別:
成員變數:類中方法外
堆記憶體中
隨著物件的建立存在
隨著物件的消失而消失
有預設初始化值
區域性變數:方法定義中或者方法宣告上
棧記憶體中
隨著方法的呼叫而存在
隨著方法呼叫完畢而消失
沒有預設初始化值,必須定義賦值,然後才能使用(error:可能未初始化變數)
【注意:區域性變數名稱可以和成員變數名稱一樣,在方法中使用的時候,採用的是就近原則】
形式引數是類名的時候如何呼叫:
上節課中我們提到,基本型別中,形式引數的改變不影響實際引數,引用型別中要影響。
引用型別包括類、介面和陣列。
在上面這個demo中,studentdemo建立了method方法,這個方法的形參是student型別的,形參名是s。
下面我們在main方法中呼叫這個studentdemo類。
如果你看到了一個方法的形式引數是一個類(引用型別),這裡需要的其實是該類的物件。
匿名物件:
沒有名字的物件。
【物件的的確確被建立了,但是它沒有名字,我們也不知道它的成員變數和方法名在堆記憶體中的地址。】
匿名物件的應用場景:
1. 僅僅只呼叫一次類中的方法的時候,呼叫方法。【newStudent().show();】
這種情況下,匿名物件 呼叫完畢就是垃圾,馬上就可以被回收了。如果我只要這麼一個方法,那麼我就拿出來用一下,就可以扔了。也就是我們俗話說的【撈一筆就跑】。
2. 匿名物件可以作為引數傳遞。比如作為引數傳給上面的方法。
多個匿名物件聯動,一個呼叫一次方法,一個作為引數傳遞。
【看懂即可,一般我們不會主動用這個玩意】
封裝:隱藏物件的屬性和實現細節,僅對外提供公共訪問方式。
被private修飾的成員只能在本類中訪問,不能在物件/其他類訪問。
比如說一個student類中,我把成員變數age設為private,設一個public方法set_age來設定age,這樣在物件中我就只能通過方法來設定age。
封裝隱藏了實現細節(不給你訪問),提供公共的訪問方式,提高了程式碼的複用性和安全性。
【就像膝上型電腦的後蓋】
private關鍵字:許可權修飾符,修飾成員變數和成員方法。被其修飾的成員只能在本類中被訪問。只有自己所在的類(中的方法)可以訪問自己。物件都不行。
private標準應用格式:把成員變數用private修飾,提供對應的getXxx和setXxx用法。
this關鍵字的概述和應用:
如果成員變數和區域性變數重名了,會發生什麼事?我們之前說過,變數的使用規則是就近原則,如果重名了,就好像是把自己賦給自己,賦值這個過程無法進行。
所以,需要對name進行限定。
限定的方法:對成員變數用this關鍵字限定。
為了實現在set和get方法中也能見名知意,我們要求採用同樣的命名,也就是要求要用this這個關鍵字。
this是當前類的物件的引用。
誰呼叫這個方法,this就代表誰!
【不過注意,如果沒有和成員變數重名的區域性變數,在方法中呼叫成員變數是不需要用this的。就算是按照就近原則,最近的也是成員變數】
構造方法:
回憶建立物件的格式:
Student s = new Student()
沒有括號的叫變數,有括號的叫方法。
所以,Student()這就是個方法。也就是,我寫Student()時,我實際上時呼叫了一個方法。
這就是Student類中的構造方法。在我寫出這一句時,這個方法被呼叫了。
構造方法:給物件的資料進行初始化
格式:
方法名與類名相同;沒有返回值,連void值都沒有;沒有具體的返回值
構造方法的注意事項:
1. 如果我們沒有給出構造方法,系統將自動提供一個無參構造方法。
2. 如果我們給出了構造方法,系統將不再提供。
3. 構造方法可以帶引數,也就是我們呼叫類時,把引數寫在括號裡。
4. 構造方法可以過載,規則和之前相同,方法名相同,形式引數不同。
因此,給成員變數賦值有兩種方式:set方法和構造方法
建議永遠自己給出無參構造方法。
重新給出類的組成:成員變數/成員方法/構造方法
建立物件做了哪些事情:
圖解在記憶體中的儲存方式:
下面有一段非常精彩的關於“什麼時候定義成員變數”的課,但是太長了,直接複製講義過來了。
/*
定義一個類Demo,其中定義一個求兩個資料和的方法,
定義一個測試了Test,進行測試。
變數什麼時候定義為成員變數:
如果這個變數是用來描述這個類的資訊的,那麼,該變數就應該定義為成員變數。
變數到底定義在哪裡好呢?
變數的範圍是越小越好。因為能及時的被回收。
*/
//方式1
/*
class Demo {
public int sum() {
int a = 10;
int b = 20;
int c = a + b;
return c;
}
}
*/
//方式1滿足了我們的要求,但是不好。
//因為參與操作的資料現在是固定的。
//方式2
/*
class Demo {
public int sum(int a,int b) {
return a + b;
}
}
*/
//方式2可以滿足我們的要求,但是呢我們學習過來面向物件的思想。
//我就再想,a,b可不可以定義為成員變數呢?
//如果可以,我們再改進一版
class Demo {
int a;
int b;
public int sum() {
return a + b;
}
}
//雖然這種方式可以,並且好像是符合了面向物件的思想。
//但是不好。
//因為我們曾經說過:類是一組相關的屬性和行為的集合。
//並且類是通過事物轉換過來的
//而類中的成員變數就是事物的屬性
//屬性是用來描述事物的
//同理:成員變數其實是用來描述類的。
//測試類
class Test {
public static void main(String[] args) {
//建立物件
//方式1測試
/*
Demo d = new Demo();
System.out.println(d.sum());
*/
//方式2測試
/*
Demo d = new Demo();
int a = 10;
int b = 20;
System.out.println(d.sum(a,b));
*/
//方式3測試
Demo d = new Demo();
d.a = 10;
d.b = 20;
System.out.println(d.sum());
}
}
static關鍵字:
當多個物件有共同的成員變數值時,java就提供了一個關鍵字來修飾:static
當一個類中的成員變數被定義為static時,所有該類的物件共享同一個值。
特點:
1. 隨著類的載入而載入。(比如跟著Demo類一起出現的main方法)
2. 優先於物件存在。(物件在new的時候才出現)
3. 被類的所有物件共享。(例子:所有人共用飲水機,但是不能共用水杯)
5. 可以通過類名呼叫。其實它本身也可以通過物件名呼叫。(反正都是一樣的)
【為什麼main方法是靜態的?因為它是被虛擬機器呼叫的。畢竟main方法所在的類,沒有物件】
推薦使用類名呼叫。
靜態修飾的內容我們一般稱其為:與類相關的類成員。
記憶體的分配方法:方法區中專門有一個靜態區,載入方法的時候同時載入進來。
記憶體圖解:
static關鍵字注意事項:
這一塊也很精彩,直接複製講義了
對於第一點,沒有this關鍵字的意思,其實是不能訪問非靜態的成員變數。
所以第二點和第二點是一樣的。
/*
static關鍵字注意事項
A:在靜態方法中是沒有this關鍵字的
如何理解呢?
靜態是隨著類的載入而載入,this是隨著物件的建立而存在。
靜態比物件先存在。
B:靜態方法只能訪問靜態的成員變數和靜態的成員方法
靜態方法:
成員變數:只能訪問靜態變數
成員方法:只能訪問靜態成員方法
非靜態方法:
成員變數:可以是靜態的,也可以是非靜態的
成員方法:可是是靜態的成員方法,也可以是非靜態的成員方法。
簡單記:
靜態只能訪問靜態。
*/
class Teacher{
public int num = 10;
public static int num2 = 20;
public void show() {
System.out.println(num); //隱含的告訴你訪問的是成員變數
System.out.println(this.num); //明確的告訴你訪問的是成員變數
System.out.println(num2);
//function();
//function2();
}
public static void method() {
//無法從靜態上下文中引用非靜態變數 num
//System.out.println(num);
System.out.println(num2);
//無法從靜態上下文中引用非靜態方法 function()
//function();
function2();
}
public void function() {
}
public static void function2() {
}
}
classTeacherDemo {
public static void main(String[] args) {
//建立物件
Teacher t = new Teacher();
t.show();
System.out.println("------------");
t.method();
}
}
為什麼main方法是靜態的:
public static void main(String[] args){…}
public:訪問許可權最大(因為要被jvm呼叫)
static:可以通過類名來呼叫,不需要建立物件
void:沒有返回值(返回給jvm沒有意義)
main:約定的程式開始的地方
String[] args:這是一個字串陣列。事實上,它是一個確實存在的、長度為零的、啥也沒有的陣列。
【事實上,這個東西早期是為了接收鍵盤錄入的資料的。這個用法已經廢棄了,成為了一種約定俗成的習慣。】