6、面向对象编程(下)
目錄
- 面向對象編程(下)
- 6.1 關鍵字:static
- 1. static 關鍵字的使用
- 2. static應用舉例和練習
- 2.1 static 關鍵字的應用
- 2.2練習
- 6.2 單例設計模式
- 1. 設計模式:
- 2. 單例設計模式:
- 2.1 單例的餓漢式
- 2.2 單例的懶漢式實現:
- 3. 單例模式的優點:
- 4. 應用場景:
- 6.3 類的成員之四:代碼塊(或初始化塊)
- 1. 對屬性可以賦值的位置:
- 2. 代碼塊練習
- 練習1:
- 練習2:
- 6.4 關鍵字:final
- 1. final關鍵字
- 2. 面試題:
- 6.5 抽象類與抽象方法
- 1. abstract 關鍵字的使用
- 2. abstract 使用上的`注意點`:
- 3. 抽象的應用場景
- 解決方案:
- 練習
- Employee類
- Manager類
- CommonEmployee類
- EmployeeTest類
- 6.6 模板方法設計模式及應用場景(多態的應用)
- 解決的問題:
- 練習1
- 練習2
- 6.7 接口
- 1. 接口(interface)是抽象方法和常量值定義的集合。
- 2. 接口的特點:
- 3. 接口舉例:
- 4. 接口的使用
- 多態性:
- 創建接口匿名實現類的對象
- 5. 接口的應用:代理模式
- 1. 概述:
- 2. 舉例:
- 3. 應用場景:
- 4. 分類:
- 5. 靜態代理:
- 6. 接口的應用:工廠模式
- 1. 面向對象的設計模式:
- 1.1 OCP(開閉原則,Open-Closed Principle)
- 1.2 DIP(依賴倒轉原則,Dependence Inversion Principle)
- 1.3 LOD(迪米特法則,Law Of Demeter)
- 2. 工廠模式的分類:
- 2.1 無工廠模式
- 2.2 簡單工廠模式
- 2.3 工廠方法模式
- 2.4 抽象工廠模式
- 7. 接口和抽象類之間的對比
- 1. 面試題1:排錯
- 2. 面試題2:排錯
- 8. 接口練習
- 1. 定義一個接口用來實現兩個對象的比較。
- 2. 定義一個 Circle 類,聲明 redius 屬性,提供 getter 和 setter 方法
- 3. 定義一個 ComparableCircle 類,繼承 Circle 類并且實現 CompareObject 接口。在 ComparableCircle 類中給出接口中方法 compareTo 的實現體,用來比較兩個圓的半徑大小。
- 4. 定義一個測試類 InterfaceTest,創建兩個 ComparableCircle 對象, 調用 compareTo 方法比較兩個類的半徑大小。
- 9. java8中關于接口的新特性
- 1. JDK8:除了全局常量和抽象方法之外,還可以定義靜態方法、默認方法(略)
- 2. subclasstest類
- 3. 練習:接口沖突的解決辦法
- 6.8 類的成員之五:內部類
- 1. 概述
- 2. 分類:
- 3. 局部內部類和成員內部類
面向對象編程(下)
6.1 關鍵字:static
1. static 關鍵字的使用
當我們編寫一個類時,其實就是在描述其對象的屬性和行為,而并沒有產生實質上
的對象,只有通過new關鍵字才會產生出對象,這時系統才會分配內存空間給對象,
其方法才可以供外部調用。我們有時候希望無論是否產生了對象或無論產生了多少
對象的情況下,某些特定的數據在內存空間里只有一份,例如所有的中國人都有個
國家名稱,每一個中國人都共享這個國家名稱,不必在每一個中國人的實例對象中
都單獨分配一個用于代表國家名稱的變量。
3.1 屬性:是否使用 static 修飾,又分為:靜態屬性 VS 非靜態屬性(實例變量)
實例變量:我們創建了類的多個對象,每個對象都獨立的擁有了一套類中的非靜態屬性。
當修改其中一個非靜態屬性時,不會導致其他對象中同樣的屬性值的修飾。
靜態變量:我們創建了類的多個對象,多個對象共享同一個靜態變量。當通過靜態變量去修改某一個變量時,會導致其他對象調用此靜態變量時,是修改過的。
3.2 static 修飾屬性的其他說明:
① 靜態變量隨著類的加載而加載??梢酝ㄟ^"類.靜態變量"的方式進行調用。
② 靜態變量的加載要早于對象的創建。
③ 由于類只會加載一次,則靜態變量在內存中也只會存在一次。存在方法區的靜態域中。
④ 類變量 實例變量
類 yes no
對象 yes yes
3.3 靜態屬性舉例:System.out;Math.PI;
4.使用 static 修飾方法:靜態方法
① 隨著類的加載而加載,可以通過"類.靜態方法"的方式調用
② 靜態方法 非靜態方法
類 yes no
對象 yes yes
③ 靜態方法中,只能調用靜態的方法或屬性
非靜態的方法中,可以調用所有的方法或屬性
5.static 注意點:
5.1 在靜態的方法內,不能使用 this 關鍵字、super 關鍵字
5.2 關于靜態屬性和靜態方法的使用,大家從生命周期的角度去理解。
6.開發中,如何確定一個屬性是否需要聲明 static 的?
》 屬性是可以被多個對象所共享的,不會隨著對象的不同而不同的。
》 類中的常量也常常聲明為 static
開發中,如何確定一個方法是否要聲明為 static 的?
》 操作靜態屬性的方法,通常設置為 static 的
》 工具類中的方法,習慣上聲明為 static 的。比如:Math、Arrays、Collections
static靜態屬性:
public class StaticTest {public static void main(String[] args) {Chinese.nation = "中國";//隨著類的加載而加載,可以使用“類.靜態變量”方式調用Chinese c1 = new Chinese();c1.name = "王五";c1.age = 40;c1.nation = "CHN";Chinese c2 = new Chinese();c2.name = "張三";c2.age = 30;c2.nation = "CHINA";System.out.println(c1.nation);//CHINA//編譯不通過 // Chinese.name = "李四";} } //中國人 class Chinese{String name;int age;static String nation; }輸出結果:說明對nation進行了修改。
CHINAstatic靜態方法:
public class StaticTest {public static void main(String[] args) {Chinese.nation = "中國";Chinese c1 = new Chinese();//編譯不通過 // Chinese.name = "張繼科";c1.eat();Chinese.show();//編譯不通過 // chinese.eat();//不能使用類調用非靜態方法 // Chinese.info();} } //中國人 class Chinese{String name;int age;static String nation;public void eat(){System.out.println("中國人吃中餐");//調用非靜態結構this.info();System.out.println("name : " + name);//調用靜態結構walk();System.out.println("nation : " + Chinese.nation);}public static void show(){System.out.println("我是一個中國人!"); // eat(); // name = "Tom";//可以調用靜態的結構System.out.println(Chinese.nation); // System.out.println(nation);//同上等價 // System.out.println(this.nation);//報錯walk();}public void info(){System.out.println("name : " + name + ",age : " + age);}public static void walk(){} }2. static應用舉例和練習
2.1 static 關鍵字的應用
public class CircleTest {public static void main(String[] args) {Circle c1 = new Circle();Circle c2 = new Circle();Circle c3 = new Circle();System.out.println("c1 的 ID:" + c1.getId());System.out.println("c2 的 ID:" + c2.getId());System.out.println("c3 的 ID:" + c3.getId());System.out.println("創建圓的個數: " + Circle.getTotal());}}class Circle{private double radius;private int id; //需要自動賦值public Circle(){id = init++;total++;}public Circle(double radius){this();//或 // id = init++; // total++;this.radius = radius;}private static int total;//記錄創建圓的個數private static int init = 1001;//static 聲明的屬性被所有對象所共享public double findArea(){return 3.14 * radius * radius;}public double getRadius() {return radius;}public void setRadius(double radius) {this.radius = radius;}public int getId() {return id;}public static int getTotal() {return total;}}運行結果:
c1 的 ID:1001 c2 的 ID:1002 c3 的 ID:1003 創建圓的個數: 32.2練習
編寫一個類實現銀行賬戶的概念,包含的屬性有“帳號”、“密碼”、“存款余額”、 “利率”、“最小余額”,定義封裝這些屬性的方法。
賬號要自動生成。編寫主類,使用銀行賬戶類,輸入、輸出 3 個儲戶的上述信息。
考慮:哪些屬性可以設計成 static 屬性。
測試類
public class AccountTest {public static void main(String[] args) {Account acct1 = new Account();Account acct2 = new Account("qwerty",2000);Account.setInterestRate(0.012);Account.setMinMoney(100);System.out.println(acct1);System.out.println(acct2);System.out.println(acct1.getInterestRate());System.out.println(acct1.getMinMoney());} }運行結果:
Account [id=1001, pwd=000000, balance=0.0] Account [id=1002, pwd=qwerty, balance=2000.0] 0.012 100.06.2 單例設計模式
1. 設計模式:
設計模式是在大量的實踐中總結和理論化之后優選的代碼結構、編程風格、以及解決問題的思考方式。設計模式免去我們自己再思考和摸索。就像是經典的棋譜,不同的棋局,我們用不同的棋譜?!碧茁贰?/p>
2. 單例設計模式:
餓漢式 VS 懶漢式
餓漢式:
壞處:對象加載時間過長。
好處:餓漢式是線程安全的。
懶漢式:
好處:延遲對象的創建。
壞處:目前的寫法,會線程不安全?!?gt;到多線程內容時,再修改
餓漢式:加載類就已經存在
懶漢式:調用方法時才創建對象
2.1 單例的餓漢式
public class SingletonTest {public static void main(String[] args) { // Bank bank1 = new Bank(); // Bank bank2 = new Bank();Bank bank1 = Bank.getInstance();Bank bank2 = Bank.getInstance();System.out.println(bank1 == bank2);} }//單例的餓漢式 class Bank{//1.私有化類的構造器private Bank(){}//2.內部創見類的對象//4.要求此對象也必須聲明為靜態的private static Bank instance = new Bank();//3.提供公共的靜態的方法,返回類的對象。public static Bank getInstance(){return instance;} }2.2 單例的懶漢式實現:
懶漢式暫時還存在線程安全問題,講到多線程時,可修復
public class SingletonTest1 {public static void main(String[] args) {Order order1 = Order.getInstance();Order order2 = Order.getInstance();System.out.println(order1 == order2);} } class Order{//1.私有化類的構造器private Order(){}//2.聲明當前類對象,沒有初始化。//此對象也必須聲明為 static 的private static Order instance = null;//3.聲明 public、static 的返回當前類對象的方法public static Order getInstance(){if(instance == null){instance = new Order();}return instance;} }3. 單例模式的優點:
由于單例模式只生成一個實例,減少了系統性能開銷,當一個對象的產生需要比較多的資源時,如讀取配置、產生其他依賴對象時,則可以通過在應用啟動時直接產生一個單例對象,然后永久駐留內存的方式來解決。
舉例:java.lang中的Runtime
4. 應用場景:
- 網站的計數器,一般也是單例模式實現,否則難以同步。
- 應用程序的日志應用,一般都使用單例模式實現,這一般是由于共享的日志文件一直處于打開狀態,因為只能有一個實例去操作,否則內容不好追加。
- 數據庫連接池的設計一般也是采用單例模式,因為數據庫連接是一種數據庫資源。
- 項目中,讀取配置文件的類,一般也只有一個對象。沒有必要每次使用配置文件數據,都生成一個對象去讀取。
- Application 也是單例的典型應用
- Windows的Task Manager (任務管理器)就是很典型的單例模式
- Windows的Recycle Bin (回收站)也是典型的單例應用。在整個系統運行過程中,回收站一直維護著僅有的一個實例。
6.3 類的成員之四:代碼塊(或初始化塊)
內部可以有輸出語句
隨著類的加載而執行,而且只執行一次
作用:初始化類的信息
如果一個類中,定義了多個靜態代碼塊,則按照聲明的先后順序執行
靜態代碼塊的執行,優先于非靜態代碼塊的執行
靜態代碼塊內只能調用靜態的屬性、靜態的方法,不能調用非靜態的結構
內部可以有輸出語句
隨著對象的創建而執行
每創建一個對象,就執行一次非靜態代碼塊。
作用:可以在創建對象時,對對象的屬性等進行初始化。
如果一個類中,定義了多個非靜態代碼塊,則按照聲明的先后順序執行
非靜態代碼塊內可以調用靜態的屬性、靜態的方法,或非靜態的屬性、非靜態的方法。
1. 對屬性可以賦值的位置:
①默認初始化
②顯式初始化
③構造器中初始化
④有了對象以后,可以通過"對象.屬性"或"對象.方法"的方式,進行賦值。
⑤在代碼塊中賦值
輸出結果:
hello,static block-1 我是一個快樂的人。11 hello,static block-2 我是一個快樂的人 hello,block-2 hello,block-1 吃飯 我是一個快樂的人。11 hello,block-2 hello,block-1 吃飯 我是一個快樂的人。11 1 我是一個快樂的人。112. 代碼塊練習
練習1:
總結:由父類到子類,靜態先行
//總結:由父類到子類,靜態先行 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();} }輸出結果:
Root 的靜態初始化塊 Mid 的靜態初始化塊 Leaf 的靜態初始化塊 Root 的普通初始化塊 Root 的無參數的構造器 Mid 的普通初始化塊 Mid 的無參數的構造器 Mid 的帶參數構造器,其參數值:尚硅谷 Leaf 的普通初始化塊 Leaf 的構造器
從object類到root類到mid類到leaf類,靜態代碼塊先跑一遍
練習2:
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();}}輸出結果:
11111111111 44444444444 77777777777 ************************ 22222222222 33333333333 55555555555 66666666666 ************************ 22222222222 33333333333 55555555555 66666666666 ************************ 22222222222 33333333333測試:
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();}輸出結果:
11111111111 44444444444 77777777777測試2:
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();}輸出結果:
11111111111 44444444444 77777777777 ************************ 22222222222 33333333333 55555555555 66666666666 ************************ 22222222222 33333333333 55555555555 666666666666.4 關鍵字:final
1. final關鍵字
在Java中聲明類、變量和方法時,可使用關鍵字final來修飾,表示“最終的”。
final標記的類不能被繼承。提高安全性,提高程序的可讀性。
比如:String類、System類、StringBuffer類
final標記的方法不能被子類重寫。
比如:Object類中的getClass()。
final標記的變量(成員變量或局部變量)即稱為常量。名稱大寫,且只 能被賦值一次。
final標記的成員變量必須在聲明時或在每個構造器中或代碼塊中顯式賦
值,然后才能使用。
final double MY_PI = 3.14;
final:最終的
1.final可以用來修飾的結構:類、方法、變量
2.final用來修飾一個類:此類不能被其他類所繼承。
比如:String類、System類、StringBuffer類
3.final修飾一個方法:final標記的方法不能被子類重寫。
比如:Object類中的getClass()。
4.final用來修飾變量:此時的"變量"(成員變量或局部變量)就是一個常量。名稱大寫,且只能被賦值一次。
4.1 final修飾屬性,可以考慮賦值的位置有:顯式初始化、代碼塊中初始化、構造器中初始化
4.2 final修飾局部變量:
尤其是使用final修飾形參時,表明此形參是一個常量。當我們調用此方法時,給常量形參賦一個實參。
一旦賦值以后,就只能在方法體內使用此形參,但不能進行重新賦值。
static final 用來修飾:全局常量
完整代碼:
public class FinalTest {final int WIDTH = 0;final int LEFT;final int RIGHT; // final int DOWN;{LEFT = 1;}public FinalTest(){RIGHT = 2;}public FinalTest(int n){RIGHT = n;}// public void setDown(int down){ // this.DOWN = down; // }public void dowidth(){ // width = 20; //width cannot be resolved to a variable}public void show(){final int NUM = 10; //常量 // num += 20;}public void show(final int num){System.out.println(num);}public static void main(String[] args) {int num = 10;num = num + 5;FinalTest test = new FinalTest(); // test.setDown(5);test.show(10);} }final class FianlA{}//class B extends FinalA{ //錯誤,不能被繼承。 // //}//class C extends String{ // //}class AA{public final void show(){} }//class BB extends AA{ // 錯誤,不能被重寫。 // public void show(){ // // } //}2. 面試題:
o是常量,但是可以對i賦值
6.5 抽象類與抽象方法
隨著繼承層次中一個個新子類的定義,類變得越來越具體,而父類則更一般,更通用。類的設計應該保證父類和子類能夠共享特征。有時將一個父類設計得非常抽象,以至于它沒有具體的實例,這樣的類叫做抽象類。
1. abstract 關鍵字的使用
此類不能實例化
抽象類中一定有構造器,便于子類實例化時調用(涉及:子類對象實例化全過程)
開發中,都會提供抽象類的子類,讓子類對象實例化,實現相關的操作
抽象方法,只有方法的聲明,沒有方法體。
包含抽象方法的類,一定是一個抽象類。反之,抽象類中可以沒有抽象方法
若子類重寫了父類中所有的抽象方法,此子類方可實例化
若子類沒有重寫了父類中所有的抽象方法,此子類也是一個抽象類
2. abstract 使用上的注意點:
完整代碼:
public class AbstractTest {public static void main(String[] args) {//一旦 Person 類抽象了,就不可實例化 // Person p1 = new Person(); // p1.eat();} }abstract class Creature{public abstract void breath(); }abstract class Person extends Creature{String name;int age;public Person(){}public Person(String name,int age){this.name = name;this.age = age;}//不是抽象方法 // public void eat(){ // System.out.println("人吃飯"); // }//抽象方法public abstract void eat();public void walk(){System.out.println("人走路");} }class Student extends Person{public Student(String name,int age){super(name,age);}public void eat(){System.out.println("學生應該多吃有營養的。");}@Overridepublic void breath() {System.out.println("學生應該呼吸新鮮的無霧霾空氣");} }3. 抽象的應用場景
抽象類是用來模型化那些父類無法確定全部實現,而是由其子類提供具體實現的對象的類。
在航運公司系統中,Vehicle類需要定義兩個方法分別計算運輸工具的燃料效率和行駛距離。
問題:卡車(Truck)和駁船(RiverBarge)的燃料效率和行駛距離的計算方法完全不同。Vehicle類不能提供計算方法,但子類可以。
解決方案:
Java 允許類設計者指定:超類聲明一個方法但不提供實現,該方法的實現由子類提 供。這樣的方法稱為抽象方法。有一個或更多抽象方法的類稱為抽象類。
Vehicle 是一個抽象類,有兩個抽象方法。
注意:抽象類不能實例化 new Vihicle()是非法的
public abstract class Vehicle{public abstract double calcFuelEfficiency();//計算燃料效率的抽象方法public abstract double calcTripDistance();//計算行駛距離的抽象方法 } public class Truck extends Vehicle{public double calcFuelEfficiency(){//寫出計算卡車的燃料效率的具體方法}public double calcTripDistance(){//寫出計算卡車行駛距離的具體方法} } public class RiverBarge extends Vehicle{public double calcFuelEfficiency() {//寫出計算駁船的燃料效率的具體方法}public double calcTripDistance( ) {//寫出計算駁船行駛距離的具體方法} }練習
編寫一個Employee類,聲明為抽象類,
包含如下三個屬性:name,id,salary。
提供必要的構造器和抽象方法:work()。
對于Manager類來說,他既是員工,還具有獎金(bonus)的屬性。
請使用繼承的思想,設計CommonEmployee類和Manager類,要求類
中提供必要的方法進行屬性訪問。
Employee類
public abstract class Employee {private String name;private int id;private double salary;public Employee(){super();}public Employee(String name, int id, double salary) {super();this.name = name;this.id = id;this.salary = salary;}public abstract void work(); }Manager類
對于 Manager 類來說,他既是員工,還具有獎金(bonus)的屬性。
public class Manager extends Employee{private double bonus; //獎金public Manager(double bonus) {super();this.bonus = bonus;}public Manager(String name, int id, double salary, double bonus) {super(name, id, salary);this.bonus = bonus;}@Overridepublic void work() {System.out.println("管理員工,提高公司運行效率。");} }CommonEmployee類
public class CommonEmployee extends Employee {@Overridepublic void work() {System.out.println("員工在一線車間生產產品。");}}EmployeeTest類
請使用繼承的思想,設計 CommonEmployee 類和 Manager 類,要求類中必須提供必要的方法進行屬性訪問
public class EmployeeTest {public static void main(String[] args) {Employee manager = new Manager("庫克",1001,5000,50000);manager.work();CommonEmployee commonEmployee = new CommonEmployee();commonEmployee.work();} }6.6 模板方法設計模式及應用場景(多態的應用)
抽象類體現的就是一種模板模式的設計,抽象類作為多個子類的通用模
板,子類在抽象類的基礎上進行擴展、改造,但子類總體上會保留抽象
類的行為方式。
解決的問題:
當功能內部一部分實現是確定的,一部分實現是不確定的。這時可以把不確定的部分暴露出去,讓子類去實現。
換句話說,在軟件開發中實現一個算法時,整體步驟很固定、通用,這些步驟已經在父類中寫好了。但是某些部分易變,易變部分可以抽象出來,供不同子類實現。這就是一種模板模式。
練習1
/** 抽象類的應用:模板方法的設計模式*/ public class TemplateTest {public static void main(String[] args) {SubTemlate t = new SubTemlate();t.sendTime();} } abstract class Template{//計算某段代碼執行所需花費的時間public void sendTime(){long start = System.currentTimeMillis();code(); //不確定部分,易變的部分long end = System.currentTimeMillis();System.out.println("花費的時間為:" + (end - start));}public abstract void code(); }class SubTemlate extends Template{@Overridepublic void code() {for(int i = 2;i <= 1000;i++){boolean isFlag = true;for(int j = 2;j <= Math.sqrt(i);j++){if(i % j == 0){isFlag = false;break;}}if(isFlag){System.out.println(i);}}} }練習2
//抽象類的應用:模板方法的設計模式 public class TemplateMethodTest {public static void main(String[] args) {BankTemplateMethod btm = new DrawMoney();btm.process();BankTemplateMethod btm2 = new ManageMoney();btm2.process();} } abstract class BankTemplateMethod {// 具體方法public void takeNumber() {System.out.println("取號排隊");}public abstract void transact(); // 辦理具體的業務 //鉤子方法public void evaluate() {System.out.println("反饋評分");}// 模板方法,把基本操作組合到一起,子類一般不能重寫public final void process() {this.takeNumber();this.transact();// 像個鉤子,具體執行時,掛哪個子類,就執行哪個子類的實現代碼this.evaluate();} }class DrawMoney extends BankTemplateMethod {public void transact() {System.out.println("我要取款!!!");} }class ManageMoney extends BankTemplateMethod {public void transact() {System.out.println("我要理財!我這里有 2000 萬美元!!");} }模板方法設計模式是編程中經常用得到的模式。各個框架、類庫中都有他的
影子,比如常見的有:
數據庫訪問的封裝
Junit單元測試
JavaWeb的Servlet中關于doGet/doPost方法調用
Hibernate中模板程序
Spring中JDBCTemlate、HibernateTemplate等
6.7 接口
一方面,有時必須從幾個類中派生出一個子類,繼承它們所有的屬性和方法。但是,Java不支持多重繼承。有了接口,就可以得到多重繼承的效果。
另一方面,有時必須從幾個類中抽取出一些共同的行為特征,而它們之間又沒有is-a的關系,僅僅是具有相同的行為特征而已。例如:鼠標、鍵盤、打印機、掃描儀、攝像頭、充電器、MP3機、手機、數碼相機、移動硬盤等都支持USB連接。
接口就是規范,定義的是一組規則,體現了現實世界中“如果你是/要…則
必須能…”的思想。繼承是一個"是不是"的關系,而接口實現則是 "能不能" 的關系。
接口的本質是契約,標準,規范,就像我們的法律一樣。制定好后大家都
要遵守
1. 接口(interface)是抽象方法和常量值定義的集合。
2. 接口的特點:
- 用 interface 來定義。
- 接口中的所有成員變量都默認是由 public static final 修飾的。
- 接口中的所有抽象方法都默認是由 public abstract 修飾的。
- 接口中沒有構造器。
- 接口采用多繼承機制。
3. 接口舉例:
4. 接口的使用
- 1.接口使用 interface 來定義。
- 2.在 Java 中:接口和類是并列的兩個結構
- 3.如何去定義兩個接口:定義接口中的成員
3.1 JDK7 及以前:只能定義全局常量和抽象方法
全局常量:public static final 的,但是書寫中,可以省略不寫。
//全局變量public static final int MAX_SPEED = 7900;int MIN_SPEED = 1;//省略了 public static final抽象方法:public abstract 的
//抽象方法public abstract void fly();void stop();//省略了 public abstract3.2 JDK8:除了全局常量和抽象方法之外,還可以定義靜態方法、默認方法(略)。
- 4.接口中不能定義構造器!意味著接口不可以實例化。
- 5.Java 開發中,接口通過讓類去實現(implements)的方式來使用。
如果實現類覆蓋了接口中的所有方法,則此實現類就可以實例化
如果實現類沒有覆蓋接口中所有的抽象方法,則此實現類仍為一個抽象類
只實現了一個抽象方法(此類仍然為抽象類abstract):
abstract class Kite implements Flayable{@Overridepublic void fly() {} }- 6.Java 類可以實現多個接口 —>彌補了 Java 單繼承性的局限性
格式:class AA extends BB implementd CC,DD,EE
class Bullet extends Object implements Flayable,Attackable,CC{}- 7.接口與接口之間是繼承,而且可以多繼承
-
8.接口的具體使用,體現多態性
接口的主要用途就是被實現類實現。(面向接口編程) -
9.接口,實際可以看作是一種規范
-
面試題:抽象類與接口有哪些異同?
完整代碼:
public class InterfaceTest {public static void main(String[] args) {System.out.println(Flayable.MAX_SPEED);System.out.println(Flayable.MIN_SPEED);} } interface Flayable{//全局變量public static final int MAX_SPEED = 7900;int MIN_SPEED = 1;//省略了 public static final//抽象方法public abstract void fly();void stop();//省略了 public abstract//Interfaces cannot have constructors // public Flayable(){ // // } } interface Attackable{void attack(); }class Plane implements Flayable{@Overridepublic void fly() {System.out.println("飛機通過引擎起飛");}@Overridepublic void stop() {System.out.println("駕駛員減速停止");}} abstract class Kite implements Flayable{@Overridepublic void fly() {} }class Bullet extends Object implements Flayable,Attackable,CC{@Overridepublic void attack() {// TODO Auto-generated method stub}@Overridepublic void fly() {// TODO Auto-generated method stub}@Overridepublic void stop() {// TODO Auto-generated method stub}@Overridepublic void method1() {// TODO Auto-generated method stub}@Overridepublic void method2() {// TODO Auto-generated method stub} }//********************************* interface AA{void method1(); } interface BB{void method2(); } interface CC extends AA,BB{}多態性:
interface USB{//常量:定義了長、寬、最大最小傳輸速度等void start();void stop(); } class Flash implements USB{@Overridepublic void start() {System.out.println("U 盤開始工作");}@Overridepublic void stop() {System.out.println("U 盤結束工作");} } class Printer implements USB{@Overridepublic void start() {System.out.println("打印機開啟工作");}@Overridepublic void stop() {System.out.println("打印機結束工作");}}computer:
class Computer{public void transferData(USB usb){//USB usb = new Flash();usb.start();System.out.println("具體傳輸數據的細節");usb.stop();}}多態性:
Computer com = new Computer();Flash flash = new Flash();com.transferData(flash);創建接口匿名實現類的對象
Computer com = new Computer();//1.創建了接口的非匿名實現類的非匿名對象Flash flash = new Flash();com.transferData(flash);//2. 創建了接口的非匿名實現類的匿名對象com.transferData(new Printer());//3. 創建了接口的匿名實現類的非匿名對象USB phone = new USB(){@Overridepublic void start() {System.out.println("手機開始工作");}@Overridepublic void stop() {System.out.println("手機結束工作");}};com.transferData(phone);//4. 創建了接口的匿名實現類的匿名對象com.transferData(new USB(){@Overridepublic void start() {System.out.println("mp3 開始工作");}@Overridepublic void stop() {System.out.println("mp3 結束工作");}});完整代碼:
/** 接口的使用* 1.接口使用上也滿足多態性* 2.接口,實際上就是定義了一種規范* 3.開發中,體會面向接口編程!**/ public class USBTest {public static void main(String[] args) {Computer com = new Computer();//1.創建了接口的非匿名實現類的非匿名對象Flash flash = new Flash();com.transferData(flash);//2. 創建了接口的非匿名實現類的匿名對象com.transferData(new Printer());//3. 創建了接口的匿名實現類的非匿名對象USB phone = new USB(){@Overridepublic void start() {System.out.println("手機開始工作");}@Overridepublic void stop() {System.out.println("手機結束工作");}};com.transferData(phone);//4. 創建了接口的匿名實現類的匿名對象com.transferData(new USB(){@Overridepublic void start() {System.out.println("mp3 開始工作");}@Overridepublic void stop() {System.out.println("mp3 結束工作");}});} }class Computer{public void transferData(USB usb){//USB usb = new Flash();usb.start();System.out.println("具體傳輸數據的細節");usb.stop();}}interface USB{//常量:定義了長、寬、最大最小傳輸速度等void start();void stop(); } class Flash implements USB{@Overridepublic void start() {System.out.println("U 盤開始工作");}@Overridepublic void stop() {System.out.println("U 盤結束工作");} } class Printer implements USB{@Overridepublic void start() {System.out.println("打印機開啟工作");}@Overridepublic void stop() {System.out.println("打印機結束工作");}}5. 接口的應用:代理模式
1. 概述:
代理模式是Java開發中使用較多的一種設計模式。代理設計就是為其他對象提供一種代理以控制對這個對象的訪問
2. 舉例:
接口:
interface NetWork{public void browse();}被代理類:
class Server implements NetWork{@Overridepublic void browse() {System.out.println("真實的服務器來訪問網絡");} }代理類:
class ProxyServer implements NetWork{private NetWork work;public ProxyServer(NetWork work){this.work = work;}public void check(){System.out.println("聯網前的檢查工作");}@Overridepublic void browse() {check();work.browse();}}主函數:通郭proxy進行代理
Server server = new Server(); // server.browse();ProxyServer proxyServer = new ProxyServer(server);proxyServer.browse();完整代碼:
package 面向對象_下.k接口;/*** @Projectname java_based* @Filename NetWorkTest* @Author an* @Data 2022/7/6 8:03* @Description TODO*/ /** 接口的應用:代理模式***/ public class NetWorkTest {public static void main(String[] args) {Server server = new Server(); // server.browse();ProxyServer proxyServer = new ProxyServer(server);proxyServer.browse();} } interface NetWork{public void browse();} //被代理類 class Server implements NetWork{@Overridepublic void browse() {System.out.println("真實的服務器來訪問網絡");} } //代理類 class ProxyServer implements NetWork{private NetWork work;public ProxyServer(NetWork work){this.work = work;}public void check(){System.out.println("聯網前的檢查工作");}@Overridepublic void browse() {check();work.browse();}}輸出結果:
聯網前的檢查工作 真實的服務器來訪問網絡3. 應用場景:
安全代理:屏蔽對真實角色的直接訪問。
遠程代理:通過代理類處理遠程方法調用(RMI)
延遲加載:先加載輕量級的代理對象,真正需要再加載真實對象
比如你要開發一個大文檔查看軟件,大文檔中有大的圖片,有可能一個圖片有100MB,在打開文件時,不可能將所有的圖片都顯示出來,這樣就可以使用代理模式,當需要查看圖片時,用proxy來進行大圖片的打開。
4. 分類:
靜態代理(靜態定義代理類)
動態代理(動態生成代理類)
JDK自帶的動態代理,需要反射等知識
5. 靜態代理:
public class StaticProxyTest {public static void main(String[] args) {Proxy s = new Proxy(new RealStar());s.confer();s.signContract();s.bookTicket();s.sing();s.collectMoney();} }interface Star {void confer();// 面談void signContract();// 簽合同void bookTicket();// 訂票void sing();// 唱歌void collectMoney();// 收錢 } //被代理類 class RealStar implements Star {public void confer() {}public void signContract() {}public void bookTicket() {}public void sing() {System.out.println("明星:歌唱~~~");}public void collectMoney() {} }//代理類 class Proxy implements Star {private Star real;public Proxy(Star real) {this.real = real;}public void confer() {System.out.println("經紀人面談");}public void signContract() {System.out.println("經紀人簽合同");}public void bookTicket() {System.out.println("經紀人訂票");}public void sing() {real.sing();}public void collectMoney() {System.out.println("經紀人收錢");} }輸出結果:
經紀人面談 經紀人簽合同 經紀人訂票 明星:歌唱~~~ 經紀人收錢6. 接口的應用:工廠模式
實現了創建者與調用者的分離,即將創建對象的具體過程屏蔽隔離起來,達到提高靈活性的目的。
其實設計模式和面向對象設計原則都是為了使得開發項目更加容易擴展和維護,解決方式就是一個“分工”。
社會的發展也是這樣,分工越來越細。
原始社會的人:人什么都要會,自己種,自己打獵,自己織衣服,自己治病
現在的人:可以只會一樣,其他都不會,只會 Java 也能活,不會做飯,不會開
車,不會…
1. 面向對象的設計模式:
(總共六個):這里說幾個和工廠模式相關的
1.1 OCP(開閉原則,Open-Closed Principle)
一個軟件的實體應當對擴展開放,對修改關閉。
當我們寫完的代碼,不能因為需求變化就修改。我們可以通過新增代碼的方式來解決變化的需求。如果每次需求變動都去修改原有的代碼,那原有的代碼就存在被修改錯誤的風險,當然這其中存在有意和無意的修改,都會導致原有正常運行的功能失效的風險,這樣很有可能會展開可怕的蝴蝶效應,使維護工作劇增。
說到底,開閉原則除了表面上的可擴展性強以外,在企業中更看重的是維護成本。
所以,開閉原則是設計模式的第一大原則,它的潛臺詞是:控制需求變動風險,縮小維護成本。
1.2 DIP(依賴倒轉原則,Dependence Inversion Principle)
要針對接口編程,不要針對實現編程。
如果 A 中關聯 B,那么盡量使得 B 實現某個接口,然后 A 與接口發生關系,不與 B 實現類發生關聯關系。
依賴倒置的潛臺詞是:面向抽象編程,解耦調用和被調用者。
1.3 LOD(迪米特法則,Law Of Demeter)
只與你直接的朋友通信,而避免和陌生人通信。
要求盡量的封裝,盡量的獨立,盡量的使用低級別的訪問修飾符。這是封裝特性的典型體現。
一個類如果暴露太多私用的方法和字段,會讓調用者很茫然。并且會給類造成不必要的判斷代碼。所以,我們使用盡量低的訪問修飾符,讓外界不知道我們的內部。這也是面向對象的基本思路。這是迪米特原則的一個特性,無法了解類更多的私有信息。
另外,迪米特原則要求類之間的直接聯系盡量的少,兩個類的訪問,通過第三個中介類來實現。
迪米特原則的潛臺詞是:不和陌生人說話,有事去中介。
2. 工廠模式的分類:
- 簡單工廠模式:用來生產同一等級結構中的任意產品。(對于增加新的產品,
需要修改已有代碼) - 工廠方法模式:用來生產同一等級結構中的固定產品。(支持增加任意產品)
- 抽象工廠模式:用來生產不同產品族的全部產品。(對于增加新的產品,無
能為力;支持增加產品族)
GOF 在《設計模式》一書中將工廠模式分為兩類:工廠方法模式(Factory
Method)與抽象工廠模式(Abstract Factory)。將簡單工廠模式(Simple
Factory)看為工廠方法模式的一種特例,兩者歸為一類。
核心本質:
實例化對象,用工廠方法代替 new 操作。
將選擇實現類、創建對象統一管理和控制。從而將調用者跟我們的實現類解耦。
2.1 無工廠模式
interface Car{ void run(); } class Audi implements Car{ public void run() { System.out.println("奧迪在跑"); } } class BYD implements Car{ public void run() { System.out.println("比亞迪在跑"); } } public class Client01 { public static void main(String[] args) { Car a = new Audi(); Car b = new BYD(); a.run(); b.run(); } }2.2 簡單工廠模式
簡單工廠模式,從命名上就可以看出這個模式一定很簡單。它存在的目的很簡單:
定義一個用于創建對象的工廠類。
調用者只要知道他要什么,從哪里拿,如何創建,不需要知道。分工,多出了一
個專門生產 Car 的實現類對象的工廠類。把調用者與創建者分離。
小結:
簡單工廠模式也叫靜態工廠模式,就是工廠類一般是使用靜態方法,通過接收的
參數的不同來返回不同的實例對象。
缺點:對于增加新產品,不修改代碼的話,是無法擴展的。違反了開閉原則(對 擴展開放;對修改封閉)。
2.3 工廠方法模式
為了避免簡單工廠模式的缺點,不完全滿足 OCP(對擴展開放,對修改關閉)。
工廠方法模式和簡單工廠模式最大的不同在于,簡單工廠模式只有一個(對于一 個項目或者一個獨立的模塊而言)工廠類,而工廠方法模式有一組實現了相同接 口的工廠類。這樣在簡單工廠模式里集中在工廠方法上的壓力可以由工廠方法模
式里不同的工廠子類來分擔。
總結:
簡單工廠模式與工廠方法模式真正的避免了代碼的改動了?沒有。在簡單工廠模
式中,新產品的加入要修改工廠角色中的判斷語句;而在工廠方法模式中,要么
將判斷邏輯留在抽象工廠角色中,要么在客戶程序中將具體工廠角色寫死(就像
上面的例子一樣)。而且產品對象創建條件的改變必然會引起工廠角色的修改。
面對這種情況,Java 的反射機制與配置文件的巧妙結合突破了限制——這在 Spring 中完美的體現了出來。
2.4 抽象工廠模式
抽象工廠模式和工廠方法模式的區別就在于需要創建對象的復雜程度上。而且抽象工廠模式是三個里面最為抽象、最具一般性的。
抽象工廠模式的用意為:給客戶端提供一個接口,可以創建多個產品族中的產品對象。
而且使用抽象工廠模式還要滿足一下條件:
7. 接口和抽象類之間的對比
在開發中,常看到一個類不是去繼承一個已經實現好的類,而是要么繼承抽象類,要么實現接口。
1. 面試題1:排錯
interface A {int x = 0; } class B {int x = 1; } class C extends B implements A {public void pX() {System.out.println(x);}public static void main(String[] args) {new C().pX();} }解答:
interface A {int x = 0; } class B {int x = 1; } class C extends B implements A {public void pX() { // 編譯不通過,x 不明確System.out.println(x); // System.out.println(super.x); //1 // System.out.println(A.x);//0}public static void main(String[] args) {new C().pX();} }2. 面試題2:排錯
interface Playable { void play(); } interface Bounceable { void play(); } interface Rollable extends Playable, Bounceable { Ball ball = new Ball("PingPang"); }class Ball implements Rollable { private String name; public String getName() { return name; } public Ball(String name) { this.name = name; } public void play() { ball = new Ball("Football"); System.out.println(ball.getName()); } } interface Playable {void play(); } interface Bounceable {void play(); } interface Rollable extends Playable, Bounceable {Ball ball= new Ball("PingPang"); //省略了 public static final } public class Ball implements Rollable {private String name;public String getName() {return name;}public Ball(String name) {this.name= name;}public void play() {ball = new Ball("Football"); //The final field Rollable.ball cannot be assigned System.out.println(ball.getName());} }8. 接口練習
1. 定義一個接口用來實現兩個對象的比較。
public interface CompareObject {public int compareTo(Object o);//若返回值是 0,代表相等;若為正數,代表當前對象大;負數代表當前對象小}2. 定義一個 Circle 類,聲明 redius 屬性,提供 getter 和 setter 方法
public class Circle {private Double radius;public Double getRadius() {return radius;}public void setRadius(Double radius) {this.radius = radius;}public Circle() {super();}public Circle(Double radius) {super();this.radius = radius;}}3. 定義一個 ComparableCircle 類,繼承 Circle 類并且實現 CompareObject 接口。在 ComparableCircle 類中給出接口中方法 compareTo 的實現體,用來比較兩個圓的半徑大小。
public class ComparableCircle extends Circle implements CompareObject{public ComparableCircle(double radius) {super(radius);}@Overridepublic int compareTo(Object o) {if(this == o){return 0;}if(o instanceof ComparableCircle){ComparableCircle c = (ComparableCircle)o;//錯誤的寫法 // return (int)(this.getRedius() - c.getRedius());//正確的方式一: // if(this.getRadius() > c.getRadius()){ // return 1; // }else if(this.getRadius() < c.getRadius()){ // return -1; // }else{ // return 0; // }//當屬性 radius 聲明為 Double 類型時,可以調用包裝類的方法//正確的方式二:return this.getRadius().compareTo(c.getRadius());}else{return 0; // throw new RuntimeException("傳入數據類型不匹配");}} }4. 定義一個測試類 InterfaceTest,創建兩個 ComparableCircle 對象, 調用 compareTo 方法比較兩個類的半徑大小。
public class InterfaceTest {public static void main(String[] args) {ComparableCircle c1 = new ComparableCircle(3.4);ComparableCircle c2 = new ComparableCircle(3.6);int compareValue = c1.compareTo(c2);if(compareValue > 0){System.out.println("c1 對象大");}else if(compareValue < 0){System.out.println("c2 對象大");}else{System.out.println("兩個一樣的");}int compareValue1 = c1.compareTo(new String("AA"));System.out.println(compareValue1);} }9. java8中關于接口的新特性
Java 8中,你可以為接口添加靜態方法和默認方法。從技術角度來說,這是完全合法的,只是它看起來違反了接口作為一個抽象定義的理念。
靜態方法:使用static關鍵字修飾。可以通過接口直接調用靜態方法,并執行其方法體。我們經常在相互一起使用的類中使用靜態方法。你可以在標準庫中找到像Collection/Collections或者Path/Paths這樣成對的接口和類。
默認方法:默認方法使用default關鍵字修飾。可以通過實現類對象來調用。我們在已有的接口中提供新方法的同時,還保持了與舊版本代碼的兼容性。比如:java 8 API中對Collection、List、Comparator等接口提供了豐富的默認方法。
1. JDK8:除了全局常量和抽象方法之外,還可以定義靜態方法、默認方法(略)
public interface CompareA {//靜態方法public static void method1() {System.out.println("CompareA:西安");}//默認方法public default void method2(){System.out.println("CompareA:深圳");}default void method3(){System.out.println("CompareA:杭州");} } public interface CompareB {default void method3(){System.out.println("CompareB:上海");} } public class SuperClass {public void method3(){System.out.println("SuperClass:北京");} }知識點 1:接口中定義的靜態方法,只能通過接口來調用。
知識點 2:通過實現類的對象,可以調用接口中的默認方法。
如果實現類重寫了接口中的默認方法,調用時,仍然調用的是重寫以后的方法
知識點 3:如果子類(或實現類)繼承的父類和實現的接口中聲明了同名同參數的默認方法,那么子類在沒有重寫此方法的情況下,默認調用的是父類中的同名同參數的方法。–>類優先原則
知識點 4:如果實現類實現了多個接口,而這多個接口中定義了同名同參數的默認方法,那么在實現類沒有重寫此方法的情況下,報錯。–>接口沖突。
這就需要我們必須在實現類中重寫此方法
2. subclasstest類
public class SubClassTest {public static void main(String[] args) {SubClass s = new SubClass(); // s.method1(); // SubClass.method1(); // 知識點 1:接口中定義的靜態方法,只能通過接口來調用。CompareA.method1(); // 知識點 2:通過實現類的對象,可以調用接口中的默認方法。 // 如果實現類重寫了接口中的默認方法,調用時,仍然調用的是重寫以后的方法s.method2(); // 知識點 3:如果子類(或實現類)繼承的父類和實現的接口中聲明了同名同參數的默認方法, // 那么子類在沒有重寫此方法的情況下,默認調用的是父類中的同名同參數的方法。-->類優先原則 // 知識點 4:如果實現類實現了多個接口,而這多個接口中定義了同名同參數的默認方法, // 那么在實現類沒有重寫此方法的情況下,報錯。-->接口沖突。 // 這就需要我們必須在實現類中重寫此方法s.method3();} } class SubClass extends SuperClass implements CompareA,CompareB{public void method2(){System.out.println("SubClass:上海");}public void method3(){System.out.println("SubClass:深圳");}// 知識點 5:如何在子類(或實現類)的方法中調用父類、接口中被重寫的方法public void myMethod(){method3(); //調用自己定義的重寫的方法super.method3(); //調用的是父類中聲明的 // 調用接口中的默認方法CompareA.super.method3();CompareB.super.method3();} }輸出結果:
CompareA:西安 SubClass:上海 SubClass:深圳若一個接口中定義了一個默認方法,而另外一個接口中也定義了一個同名同參數的方法(不管此方法是否是默認方法),在實現類同時實現了這兩個接口時,會出現:接口沖突。
解決辦法:實現類必須覆蓋接口中同名同參數的方法,來解決沖突。
若一個接口中定義了一個默認方法,而父類中也定義了一個同名同參數的非抽象方法,則不會出現沖突問題。因為此時遵守:類優先原則。接口中具有相同名稱和參數的默認方法會被忽略。
3. 練習:接口沖突的解決辦法
/** 練習:接口沖突的解決方式*/ interface Filial {// 孝順的default void help() {System.out.println("老媽,我來救你了");} }interface Spoony {// 癡情的default void help() {System.out.println("媳婦,別怕,我來了");} }class Father{public void help(){System.out.println("兒子,救我媳婦!");} }class Man extends Father implements Filial, Spoony {@Overridepublic void help() {System.out.println("我該就誰呢?");Filial.super.help();Spoony.super.help();}}6.8 類的成員之五:內部類
1. 概述
當一個事物的內部,還有一個部分需要一個完整的結構進行描述,而這個內部的完整的結構又只為外部事物提供服務,那么整個內部的完整結構最好使用內部類。
在Java中,允許一個類的定義位于另一個類的內部,前者稱為內部類,后者稱為外部類。
Inner class一般用在定義它的類或語句塊之內,在外部引用它時必須給出完
整的名稱。
Inner class的名字不能與包含它的外部類類名相同;
2. 分類:
成員內部類(static成員內部類和非static成員內部類)
局部內部類(不談修飾符)、匿名內部類
- 1.Java中允許將一個類A聲明在另一個類B中,則類A就是內部類,類B就是外部類.
- 2.內部類的分類:成員內部類(靜態、非靜態) VS 局部內部類(方法內、代碼塊內、構造器內)
- 3.成員內部類
作為外部類的成員,
- 調用外部類的結構
- 可以被static修飾
- 可以被4種不同的權限修飾
作為一個類,
- 類內可以定義屬性、方法、構造器等
- 可以被final修飾,表示此類不能被繼承。言外之意,不使用final,就可以被繼承
- 可以abstract修飾
- 4.關注如下的3個問題
如何實例化成員內部類的對象
//創建Dog實例(靜態的成員內部類)Person.Dog dog = new Person.Dog();dog.show();//創建Bird實例(非靜態的成員內部類) // Person.Bird bird = new Person.Bird();Person p = new Person();Person.Bird bird = p.new Bird();bird.sing();如何在成員內部類中區分調用外部類的結構
public void display(String name){System.out.println(name); //方法的形參System.out.println(this.name); //內部類的屬性System.out.println(Person.this.name); //外部類的屬性}開發中局部內部類的使用 見《InnerClassTest1.java》
public class InnerClassTest1 {// 開發中很少見public void method(){ // 局部內部類class AA{}}// 返回一個實現了Comparable接口的類的對象public Comparable getComparable(){// 創建一個實現了Comparable接口的類:局部內部類//方式一: // class MyComparable implements Comparable{ // // @Override // public int compareTo(Object o) { // return 0; // } // // } // // return new MyComparable();//方式二:匿名return new Comparable(){@Overridepublic int compareTo(Object o) {return 0;}};} }3. 局部內部類和成員內部類
class Person{//靜態成員內部類static class Dog{}//非靜態成員內部類class Cat{}public void method(){//局部內部類class AA{}} } public class InnerClassTest {public static void main(String[] args) {//創建Dog實例(靜態的成員內部類)Person.Dog dog = new Person.Dog();dog.show();//創建Bird實例(非靜態的成員內部類) // Person.Bird bird = new Person.Bird();Person p = new Person();Person.Bird bird = p.new Bird();bird.sing();System.out.println();bird.display("喜鵲");} } class Person{String name = "李雷";int age;public void eat(){System.out.println("人,吃飯");}//靜態成員內部類static class Dog{String name;int age;public void show(){System.out.println("卡拉是條狗"); // eat();}}//非靜態成員內部類class Bird{String name = "杜鵑";public Bird(){}public void sing(){System.out.println("我是一只貓頭鷹");Person.this.eat();//調用外部類的非靜態屬性eat();System.out.println(age);}public void display(String name){System.out.println(name); //方法的形參System.out.println(this.name); //內部類的屬性System.out.println(Person.this.name); //外部類的屬性}}public void method(){//局部內部類class AA{}}{//局部內部類class BB{}}public Person(){//局部內部類class CC{}} }總結
以上是生活随笔為你收集整理的6、面向对象编程(下)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 利用计算机辅助药物设计方法有何优点,计算
- 下一篇: 杂项-报表-Minitab:Minita