爲何要定義抽象方法:若是定義某個方法時不能肯定該方法的具體實現細節; 好比定義 Person 類的 eat 方法時, 不能肯定其具體實現細節,由於中國人、 西方國家的人、 南亞國家的人吃飯方式不同。 能夠把該方法定義成一個抽象方法,具體 的實現細節,交給其後代(子類)來實現。java
使用 abstract 關鍵字修飾方法的定義,方法體必須爲空(不然就不是抽象方法),抽象方法必須是非靜態的(抽象方法不能被 static 修飾), 抽象方法不能被 final 修飾、 不能被 private 修飾.ide
[ 修飾符 ] abstract 返回值類型 methodName() ; //注意這裏沒有 { }
爲何要定義抽象類:定義抽象方法的類, 必須被定義成抽象類
抽象類的定義方法設計
[ 修飾符 ] abstract class className { //使用 abstract 修飾類定義 }
/** * 爲何要有抽象類 * 一、含有抽象方法的類,必須被定義成抽象類; * 可是,抽象類未必非要有抽象方法 * 二、若是指望當前類不能被實例化, * 而是交給子類完成實例化操做,能夠定義抽象類 * (抽象類有構造方法,抽象類不能被實例化(直接建立該類的對象)) * Person p = new Person(); // 錯誤的 */ public abstract class Person { // 只要有花括號,就能夠執行,這樣的方法已經實現過了 /**當一個方法在定義時沒法肯定其實現細節(具體處理什麼、怎麼處理) * 若是一個方法不是native 修飾的, * 當它沒有方法體時,這個方法是不能被執行的,此時這個方法就是一個抽象的方法, * 須要使用抽象關鍵字來修飾(abstract) */ public abstract void eat(String food); /** * abstract 修飾方法時,不能與 static 、 final連用 */ } /** * 子類繼承某個抽象類 * 一、若是子類依然不肯定某個方法的實現細節(不實現繼承自父類的抽象方法), * 則能夠將該類繼續聲明爲抽象類 * 二、若是子類不但願是抽象類,必須實現繼承自父類的抽象方法 */ public class Sinaean extends Person{ public Sinaean(){ super(); } // 這個方法再也不是抽象方法了,並且能夠有方法體 @Override public void eat(String food) { System.out.println("中國人大部分都用筷子吃"+ food); } } public class Thai extends Person{ @Override public void eat(String food) { System.out.println("泰國人有時候用手抓着吃: "+ food); } } /** * 建立抽象類的實例: * 一、建立其子類類型的實例(這是本質) * 二、能夠經過靜態方法來得到其實例(本質仍是建立子類類型對象 ) */ public class Main { public static void main(String[] args) { // 不能實例化Person 類型:抽象類不能被實例化 // Person p = new Person();//Cannot instantiate the type Person // 聲明一個Person 類型的變量p(p的編譯時類型是 Person) // 建立抽象類的子類類型的對象,並將其堆內存中首地址賦值給棧空間中的p變量 Person p =new Sinaean(); p.eat("火鍋"); System.out.println("運行時類型: " + p.getClass());System.out.println("內存中的首地址是: "+ System.identityHashCode(p)); // 建立抽象類的子類類型的對象,並將其堆內存中首地址賦值給棧空間中的p變量 // p 變量中原來存儲的地址將被覆蓋 p = new Thai(); p.eat("米飯"); System.out.println("運行時類型: " + p.getClass()); System.out.println("內存中的首地址是: "+ System.identityHashCode(p)); Calendar c = Calendar.getInstance(); // 經過靜態方法來得到一個實例 Class<?> clazz = c.getClass();// 得到c 所引用的對象的真實類型(運行時類型) System.out.println(clazz); Class<?> superClass = clazz.getSuperclass();// 得到clazz的父類 System.out.println(superClass); } }
抽象類的特色 一、抽象類【有構造】,可是不能被實例化 抽象類的構造方法專供子類調用(構造方法也是能夠執行的) 二、抽象類中能夠有抽象方法,也能夠沒有 含有抽象方法的類必須是抽象類(參看Person中的第一點) 抽象類中能夠沒有抽象方法(參看Person中的第二點) 三、怎麼建立抽象類的實例:建立其子類類型的實例(這是本質) 待建立對象的子類類型必須是非抽象類 不必定非要是直接子類,間接子類也能夠 能夠經過靜態方法來得到其實例(Calendar.getInstance() ) Calendar c = Calendar.getInstance(); 四、應該選擇哪一種方式來建立抽象類的實例: a>、若是當前抽象類中有靜態方法,則優先使用靜態方法 b>、若是子類中有靜態方法返回相應實例,用子類的靜態方法 c>、尋找非抽象的子類,建立子類類型的對象便可 d>、本身繼承這個類並實現其中的抽象方法,而後建立實例 注意:有時爲了實現咱們的需求,可能會不調用靜態方法來得到實例,而是選擇建立子類對象
接口是一種比抽象類更抽象的類型;接口是從多個類似的類中抽象出來的規範: 它定 義了某一批類(接口的實現類或實現類的子類)所要必須遵循的規範。 接口只定義常量 或方法, 而不關注方法的實現細節,接口體現了規範和實現相分離的設計哲學。code
[ 修飾符 ] interface InterfaceName { 定義在接口中的常量 ( 0 到 n 個) 定義在接口中的抽象方法 ( 0 到 n 個) static 修飾的方法 ( 0 到 n 個) default 修飾的方法( 0 到 n 個) }
接口的繼承使用 extends 關鍵字實現:對象
public interface Usb1 extends Usb {};
Java 語言中的接口能夠繼承多個接口: 多個接口之間使用 , 隔開 ( 英文狀態的逗 號 );子接口能夠繼承父接口中的: 抽象方法、常量屬性、內部類、枚舉類繼承
類能夠實現接口:使用 implements 關鍵字來實現接口
接口中的屬性默認都是 public 、 static 、 final 類型:這些成員必須被顯式初始化;接口中的方法默認都是 public 、 abstract 類型的。內存
接口中根本就沒有構造方法, 也就可能經過構造來實例化,但容許定義接口類型的引用變量,該引用變量引用實現了這個接口的類的實例。get
接口不能實現另外一個接口, 但能夠繼承多個接口。it
接口必須經過實現類來實現它的抽象方法,當某個類實現了某個接口時, 必須實現其中全部的抽象方法,或者是不實現其中的抽象方法, 而把該類定義成抽象類。
類只能繼承一個類, 但能夠實現多個接口,多個接口之間用逗號分開。
共同點: 接口和抽象類都不能被實例化 接口和抽象類都處於繼承樹的頂端 接口和抽象類均可以包含抽象方法 實現接口或繼承抽象類的普通類必須實現其中的抽象方法 區別 抽象類中能夠有非抽象方法, 接口中只能有抽象方法或static修飾的方法或default修飾的方法 一個類只能繼承一個直接父類, 而接口能夠實現多繼承 抽象類可定義靜態屬性和普通屬性, 而接口只能定義靜態屬性 抽象類有本身的構造, 接口徹底沒有 抽象類中能夠有代碼塊, 接口中不能夠有
/** * 聲明接口,並肯定接口中能夠有什麼 * 一、常量 * 二、抽象方法 * 三、 default 修飾的非抽象方法(JDK1.8開始)* 四、接口沒有構造方法 */ public interface Usb { // 接口沒有構造方法 // public Usb(){} /** * 接口中只能定義常量(沒有不是否是常量的屬性) * 一、接口中全部的屬性默認都是 public static final 修飾的 * 二、常量的命名:全部字母都是大寫,若是有多個單詞,中間用下劃線隔開 * */ int POWER_UNIT = 100 ;// 充當供電單位 /** * JDK1.8 以前 僅容許在接口中聲明抽象方法 * 全部的方法都是 public abstrct 修飾的 */ void power(); /** * JDK1.8 開始,容許定義被default修飾的非抽象方法 * 這個方法是個public 修飾的非靜態方法(子類或子接口能夠重寫) */ default void show(){ System.out.println("每次供電單位是: "+POWER_UNIT) ; } } /** * 一、類 能夠實現接口,用關鍵字implements來完成實現 * 二、若是原本不但願是抽象類,則須要實現從接口"繼承"的全部抽象方法 */ public class MiUsb extends Object implements Usb { /** * MiUsb中都有什麼 * 從Object中繼承的全部方法 * 從Usb中繼承的常量 * 從Usb中繼承的default的方法(JDK1.8開始) * 實現了全部的抽象方法 */ @Override public void power() { System.out.println("小米Usb充電器,供電單位: "+POWER_UNIT); } @Override public void show() { Usb.super.show(); } } public class Test { public static void main(String[] args) { // 聲明一個接口類型的引用變量Usb u = null; // 建立實現類的實例 並將其堆內存首地址賦值給u變量 u = new MiUsb(); u.power(); } } 一個類實現多個接口 public interface Transfer { void transmission(); } /** * 一、用接口繼承接口 * 二、接口能夠繼承父接口中的常量、抽象方法、 default方法 * 三、一個接口能夠繼承多個接口,中間用逗號隔開就行 */ public interface UsbTypeC extends Usb , Transfer{} /** * 一個類能夠實現多個接口,中間用逗號分隔開就能夠 */ public class OppoUsb implements UsbTypeC,Usb{ @Override public void transmission() { System.out.println("Oppo手機"); } @Override public void power() { System.out.println("Oppo 手機,供電單位"+ POWER_UNIT); } } public class Test2 { public static void main(String[] args) { // 聲明一個接口類型的引用變量 OppoUsb u = null; u = new OppoUsb(); u.power();// 實現了Usb接口中的方法 u.transmission();// 實現了Transfer接口中的方法 } }
內部類的分類以下:
成員內部類: 實例內部類 靜態內部類 局部內部類: 匿名內部類
public class Human {/* 類體括號 */ public static void main(String[] args){ // main 方法的方法體開始 int a = 250; System.out.println(a); class ON{ // 局部內部類(Local Inner Class) } ON oo = new ON(); System.out.println(oo); class OFF{ // 局部內部類(Local Inner Class) } }// main 方法的方法體結束static String earth; // 屬性:靜態屬性( 類屬性 ) String name ; // 屬性 :實例屬性(實例變量) static class Country{ // 靜態內部類[ static Inner Class] } class Head{// 實例內部類 (成員內部類) [ Member Inner Class ] } class Hand{// 實例內部類 } }
/** * 得到某個類內部的全部的靜態內部類和全部的成員內部類 * 注意:不能得到到局部內部類 */ public class GetInnerClass { public static void main(String[] args) { Class<?> c = Human.class; // 得到 c 內部的內部類(靜態內部類、成員內部類) Class<?>[] classes = c.getDeclaredClasses();// 得到本類內聲明的非 局部內部類 for (int i = 0; i < classes.length; i++) { Class<?> cc = classes[i]; System.out.println(cc); } } }
也能夠經過一個內部類獲取本身聲明在哪一個類內部
public class GetOutterClass { public static void main(String[] args) { Class<?> c = Human.Country.class; // 得到某個內部類聲明在那個外部類中 Class<?> oc = c.getDeclaringClass(); // 得到聲明本身的 那個類 System.out.println(oc); } }
public class GetInstance1 { public static void main(String[] args) { /** 靜態內部類的實例 */ Human.Country c = new Human.Country(); System.out.println(c); /** 實例內部類的實例 */ Human h = new Human();// 建立外部類的實例 Human.Hand hand = h.new Hand();// 之外部類的實例 h 爲基礎,建立內部類的實例 System.out.println(hand); // 或者: Human.Head head= new Human().new Head(); System.out.println(head); } }
有一個局部內部類,它連名字都沒有,則它就是匿名內部類,可是它有對應的.class文件。
新建一個新的 Class,叫作 TestAnonyous1。隨後建立一個接口,叫作 USB,並提供一個方法(void transfer) 。具體在 TestAnonyous1 中的例子:用匿 名內部類實現接口。
/** * 建立匿名內部類 */ public class TestAnonymours1 { public static void main(String[] args) { // 編譯時類型:變量u 聲明的類型是USB // 用匿名內部類來實現接口 USB u = new USB(){ @Override public void transfer() { System.out.println("USB正在傳輸"); } };// 把USB當成屍體,結果鬼{}上身了,就能實例化了 u.transfer(); System.out.println(System.identityHashCode(u)); // 得到建立的實例的運行時類型 Class<?> c = u.getClass();// 任何一個對象均可以經過getClass來得到其 運行時類型 System.out.println(c); Class<?> oc = c.getDeclaringClass();// 嘗試得到聲明本身的那個外部類 System.out.println(oc);// null 說明 匿名內部類不是直接聲明在類體內部的 Class<?>[] inters = c.getInterfaces(); for (int i = 0; i < inters.length; i++) { System.out.println(inters[i]); } } }
public abstract class AbstractUSB implements USB{ // 從實現的接口中繼承了抽象方法 transfer } /** * 建立匿名內部類 */ public class TestAnonymours2 { public static void main(String[] args) { // 建立一個抽象類的實例(本質必定是建立其子類類型的實例) // 用匿名內部類來繼承抽象類,並實現其中的抽象方法 AbstractUSB au = new AbstractUSB() { @Overridepublic void transfer() { System.out.println("AbstractUSB正在傳輸"); } }; au.transfer(); Class<?> c = au.getClass();// 得到au 對象的運行時類型 System.out.println("匿名內部類: "+ c.getName()); Class<?> sc = c.getSuperclass(); System.out.println("匿名內部類的父類: " + sc.getName() ); } }
/** * 建立匿名內部類 */ public class TestAnonymours3 { public static void main(String[] args) { // 用匿名內部類繼承一個普通的類 // 並重寫其中的方法 Object o = new Object(){ @Override public String toString(){ return "我是鬼。。 "; }}; System.out.println(o); System.out.println(o.getClass()); System.out.println(o.getClass().getSuperclass()); } }
一、內部類 嵌套在另外一個類內部的類 二、內部類的分類 直接寫在類體括號內的: 靜態內部類、非靜態內部類(實例內部類、成員內部類) 不是直接寫在類體括號內,好比寫在方法中、寫在代碼塊中:局部內部類 若是某個局部內部類連名字都沒有,那它就是匿名內部類 三、問題: 對於 Human.java 來講有一個與它對應的 Human.class 文件,內部類是否有對應的 .class 文件? 有.class 文件,對於靜態內部類、實例內部類來講,他們對應的 .class 的名稱是: 外部類類名$內部類類名.class好比 Human 類中的 Country 類對應的 字節碼文件的名稱是:Human$Country.class 對於局部內部類(有名稱的)來講:他們對應的 .class 文件名稱是:外部類類名$Number 內部類類名.class 其中的 Number 是 使用 該名稱 的 內部類 在 外部類 出現的位置(第幾個) 四、一個類可否獲取到本身的內部類(靜態內部類、成員內部類) GetInnerClass.java 五、一個內部類可否獲取本身聲明在哪一個類內部: GetOutterClass.java 六、建立內部類的實例 a>、局部內部類的實例,只能在當前的代碼塊內部使用, 好比 Human 類內部的 main 方法的 ON 類,則這個類只能在 main 方法內部使用 class ON{ // 局部內部類(Local Inner Class) } ON oo = new ON();// 建立局部內部類的實例 System.out.println(oo); b>、 建立靜態內部類的實例: // 外部類.靜態內部類 變量名 = new 外部類.靜態內部類()Human.Country c = new Human.Country(); c>、建立實例內部類的實例: Human h = new Human();// 建立外部類的實例 外部類.實例內部類 變量名 = 外部類實例.new 實例內部類(); Human.Hand hand = h .new Hand(); 七、匿名內部類 有一個局部內部類,它連名字都沒有,則它就是匿名內部類,可是它有對應的.class 文件 匿名內部類對應的.class 文件名 是外部類類名$數字.class a>、用匿名內部類實現接口: TestAnonymous1.java b>、用匿名內部類繼承抽象類: TestAnonymous2.java c>、用匿名內部類繼承普通的類: TestAnonymous3.java