(1)同一個對象(事物),在不同時刻體現出來的不同狀態
舉例:
貓是貓,貓是動物。
水(液態,固態,氣態)。
(2)多態的前提:
A:要有繼承關係。
B:要有方法重寫。
其實沒有也是可以的,但是如果沒有這個就沒有意義。
動物 d = new 貓();
d.show();
動物 d = new 狗();
d.show();
C:要有父類引用指向子類對象那個。
父 f = new 子類;
(3)多態中的成員訪問特點:A:成員變量
編譯看左邊,運行看左邊
B:構造方法
創建子類對象的時候,訪問父類的構造方法,對父類的數據進行初始化
C:成員方法
編譯看左邊,運行看右邊(成員方法存在重寫)
D:靜態方法
編譯看左邊,運行看左邊
(靜態和類相關,算不上重寫,所以訪問還是左邊的)
由於成員方法存在方法重寫,所以它看右邊
class Fu{
public int num =100;
public void show(){
System.out.println("show Fu");
}
public static void function(){
System.out.println("function Fu");
}
}
class Zi extend Fu{
public int num =1000;
public int num2 =2000;
public void show(){
System.out.println("show Zi");
}
public static void function(){
System.out.println("function Zi");
}
}
class DuoTaiDemo{
public static void main(String[] args){
Fu f = new Zi();
System.out.println(f.num);
//報錯 父類中找不到num2
//System.out.println(f.num2);
f.show();
f.function();
}
}
輸出結果:100 show Zi function Fu
(4) 多態的好處
A:提高了代碼的維護性(繼承保證)
B:提高了代碼的擴展性(調用時,直接調用父類名,而不用直接調用子類名)
例如:
Dog a = new Dog();
Cat b = new Cat();
Pig c = new Pig();
AnimalTool.useDog(a);
AnimalTool.useCat(b);
AnimalTool.usePig(c);
----------------------------------------
Dog a = new Dog();
Cat b = new Cat();
Pig c = new Pig();
AnimalTool.useAnimal(a);
AnimalTool.useAnimal(b);
AnimalTool.useAnimal(c);
(5) 多態的弊端
不能使用子類的特有功能,只能使用父類中定義了的功能。
那如何使用子類的特有功能?
A:創建子類對象調用特有功能。(可以,但是很多時候不合理,而且太佔內存了)
Fu f = new Zi();
f.show();
//f.method(); 無法調用子類的method
//所以創建另一個子類對象
Zi z = new Zi();
z.show();
z.method();
B:把父類的引用強制轉換爲子類的引用。(向下轉型)
Zi z = (Zi)f;
z.show();
z.method();
-----------------------------------------
對象間的轉型問題:
向上轉型:
Fu f = new Zi();
向下轉型:
Zi z = (Zi)f; //要求該f必須是能夠轉換爲Zi的。
(6) 繼承的時候:
子類中有和父類一樣的方法,叫做重寫。
子類中沒有父親中出現過的方法,方法就被繼承過來了
2 抽象類
(1)抽象類的概述:
動物不應該定義爲具體的東西,而且動物中的吃,睡等也不應該是具體的。
我們把一個不是具體的功能成爲抽象的功能,而一個類中如果有抽象的功能,該類必須是抽象類。
(2)抽象類的特點:
A:抽象類和抽象方法必須用abstract關鍵字修飾
B:抽象類中不一定有抽象方法,但是有抽象方法的類必須定義爲抽象類
C:抽象類不能實例化
因爲它不是具體的
抽象類有構造方法,但是不能實例化?構造方法的作用是什麼呢?
用於子類訪問父類數據的初始化
D:抽象的子類
a:如果不想重寫抽象方法,該子類是抽象類
b:重寫所有的抽象方法,這個時候子類是一個具體的類
**抽象類的實例化其實是靠具體的子類實現的,是多態的方式。
Animal a = new Dog();
a.eat();
abstract class Animal{//抽象方法
//public abstract void eat(){} //空方法體,這個會報錯,抽象方法不能有主體
public abstract void eat();
}
(3)抽象類的成員特點:
成員變量:既可以是變量,也可以是常量。
構造方法: 有。
用於子類訪問父類數據的初始化。
成員方法:既可以是抽象的,也可以是非抽象的。
抽象類的成員方法特性:
A:抽象方法,強制要求子類做的事情
B:非抽象方法 子類繼承的事情,提高代碼複用性。
(4)抽象類的幾個小問題
A:一個類如果沒有抽象方法,可不可以定義爲抽象類?如果可以,有什麼意義
a:可以
b:不讓創建對象
B:abstract不能和哪些關鍵字共存
private 衝突 (不能被繼承,但抽象要求重寫)
final 衝突 (不能被重寫,但抽象要求重寫)
static 無意義 (抽象無方法體,static可以直接訪問方法體)
3 接口
爲了體現事物功能的擴展性,java中就提供了接口來定義這些額外功能,並不給出具體實現。
(1) 接口的特點:
A:接口用關鍵字interface表示
interface 接口名{}
B:類實現接口用implements表示
class 類名 implements 接口名{}
C:接口不能實例化
那麼,接口如何實例化呢?
按照多態的方式來實例化
D:接口的子類
a:可以是抽象類,但意義不大
b:可以是具體類,要重寫接口中的所有抽象方法(推薦方案)
由此可見:
A:具體類多態(幾乎沒有)
B:抽象類多態(常用)
C:接口多態(最常用)
//定義動物培訓接口
interface AnimalTrain{
public abstract void jump();
}
(2)接口成員特點
成員變量:只能是常量
默認修飾符 public static final
構造方法:沒有,因爲接口主要是擴展功能的,而沒有具體存在
成員方法:只能是抽象方法
默認修飾符public abstract
(3) 類與類:
繼承關係:只能單繼承,可以多層繼承。
類與接口:
實現關係,可以單實現,也可以多實現。
並且還可以在繼承一個類的時候同時實現多個接口。
接口與接口:
繼承關係:可以單繼承,也可以多繼承
4 抽象類與接口的區別
A:成員區別
抽象類:
成員變量:可以變量,也可以常量
構造方法:有
成員方法:可以抽象,也可以非抽象
接口:
成員變量:只可以是常量
構造方法:無
成員方法:只可以是抽象
B:關係區別
類與類:
繼承關係:只能單繼承,可以多層繼承。
類與接口:
實現關係,可以但實現,也可以多實現。
並且還可以在繼承一個類的時候同時實現多個接口。
接口與接口:
繼承關係:可以單繼承,也可以多繼承
**C:設計理念區別
抽象類 被繼承體現的是:"is a"的關係,抽象類中定義的是該繼承體系的共性功能。
接口 被實現體現的是:"like a"的關係,接口中定義的是該繼承體系的擴展功能。
5 形式參數和返回值問題
形式參數:
基本類型: 8種基本類型
引用類型:
類:(匿名對象的時候已經用過)需要的是該類的對象
抽象類:需要的是該抽象類的子類的對象
接口:跟抽象類同理
返回值類型:
基本類型: 8種基本類型
引用類型:
類:返回的是該類的對象
抽象類:返回的是該抽象類的子類的對象
接口:返回的是該接口的實現類的對象
6 鏈式編程
每次調用完畢方法後,返回的是一個對象。
class StudentDemo{
public Student getStudent(){
return new Student();
}
}
sd.getStudent().study();//鏈式編程
7 包
A:其實就是文件夾
B:作用
a:把相同的類名放到不同的包中
b:對類進行分類管理
舉例:
學生:增加,刪除,修改,查詢
老師:增加,刪除,修改,查詢
。。。
方案1:按照功能分
cn.itcast.add
AddStudent
AddTeacher
cn.itcast.delete
DeleteStudent
DeleteTeacher
cn.itcast.update
UpdateStudent
UpdateTeacher
方案2:按照模塊分
cn.itcast.teacher
AddTeacher
DeleteTeacher
UpdateTeacher
cn.itcast.student
AddStudent
DeleteStudent
UpdateStudent
包的定義
package 包名;
多級包用.分開即可
注意事項:
A:package語句必須是程序的第一條可執行的代碼
B:package語句在一個java文件中只能有一個
C:如果沒有package,默認表示無包名
8 不同包下類之間的訪問
第一個問題:找不到Demo 需要用包名.Demo
第二個問題:程序包不存在 需要建立工程包
第三個問題:Demo在包中不是公共的,無法訪問 設置訪問權限。
導包:
格式:import 包名;
這種方式導入時到類的名稱
**面試題:
package,import,class有沒有順序關係?
有
package>import>class
package:只能有一個
import:可以有多個
class:可以有多個,以後建議是一個
9 訪問修飾符
public protected 默認 private
同一類中 √ √ √ √
同一包子類,其他類 √ √ √
不同包子類 √ √
不同包其他類 √
10 內部類
(1)內部類概述:把類定義在其他類的內部,這個類就被稱爲內部類。
舉例:在類A中定義了一個類B,類B就是內部類。
(2)內部類的訪問特點:
A:內部類可以直接訪問外部類的成員,包括私有。
B:外部類要訪問內部類的成員,必須創建對象。
(3)內部類位置:
成員位置:在成員位置定義的類,被稱爲成員內部類。
局部位置:在局部位置定義的類,被稱爲局部內部類。(例如方法中)
(4)成員內部類:
如何直接訪問內部類的成員?
外部類名.內部類名 對象名 = 外部類對象.內部類對象;
Outer.Inner oi = new Outer().new Inner();
oi.show();
(5)成員內部類的修飾符:
**private:爲了保證數據的安全性
**static:爲了方便訪問數據
注意:靜態內部類訪問的外部類數據必須用靜態修飾
案例:我有一個人(人有身體,身體內有心臟)
不能直接讓外部訪問,必須要保證安全性。
class Body{
private class Heart{
public void operator(){
System.out.println("心臟搭橋");
}
}
public void method(){
if(如果你是外科醫生){
Heart h = new Heart();
h.operator();
}
}
}
(6) 用static修飾後的內部類訪問
class Outer{
private int num = 10;
private static int num2 = 100;
//內部類用靜態修飾是因爲內部類可以看出是外部類的成員
public static class Inner{
public void show(){
System.out.println(num);
}
public static void show2(){
System.out.println(num);
}
}
}
//格式:外部類名.內部類名 對象名 = new 外部類名.內部類名();
Outer.Inner oi = new Outer.Inner();
oi.show();
oi.show2();
//show2()的另一種調用方式
Outer.Inner.show2();
靜態內部類的作用:
https://www.zhihu.com/question/28197253***11 成員內部類的面試題
要求請填空,分別輸出30,20,10
class Outer{
public int num = 10;
class Inner{
public int num = 20;
public void show(){
int num = 30;
System.out.println(?); // num
System.out.println(??); // this.num
System.out.println(???); // Outer.this.num /new Outer().num
}
}
}
12 局部內部類
A:可以直接訪問外部類的成員
B:在局部位置,可以創建內部類對象,通過對象調用內部類方法,來使用局部內部類功能
***面試題:
局部內部類訪問局部變量的注意事項?
A:局部內部類訪問局部變量必須使用final修飾
B:爲什麼?
局部變量是隨着方法的調用而調用,隨着調用完畢而消失。
而堆內存的內容並不會立即消失,所以,我們加finaal修飾。
加入final修飾後,這個變量就變成了常量,既然是常量,你消失了,我在內存中存儲的數據是20,所以,我還是有數據在使用。
(反編譯之後,就是一個常量)
class Outer{
private int num = 10;
public void method(){
final int num2 = 20;
class Inner{
public void show(){
System.out.println(num);
// 從內部類中訪問本地變量num2,需要被聲明爲最終類型
System.out.println(num2);
}
}
Inner i = new Inner();
i.show();
}
}