Java第八課. 物件導向特徵3-多型&抽象類
回顧
1. toString ( ) : 返回物件資訊;
列印: syso ( 物件名. toString ( ) ) ; toString ( ) 可以省略, syso ( 物件名) ;
2. 繼承: 關鍵字 [ extends ]
子類繼承父類的的特徵和行為( 公共的特徵和行為) ; 構造方法不不能被繼承;
extends 繼承; 擴充套件
子類可以擴充套件父類 子類可以包含自己的特殊部分
3. 重寫( 覆寫) : 發生在繼承父類的子類中, 在子類的某個方法, 方法的修飾符, 返回值型別, 方法名, 引數列表和父類的某個方法完全一樣; ( Object 是所有類的父類)
4. 構造方法和繼承: 在子類物件例項化的時候, 因為繼承的原因會預設先呼叫父類的無參構造, 再呼叫子類的構造方法;
5. super 關鍵字: 子類可以用來呼叫父類的構造方法和普通方法; 呼叫構造方法時要放第一行, 普通方法時沒有要求;
在呼叫構造方法時 this 和 super 不能同時使用;
1. 多型性
1.1 多型的引入
模擬課堂上課: 小張( JavaTeacher) 來了, 我們開始上正經的java課程; 小李( Driver) 來了, 我們就開始開車; 小王( OldDriver) 來了, 我們就上職業素養課, 飆車;
步驟1 : 先建立父類Teacher
public class Teacher {
private String name;
public String getName ( ) {
return name;
}
public void setName ( String name) {
this . name = name;
}
public void teach ( ) {
System. out. println ( name+ "來了" ) ;
}
}
步驟2 : 再建立Teacher的各個子類
public class JavaTeacher extends Teacher {
@Override
public void teach ( ) {
super . teach ( ) ;
System. out. println ( "我們開始上正經的java課程" ) ;
}
}
public class Driver extends Teacher {
@Override
public void teach ( ) {
super . teach ( ) ;
System. out. println ( "我們就開始開車" ) ;
}
}
public class OldDriver extends Teacher {
@Override
public void teach ( ) {
super . teach ( ) ;
System. out. println ( "我們就上職業素養課,飆車" ) ;
}
}
步驟3 : 建立一個教室, 宣告一個上課的方法, 這個方法指定特定的老師來上課
public class Classroom {
public void showLesson ( JavaTeacher javaTeacher) {
javaTeacher. teach ( ) ;
}
public void showLesson ( Driver driver) {
driver. teach ( ) ;
}
public void showLesson ( OldDriver oldDriver) {
oldDriver. teach ( ) ;
}
}
步驟4 : 測試
public class TestClassroom {
public static void main ( String[ ] args) {
Classroom classroom= new Classroom ( ) ;
JavaTeacher javaTeacher= new JavaTeacher ( ) ;
javaTeacher. setName ( "小張" ) ;
classroom. showLesson ( javaTeacher) ;
Driver driver= new Driver ( ) ;
driver. setName ( "小李" ) ;
classroom. showLesson ( driver) ;
OldDriver oldDriver= new OldDriver ( ) ;
oldDriver. setName ( "小王" ) ;
classroom. showLesson ( oldDriver) ;
}
}
小張來了
我們開始上正經的java課程
小李來了
我們就開始開車
小王來了
我們就上職業素養課, 飆車
[ 問題] :
每增加一個老師, 這個類中就要多一個方法;
public class TestClassroom {
public void showLesson ( JavaTeacher javaTeacher) {
javaTeacher. teach ( ) ;
}
}
[ 改進] :
將父類作為一個方法的引數, 定義方法的時候, 並不確定這個引數的實際物件; [ 因為前面3 種老師都是Teacher的子類, 就可以把形式引數改成父類的引用, 然後再呼叫的時候將子類的物件作為實參傳進去] ;
public void showLesson ( Teacher teacher) {
teacher. teach ( ) ;
}
對於不同的物件, JavaTeacher的物件和Driver的物件, OldDriver的物件; 執行的過程和結果可能是不同的; [ 這就是多型]
1.2 多型性定義
Java中多型性指允許不同類的物件對同一訊息做出響應。即同一訊息可以
根據傳送物件的不同而採用多種不同的行為方式
• 傳送訊息就是方法呼叫;
• 現實中,關於多型的例子不勝列舉。比方說按下 F1 鍵這個動作,如果當前在IE介面下彈出的瀏覽器的幫助文件;如果當前在 Word 下彈出的就是office幫助;在 Windows 下彈出的就是 Windows 幫助和支援
• 可見,同一個事件發生在不同的物件上會產生不同的結果,因此,多型的
主要作用適用於[ 消除型別之間的耦合關係] ;
1.3 多型實現方式1-使用繼承
也是我們[ 物件導向的特徵之一]
概念:多型是同一個方法具有多個不同的表現形態。
多型其實就是同一個父類( 介面) 的引用,使用不同的子類( 實現類) 而執行不同的操作。
操作步驟: 建立父類, 建立子類, 重寫父類的方法; 特定的場景中, 將父類作為形式引數, 實際引數為子類, 執行的過程和結果和子類物件有關;
不同的物件, 對於同一個方法執行過程和響應是不同的.
1.4 練習
樂器(Instrument)分為:鋼琴(Piano), 小提琴(Violin)
各種樂器的彈奏(play)方法各不相同。
編寫一個測試類InstrumentTest, 要求:
編寫方法testPlay, 對各種樂器進行彈奏測試,要依據樂器的不同,進行相應的彈奏。
在main ( ) 方法中進行測試
public class Instrument {
private String name;
public String getName ( ) {
return name;
}
public void setName ( String name) {
this . name = name;
}
public void play ( ) {
System. out. println ( "開始演奏:" + name) ;
}
}
public class Piano extends Instrument {
@Override
public void play ( ) {
super . play ( ) ;
System. out. println ( getName ( ) + "朵蕾咪發~" ) ;
}
}
public class Violin extends Instrument {
@Override
public void play ( ) {
super . play ( ) ;
System. out. println ( getName ( ) + "啦啦啦啦啦~" ) ;
}
}
public class InstrumentTest {
public void testPlay ( Instrument ins) {
ins. play ( ) ;
}
public static void main ( String[ ] args) {
InstrumentTest test= new InstrumentTest ( ) ;
Piano piano= new Piano ( ) ;
piano. setName ( "鋼琴" ) ;
test. testPlay ( piano) ;
Violin violin= new Violin ( ) ;
violin. setName ( "小提琴" ) ;
test. testPlay ( violin) ;
}
}
開始演奏: 鋼琴
鋼琴朵蕾咪發~
開始演奏: 小提琴
小提琴啦啦啦啦啦~
1.5 多型總結:
• 可替換性(substitutability)
• 多型對已存在程式碼具有可替換性;
• 可擴充性(extensibility)
• 多型對程式碼具有可擴充性。增加新的子類不影響已存在類的多型性、繼 承性,以及其他特性的執行和操作。實際上新加子類更容易獲得多型功能;
• 介面性(interface - ability)
• 多型是超類通過方法簽名,向子類提供了一個共同介面,由子類來完善 或者覆蓋它而實現的;
• 靈活性(flexibility)
• 它在應用中體現了靈活多樣的操作,提高了使用效率;
• 簡化性(simplicity)
• 多型簡化對應用軟體的程式碼編寫和修改過程,尤其在處理大量物件的運 算和操作時,這個特點尤為突出和重要;
2. 抽象類與抽象方法
2.1 抽象類
存在一個類, 這個類不太好描述, 但是確實是一個類; 通常一個類中會有屬性和方法 ; 而這種類內部的方法又不太好實現;
[ 引入例子] : 形狀是否能定義成一個類, 如果可以請問該類可以擁有什麼屬性和方法? 邊長? 求面積的方法? 子類: 圓形: R 矩形: w h
[ 出現問題] : 如果將形狀設定為父類, 此時其實沒有共同的屬性;
[ 解決問題] : 可以將這個類變成抽象;
[ 概念] :
在物件導向的概念中,所有的物件都是通過類來描繪,但是反過來,並不是所有的類都是用來描繪物件的。
[ 如果一個類中沒有包含足夠的資訊來描繪一個具體的物件,這樣的類就是抽象類] 。
基本結構:
abstract class 類名{ }
public abstract class Shape {
public abstract void getArea ( ) ;
public abstract void getLength ( ) ;
public void test ( ) {
System. out. println ( "普通方法" ) ;
}
}
public class Circle extends Shape {
private double r;
public double getR ( ) {
return r;
}
public void setR ( double r) {
this . r = r;
}
@Override
public void getArea ( ) {
System. out. println ( "圓的面積:" + ( Math. PI* r* r) ) ;
}
@Override
public void getLength ( ) {
System. out. println ( "圓的周長:" + ( Math. PI* r* 2 ) ) ;
}
public void testCircle ( ) {
System. out. println ( "這是子類特有的方法" ) ;
}
}
public abstract class Square extends Shape {
}
public class TestShape {
public static void main ( String[ ] args) {
Circle circle= new Circle ( ) ;
circle. setR ( 2.5 ) ;
circle. getArea ( ) ;
circle. test ( ) ;
圓的面積: 19.634954084936208
普通方法
抽象類能否包含普通方法? [ 可以 反之不行] ;
如果某個類中包含抽象方法, 那麼這個類就必須定義成抽象類;
( 有抽象方法一定是抽象類, 但抽象類不一定只有抽象方法)
抽象類的普通方法, 子類能不能繼承? [ 可以]
2.2 抽象類和抽象方法的特點
①抽象方法:被 abstract 修飾的方法就是抽象方法,沒有方法體。{ }
②抽象類:一個類中如果有至少1 個抽象方法,那麼這麼類必須也是抽象類,抽象類中也可以包含普通方法。
③抽象類不能直接例項化,只可以被繼承,如果一個類繼承了抽象類,需要重寫抽象類中的所有抽象方法( 如果不想重寫可以把這個子類設定成抽象類) 。
④抽象類中有構造方法, 但是不能被 abstract 修飾( 被修飾了就必須要重寫, 但構造方法不能被繼承) ,因為子類構造的時候需要呼叫父類的構造方法。
2.3 物件向上造型
[ 向上轉型] : 父類的引用指向子類物件
父類 引用名= new 子類( )
Shape s= new Circle ( ) ;
s. test ( ) ;
circle. testCircle ( ) ;
普通方法
這是子類特有的方法
[ 注意] :
只能呼叫[ "父類的所有屬性和方法+子類和父類共有的屬性和方法" ] , 對於[ "只存在子類中的方法或屬性" ] 無法呼叫;
2.4 抽象類的作用
為什麼要用抽象類:
分析, 設計, 定規則規範; A ( 分配 告訴大家要做什麼 設計, 不做具體實現) B ( 要做具體實現) C ( 要做具體實現) . 實現之前做一個標準- > 定規範- > 抽象類;
2.5【面試題】普通類和抽象類的區別
1. 普通類中不能包含抽象方法, 但抽象方法中可以包含普通方法; 一個類中有抽象方法存在就會被定義為抽象方法;
2. 抽象方法必須用 public 或 protected 修飾( 因為如果為 private 則子類無法繼承, 也就無法重寫該方法) ;
4. 普通類可以例項化物件, 抽象類則不可以直接例項化;
5. 如果一個類繼承抽象類, 則需要實現父類的抽象方法; 如果子類沒有實現父類的抽象方法, 則必須將子類也定義為 abstract 類;
2.6練習:
public abstract class Draw {
private int x;
private int y;
private String color;
public int getX ( ) {
return x;
}
public void setX ( int x) {
this . x = x;
}
public int getY ( ) {
return y;
}
public void setY ( int y) {
this . y = y;
}
public String getColor ( ) {
return color;
}
public void setColor ( String color) {
this . color = color;
}
public abstract String drawing ( ) ;
public Draw ( int x, int y, String color) {
super ( ) ;
this . x = x;
this . y = y;
this . color = color;
}
public Draw ( ) {
}
}
public class Line extends Draw {
private int endX;
private int endY;
public int getEndX ( ) {
return endX;
}
public void setEndX ( int endX) {
this . endX = endX;
}
public int getEndY ( ) {
return endY;
}
public void setEndY ( int endY) {
this . endY = endY;
}
@Override
public String drawing ( ) {
return "線條的繪製功能 [endX=" + endX + ", endY=" + endY + ", X=" + getX ( ) + ", Y=" + getY ( ) + ", Color="
+ getColor ( ) + "]" ;
}
public Line ( int x, int y, String color, int endX, int endY) {
super ( x, y, color) ;
this . endX = endX;
this . endY = endY;
}
}
public class Rectangle extends Draw {
private int width;
private int height;
public int getWidth ( ) {
return width;
}
public void setWidth ( int width) {
this . width = width;
}
public int getHeight ( ) {
return height;
}
public void setHeight ( int height) {
this . height = height;
}
@Override
public String drawing ( ) {
return "矩形的繪製功能: [width=" + width + ", height=" + height + ", X=" + getX ( ) + ", Y=" + getY ( )
+ ", Color=" + getColor ( ) + "]" ;
}
public Rectangle ( int x, int y, String color, int width, int height) {
super ( x, y, color) ;
this . width = width;
this . height = height;
}
}
public class TestDraw {
public String testDraw ( Draw draw) {
return draw. drawing ( ) ;
}
public static void main ( String[ ] args) {
TestDraw test= new TestDraw ( ) ;
System. out. println ( test. testDraw ( new Line ( 0 , 0 , "black" , 10 , 20 ) ) ) ;
System. out. println ( test. testDraw ( new Rectangle ( 0 , 0 , "red" , 80 , 90 ) ) ) ;
}
}
線條的繪製功能 [ endX= 10 , endY= 20 , X= 0 , Y= 0 , Color= black]
矩形的繪製功能: [ width= 80 , height= 90 , X= 0 , Y= 0 , Color= red]