引用類型變量java
爲了可以對實例化的對象進行訪問控制,需一個特殊的變量,即引用。對引用有兩點須要說明: 1. 引用類型變量能夠存儲該類對象的地址信息,一般稱爲「指向該類的對象」,當一個引用類型變量指向該類的對象,就能夠經過這個變量對對象實施訪問。 2. 除8種基本類型以外,用類、接口、數組等聲明的變量都稱爲引用類型變量,簡稱「引用」。
null和NullPointerException程序員
須要注意:當一個引用的值爲null的時候,若是經過引用訪問對象成員變量或者調用方法是不合邏輯的(因其沒有指向某對 象,天然不會有屬性和方法)。此時,會產生NullPointerException(空指針異常)。
方法的重載數組
方法的簽名安全
方法的簽名包含以下兩個方面:方法名和參數列表。 Java語法規定,一個類中不能夠有兩個方法簽名徹底相同的方法,即:一個類中不能夠有兩個方法的方法 名和參數列表都徹底相同,可是,若是一個類的兩個方法只是方法名相同而參數列表不一樣,是能夠的。
方法重載及其意義數據結構
在Java語言中,容許多個方法的名稱相同,但參數列表不一樣,此種方式稱爲方法的重載(overload)。函數
構造方法this
構造方法語法結構操作系統
構造方法是在類中定義的方法, 但不一樣於其餘的方法,構造方法的定義有以下兩點規則:線程
經過構造方法初始化成員變量指針
this關鍵字的使用
this指代當前對象
默認的構造方法
JAVA語法規定,任何一個類都必須含有構造方法,假如源程序中沒有定義,則編譯器在編譯時將爲其添加 一個無參的空構造方法(此方法稱之爲「默認的構造方法」)
構造方法的重載
不少時候,爲了使用的方便,能夠對一個類定義多個構造方法,這些構造方法都有相同的名稱(類名),只是方法的參數不一樣,稱之爲構造方法的重載。 在建立對象時,Java編譯器會根據不一樣的參數調用來不一樣構造方法
引用類型數組
數組是對象
在java中,數組屬於引用數據類型,數組對象存放在堆中存儲,數組變量屬於引用類型,存儲數組對象的地址信息,指向數組對象。 而數組的元素能夠當作數組對象的成員變量(只不過類型所有相同)
引用類型數組的聲明
剛剛聲明的數組爲基本類型數組,除了基本類型數組之外,也能夠聲明引用類型數組。所謂引用類型數組,即數組元素的類型不是基本類型(int,char,float。。) , 而是引用類型,看以下代碼:
Cell [ ] cells = new Cell [ 4 ] ;
其內存分配以下圖
從上圖示能夠看出,new Cell[4]實際是分配了4個空間用於存放4個Cell類型的引用,並賦初始值爲null,而並不是是分配了4個Cell類型的對象。
引用類型數組的初始化
若是但願每個元素都指向具體的對象,則須要針對每個數組元素進行「new」運算。與基本類型數組同樣,也能夠採用靜態初始化的方式進行初始化操做。以下代碼所示:
Cell[ ] cells = new Cell[4]; cells[0] = new Cell(0,4); cells[1] = new Cell(1,3); cells[2] = new Cell(1,4); cells[3] = new Cell(1,5);
等價於:
Cell[ ] cells = new Cell[ ] { new Cell(0,4) , new Cell(1,3) , new Cell(1,4) , new Cell(1,5) } ;
如上數組內存分配圖以下圖– 6 所示:
數組的類型是基本類型數組
int [ ][ ] arr = new int[3][ ]; arr[0] = new int[2]; arr[1] = new int[3]; arr[2] = new int[2]; arr[1][1] = 100; 分析如上代碼能夠看出,變量arr指向一個數組,該數組有三個元素,每一個元素都是int類型數組,長度分別爲 2,3,2,arr[1][1]=100表示將arr數組中的第2個元素(數組)的第2個元素賦值爲100, 其內存分配如圖所示:
對象內存管理
堆內存
對象存儲在堆中
JVM在其內存空間開闢了一個稱爲「堆」的存儲空間,這部分空間用於存儲使用new關鍵字所建立的對象。請看以下代碼:
Cell c = new Cell ();
其內存分佈如圖所示:
從圖中能夠看到右側的堆內存,new Cell()所建立的對象在堆中分配,同時成員變量亦在此分配,並賦初始值爲零。引用類型變量c在棧內存中分配,其中保存的數據,爲對象在堆內存中的地址信息,假設對象在堆內存的地址爲40DF,則c中保存的便是40DF。
成員變量的生命週期
當聲明好對象以後,對該對象(堆中的Cell)的訪問須要依靠引用變量(棧中的c),那麼當一個對象沒有任 何引用時,該對象被視爲廢棄的對象,屬於被回收的範圍,同時該對象中的全部成員變量也隨之被回收。 能夠這樣認爲,成員變量的生命週期爲:從對象在堆中建立開始到對象從堆中被回收結束。 Cell c = new Cell(); c = null ; 當將c賦值爲null時,表示c再也不指向剛剛分配的對象空間,此時成員變量失效。
垃圾回收機制
Java程序的內存泄漏問題
System.gc()方法
非堆---棧
棧用於存放方法中的局部變量
JVM在其內存空間開闢一個稱爲」棧」的存儲空間,這部分空間用於存儲程序運行時在方法中聲明的全部的局部變量,例如,在main方法中有以下代碼:
Cell c = new Cell ( ); int num = 5;
其內存分配如圖所示:
說明:方法中的變量即爲局部變量,是在棧內存中分配,若變量爲值類型,則在棧中存儲的就是該變量的值。若變量爲引用類型,則在棧中存儲的是堆中對象的地址。
局部變量的生命週期
成員變量和局部變量
成員變量與局部變量的差異以下: 局部變量: 1) 定義在方法中; 2) 沒有默認值,必須自行設定初始值; 3) 方法被調用時,存在棧中,方法調用結束時局部變量從棧中清除; 成員變量: 1) 定義在類中,方法外; 2) 由系統設定默認初始值,能夠不顯式初始化; 3) 所在類被實例化後,存在堆中,對象被回收時,成員變量失效;
非堆---方法區
方法區用於存放類的信息
方法區用於存放類的信息,Java程序運行時,首先會經過類裝載器載入類文件的字節碼信息,通過解析後將其裝入方法區。類的各類信息(包括方法)都在方法區存儲,看以下代碼:
Cell c = new Cell();
程序在執行這句話時,Cell類首先被裝載到JVM的方法區,其中包括類的基本信息和方法定義等,以下圖– 3 所示:
經過圖示能夠看出,在方法區中,包含Cell類的字節碼文件,及類的基本信息及方法drop等。
方法只有一份
當類的信息被加載到方法區時,除了類的類型信息之外,同時類內的方法定義也被加載到方法區;
類在實例化對象時,多個對象會擁有各自在堆中的空間,但全部實例對象是共用在方法區中的一份方法定義的。意味着,方法只有一份。看以下代碼:
JFrame f1 = new JFrame(); JFrame f2 = new JFrame(); f1.setSize(200, 300); f2.setSize(300,400);
如上的代碼中,對象有兩個,可是setSize方法只有一份,分別針對f1指向的對象和f2指向的對象調用了兩次。
繼承
泛化的過程
extends關鍵字
繼承中構造方法
父類引用指向子類的對象
一個子類的對象能夠向上造型爲父類的類型。
重寫
方法的重寫
重寫中使用super關鍵字
在子類重寫的方法中,能夠經過super關鍵字調用父類的版本
重寫和重載的區別
重載與重寫是徹底不一樣的語法現象,區別以下所示: · 重載: 是指在一個類中定義多個方法名相同但參數列表不一樣的方法,在編譯時,根據參數的個數和類型來決定綁定哪一個方法。 · 重寫: 是指在子類中定義和父類徹底相同的方法,在程序運行時,根據對象的類型(而不是引用類型)而調用不一樣的方法。 分析以下代碼的輸出結果: class Super { public void f() { System.out.println ("super.f()"); } } class Sub extends Super { public void f() { System.out.println ("sub.f()"); } } class Goo { public void g(Super obj) { System.out.println ("g(Super)"); obj.f(); } public void g(Sub obj) { System.out.println ("g(Sub) "); obj.f(); } } class Test{ public static void main(String[] args){ Super obj = new Sub(); Goo goo = new Goo(); goo.g(obj); } } 首先,重載遵循所謂「編譯期綁定」,即在編譯時根據參數變量的類型判斷應該調用哪一個方法, 由於變量 obj爲Super類型引用, 因此,Goo的g(Super)被調用,先輸出g(Super)。 重寫遵循所謂「運行期綁定」,即在運行的時候,根據引用變量所指向的實際對象的類型來調用方法,由於 obj實際指向的是子類Sub的對象,所以,子類重寫後的f方法被調用,即sub.f()。
包的概念
package語句
在Java語言中,命名衝突問題是用包(package)的概念來解決的,也就是說,在定義一個類時,除了定義類的名稱通常還要指定一個包的名稱,定義包名的語法以下所示:
package 包名;
須要注意的是,在定義包時,package語句必須寫在Java源文件的最開始處,即在類定義以前,以下面的語句將爲Point類指定包名爲「test」:
package test; class Point{ …… }
在命名包名時,包名能夠有層次結構,在一個包中能夠包含另一個包
import語句
能夠經過import語句對類的全稱進行聲明,import語句的語法以下所示:
import 類的全侷限定名(即包名+類名);
有時,在import語句中也可使用「*」符號,例如:
import org.whatisjava.core.*;
訪問控制修飾符
封裝的意義
假設有水果店賣水果,分兩種方式進行管理,方式一爲須要店員,由店員實現取水果、包裝、找零等功 能。方式二爲不須要店員,由顧客自行完成取水果、包裝、找零等功能。 那麼想想,哪種方式更適合管理呢?通常認爲方式一更適合,由於方式二沒有人來進行管理,安全性 較低,除非來的都是活雷鋒,徹底靠自覺。而方式一的安全性更高一些,並不是任何人均可以操做水果。 在軟件系統中,經常經過封裝來解決上面的問題。即:將容易變化的、具體的實現細節(賣水果)封裝起 來,外界不可訪問,而對外提供可調用的、穩定的功能(店員),這樣的意義在於: 1. 下降代碼出錯的可能性,更便於維護。 2. 當內部實現細節改變時,只要保證對外的功能定義不變,其餘的模塊不須要更改。 在軟件系統中,封裝經常須要依靠一些訪問控制修飾符來實現。
訪問控制修飾符修飾類
訪問控制符修飾成員
4種訪問修飾(public、private、protected、默認),均可以修飾成員,其權限以下圖所示
public 修飾符,在任何地方均可以訪問;protected能夠在本類、同一包中的類、子類中訪問,除此以外的其它類不能夠訪問;默認方式爲能夠本類及同一包中的類訪問,除此以外其它類不能夠訪問;private只能夠在本類中訪問,其它任何類都不能夠。
static關鍵字
static修飾成員變量
static修飾方法
static塊
static塊爲屬於類的代碼塊,在類加載期間執行的代碼塊,只執行一次,能夠用來在軟件中加載靜態資源(圖像、音頻等等)。
final關鍵字
final修飾變量
final關鍵字修飾變量,意爲不可改變。final能夠修飾成員變量,也能夠修飾局部變量,當final修飾成員變量時,能夠有兩種初始化方式:
final關鍵字修飾局部變量,在使用以前初始化便可。
final修飾方法
final關鍵字修飾的方法不能夠被重寫。使一個方法不能被重寫的意義在於:防止子類在定義新方法時形成的「不經意」重寫。
final修飾類
final關鍵字修飾的類不能夠被繼承。使一個類不能被繼承的意義在於:能夠保護類不被繼承修改,能夠控制濫用繼承對系統形成的危害。在JDK中的一些基礎類庫被定義爲final的,例如:String、Math、Integer、Double 等等。
static final常量
static final 修飾的成員變量稱爲常量,必須聲明同時初始化,而且不可被改變。常量建議全部字母大寫。
實際應用中應用率較廣,由於static final常量是在編譯期被替換的,能夠節約沒必要要的開支,以下代碼演示了static final的用法:
class Foo { public static final int NUM = 100; } class Goo { public static void main(String[] args) { Sytem.out.println(Foo.NUM); // 代碼編譯時,會替換爲:System.out.println(100); } }
說明:static final常量Foo.NUM會在編譯時被替換爲其常量值(100),在運行Goo類時,Foo類不須要被載入。這樣減小了沒必要要的開支。
使用抽象類
抽象方法和抽象類
抽象類不能夠實例化
繼承抽象類
抽象類的意義
定義抽象類的意義在於: 1. 爲其子類提供一個公共的類型(父類引用指向子類對象); 2. 封裝子類中的重複內容(成員變量和方法); 3. 定義有抽象方法,子類雖然有不一樣的實現,但該方法的定義是一致的。(子類須要實現此抽象方法)。
使用接口
定義一個接口
接口能夠當作是特殊的抽象類。即只包含抽象方法和常量的抽象類。能夠經過interface關鍵字來定義接口。看以下代碼:
interface Runner { public static int DEFAULT_SPEED = 100 public void run(); }
注意,run()方法,此處能夠省略public abstract。因其默認就是public abstract的。
實現接口
接口的繼承
接口間能夠存在繼承關係,一個接口能夠經過extends關鍵字繼承另一個接口。子接口繼承了父接口中定義的全部方法
接口和抽象類的區別
多態
多態的意義
// 前面所講解的現象就是多態,多態即多種形態,主要有兩個方面的表現。 // 首先,一個類型的引用在指向不一樣的對象時會有不一樣的實現,看以下的代碼: 達內職員 emp1 = new 達內講師(); 達內職員 emp2 = new 達內項目經理(); emp1.完成工做(); emp2.完成工做(); // 一樣是達內職員類型,當指向不一樣的對象時,能夠有不一樣的表現。 // 其次,一樣一個對象,造型成不一樣的類型時,會有不一樣的功能,看以下代碼所示: 達內講師 teacher = new 達內講師(); 企業技術顧問 consultant = teacher; 技術圖書做者 author = teacher; consultant.培訓員工(); author.編輯稿件(); // 經過上面的代碼,能夠看出,一樣的達內講師對象,當將其造型爲企業技術顧問及技術圖書做者時,能夠實現不一樣的功能。
向上造型
父類的引用指向子類的對象。這個現象就是下面要給你們介紹的現象,叫作向上造型。
一個類的對象能夠向上造型的類型有:父類的類型及其實現的接口類型。當發生向上造型時,Java編譯器會根據類型檢查調用方法是否匹配
強制轉型
在實際應用中,還能夠經過強制轉換將父類型變量轉換爲子類型變量,前提是該變量指向的對象確實是該子類類型。也可經過強制轉換將變量轉換爲某種接口類型,前提是該變量指向的對象確實實現了該接口。若是在強制轉換過程當中出現違背上述兩個前提,將會拋出ClassCastException。
instanceof關鍵字
在強制轉型中,爲了不出現ClassCastException,能夠經過instanceof關鍵字判斷某個引用指向的對象是否爲指定類型。
內部類
定義成員內部類
一個類能夠定義在另一個類的內部,定義在類內部的類稱之爲Inner,其所在的類稱之爲Outer;Inter 定義在Outer的內部,一般只服務於Outer,對外不具有可見性,Inter能夠直接調用Outer的成員及方法(包括私有的)。
建立內部類對象
通常狀況下,Inner對象會在Outer對象中建立(構造方法或其餘方法);Inner對象中會有一個隱式的引用指向建立它的Outer類對象。
定義匿名內部類
若是在一段程序中須要建立一個類的對象(一般這個類須要實現某個接口或者繼承某個類),並且對象建立後,這個類的價值也就不存在了,這個類能夠沒必要命名,稱之爲匿名內部類。
面向對象三大特徵:封裝、繼承、多態