多態(tài)
多態(tài)是面向對象編程中最后一個(封裝、繼承、多態(tài))也是最重要的特征。
程序設計當中,多態(tài)意味著,允許不同類的對象對同一消息做出不同的響應。
多態(tài)分為:
- 編譯時多態(tài) (設計時多態(tài)方法重載)
-
運行中多態(tài) (程序運行時動態(tài)決定調用哪個方法)
image.png
一般所說的java中的多態(tài)大多是運行時多態(tài)。
必要條件
- 滿足繼承關系
- 父類引用指向子類對象
示例

新建一個Animal類,作為動物基類,有兩個屬性,name、month,和一個eat方法。
Animal的子類中有自己特有的子類屬性和方法,
Cat中有weight、run(),
Dog中有sex、sleep()。
且都重寫了父類Animal中的eat()方法。
新建Animal.java:
public class Animal {
private String name;
private int month;
public Animal(){
}
public Animal(String name, int month){
this.name = name;
this.month = month;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getMonth() {
return month;
}
public void setMonth(int month) {
this.month = month;
}
public void eat(){
System.out.println("動物都有吃東西的能力");
}
}
新建Cat.java:
public class Cat extends Animal{
private double weight;
public Cat(){
}
public Cat(String name, int monnth, double weight){
super(name, monnth);
this.weight = weight;
}
public double getWeight() {
return weight;
}
public void setWeight(double weight) {
this.weight = weight;
}
public void run(){
System.out.println("小貓快樂地奔跑");
}
@Override
public void eat() {
super.eat();
System.out.println("貓吃魚");
}
}
新建Dog.java:
public class Dog extends Animal {
private String sex;
public Dog(){
}
public String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
public Dog(String name, int month, String sex){
this.setMonth(month);
this.setName(name);
this.setSex(sex);
}
public void sleep(){
System.out.println("小狗午睡");
}
@Override
public void eat() {
System.out.println("狗吃肉");
}
}
然后在定義一個測試文件Test.java:
public class Test {
public static void main(String[] args){
Animal one = new Animal();
Animal two = new Cat();
Animal three = new Dog();
one.eat();
two.eat();
three.eat();
}
}
運行Test.java

雖然都是吃這種行為,也同樣都是Animal類型的引用,但是隨著它具體在程序運行時實例化的對象類型不同,那么它的執(zhí)行的具體行為能力是不一樣的,這就是在java中多態(tài)的表現(xiàn)。
向上轉型
父類引用指向子類實例:Animal one = new Animal();
把一個子類對象轉型為父類對象,向上轉型(隱式轉型、自動轉型),代碼中是父類引用指向子類實例,
父類引用指向子類實例,可以調用子類重寫父類的方法以及父類派生的方法,無法調用子類獨有的方法。
注意:
父類中的靜態(tài)方法無法被子類重寫,所以向上轉型之后,只能調用父類原有的靜態(tài)方法
向下轉型(強制類型轉換)
子類引用指向父類實例,必須進行強制類型轉換,可以調用子類特有的方法。
必須滿足轉型條件才能強轉。
instanceof運算符可以進行判斷,左邊對象是否是他右邊對象的實例,換句話說就是左側對象是否滿足右側對象類型的特征如果是,返回true。
if (obj instanceof Cat)
父類中的靜態(tài)方法(含有static修飾的方法),只能被子類繼承使用,無法被子類重寫。
public static void say(){
}
抽象類
Java中使用抽象類,限制實例化
public abstract class A{
}
通過abstract 修飾的類叫做抽象類。
當一個類為抽象類時,就不允許實例化了,可以通過向上轉型指向子類。
抽象類應用場景:
某個父類只是知道其子類應該包含怎樣的方法,但無法準確知道這些子類如何實現(xiàn)這些方法。
當我們將父類設置為抽象類時,既可以借由父類和子類的繼承關系限制子類隨意性,同時也在一定程度上避免了無意義的實例化。
抽象方法
abstract 修飾的方法為抽象方法。
抽象方法要求:
- 不允許包含方法體
- 子類中必須重寫父類中的抽象方法
- 如果不重寫,子類自己必須被定義為抽象類
- 包含抽象方法的類必須是抽象類
總結:
- 抽象類不能直接實例化
- 子類如果沒有重寫父類所有的抽象方法,則也要定義為抽象類
- 抽象方法所在的類一定是抽象類
- 抽象類中可以沒有抽象方法
- static、final、private關鍵字不能與abstract 并存。
接口
當多個類型之間具有相同的行為能力的時候,java中可以借由接口來進行類型之間的聯(lián)系。
通過接口可以解決java當中單繼承所帶來的一些類型無法共享的問題。
- 接口定義了某一批類所需要的遵守的規(guī)范
- 接口不關心這些類的內部數(shù)據(jù),也不關心這些類里方法的實現(xiàn)細節(jié),它只規(guī)定這些類里必須提供某些方法。
語法:
[修飾符] interface 接口名 [extends 父接口1,父接口2...]
{
零個到多個常量定義...
零個到多個抽象方法定義...
零個到多個默認方法定義...(jdk1.8新增)
零個到多個靜態(tài)方法方法的定義...(jdk1.8新增)
}
- 接口可以實現(xiàn)多繼承,即一個子接口可以同時繼承多個父接口
- 實現(xiàn)接口的類如果不能實現(xiàn)所有接口中待重寫的方法,則必須設置為抽象類。
- 一個類可以繼承自一個父類,同時實現(xiàn)多個接口
內部類
在Java中,可以將一個類定義在另一個類里面或者一個方法里面,這樣的類稱為內部類。與之對應,包含內部類的類稱為外部類。
內部類分為四種:
- 成員內部類
- 靜態(tài)內部類
- 方法內部類
- 匿名內部類
優(yōu)勢:內部類提供了更好的封裝,可以把內部類隱藏在外部類之內,不允許同一個包的其他類訪問該類,更好的實現(xiàn)了信息隱藏。
1.成員內部類
內部類中最常見的就是成員內部類,也稱為普通內部類。
如下:
package com.imooc.people;
//外部類
public class Demo {
int name;
public He getSex(){
return new He();
}
//成員內部類
class He{
public String sex(){
return "男";
}
}
}
獲取內部類對象實例的三種方式:
public static void main(String[] args){
Demo a = new Demo();
a.name = 3;
//方式一
Demo.He h = new Demo().new He();
//方式二
h = a.new He();
//方式三
a.getSex();
}
- 內部類在外部使用時,無法直接實例化,需要借由外部類信息才能完成實例化
- 內部類的訪問修飾符,可以任意,但是訪問范圍會受到影響
- 內部類可以直接訪問外部類的成員;如果出現(xiàn)同名屬性,優(yōu)先訪問內部類中定義的
- 可以使用外部類.this.成員的方式,訪問外部類中同名的信息
- 外部類訪問內部類信息,需要通過內部類實例,無法直接訪問
- 內部類編譯后.class文件命名:外部類$內部類.class
2.靜態(tài)內部類
- 靜態(tài)內部類中,只能直接訪問外部類的靜態(tài)成員,如果需要調用非靜態(tài)成員,可以通過對象實例
- 靜態(tài)內部類對象實例時,可以不依賴于外部類對象
- 可以通過外部類.內部類.靜態(tài)成員的方式,訪問內部類中的靜態(tài)成員
- 當內部類屬性與外部類屬性同名時,默認直接調用內部類中的成員;
- 如果需要訪問外部類中的靜態(tài)屬性,則可以通過 外部類.屬性 的方式;
- 如果需要訪問外部類中的非靜態(tài)屬性,則可以通過 new 外部類().屬性的方式;
3.方法內部類
定義在外部類方法中的內部類,也稱為局部內部類。

方法的約束對方法內部類同樣有效。
- 定義在方法內部,作用范圍也在方法內
- 和方法內部成員使用規(guī)則一樣,class前面不可以添加public、private、protected、static
- 類中不能包含靜態(tài)成員
- 類中可以包含final、abstract修飾的成員
4.匿名內部類
匿名內部類
public static void main(String[] args) {
PersonTest test=new PersonTest();
test.getRead(new Person(){
{
//構造代碼塊
}
@Override
public void read() {
System.out.println("男生喜歡看科幻類書籍");
}
});
test.getRead(new Person(){
@Override
public void read() {
System.out.println("女生喜歡讀言情小說");
}
});
}
}
- 匿名內部類沒有類型名稱、實例對象名稱
- 編譯后的文件命名:外部類$數(shù)字.class
- 無法使用private、public、protected、abstract、static修飾
- 無法編寫構造方法,可以添加構造代碼塊
- 不能出現(xiàn)靜態(tài)成員
- 匿名內部類可以實現(xiàn)接口也可以實現(xiàn)繼承父類,但是不可兼得
如果內容對你有幫助,記得關注作者給個贊哦~,后續(xù)會持續(xù)更新。
