類中主要包括五種結構,下面進行對這五種結構進行詳細的介紹。前端
舉例對比:把大象裝進冰箱。java
類:對一類事物的描述,是抽象的、概念上的定義 對象:是實際存在的該類事物的每一個個體,於是也稱爲實例(instance)面試
面向對象程序設計的重點是類的設計 設計類,就是設計類的成員。數據庫
兩者的關係:對象,是由類new出來的,派生出來的。後端
建立類,設計類的成員數組
建立類的對象網絡
經過「對象.屬性」或「對象.方法」調用對象的結構dom
補充:幾個概念的使用說明ide
典型代碼:函數
Person p1 = new Person(); Person p2 = new Person(); Person p3 = p1;//沒有新建立一個對象,共用一個堆空間中的對象實體。 /*說明: *若是建立了一個類的多個對象,則每一個對象都獨立的擁有一套類的屬性。(非static的) *意味着:若是咱們修改一個對象的屬性a,則不影響另一個對象屬性a的值。 */
內存解析:
編譯完源程序之後,生成一個或多個字節碼文件。 咱們使用JVM中的類的加載器和解釋器對生成的字節碼文件進行解釋運行。意味着,須要將字節碼文件對應的類加載到內存中,涉及到內存解析。
《JVM規範》
虛擬機棧,即爲平時提到的棧結構。咱們將局部變量存儲在棧結構中 堆,咱們將new出來的結構(好比:數組、對象)加載在對空間中。
補充:對象的屬性(非static的)加載在堆空間中。 方法區:類的加載信息、常量池、靜態域
咱們建立的對象,沒顯式的賦給一個變量名。即爲匿名對象 特色:匿名對象只能調用一次。 舉例:
new Phone().sendEmail(); new Phone().playGame(); new Phone().price = 1999; new Phone().showPrice();//0.0
應用場景:
PhoneMall mall = new PhoneMall(); //匿名對象的使用 mall.show(new Phone()); 其中, class PhoneMall{ public void show(Phone phone){ phone.sendEmail(); phone.playGame(); } }
對比:屬性 vs 局部變量
1.1 定義變量的格式:數據類型 變量名 = 變量值
1.2 先聲明,後使用
1.3 變量都其對應的做用域
屬性:直接定義在類的一對{}內
局部變量:聲明在方法內、方法形參、代碼塊內、構造器形參、構造器內部的變量。
屬性:能夠在聲明屬性時,指明其權限,使用權限修飾符。
經常使用的權限修飾符:private、public、缺省、protected --->封裝性
目前,聲明屬性時,使用缺省就能夠。
局部變量:不可使用權限修飾符。
屬性:類的屬性,根據其類型,都默認初始化值。
整型(byte、short、int、long:0)
浮點型(float、double:0.0)
字符型(char:0 (或'\u0000'))
布爾型(boolean:false)
引用數據類型(類、數組、接口:null)
局部變量:沒默認初始化值。
意味着,咱們在調用局部變量以前,必定要顯式賦值。
特別地:形參在調用時,咱們賦值便可。
屬性:加載到堆空間中 (非static)
局部變量:加載到棧空間
補充:回顧變量的分類: 方式一:按照數據類型:
方式二:按照在類中聲明的位置:
方法:描述類應該具的功能。
好比:Math類:sqrt()\random() ...
Scanner類:nextXxx() ...
Arrays類:sort() \ binarySearch() \ toString() \ equals() \ ...
public void eat(){} public void sleep(int hour){} public String getName(){} public String getNation(String nation){}
權限修飾符 返回值類型 方法名(形參列表){
方法體
}
注意:static、final、abstract 等關鍵字修飾的方法,後面再聊。
Java規定的4種權限修飾符:private、public、缺省、protected -->封裝性
3.2.1 若是方法返回值,則必須在方法聲明時,指定返回值的類型。同時,方法中,須要使用
return關鍵字來返回指定類型的變量或常量:「return 數據」。
若是方法沒返回值,則方法聲明時,使用void來表示。一般,沒返回值的方法中,就不須要
使用return.可是,若是使用的話,只能「return;」表示結束此方法的意思。
3.2.2 咱們定義方法該不應返回值?
① 題目要求
② 憑經驗:具體問題具體分析
3.4.1 格式:數據類型1 形參1,數據類型2 形參2,...
3.4.2 咱們定義方法時,該不應定義形參?
① 題目要求
② 憑經驗:具體問題具體分析
特殊的:方法A中又調用了方法A:遞歸方法。
方法中,不能夠定義方法。
1.使用範圍:使用在方法體中 2.做用:
① 結束方法
② 針對於返回值類型的方法,使用"return 數據"方法返回所要的數據。 3.注意點:return關鍵字後面不能夠聲明執行語句。
定義:在同一個類中,容許存在一個以上的同名方法,只要它們的參數個數或者參數類型不一樣便可。
總結:"兩同一不一樣":
舉例一:Arrays類中重載的sort() / binarySearch();PrintStream中的println() 舉例二: //以下的4個方法構成了重載 public void getSum(int i,int j){ System.out.println("1"); } public void getSum(double d1,double d2){ System.out.println("2"); } public void getSum(String s ,int i){ System.out.println("3"); } public void getSum(int i,String s){ System.out.println("4"); }
不構成重載的實例:
//以下的3個方法不能與上述4個方法構成重載 public int getSum(int i,int j){ return 0; } public void getSum(int m,int n){ } private void getSum(int i,int j){ }
嚴格按照定義判斷:兩同一不一樣。 跟方法的權限修飾符、返回值類型、形參變量名、方法體都不要緊!
①方法名 ---> ②參數列表
JDK 5.0新增的內容
JDK 5.0之前:採用數組形參來定義方法,傳入多個同一類型變量 public static void test(int a, String[ ]books);
JDK 5.0:採用可變個數形參來定義方法,傳入多個同一類型變量 public static void test(int a, String ... books);
具體使用:
2.1 可變個數形參的格式:數據類型 ... 變量名
2.2 當調用可變個數形參的方法時,傳入的參數個數能夠是:0個,1個,2個,。。。
2.3 可變個數形參的方法與本類中方法名相同,形參不一樣的方法之間構成重載
2.4 可變個數形參的方法與本類中方法名相同,形參類型也相同的數組之間不構成重載。換句話說,兩者不能共存。
2.5 可變個數形參在方法的形參中,必須聲明在末尾
2.6 可變個數形參在方法的形參中,最多隻能聲明一個可變形參。
public void show(int i){ } public void show(String s){ System.out.println("show(String)"); } public void show(String ... strs){ System.out.println("show(String ... strs)"); for(int i = 0;i < strs.length;i++){ System.out.println(strs[i]); } } //不能與上一個方法同時存在 // public void show(String[] strs){ // // } 調用時:可變形參與數組相似 test.show("hello"); test.show("hello","world"); test.show(); test.show(new String[]{"AA","BB","CC"});
System.out.println("***********基本數據類型:****************"); int m = 10; int n = m; System.out.println("m = " + m + ", n = " + n); n = 20; System.out.println("m = " + m + ", n = " + n); System.out.println("***********引用數據類型:****************"); Order o1 = new Order(); o1.orderId = 1001; Order o2 = o1;//賦值之後,o1和o2的地址值相同,都指向了堆空間中同一個對象實體。 System.out.println("o1.orderId = " + o1.orderId + ",o2.orderId = " +o2.orderId); o2.orderId = 1002; System.out.println("o1.orderId = " + o1.orderId + ",o2.orderId = " +o2.orderId);
規則: 若是變量是基本數據類型,此時賦值的是變量所保存的數據值。 若是變量是引用數據類型,此時賦值的是變量所保存的數據的地址值。
形參:方法定義時,聲明的小括號內的參數 實參:方法調用時,實際傳遞給形參的數據
規則:
推廣:
內存解析畫法要點:
1.內存結構:棧(局部變量)、堆(new出來的結構:對象(非static成員變量)、數組
2.變量:成員變量 vs 局部變量(方法內、方法形參、構造器內、構造器形參、代碼塊內)
舉例一
舉例二
遞歸方法:一個方法體內調用它自身。
方法遞歸包含了一種隱式的循環,它會重複執行某段代碼,但這種重複執行無須循環控制。 遞歸必定要向已知方向遞歸,不然這種遞歸就變成了無窮遞歸,相似於死循環。
// 例1:計算1-n之間所天然數的和 public int getSum(int n) {// 3 if (n == 1) { return 1; } else { return n + getSum(n - 1); } } // 例2:計算1-n之間所天然數的乘積:n! public int getSum1(int n) { if (n == 1) { return 1; } else { return n * getSum1(n - 1); } } //例3:已知一個數列:f(0) = 1,f(1) = 4,f(n+2)=2*f(n+1) + f(n), //其中n是大於0的整數,求f(10)的值。 public int f(int n){ if(n == 0){ return 1; }else if(n == 1){ return 4; }else{ // return f(n + 2) - 2 * f(n + 1); return 2*f(n - 1) + f(n - 2); } } //例4:斐波那契數列 //例5:漢諾塔問題 //例6:快排
子類繼承父類之後,能夠對父類中同名同參數的方法,進行覆蓋操做.
重寫之後,當建立子類對象之後,經過子類對象調用子父類中的同名同參數的方法時,實際執行的是子類重寫父類的方法。
class Circle{ public double findArea(){}//求面積 } class Cylinder extends Circle{ public double findArea(){}//求表面積 } ********************************************** class Account{ public boolean withdraw(double amt){} } class CheckAccount extends Account{ public boolean withdraw(double amt){} }
方法的聲明:
權限修飾符 返回值類型 方法名(形參列表) throws 異常的類型{ //方法體 }
約定俗稱:子類中的叫重寫的方法,父類中的叫被重寫的方法
特殊狀況:子類不能重寫父類中聲明爲private權限的方法
父類被重寫的方法的返回值類型是void,則子類重寫的方法的返回值類型只能是void
父類被重寫的方法的返回值類型是A類型,則子類重寫的方法的返回值類型能夠是A類或A類的子類
父類被重寫的方法的返回值類型是基本數據類型(好比:double),則子類重寫的方法的返回值類型必須是相同的基本數據類型(必須也是double)
子類和父類中的同名同參數的方法要麼都聲明爲非static的(考慮重寫,要麼都聲明爲static的(不是重寫)。
開發中通常保持子父類一致
區分方法的重寫和重載?
引用一句Bruce Eckel的話:「不要犯傻,若是它不是晚綁定,它就不是多態。」
構造器的做用:(只要造對象就得用構造器)
建立對象
初始化對象的信息
1.若是沒顯式的定義類的構造器的話,則系統默認提供一個空參的構造器
2.定義構造器的格式:權限修飾符 類名(形參列表){}
3.一個類中定義的多個構造器,彼此構成重載
4.一旦咱們顯式的定義了類的構造器以後,系統就再也不提供默認的空參構造器
5.一個類中,至少會有一個構造器。
//構造器不等於方法 public Person(){ System.out.println("Person()....."); } public Person(String n){ name = n; } public Person(String n,int a){ name = n; age = a; }
構造器默認權限和類的權限一致
總結:屬性賦值的前後順序
① 默認初始化
② 顯式初始化
③ 構造器中初始化
④ 經過"對象.方法" 或 "對象.屬性"的方式,賦值
以上操做的前後順序:① - ② - ③ - ④
所謂JavaBean,是指符合以下標準的Java類:
代碼塊(初始化塊)(重要性較屬性、方法、構造器差一些)
用來初始化類、對象的信息
代碼塊要是使用修飾符,只能使用static 分類:靜態代碼塊 vs 非靜態代碼塊
靜態代碼塊:
非靜態代碼塊:
注意:實例化子類對象時,涉及到父類、子類中靜態代碼塊、非靜態代碼塊、構造器的加載順序:由父及子,靜態先行。
舉例:
舉例一
class Root{ static{ System.out.println("Root的靜態初始化塊"); } { System.out.println("Root的普通初始化塊"); } public Root(){ System.out.println("Root的無參數的構造器"); } } class Mid extends Root{ static{ System.out.println("Mid的靜態初始化塊"); } { System.out.println("Mid的普通初始化塊"); } public Mid(){ System.out.println("Mid的無參數的構造器"); } public Mid(String msg){ //經過this調用同一類中重載的構造器 this(); System.out.println("Mid的帶參數構造器,其參數值:" + msg); } } class Leaf extends Mid{ static{ System.out.println("Leaf的靜態初始化塊"); } { System.out.println("Leaf的普通初始化塊"); } public Leaf(){ //經過super調用父類中有一個字符串參數的構造器 super("調用父類構造器"); System.out.println("Leaf的構造器"); } } public class LeafTest{ public static void main(String[] args){ new Leaf(); //new Leaf(); } }
舉例二
class Father { static { System.out.println("11111111111"); } { System.out.println("22222222222"); } public Father() { System.out.println("33333333333"); } } public class Son extends Father { static { System.out.println("44444444444"); } { System.out.println("55555555555"); } public Son() { System.out.println("66666666666"); } public static void main(String[] args) { // 由父及子 靜態先行 System.out.println("77777777777"); System.out.println("************************"); new Son(); System.out.println("************************"); new Son(); System.out.println("************************"); new Father(); } }
①默認初始化
②顯式初始化/⑤在代碼塊中賦值
③構造器中初始化
④有了對象之後,能夠經過"對象.屬性"或"對象.方法"的方式,進行賦值
執行的前後順序:① - ② / ⑤ - ③ - ④
類的第五個成員
Java中容許將一個類A聲明在另外一個類B中,則類A就是內部類,類B稱爲外部類.
成員內部類(靜態、非靜態 ) vs 局部內部類(方法內、代碼塊內、構造器內)
一方面,做爲外部類的成員:
調用外部類的結構
能夠被static修飾
能夠被4種不一樣的權限修飾
另外一方面,做爲一個類:
類內能夠定義屬性、方法、構造器等
能夠被final修飾,表示此類不能被繼承。言外之意,不使用final,就能夠被繼承
能夠被abstract修飾
4.1如何建立成員內部類的對象?(靜態的,非靜態的)
//建立靜態的Dog內部類的實例(靜態的成員內部類): Person.Dog dog = new Person.Dog(); //建立非靜態的Bird內部類的實例(非靜態的成員內部類): //Person.Bird bird = new Person.Bird();//錯誤的 Person p = new Person(); Person.Bird bird = p.new Bird();
4.2如何在成員內部類中調用外部類的結構?
class Person{ String name = "小明"; public void eat(){ } //非靜態成員內部類 class Bird{ String name = "杜鵑"; public void display(String name){ System.out.println(name);//方法的形參 System.out.println(this.name);//內部類的屬性 System.out.println(Person.this.name);//外部類的屬性 //Person.this.eat(); } } }
//返回一個實現了Comparable接口的類的對象 public Comparable getComparable(){ //建立一個實現了Comparable接口的類:局部內部類 //方式一: // class MyComparable implements Comparable{ // // @Override // public int compareTo(Object o) { // return 0; // } // // } // // return new MyComparable(); //方式二: return new Comparable(){ @Override public int compareTo(Object o) { return 0; } }; }
注意點: 在局部內部類的方法中(好比:show若是調用局部內部類所聲明的方法(好比:method)中的局部變量(好比:num)的話,要求此局部變量聲明爲final的。 緣由:局部內部類也會生成字節碼文件,在調用所屬類的局部變量時,由於是兩個類,因此不能修改所屬類的屬性,所以所屬類將屬性設置爲final的爲內部類調用提供一個副本,而內部類不能進行修改。 jdk 7及以前版本:要求此局部變量顯式的聲明爲final的 jdk 8及以後的版本:能夠省略final的聲明
總結: 成員內部類和局部內部類,在編譯之後,都會生成字節碼文件。 格式:成員內部類:外部類$內部類名.class 局部內部類:外部類$數字 內部類名.class