轉-Java基礎深入解析——類與對象
轉自CSDN博客,u010425776,http://m.blog.csdn.net/u010425776/article/details/46932867
成員變量與局部變量的區別
1.成員變量定義在類中,整個類中都能夠訪問。
局部變量定義在局部代碼塊中,只能在局部代碼塊中訪問。
2.成員變量存在於堆內存中,有初始值。
局部變量存在於棧內存中,沒有初始值。
PS:成員變量分為靜態成員變量和非靜態成員變量,非靜態成員變量存在堆內存中,靜態成員變量存在靜態方法區中。
靜態方法區只存靜態成員變量;
非靜態方法區存類和函數的代碼;
堆內存只存非靜態成員變量(就是對象);
棧內存只存局部變量;
3.成員變量隨著對象的創建而創建,隨著對象的消失而消失
局部變量隨著局部代碼塊的出現而出現,隨著局部代碼塊的結束而消失。
註:類就相當於一個手機模板,對象是這個模板創造出來的一個個手機,而且每個手機(對象)中的數據都是獨立存在的,即在堆內存中有各自的空間,互不影響。
匿名對象
1.定義:new Car();
2.使用場景
a) 當只需要對一個對象進行一次方法調用時使用,如:
newCar().run();
//用完就找不到這個對象了,這個對象就變成垃圾
b) 當做函數的實際參數進行傳遞,如:
run(new Car());
//這個對象不會變成垃圾,函數中必有一個引用類型的變量接收它
封裝成員變量
1.實現方法
a) private int age;//在成員變量前加上private
b) public void setAge(int age){
if(age>=0&&age<=120)
this.age= age;
else
System.out.println(“年齡不符合要求!”);
}
public int getAge(){
return this.age;
}
2.封裝成員變量的好處
對給成員變量賦值操作進行限定,在set方法中增加if語句,當輸入非法數據時可以提示用戶,從而提升了安全性。
對於只需要訪問的成員變量就只提供get
註:1.private是權限修飾符,只能用於修飾成員變量和成員函數,不能用於修飾局部變量!
2.封裝是一個範圍大的概念,只要把實現細節裝起來,用戶只要知道如何使用就是封裝。而私有是封裝的一種體現,私有一定是封裝,而封裝不一定非要私有。比如:類、函數都是封裝,這個函數、這個類可以是對外開放的,但用戶無需知道其中的實現細節,只要知道怎麽用就行了,這就是封裝。
構造函數
1.特點
a) 構造函數的名字與類名一致
b) 構造函數沒有返回值
2.作用
構造函數是用來給對象進行初始化(即創建對象的時候就給對象中的成員變量一些初始化值)
註:Person person = new Person();
new Person()其實就是調用構造函數Person()。
3.默認構造函數
在一個類中若沒有定義構造函數,編譯器會自動加一個默認構造函數:public Person(){}
在一個類中若有構造函數,就沒有默認構造函數。
4.構造函數與一般函數的區別
a) 構造函數是在對象創建時被調用,一個對象只能調用一次構造函數,用於給對象的成員變量進行初始化的賦值。
b) 一般函數是在對象被創建之後才能被調用,可以被多次調用。
5.何時使用構造函數
若某一事物已存在就需要具備一些內容,則這些內容通過構造函數傳遞給成員變量。
6.構造函數的重載
與普通函數重載一致,函數名相同,形式參數個數不同or形式參數類型不同。
7.構造函數的內存分配過程
Person p2 = new Person(“小強”,10);
p2.speak();
1.執行main函數:main函數進入棧內存
2.Person p2:main的方法棧中創建引用類型的變量p2
3.new Person:在堆內存中創建Person類型的對象,並將name和age賦上初始化值null、0
4.new Person(“小強”,10):找到構造函數Person,將其壓入棧內存,並創建局部變量n、a,並完成賦值:n=小強,a=10。
5.=:將構造函數Person中n、a的值賦給剛才的對象
最後將對象的首地址賦給p2,結束對象的構造。
註意:
a)函數中的局部變量進的是棧內存(構造函數也不例外),而對象中的成員變量進的是堆內存。
b)對象首先被初始化,且值都是默認值,然後再在棧內存中創建構造函數並進行賦值操作。最後將棧內存中構造函數的局部變量值賦給剛才的那個對象的成員變量。
c)棧內存中的構造函數尋找它所對應的對象是通過this指針。
8.有了帶參的構造函數是否還需要set方法?
需要。構造函數只能在對象初始化的時候給對象中的成員變量進行一次賦值,創建完對象之後就不能再賦值了;若今後需要修改對象中的成員變量,就需要用set方法。
9.能否在成員函數中調用構造函數?
不行!構造函數只能在初始化對象的時候調用,其他任何情況都不能使用。
10.構造函數是否有return?
有!任何一個函數中都有return,只不過若函數沒有返回值的話可以不寫return,編譯器自動加上“return;”。構造函數是可以寫的,不過只能是return;表示中斷方法而不返回值。
11.構造代碼塊
a) 定義:{}
b) 位置:類之中,函數之外。
c) 特點:創建對象時被執行,而且每創建一個對象被執行一次。
d) 作用:若一個類的多個構造函數中有相同的操作,那麽把這些操作抽取出來放在構造代碼塊中,每次創建對象都會被執行,從而提高了代碼的復用性。
e) 註:構造代碼塊是在創建對象時被執行,而且先於構造函數執行。
f) 構造函數執行次序
i. 進入構造函數
ii. 執行super,即進入父類構造函數
iii. 對本類成員變量顯式初始化
iv. 執行本類構造代碼塊
v. 執行super之後的語句
註:局部代碼塊、靜態代碼塊、構造代碼塊的區別是什麽?
1.位置
a) 局部代碼塊處在函數中
b) 靜態代碼塊、構造代碼塊處在類之中、函數之外。
2.生命周期不同
a) 局部代碼塊:函數被調用時執行,執行完自動釋放內存。
b) 靜態代碼塊:類被加載的時候執行,執行完之後自動釋放內存。
c) 構造代碼塊:對象被創建的時候執行,類消失才消失。
3.各自特點
a) 局部代碼塊:在函數中只執行一次,執行完自動銷毀。
b) 靜態代碼塊:類被加載之後立即執行一次,執行完自動銷毀。
c) 構造代碼塊:對象被創建的時候先於構造函數執行,而且執行完後仍然保存在內存中,對象被創建一次它就執行一次。
4.各自作用
a) 局部代碼塊:是得程序員手動控制局部變量的生命周期,從而能夠節約內存。
b) 靜態代碼塊:為全是靜態成員變量的類初始化。
c) 構造代碼塊:把同一個類中多個構造函數中通用的操作放在其中,從而提升代碼復用率。
this關鍵字
1.定義
this是當前函數所屬對象的引用。
註:
a) this一定在函數中。
b) this是棧內存中的函數中的局部變量與堆內存中的對象的橋梁。函數中的this就代表了當前這個函數所屬的對象。
2.this內存過程
Person p = new Person(“旺財”);
a) main函數全部代碼存入方法區,依次執行main中代碼。
b) Person p:在main方法棧中創建引用類型變量p
c) new Person:在堆內存中創建對象,且在對象中創建成員變量,並給成員變量賦上初始值null、0。
d) new Person(“旺財”):將構造函數Person所有代碼壓入方法區,在Person函數對應的方法棧中創建局部變量name,並同時還創建了這些局部變量所屬對象的this指針。(此時,棧內存中的Person的局部變量們與堆內存中的對象便有了橋梁,連接在了一起。)
e) Person(name){this.name=name}
在Person構造函數中,將局部變量name賦給對象中的name。
f) 最後將對象的首地址賦給棧內存中的p。
g) p.speak():調用speak函數,則該函數的全部代碼進入方法區,由於是對象調用函數,對象會給函數添加一個this指針,表示方法區中的這個函數屬於堆內存中的對象。
3.構造函數間的調用過程
a) 在一個構造函數中調用另一個構造函數:this(參數);Person(Stringname){
this.name= name;
}
Person(Stringname,int age){
this(name);//調用第一個構造函數
this.age= age;
}
b) 內存過程
c) 構造函數的相互調用時要用到this(XXX),這句話一定得是構造函數的第一句話,否則報錯。
static關鍵字
1.特點
a) static用於修飾類中的成員變量和成員函數,修飾完之後是被類所產生的所有對象共享。
b) 靜態成員存在於類中,類存在之後,靜態成員也便存在。因此,先出現類,再出現靜態成員,最後出現對象。
2.靜態成員的調用
類名.成員名
3.靜態變量與成員變量的區別
a) 生命周期不一樣。
靜態變量隨著類的產生而產生,隨著類的消失而消失。
PS:程序一執行就把main函數所在的類加載到內存裏(其他類的進入內存是在new一個對象時或類名.xxx時),因此靜態變量也在這個時候被創建;JVM停止類才消失,從而靜態變量才消失。
成員變量隨著對象的產生而產生,隨著對象的消失而消失。
b) 調用方式不一樣。
成員變量只能被對象調用;
靜態變量既可以被對象調用,又可以被類名調用。
c) 別名不一樣。
成員變量=實例變量
靜態變量=類變量
d) 存儲位置不一樣。
成員變量存儲在堆內存中(是屬於對象的特有數據);
靜態變量存儲在方法區(==共享數據區)的靜態區(是所有對象的共享數據)
PS:糾正一個錯誤:堆內存只存對象(非靜態成員變量),棧內存只存局部變量,而局部變量所屬的函數不放在棧內存中,函數都放在方法區!方法區=共享數據區。
4.內存終極版(to be continue…)
PS:糾正:類何時被加載?主函數所屬的類是在程序開始執行的時候被加載進內存,而其余的類是在執行到的時候才被加載進內存!
5.靜態函數何時使用?
就看一點,只要函數中使用到了某一對象特有的數據,就只能使用普通函數了;若函數中沒有使用到某一對象的特有數據,則靜態函數和非靜態函數都可以使用。
6.靜態代碼塊
1.定義
static{}
2.作用
隨著類的創建而執行,而且就在類被創建的時候執行一次。
用於給全是靜態成員的類進行初始化值。
PS:
a)Person p = new Person()這種方式叫做:通過構造函數初始化類,並創建一個對象。
b)一個類要是全是靜態成員,它沒有必要通過構造函數初始化,通過靜態代碼塊初始化即可。
主函數的解析
1.主函數與普通函數的區別
a) 主函數格式固定不變。
b) 主函數被JVM調用,而普通函數被程序員調用。
2.public
主函數要給JVM訪問,因此得公有。
3.static
主函數是個靜態函數,不需要創建對象就能夠訪問。
運行程序時我們輸入命令“java 類名”,然後虛擬機直接執行“類名.main”。
4.void
主函數不需要返回值,沒必要把執行結果返回給JVM。
5.String[]args
這是主函數的形式參數,是一個String類型的數組。
a) 幹嘛用?
執行main函數的時候可以往裏面傳入一些值
b) 怎麽用?
在DOS中運行程序時:
java類名參數1 參數2 參數3……
註:args是形式參數名,一個函數的形式參數名可以隨便改。
javadoc的使用
javadoc -d [存放的目錄] -auther-version XXX.java。
XXX.java這個類必須得是public。
只有/** */這樣的註釋才會被解析。
單例設計模式
1.設計模式是什麽?
是解決問題的一種思想,任何語言都可以使用。
2.單例設計模式是什麽?
保證一個類在整個電腦的內存中只有一個對象。
3.何時使用單例設計模式?
比如,我們可以把軟件的配置信息加載到一個類中進行讀寫操作,此時這個配置信息的對象只能有一個,這樣才能保證不同的地方讀寫配置信息的時候是對同一個配置信息進行操作的。
4.解決辦法?
a) 不允許其他程序new該類的對象
b) 在該類創建一個本類的實例
c) 對外提供一個方法,讓其他程序能通過這個方法來獲取這個實例。
5.程序實現
PS:創建對象只能通過構造函數實現,如果構造函數是private,則在這個類之外就不能創建對象了。
a) 為了其他程序無法new本類對象,將本類構造函數私有化。
b) 自己在類中new一個對象。
c) 對外提供一個共有方法來提供這個對象。
class Single{
private static Single s = new Single();
private Single(){}
public static Single getInstance(){
returns;
}
}
class Test(){
public static void main(){
//獲取同一個對象!
Singles1 = Single.getInstance();
Singles2 = Single.getInstance();
}
}
註:單例模式中外界只能通過公有函數getInstance()來獲取對象,而訪問類中的公有方法有兩種途徑,一種是構造對象,通過對象調用;一種是類名.函數名。由於單例模式中構造函數已經被私有化,因此無法通過new來創建對象來調用getinstance,只能通過靜態調用,因此,getInstance必須是static,從而getInstance中的Single對象也必須是static。
6.內存圖解
7.單例第二種實現方式(懶漢式=延遲加載形式)
class Single{
private static Single s = null;//類初始化時對象不加載
private Single(){}
public static Single getInstance(){
if(s==null)
//調用getInstance時再創建對象
returns = new Single();
}
}
第一種方式:餓漢式,類一被加載對象就被創建。
第二種方式:懶漢式,調用getinstance時對象才被創建。
註:效率其實差不多,因為不管什麽時候創建對象,這個對象在內存中就只有一個,小的忽略不計,一般都選第一種。
第二種方式在多線程中會有問題!
包的概述
1.包在文件系統中就是文件夾。
2.同一個文件夾下不能有重名的文件,因此用包來區分。
3.包的定義寫在類文件的第一行:
package 包名1.包名2
4.包也是一種封裝的形式。
5.編譯含有包的.java文件
javac -d . 類名.java
-d:編譯前根據包名自動地創建文件夾。
“.”:表示當前目錄,即在當前目錄下根據包名創建文件夾,然後再編譯.java文件。
6.運行含有包的類文件.class
java 包名1.包名2.類名
包的權限?
1.在一個包中要訪問另一個包的成員函數的話,被訪問成員函數和其所在的類必須是public。
註:public修飾的類的類名必須和該類所在的文件名一致。
2.被protected修飾類,能被本包的類訪問,不能被其他包的類訪問,但被protected修飾的類的子類在其他包中,這些子類可以訪問父類。
|
public |
protected |
default |
private |
同一類中 |
OK |
OK |
OK |
OK |
同一包不同類 |
OK |
OK |
OK |
|
子類中(不論是否在同一包中) |
OK |
OK |
|
|
不同包中 |
OK |
|
|
|
包的導入?
在包頂一下寫:
1.導入特定包下的特定類
import 包名1.包名2.包名3.類名;
2.導入特定包下所有的類
import 包名1.包名2.包名3.*;
註:只導入 包名1.包名2.包名3中的所有類文件,若裏面還有子包則不導入。
3.一般用到哪個類導入哪個類,不用通配符導入。
把項目打包成Jar文件?
使用JDK/bin/Jar工具。
輸入“jar”查看幫助。
“jar -cf 文件名.jar 需要放入jar包的包名”
為什麽要把項目打包成Jar文件?
Jar包實質上給項目又多加了一層目錄,而且Jar無需解壓可以直接調用裏面的類。
第三方工具包都是Jar包的形式,我們拿到後只要把Jar包所在的路徑配置到classpath中去之後,我們就可以直接調用Jar包中內容了。
轉-Java基礎深入解析——類與對象