看一個示例:java
package com.zhangguo.chapter5.s1; /**動物園*/ public class Zoo { public static void main(String[] args) { Animal animal=new Animal(); animal.eat(); /**new誰調誰*/ /**LSP*/ Animal dog=new Dog(); dog.eat(); } } /**動物*/ class Animal { /**吃*/ public void eat(){ System.out.println("動物吃東西"); } } class Cat extends Animal{ /**重寫吃*/ public void eat(){ System.out.println("貓吃魚"); } } class Dog extends Animal{ /**重寫吃*/ public void eat(){ System.out.println("狗吃骨頭"); } }
結果:程序員
問題:面試
從上面的示例能夠看出Animal是抽象的父類,其實現實中並不存在一種叫動物的實際對象,而動物僅僅是一個被抽象的概念。express
既然這樣,Animal就不該該實例化,只能做爲父類,在面向對象中(OOP)充當這種角色的類型有:抽象類,接口。設計模式
抽象類與接口是一種比類更加抽象的類型。安全
從上面的概念中能夠得知有些類型是不該該實例化的,沒有意義。多線程
java中抽象類更利於代碼的維護和重用。架構
1.由於抽象類不能實例化對象,因此必需要有子類來實現它以後才能使用。這樣就能夠把一些具備相同屬性和方法的組件進行抽象,這樣更有利於代碼和程序的維護。app
2.當又有一個具備類似的組件產生時,只須要實現該抽象類就能夠得到該抽象類的那些屬性和方法。less
在面向對象方法中,抽象類主要用來進行類型隱藏。構造出一個固定的一組行爲的抽象描述,可是這組行爲卻可以有任意個可能的具體實現方式。這個抽象描述就是抽象類,而這一組任意個可能的具體實現則表現爲全部可能的派生類。模塊能夠操做一個抽象體。因爲模塊依賴於一個固定的抽象體,所以它能夠是不容許修改的;同時,經過從這個抽象體派生,也可擴展此模塊的行爲功能。爲了可以實現面向對象設計的一個最核心的原則OCP(Open-Closed Principle),抽象類是其中的關鍵所在。
(1)、接口
(2)、抽象類
(3)、構造方法的訪問權限爲私有
package com.zhangguo.chapter5.s1; /** 吃 接口 */ interface Ieatable { void eat(); } /** 動物 抽象類 */ abstract class Animal { /** 吃 抽象方法 */ public abstract void eat(); } /** 學生 普通類 */ class Student { /** 私有構造方法 */ private Student() { } } public class NoInstance { public static void main(String[] args) { Ieatable obj1 = new Ieatable(); // 錯誤 不能實例化接口 Animal obj2 = new Animal(); // 錯誤 不能實例化抽象類 Student obj3 = new Student(); // 錯誤 不能實例化私有構造方法類 } }
有些語言中靜態類也不能實例化,如C#
意義:越抽象,越穩定。抽象的能夠定義上層結構,規範頂層設計。抽象不會也不該該隨意變化。
2.一、語法定義
抽象類定義,抽象類前使用abstract關鍵字修飾,則該類爲抽象類。
a、在某些狀況下,某個父類只是知道其子類應該包含怎樣的方法,但沒法準確知道這些子類如何實現這些方法
(抽象類約束子類必須有哪些方法,但並不關注子類怎麼去實現這些方法。)
b、從多個具備相同特徵的類中抽象出一個抽象類,以這個抽象類做爲子類的模板,從而避免了子類設計的隨意性。
限制規定子類必須實現某些方法,但不關注實現細節。
1,抽象方法必定在抽象類中
2,抽象方法和抽象類都必須被abstract關鍵字修飾
3,抽象類不能夠用new建立對象。由於調用抽象方法沒意義4,抽象類中的抽象方法要被使用,必須由子類複寫起全部的抽象方法後,創建子類對象調用。
若是子類只覆蓋了部分抽象方法,那麼該子類仍是一個抽象類。
五、抽象方法沒有方法體,以分號結束
示例:
package com.zhangguo.chapter5.s2; import java.util.Scanner; /** 動物 */ public abstract class Animal { /** 名稱 */ public String name; /** 抽象方法,無方法體,必須被子類實現(重寫) */ public abstract void eat(); /**測試*/ public static void main(String[] args) { //LSP 里氏替換原則 Animal dog=new Dog(); dog.name="博美"; //int i=1; //Scanner input=new Scanner(System.in); dog.eat(); } /**抽象類中能夠有非抽象方法,能夠有靜態方法*/ public void show(){}; } /**抽象類動物(Animal)的子類,必須實現父類未實現的方法*/ class Dog extends Animal { //註解 @Override public void eat() { System.out.println(this.name+"狗在吃骨頭"); } }
運行結果:
接口是一組沒有實例的標準與規範。
沒有接口的電腦是怎樣的?
繼承:描述事物的天然屬性和行爲的複用。
接口:描述事物的社會屬性和行爲的複用。
一、重要性:在Java語言中, abstract class 和interface 是支持抽象類定義的兩種機制。正是因爲這兩種機制的存在,才賦予了Java強大的 面向對象能力。
二、簡單、規範性:若是一個項目比較龐大,那麼就須要一個能理清全部業務的架構師來定義一些主要的接口,這些接口不只告訴開發人員你須要實現那些業務,並且也將命名規範限制住了(防止一些開發人員隨便命名致使別的程序員沒法看明白)。
三、維護、拓展性:好比你要作一個畫板程序,其中裏面有一個面板類,主要負責繪畫功能,而後你就這樣定義了這個類。
四、安全、嚴密性:接口是實現軟件鬆耦合的重要手段,它描敘了系統對外的全部服務,而不涉及任何具體的實現細節。這樣就比較安全、嚴密一些(通常軟件服務商考慮的比較多)。
由於類具備「單根性」,全部的類只能有一個直接父類,經過能夠實現一個類有多個父類,能夠實現多重繼承。
package com.zhangguo.chapter5.s2; /**usb接口*/ public interface IUSB { /**未實現的方法,發送數據*/ void sendData(); } /**網線接口*/ interface IRJ45 { /**未實現的方法,接收數據*/ void receiveData(); } /**設備*/ class Device{ } /**電腦*/ /**一個類只能繼承一個類,但能夠實現多個接口*/ class Computer extends Device implements IUSB,IRJ45{ @Override public void receiveData() { System.out.println("接收數據"); } @Override public void sendData() { System.out.println("發送數據"); } interface IA{} interface IB{} /**接口能夠繼承其它他口*/ interface IC extends IA,IB{} class CC{} /**繼承須要寫在實現接口前*/ class DD extends CC implements IC {} }
測試:
package com.zhangguo.chapter5.s2; public class ComputerClient { public static void main(String[] args) { Computer ln=new Computer(); ln.sendData(); ln.receiveData(); /**接口是一種類型*/ IUSB usb=new Computer(); /**一個對象能夠有多個不一樣的類型*/ } }
1)、接口中的方法能夠有參數列表和返回類型,但不能有任何方法體。
2)、接口中能夠包含字段,可是會被隱式的聲明爲static和final。
3)、接口中的字段只是被存儲在該接口的靜態存儲區域內,而不屬於該接口。
4)、接口中的方法能夠被聲明爲public或不聲明,但結果都會按照public類型處理。
5)、當實現一個接口時,須要將被定義的方法聲明爲public類型的,不然爲默認訪問類型,Java編譯器不容許這種狀況。
6)、若是沒有實現接口中全部方法,那麼建立的仍然是一個接口。子類必須實現接口中未實現的方法,除非子類也是接口。
7)、擴展一個接口來生成新的接口應使用關鍵字extends,實現一個接口使用implements。
8)、接口中的方法是抽象方法(abstract),不能是靜態方法(static))、接口的全部方法都是抽象的,而抽象方法是沒有static,有static的方法是不能override的,因此這樣定義接口才有意義。
接口中的字段是默認爲:static final ,通俗說就是常量
final修飾的類不容許被繼承。
一個類不能既是final的,又是abstract的。由於abstract的主要目的是定義一種約定,讓子類去實現這種約定,而final表示該類不能被繼承,二者矛盾。
final修飾方法,表示該方法不能被子類中的方法覆寫Override。不能被重寫
final成員變量表示常量,只能被賦值一次,賦值後值再也不改變。
當final修飾一個原生數據類型時,表示該原生數據類型的值不能發生變化;
若是final修飾一個引用類型時,表示該引用類型不能再指向其餘對象了,但該引用所指向的對象的內容是能夠發生變化的。
本質上是一回事,由於引用的值是一個地址,final要求值,即地址的值不發生變化。
final修飾一個成員變量(屬性),必需要顯示初始化。
這裏有兩種初始化方式,一種是在變量聲明的時候初始化;第二種方法是在聲明變量的時候不賦初值,可是要在這個變量所在的類的全部的構造函數中對這個變量賦初值。
當函數的參數類型聲明爲final時,說明該參數是隻讀型的。
內部類是指在一個外部類的內部再定義一個類。內部類做爲外部類的一個成員,而且依附於外部類而存在的。內部類可爲靜態,可用protected和private修飾(而外部類只能使用public和缺省的包訪問權限)。內部類主要有如下幾類:成員內部類、局部內部類、靜態內部類、匿名內部類
示例:
package com.zhangguo.innnerclass; public class InnerDemo2 { public static void main(String[] args) { //實例化的方法一 Box box=new Box(); box.height=286; Box.InBox inbox=box.new InBox(); inbox.show(); //實例化的方法二 Box.InBox box2=new Box().new InBox(); box2.show(); } } //外部類 class Box { //外部類的成員變量 public int height=198; //成員內部類 class InBox{ //內部類的成員 public void show(){ System.out.println("外部類的高度:"+height); } } }
結果:
外部類的高度:286
外部類的高度:198
從上面的例子不難看出,內部類其實嚴重破壞了良好的代碼結構,但爲何還要使用內部類呢?
由於內部類能夠隨意使用外部類的成員變量(包括私有)而不用生成外部類的對象,這也是內部類的惟一優勢程序編譯事後會產生兩個.class文件,分別是Out.class和Out$In.class其中$表明了上面程序中Out.In中的那個。
Out.In in = new Out().new In()能夠用來生成內部類的對象,這種方法存在兩個小知識點須要注意
1.開頭的Out是爲了標明須要生成的內部類對象在哪一個外部類當中
2.必須先有外部類的對象才能生成內部類的對象,由於內部類的做用就是爲了訪問外部類中的成員變量
示例:
package com.zhangguo.innnerclass; public class InnerDemo3 { public static void main(String[] args) { new OutBox().new InBox().show(); } } //外部類 class OutBox { //外部類的成員變量 private int height=197; //成員內部類 class InBox{ //內部類的成員變量 private int height=198; //內部類的成員 public void show(){ //內部類的局部變量 int height=199; System.out.println("內部類的局部變量:"+height); System.out.println("內部類的成員變量:"+this.height); System.out.println("外部類的成員變量:"+OutBox.this.height); } } }
結果:
內部類的局部變量:199 內部類的成員變量:198 外部類的成員變量:197
內部類在沒有同名成員變量和局部變量的狀況下,內部類會直接訪問外部類的成員變量,而無需指定Out.this.屬性名
不然,內部類中的局部變量會覆蓋外部類的成員變量
而訪問內部類自己的成員變量可用this.屬性名,訪問外部類的成員變量須要使用Out.this.屬性名
(1)、內部類仍然是一個獨立的類,在編譯以後內部類會被編譯成獨立的.class文件,可是前面冠之外部類的類名和$符號 。
(2)、內部類不能用普通的方式訪問。
(3)、內部類聲明成靜態的,就不能隨便的訪問外部類的成員變量了,此時內部類只能訪問外部類的靜態成員變量 。
(4)、外部類不能直接訪問內部類的的成員,但能夠經過內部類對象來訪問
內部類是外部類的一個成員,所以內部類能夠自由地訪問外部類的成員變量,不管是不是private的。
由於當某個外圍類的對象建立內部類的對象時,此內部類會捕獲一個隱式引用,它引用了實例化該內部對象的外圍類對象。經過這個指針,能夠訪問外圍類對象的所有狀態。
經過反編譯內部類的字節碼,分析以後主要是經過如下幾步作到的:
1 編譯器自動爲內部類添加一個成員變量, 這個成員變量的類型和外部類的類型相同, 這個成員變量就是指向外部類對象的引用;
2 編譯器自動爲內部類的構造方法添加一個參數, 參數的類型是外部類的類型, 在構造方法內部使用這個參數爲1中添加的成員變量賦值;
3 在調用內部類的構造函數初始化內部類對象時, 會默認傳入外部類的引用。
其主要緣由有如下幾點:
內部類方法能夠訪問該類定義所在的做用域的數據,包括私有的數據
內部類能夠對同一個包中的其餘類隱藏起來,通常的非內部類,是不容許有 private 與protected權限的,但內部類能夠
能夠實現多重繼承
當想要定義一個回調函數且不想編寫大量代碼時,使用匿名內部類比較便捷
使用內部類最吸引人的緣由是:
每一個內部類都能獨立地繼承自一個(接口的)實現,因此不管外圍類是否已經繼承了某個(接口的)實現,對於內部類都沒有影響。你們都知道Java只能繼承一個類,它的多重繼承在咱們沒有學習內部類以前是用接口來實現的。但使用接口有時候有不少不方便的地方。好比咱們實現一個接口就必須實現它裏面的全部方法。而有了內部類就不同了。它可使咱們的類繼承多個具體類或抽象類。
你們看下面的例子:
package com.zhangguo.innnerclass; public class InnerDemo4 { public static void main(String[] args) { Person person=new Person(); person.bark(); } } abstract class Fruit{ public String name="水果"; } abstract class Animal{ public void bark(){ System.out.println("呱呱..."); } } class Person{ class FruitAttr extends Fruit{ } class AnimalAttr extends Animal{ @Override public void bark() { super.bark(); System.out.println(getName()+"嘎嘎..."); } } public String getName(){ return new FruitAttr().name; } public void bark(){ new AnimalAttr().bark(); } }
結果:
呱呱...
水果嘎嘎...
即在一個類中直接定義的內部類, 成員內部類與普通的成員沒什麼區別,能夠與普通成員同樣進行修飾和限制。成員內部類不能含有static的變量和方法。
public class Outer { private static int i = 1; private int j = 10; private int k = 20; public static void outer_f1() {} public void outer_f2() {} // 成員內部類中,不能定義靜態成員 // 成員內部類中,能夠訪問外部類的全部成員
class Inner { // static int inner_i = 100;//內部類中不容許定義靜態變量
int j = 100; // 內部類和外部類的實例變量能夠共存
int inner_i = 1; void inner_f1() { System.out.println(i); // 在內部類中訪問內部類本身的變量直接用變量名
System.out.println(j); // 在內部類中訪問內部類本身的變量也能夠用this.變量名
System.out.println(this.j); // 在內部類中訪問外部類中與內部類同名的實例變量用外部類名.this.變量名
System.out.println(Outer.this.j); // 若是內部類中沒有與外部類同名的變量,則能夠直接用變量名訪問外部類變量
System.out.println(k); outer_f1(); outer_f2(); } } // 外部類的非靜態方法訪問成員內部類
public void outer_f3() { Inner inner = new Inner(); inner.inner_f1(); } // 外部類的靜態方法訪問成員內部類,與在外部類外部訪問成員內部類同樣
public static void outer_f4() { // step1 創建外部類對象
Outer out = new Outer(); // step2 根據外部類對象創建內部類對象
Inner inner = out.new Inner(); // step3 訪問內部類的方法
inner.inner_f1(); } public static void main(String[] args) { //outer_f4();//該語句的輸出結果和下面三條語句的輸出結果同樣 // 若是要直接建立內部類的對象,不能想固然地認爲只需加上外圍類Outer的名字, // 就能夠按照一般的樣子生成內部類的對象,而是必須使用此外圍類的一個對象來 // 建立其內部類的一個對象: // Outer.Inner outin = out.new Inner() // 所以,除非你已經有了外圍類的一個對象,不然不可能生成內部類的對象。由於此 // 內部類的對象會悄悄地連接到建立它的外圍類的對象。若是你用的是靜態的內部類, // 那就不須要對其外圍類對象的引用。
Outer out = new Outer(); Outer.Inner outin = out.new Inner(); outin.inner_f1(); } }
示例:
class Person{ static class MyClass{ double PI=3.14; //容許 } class FruitAttr extends Fruit{ //The field PI cannot be declared static in a non-static inner type, unless initialized with a constant expression //默認狀況下內部類的成員不能是靜態的,除非內部類也是靜態的,或者將成員聲明爲常量表達式如(static final) //static double PI=3.14; static final double PI=3.14; } }
在方法中定義的內部類稱爲局部內部類。與局部變量相似,局部內部類不能有訪問說明符,由於它不是外圍類的一部分,可是它能夠訪問當前代碼塊內的常量,和此外圍類全部的成員。
須要注意的是:
(1)、局部內部類只能在定義該內部類的方法內實例化,不能夠在此方法外對其實例化。
(2)、局部內部類對象不能使用該內部類所在方法的非final局部變量。
具體緣由等下再說
public class Outer { private int s = 100; private int out_i = 1; public void f(final int k) { final int s = 200; int i = 1; final int j = 10; // 定義在方法內部
class Inner { int s = 300;// 能夠定義與外部類同名的變量 // static int m = 20;//不能夠定義靜態變量
Inner(int k) { inner_f(k); } int inner_i = 100; void inner_f(int k) { // 若是內部類沒有與外部類同名的變量,在內部類中能夠直接訪問外部類的實例變量
System.out.println(out_i); // 能夠訪問外部類的局部變量(即方法內的變量),可是變量必須是final的
System.out.println(j); // System.out.println(i); // 若是內部類中有與外部類同名的變量,直接用變量名訪問的是內部類的變量
System.out.println(s); // 用this.變量名訪問的也是內部類變量
System.out.println(this.s); // 用外部類名.this.內部類變量名訪問的是外部類變量
System.out.println(Outer.this.s); } } new Inner(k); } public static void main(String[] args) { // 訪問局部內部類必須先有外部類對象
Outer out = new Outer(); out.f(3); } }
若是你不須要內部類對象與其外圍類對象之間有聯繫,那你能夠將內部類聲明爲static。這一般稱爲嵌套類(nested class)。想要理解static應用於內部類時的含義,你就必須記住,普通的內部類對象隱含地保存了一個引用,指向建立它的外圍類對象。然而,當內部類是static的時,就不是這樣了。嵌套類意味着:
1. 要建立嵌套類的對象,並不須要其外圍類的對象。
2. 不能從嵌套類的對象中訪問非靜態的外圍類對象。
public class Outer { private static int i = 1; private int j = 10; public static void outer_f1() {} public void outer_f2() {} // 靜態內部類能夠用public,protected,private修飾 // 靜態內部類中能夠定義靜態或者非靜態的成員
private static class Inner { static int inner_i = 100; int inner_j = 200; static void inner_f1() { // 靜態內部類只能訪問外部類的靜態成員(包括靜態變量和靜態方法)
System.out.println("Outer.i" + i); outer_f1(); } void inner_f2() { // 靜態內部類不能訪問外部類的非靜態成員(包括非靜態變量和非靜態方法) // System.out.println("Outer.i"+j); // outer_f2();
} } public void outer_f3() { // 外部類訪問內部類的靜態成員:內部類.靜態成員
System.out.println(Inner.inner_i); Inner.inner_f1(); // 外部類訪問內部類的非靜態成員:實例化內部類便可
Inner inner = new Inner(); inner.inner_f2(); } public static void main(String[] args) { new Outer().outer_f3(); } }
生成一個靜態內部類不須要外部類成員:這是靜態內部類和成員內部類的區別。靜態內部類的對象能夠直接生成:Outer.Inner in = new Outer.Inner();而不須要經過生成外部類對象來生成。這樣實際上使靜態內部類成爲了一個頂級類(正常狀況下,你不能在接口內部放置任何代碼,但嵌套類能夠做爲接口的一部分,由於它是static 的。只是將嵌套類置於接口的命名空間內,這並不違反接口的規則)
匿名內部類不能有構造方法。
匿名內部類不能定義任何靜態成員、方法和類。
匿名內部類不能是public,protected,private,static。
只能建立匿名內部類的一個實例。
一個匿名內部類必定是在new的後面,用其隱含實現一個接口或實現一個類。
因匿名內部類爲局部內部類,因此局部內部類的全部限制都對其生效。
public class Parcel7 { public Wrapping wrap(int x) { // Base constructor call:
return new Wrapping(x) { // Pass constructor argument.
public int value() { return super.value() * 47; } }; // Semicolon required
} public static void main(String[] args) { Parcel7 p = new Parcel7(); Wrapping w = p.wrap(10); } }
public class Parcel8 { // Argument must be final to use inside // anonymous inner class:
public Destination dest(final String name, String city) { return new Destination(name, city) { private String label = name; public String getName() { return label; } }; } public static void main(String[] args) { Parcel8 p = new Parcel8(); Destination d = p.dest("Tanzania", "gz"); } abstract class Destination { Destination(String name, String city) { System.out.println(city); } abstract String getName(); } }
匿名內部類也就是沒有名字的內部類
正由於沒有名字,因此匿名內部類只能使用一次,它一般用來簡化代碼編寫
但使用匿名內部類還有個前提條件:必須繼承一個父類或實現一個接口
示例:
package com.zhangguo.innnerclass; public class InnerDemo5 { public static void main(String[] args) { IFly bird=new Bird(); bird.fly(); IFly pig=new IFly() { @Override public void fly() { System.out.println("豬在飛..."); } }; pig.fly(); Display(new Man(){ @Override public void show() { super.show(); System.out.println("我是一個男人!"); } }); Man woman=new Man(){ @Override public void show() { super.show(); System.out.println("我是一個女人!"); } }; woman.show(); } public static void Display(Man man){ man.show(); } } interface IFly{ void fly(); } class Man{ public void show(){ System.out.println("我是一我的"); } }
Bird類:
package com.zhangguo.innnerclass; public class Bird implements IFly { @Override public void fly() { System.out.println("鳥在飛..."); } }
結果:
鳥在飛...
豬在飛...
我是一我的
我是一個男人!
我是一我的
我是一個女人!
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
abstract
class
Person {
public
abstract
void
eat();
}
class
Child
extends
Person {
public
void
eat() {
System.out.println(
"eat something"
);
}
}
public
class
Demo {
public
static
void
main(String[] args) {
Person p =
new
Child();
p.eat();
}
}
|
運行結果:eat something
能夠看到,咱們用Child繼承了Person類,而後實現了Child的一個實例,將其向上轉型爲Person類的引用
可是,若是此處的Child類只使用一次,那麼將其編寫爲獨立的一個類豈不是很麻煩?
這個時候就引入了匿名內部類
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
abstract
class
Person {
public
abstract
void
eat();
}
public
class
Demo {
public
static
void
main(String[] args) {
Person p =
new
Person() {
public
void
eat() {
System.out.println(
"eat something"
);
}
};
p.eat();
}
}
|
運行結果:eat something
能夠看到,咱們直接將抽象類Person中的方法在大括號中實現了
這樣即可以省略一個類的書寫
而且,匿名內部類還能用於接口上
interface
Person {
public
void
eat();
}
public
class
Demo {
public
static
void
main(String[] args) {
Person p =
new
Person() {
public
void
eat() {
System.out.println(
"eat something"
);
}
};
p.eat();
}
}
|
運行結果:eat something
由上面的例子能夠看出,只要一個類是抽象的或是一個接口,那麼其子類中的方法均可以使用匿名內部類來實現
最經常使用的狀況就是在多線程的實現上,由於要實現多線程必須繼承Thread類或是繼承Runnable接口
public
class
Demo {
public
static
void
main(String[] args) {
Thread t =
new
Thread() {
public
void
run() {
for
(
int
i =
1
; i <=
5
; i++) {
System.out.print(i +
" "
);
}
}
};
t.start();
}
}
|
運行結果:1 2 3 4 5
1
2
3
4
5
6
7
8
9
10
11
12
13
|
public
class
Demo {
public
static
void
main(String[] args) {
Runnable r =
new
Runnable() {
public
void
run() {
for
(
int
i =
1
; i <=
5
; i++) {
System.out.print(i +
" "
);
}
}
};
Thread t =
new
Thread(r);
t.start();
}
}
|
運行結果:1 2 3 4 5
class Egg { private Yolk y; protected class Yolk { public Yolk() { System.out.println("Egg.Yolk()"); } } public Egg() { System.out.println("New Egg()"); y = new Yolk(); } } public class BigEgg extends Egg { public class Yolk { public Yolk() { System.out.println("BigEgg.Yolk()"); } } public static void main(String[] args) { new BigEgg(); }
}
class Egg2 { protected class Yolk { public Yolk() { System.out.println("Egg2.Yolk()"); } public void f() { System.out.println("Egg2.Yolk.f()"); } } private Yolk y = new Yolk(); public Egg2() { System.out.println("New Egg2()"); } public void insertYolk(Yolk yy) { y = yy; } public void g() { y.f(); } } public class BigEgg2 extends Egg2 { public class Yolk extends Egg2.Yolk { public Yolk() { System.out.println("BigEgg2.Yolk()"); } public void f() { System.out.println("BigEgg2.Yolk.f()"); } } public BigEgg2() { insertYolk(new Yolk()); } public static void main(String[] args) { Egg2 e2 = new BigEgg2(); e2.g(); } }
class WithInner { class Inner { Inner(){ System.out.println("this is a constructor in WithInner.Inner"); }; } } public class InheritInner extends WithInner.Inner { // ! InheritInner() {} // Won't compile
InheritInner(WithInner wi) { wi.super(); System.out.println("this is a constructor in InheritInner"); } public static void main(String[] args) { WithInner wi = new WithInner(); InheritInner ii = new InheritInner(wi); } }
爲何非靜態內部類中不能有static修飾的屬性,但卻能夠有常量?
如:
public class InnerClassDemo{ int x; class A{ static int a = 0;//這樣寫是不合法的.
static final int b=0;//這樣寫是合法的
} }
定義一個靜態的域或者方法,要求在靜態環境或者頂層環境,即若是加上 static class A變成靜態內部類就ok非靜態內部類 依賴於一個外部類對象,而靜態域/方法是不依賴與對象——僅與類相關(細說了,就是加載靜態域時,根本沒有外部類對象)所以,非靜態內部類中不能定義靜態域/方法,編譯過不了。
而常量之因此能夠(不論有無static),由於java在編譯期就肯定全部常量,放到所謂的常量池當中。常量的機制和普通變量不同
匿名內部類和局部內部類只能訪問final變量
一、Java中有那些不能實例化的類型?
二、抽象類有何特色?
三、接口有何特色?
8.一、面向對象5大設計原則
8.二、設計模式