一、面向對象基礎apache
1.一、面向對象的定義:ide
定義了一個類就等於定義一種新的數據類型,任何類都是由靜態屬性和動態屬性表示的,函數
靜 態的屬性經過變量進行存儲(屬性、實例變量),動態的屬性經過函數表示this
(行爲、實例函數)。spa
1.1.1 經過new建立一個類的對象指針
1.1.2 經過對象.屬性名完成對屬性的定義。不能經過類.屬性。屬性都是屬於對象的。code
1.1.3 經過對象.函數名調用這個對象的方法。對象
1.二、面向對象屬性的初始化繼承
只要是屬性,JVM會自動爲其賦值。接口
對象類型默認賦值爲:String-->null,int-->0,double-->0,char-->空格,boolean-->false。
面向對象的內存模型
1.三、構造函數
構造函數存在的意義是在對象初始化時進行屬性的賦值操做。
特色:
一、名稱必須和類名徹底一致(包括大小寫);
二、不寫返回值;
三、當開發人員沒有爲類寫任何構造函數時,JVM會自動生成一個不帶參數的構造函數,在這個函數中什麼都不作。
四、當開發人員手動寫了任意一個構造函數以後,JVM就不會再生成不帶參數的構造函數了。
注意:構造函數只是在建立時使用new來調用,不能直接用對象調用。
構造函數也能夠設置參數,可是就不會產生不帶參數的構造函數,不能再使用new XXX()來建立對象。
1.四、函數重載
函數的名稱同樣可是參數不一致(類型不一致),就稱爲函數的重載。
1.五、this指針
在每個對象內部都有一個this指針指向它本身。
調用時,經過this.(點)的方式調用本身內部的屬性。
1.六、Java的內存管理
Person p1 = new Person(); p1.name = "老張"; //引用的賦值是將p1所指向的對象賦值給p2 //此時p1和p2指向同一塊內存,因此修改p2等於修改p1 Person p2 = p1; p2.name = "老李"; p1.show(); //老李 p2.show(); //老李 p1 = new Person(); //指向一塊新內存 p2 = new Person(); //指向一塊新內存 //此時name爲老李的內存就是垃圾內存,在內存不夠用時會自動清理 int a = 10; //基本數據類型的賦值 int b = a; //把a的值給b b = 30; //不會修改a的值 System.out.println(a+","+b); //10,30
1.七、對象的初始化順序
對象初始化順序
一、初始化屬性
二、調用構造方法
public class TestInit { public static void main(String[] args) { Bag bag = new Bag(); } } class Bag { /* * 對象初始化順序 * 一、初始化屬性 * 二、調用構造方法 */ Book b1 = new Book(1); public Bag() { System.out.println("bag"); } Book b2 = new Book(2); }
輸出結果:book1,book2,bag.
1.八、static關鍵字
static關鍵字所修飾的屬性或者方法都是屬於類的,而不是屬於對象的,使用類名調用
public static void main(String[] args) { Student stu1 = new Student(); stu1.name = "a"; //如下調用方式不對,雖然不會報錯 //stu1.claId = 1; //應該使用如下方法調用 Student.claId = 1; //static所修飾的變量用類名調用 Student stu2 = new Student(); stu2.name = "b"; //stu2.claId = 2; Student.claId = 2; stu1.show(); stu2.show(); } } class Student { String name; //使用static修飾的關鍵字是屬於整個類的 //因此爲static所修飾的屬性賦值或者調用方法建議使用類名調用 static int claId; public void show() { System.out.println(name+","+claId); }
其實static所聲明的屬性或者函數其實就是全局的函數。
1.九、static的初始化順序
int num = 10; public static void main(String[] args) { //這句話會報錯,由於static所修飾的屬性和方法首先會被初始化 //在初始化該方法時,尚未初始化num //num = 30; new People(); } } class People { Study s1 = new Study(1); public People() { System.out.println("people"); } //static所聲明的變量首先被初始化 static Study s2 = new Study(2); } class Study { Leaf l1 = new Leaf(1); Study(int page) { System.out.println("study["+page+"]"); } //static所修飾的變量僅僅只會初始化一次 static Leaf l2 = new Leaf(2); } class Leaf { public Leaf(int page) { System.out.println("leaf("+page+")"); } }
二、package:用來解決類名的衝突問題
2.一、package的建立
在有效代碼的第一行使用package關鍵字完成建立
當定義了一個包名以後,表示這個類必須放到包名文件夾中。
在執行程序時,僅僅會默認在當前目錄中找當前包中的類,若是但願找到其它包中的類,須要使用import導入。
2.二、import
在class以前使用import能夠導入其它包中的類;
當導入的類有名稱衝突須要使用類名的全名訪問;
若是使用import org.apache.*;僅僅只會導入org/apache這個文件夾下的全部類,子文件中的類不會被導入。
2.三、包的命名
2.3.一、包名第一個字母用小寫。
2.3.二、爲了解決衝突問題,通常都是使用域名的反向操做來設置包。
2.四、classpath的設置
設置classpath目的爲了讓程序能夠在classpath的路徑下去找包。
三、繼承
若是可以經過XXX是XX這樣一種話來描述兩個class,表示這兩個類之間有繼承關係,使用extends關鍵字完成繼承,當子類繼承了父類以後就會繼承父類的屬性和方法。
3.1繼承的描述
使用extends關鍵字完成繼承,此時具備父類的全部屬性和方法。
完成繼承後,子類會擁有父類的屬性,可是父類不會有子類的屬性和方法。
3.二、方法的覆蓋
子類的方法名和父類的方法名同樣會造成方法覆蓋。
3.三、繼承的初始化
3.3.一、建立子類以前會先建立父類,默認調用父類不帶參數的構造方法。
3.3.二、在構造父類時,默認調用的是不帶參數的構造方法,若是沒有這個構造方法,會編譯報錯。
使用super關鍵字解決以上問題
super必定要在構造函數的第一行
class School { public School(String str) { System.out.println(str); } public School() { System.out.println("school"); } } class MiddleSchool extends School { Student stu = new Student(); public MiddleSchool() { //super必定要在構造函數的第一行 super("abc"); //調用父類帶參數的構造函數 System.out.println("middle"); }
super的使用
//super必定要在構造函數的第一行 super("abc"); //調用父類帶參數的構造函數 System.out.println("middle"); //調用父類的構造方法 super.test("kkk");
四、類的訪問控制
public>protected>default>private
private:同一個類中能夠訪問
default:同一個包中能夠訪問
protected:不一樣包的子類能夠訪問
public:全部均可以訪問
4.一、private:使用private修飾的變量或者方法只能在同一個類中訪問。
4.二、default:就是什麼都不寫,在同一個類和不一樣類中均可以訪問,不一樣的包中沒法訪問
總結:同一個包中能夠訪問。
4.三、protected:不一樣包中依然沒法訪問,同一個包中能夠訪問。
不一樣包的子類能夠訪問
4.四、public:因此地方均可以訪問
4.五、最佳實踐:
全部類中的屬性都是private的,爲每個屬性增長兩個方法getter和setter,全部的getter和setter方法都是public的,
這就是Java Bean的寫法。
把全部的屬性都設置爲private的,而且經過getter和setter方法來分別對應獲取值和設置值。這個就是標準的Java Bean
的寫法。
五、多態
//父類引用指向子類對象 Person p = new Student(); p.name = "李四"; p.show(); //因爲p這個對象實際是指向student的,因此此處可使用強制類型轉換將其轉化爲student Student s = (Student)p; //因爲引用p是指向了一個具體的student對象,因此能夠進行強制類型轉換 s.no = "123"; s.show(); //p2指向的是父類對象,因此沒法強制類型轉換爲子類對象 Person p2 = new Person(); Student s2 = (Student)p2;
多態實現的基本條件
一、繼承
二、有方法的覆蓋
三、有父類引用指向子類對象
六、抽象類和接口
6.一、抽象類
/** * 有一個抽象方法的類就必須是抽象類 * 抽象類不能用來建立對象 * 抽象類所存在的意義,就是用來被繼承 * 因此抽象類等於爲開發人員肯定了相應的約束 * */ public abstract class Pet { private String name; public String getName() { return name; } public void setName(String name) { this.name = name; } /** * 該方法存在的意義只有一個:就是用來被子類覆蓋 * 這種方法,能夠聲明爲抽象方法 * 有一個抽象方法的類就是抽象類 */ public abstract void enjoy(); }
6.二、接口
接口和類同樣,惟一區別就是:接口中的全部方法都是抽象方法,接口中不存在屬性,僅僅存在常量,接口中的全部
常量和方法都是public的。
經過關鍵字interface來完成接口的建立。
因爲接口中全部的方法都是抽象和public的,因此能夠省略abstract和public關鍵字,可是建議的方式是:
不要省略public而省略abstract。
public interface Studyable { public void study(); //用下面的方式一樣能夠定義接口,和上面方式徹底同樣 //public abstract void study();==void study(); }
子類經過實現來替代繼承(也就等於繼承)。
//接口支持多實現 public class Student implements Studyable, Talkable { //須要實現接口中的全部方法 @Override public void talk() { System.out.println("talk"); } @Override public void study() { System.out.println("study"); }
實現和繼承基本相似,都是支持多態的。
public static void main(String[] args) { Talkable ta = new Student(); ta.talk(); Studyable sa = (Studyable)ta; sa.study(); Student stu = (Student)ta; //Student stu = (Student)sa; stu.talk(); stu.study(); }