三個重要概念:java
封裝app
繼承dom
多態ui
類之間的常見關係有:this
依賴(uses-a):一個類的方法操縱另外一個類的對象lua
聚合(has-a):一個類的對象包含另外一個類的對象spa
繼承(is-a):一個類是另外一個類的拓展(子集)設計
3d
在設計類時,應儘量將相互依賴的類減至最少,用軟件工程的術語來講,就是讓類的之間的耦合度最小。指針
一個對象變量(引用)並無實際包含一個對象,而僅僅存放了這個對象實體的內存地址,換句話說,任何對象變量的值都是對存儲在堆(heap)中的一個對象的引用。能夠將 Java 的對象變量看做 C++ 的對象指針(而不是 C++ 的引用),這個值能夠是 null ,代表目前沒有指向任何對象。
對引用的值進行拷貝,結果以下:
一個源文件只能有一個公有類,但能夠有任意數目的非公有類,源文件名必須與公有類的名字相同,不然沒法編譯。
關於多個源文件的編譯順序,「能夠認爲 Java 編譯器內置了 make 功能。」
不能對一個已經存在的對象調用構造器
若是沒有編寫構造器,默認的無參數構造器會將實例域設置爲默認值
一旦編寫了構造器,就再也不提供默認的無參數構造器
隱式參數是出如今實例方法名前的類對象,也就是方法調用的目標或接受者,能夠在方法內部用 this 表示,與之對應,列在方法聲明中的參數就屬於顯式參數。
不要編寫返回引用可變對象的訪問器方法,由於對這個引用進行操做會改變原有的實例。若是須要返回一個可變數據域的拷貝,應該使用 clone 方法。
一個類的方法能夠訪問這個類的私有特性,即全部對象的私有數據,而不侷限於調用它的單一對象的私有數據。
方法名以及參數類型(不包括返回類型)構成了方法的簽名(signature)。若是多個方法有相同的名字、不一樣的參數類型或順序,便產生了重載(overload),編譯器經過用各個方法給出的參數類型,與特定方法調用所使用的值類型進行匹配,挑選出相應的方法。
用 final 修飾的實例域必須在構建對象時進行初始化,在後面的操做中不能再對它進行修改,大都應用於基本(primitive)類型域,或不可變(immutable)類的域(該類中的每一個方法都不會改變其對象)。
對可變的類使用 final 修飾符可能會難以理清關係,例如:
public class Employee { private final StringBuilder evaluations; // ... Employee() { evaluations = new StringBuilder(); // evaluations 不可引用其餘 StringBuilder 對象,但能夠對當前對象的狀態進行更改: evaluations.append(str); // ... } }
在絕大多數面嚮對象語言中,靜態域被稱爲類域,由這個類的全部對象共享。
靜態方法是一種沒有隱式參數的方法,用類名進行調用(不提倡用其對象的引用),用於如下狀況:
一個方法只須要訪問類的靜態域
工廠方法(factory method)
main 方法
按引用調用(call by reference):方法接收的是調用者提供的變量地址
Java 老是按值調用,方法獲得的是參數值的拷貝,不能修改傳遞參數變量的內容。爲了說明這個問題,咱們先作一個小實驗:
public static void swap(Employee x, Employee y) { Employee temp = x; x = y; y = temp; }
Employee a = new Employee("Alice", ...); Employee b = new Employee("Bob", ...); swap(a, b); // x -> Bob, y -> Alice, a -> Alice, b -> Bob
下面兩幅圖能很好地分清「不能夠修改變量」和「能夠修改引用指向的對象」之間的不一樣:
總之,一個方法
能夠改變一個對象參數的狀態
不能讓對象參數引用一個新的對象
必須明確地初始化方法中的局部變量,但若是沒有初始化類中的域,將會被自動初始化爲默認值(0 / false / null)。
顯式的域初始化方法:
定義實例域時直接賦值
用 this 關鍵字調用另外一個構造器(節省代碼)
初始化塊
class Person { private int age; private boolean sex; private String name; private double asset; // initialization block { asset = 0; } // ... }
在一個類的聲明中,能夠包含多個代碼塊,這些塊會在構造對象時執行,運行順序先於構造器。
構建一個對象實例時,具體的處理步驟是:
按照類聲明中的次序,依次執行全部域初始化語句和初始化塊
若是構造器第一行調用了第二個構造器,執行第二個構造器主體
執行這個構造器主體
在初始化塊以前使用 static 關鍵字能夠對靜態域進行初始化,適用於沒法準確知道賦值內容的時候:
// static initialization block static { Random generator = new Random(); nextId = generator.nextInt(10000); }
類第一次加載時就會進行靜態域的初始化,全部的靜態域初始化語句、靜態初始化塊都將按照定義的順序進行。
Java 有自動的垃圾回收器(GC),不須要人工回收內存,所以 Java 不支持析構器。不過,若是對象使用了內存以外的其餘資源(好比文件),那麼當資源再也不須要時,應該將其回收和再用。能夠在類中添加 finalize 方法,它會在 GC 清除對象以前調用以回收資源。
因爲難以預料 GC 何時會清除對象,因此不要依賴 finalize 方法來回收短缺的資源。想在某個資源使用後馬上關閉,能夠在對象的方法中調用一個相應的 close 方法。
名字相同的類放置於不一樣的包中,就不會產生衝突。藉助包能夠方便組織本身的代碼,並與別人提供的代碼庫分開管理。標準的 Java 包具備一個層次結構,它們都處於 java 和 javax 包層次中。不過從編譯器的角度來看,嵌套的包之間沒有任何關係,每個包的類集合都是獨立的。
一個類可使用所屬包中的全部類,以及導入的其餘包中的公有類。 import 語句能夠導入一個特定的類或者整個包(用 *),不存在一條語句導入多個包的狀況。Java 中的 package 和 import 語句相似於 C++ 中的 namespace 和 using 指令。
前面提到過靜態導入,結合 static 關鍵字並在類名後再接上星號,就可使用指定類的靜態方法和靜態域,沒必要再加類名前綴。例如:
import static java.lang.System.*; // ... out.println("good good study"); exit(0); // ...
若是一個類、方法或變量沒有指定爲 private 或 public,則這個部分能夠被同一個包中的全部方法訪問(默認訪問權限)。對類來講,這種設計有必定的方便性,但對變量來講並不合適,有時會忘記加上修飾符,從而破壞封裝性。所以,最好記得在聲明變量時對訪問權限做出顯式標記。
對數據初始化
儘可能用類替代多個基本類型的使用
get 方法和 set 方法並不是必需
將職責過多的類進行分解
名字要體現職責
優先使用不可變的類