文檔版本 | 開發工具 | 測試平臺 | 工程名字 | 日期 | 作者 | 備注 |
---|---|---|---|---|---|---|
V1.0 | 2016.02.29 | lutianfei | none |
[TOC]
final 關鍵字
final關鍵字,可以修飾
類
,成員變量
,成員方法
。-
特點:
- 修飾的
類
,類不能被繼承 - 修飾的
變量
,變量就變成了常量,只能被<font color = red>賦值一次</font> - 修飾的
方法
,方法不能被重寫
- 修飾的
final關鍵字面試題
-
Eg1: final修飾局部變量
- 在方法內部,該變量不可以被改變
- 在方法聲明上,分為
基本類型
和引用類型
作為參數的情況- 基本類型,是值不能被改變
- 引用類型,是地址值不能被改變,但是該對象堆內存的值可以改變。
-
Eg2: final修飾變量的初始化時機
- 在對象構造完畢前即可
class Student {
int age = 10;
}
class FinalTest {
public static void main(String[] args) {
//局部變量是基本數據類型
int x = 10;
x = 100;
System.out.println(x);
final int y = 10;
//無法為最終變量y分配值
//y = 100;
System.out.println(y);
System.out.println("--------------");
//局部變量是引用數據類型
Student s = new Student();
System.out.println(s.age);
s.age = 100;
System.out.println(s.age);
System.out.println("--------------");
final Student ss = new Student();
System.out.println(ss.age);
ss.age = 100;
System.out.println(ss.age);
//重新分配內存空間
//無法為最終變量ss分配值
ss = new Student();
}
}
多態
多態概述
- 某一個事物,在不同時刻表現出來的不同狀態。
- 舉例:
- 貓可以是貓的類型。貓 m = new 貓();
- 同時貓也是動物的一種,也可以把貓稱為動物。
- 動物 d = new 貓();
- 再舉一個例子:水在不同時刻的狀態
- 舉例:
- 多態前提和體現
- 有繼承關系
- 有方法重寫
- 有父類引用指向子類對象
- Fu f = new Zi();
多態的分類:
- 具體類多態:
- class Fu{}
- class Zi extends Fu{}
- Fu f = new Zi();
- 抽象類多態:
- abstract class Fu{}
- class Zi extends Fu{}
- Fu f = new Zi();
- 接口多態:
- interface Fu{}
- class Zi implements Fu{}
- Fu f = new Zi();
多態中的成員訪問特點:
A:
成員變量
:編譯看左邊,運行看左邊。B:
構造方法
:創建子類對象的時候,訪問父類的構造方法,對父類的數據進行初始化。C:
成員方法
: <font color = red>編譯看左邊,運行看右邊</font>。由于成員方法存在方法重寫,所以它運行看右邊。-
D:
靜態方法
:編譯看左邊,運行看左邊。- (靜態和類相關,算不上重寫,所以,訪問還是左邊的)
/*
多態:同一個對象(事物),在不同時刻體現出來的不同狀態。
舉例:
貓是貓,貓是動物。
水(液體,固體,氣態)。
多態的前提:
A:要有繼承關系。
B:要有方法重寫。
其實沒有也是可以的,但是如果沒有這個就沒有意義。
動物 d = new 貓();
d.show();
動物 d = new 狗();
d.show();
C:要有父類引用指向子類對象。
父 f = new 子();
*/
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 extends Fu {
public int num = 1000;
public int num2 = 200;
public void show() {
System.out.println("show Zi");
}
public void method() {
System.out.println("method zi");
}
public static void function() {
System.out.println("function Zi");
}
}
class DuoTaiDemo {
public static void main(String[] args) {
//要有父類引用指向子類對象。
//父 f = new 子();
Fu f = new Zi();
System.out.println(f.num);
//找不到符號
//System.out.println(f.num2);
f.show();
//找不到符號
//f.method();
f.function();
}
}
/*
* 運行結果:
100
show Zi
function Fu
*/
多態的優缺點
-
多態的好處
- 提高了程序的維護性(由繼承保證)
- 提高了程序的擴展性(由多態保證)
-
多態的弊端
- 父類不能訪問子類特有功能
-
如何才能訪問子類的特有功能呢?
- 創建子類對象,調用方法即可。(然而很多時候不合理,且太占內存)
-
向下轉型
:把父類的引用強制轉換為子類的引用。- Zi z = (Zi)f; //要求該f必須是能夠轉換為Zi的
現象: 子可以當做父使用,父不能當作子使用。
多態中的轉型問題
- 向上轉型
- 從子到父
- 父類引用指向子類對象
- 向下轉型
- 從父到子
- 父類引用轉為子類對象
- 孔子裝爹案例
//多態的問題理解:
class 孔子爹 {
public int age = 40;
public void teach() {
System.out.println("講解JavaSE");
}
}
class 孔子 extends 孔子爹 {
public int age = 20;
public void teach() {
System.out.println("講解論語");
}
public void playGame() {
System.out.println("英雄聯盟");
}
}
//Java培訓特別火,很多人來請孔子爹去講課,這一天孔子爹被請走了
//但是還有人來請,就剩孔子在家,價格還挺高。孔子一想,我是不是可以考慮去呢?
//然后就穿上爹的衣服,帶上爹的眼睛,粘上爹的胡子。就開始裝爹
//向上轉型
孔子爹 k爹 = new 孔子();
//到人家那里去了
System.out.println(k爹.age); //40
k爹.teach(); //講解論語
//k爹.playGame(); //這是兒子才能做的,一做就報錯!
//講完了,下班回家了
//脫下爹的裝備,換上自己的裝備
//向下轉型
孔子 k = (孔子) k爹;
System.out.println(k.age); //20
k.teach(); //講解論語
k.playGame(); //英雄聯盟
-
多態中的對象變化內存圖
- 多態練習:貓狗案例
class Animal {
public void eat(){
System.out.println("吃飯");
}
}
class Dog extends Animal {
public void eat() {
System.out.println("狗吃肉");
}
public void lookDoor() {
System.out.println("狗看門");
}
}
class Cat extends Animal {
public void eat() {
System.out.println("貓吃魚");
}
public void playGame() {
System.out.println("貓捉迷藏");
}
}
class DuoTaiTest {
public static void main(String[] args) {
//定義為狗
Animal a = new Dog();
a.eat();
System.out.println("--------------");
//還原成狗
Dog d = (Dog)a;
d.eat();
d.lookDoor();
System.out.println("--------------");
//變成貓
a = new Cat();
a.eat();
System.out.println("--------------");
//還原成貓
Cat c = (Cat)a;
c.eat();
c.playGame();
System.out.println("--------------");
}
}
- 不同地方飲食文化不同的案例
class Person {
public void eat() {
System.out.println("吃飯");
}
}
class SouthPerson extends Person {
public void eat() {
System.out.println("炒菜,吃米飯");
}
public void jingShang() {
System.out.println("經商");
}
}
class NorthPerson extends Person {
public void eat() {
System.out.println("燉菜,吃饅頭");
}
public void yanJiu() {
System.out.println("研究");
}
}
class DuoTaiTest2 {
public static void main(String[] args) {
//測試
//南方人
Person p = new SouthPerson();
p.eat();
System.out.println("-------------");
SouthPerson sp = (SouthPerson)p;
sp.eat();
sp.jingShang();
System.out.println("-------------");
//北方人
p = new NorthPerson();
p.eat();
System.out.println("-------------");
NorthPerson np = (NorthPerson)p;
np.eat();
np.yanJiu();
}
}
/*
運行結果:
炒菜,吃米飯
-------------
炒菜,吃米飯
經商
-------------
燉菜,吃饅頭
-------------
燉菜,吃饅頭
研究
*/
多態中繼承練習
-
繼承的時候:
- 子類中有和父類中一樣的方法,叫
重寫
。 - 子類中沒有父親中出現過的方法,方法就被
繼承
過來了。
- 子類中有和父類中一樣的方法,叫
Eg:(<font color = red>不太理解</font>)
/*
多態的成員訪問特點:
方法:編譯看左邊,運行看右邊。
繼承的時候:
子類中有和父類中一樣的方法,叫重寫。
子類中沒有父親中出現過的方法,方法就被繼承過來了。
*/
class A {
public void show() {
show2();
}
public void show2() {
System.out.println("我");
}
}
class B extends A {
/*
public void show() {
show2();
}
*/
public void show2() {
System.out.println("愛");
}
}
class C extends B {
public void show() {
super.show();
}
public void show2() {
System.out.println("你");
}
}
public class DuoTaiTest4 {
public static void main(String[] args) {
A a = new B();
a.show();
B b = new C();
b.show();
}
}
// 運行結果:
//愛
//你
抽象類
抽象類概述
- 動物本身并不是一個具體的事物,而是一個抽象的事物。只有真正的貓,狗才是具體的動物。同理,我們也可以推想,不同的動物吃的東西應該是不一樣的,所以,我們不應該在動物類中給出具體體現,而是應該給出一個聲明即可。在Java中,一個沒有
方法體
(連<font color = red>大括號</font>也沒有)的方法應該定義為抽象方法
,而類中如果有抽象方法
,該類必須定義為抽象類
。
抽象類特點
-
抽象類
和抽象方法
必須用abstract
關鍵字修飾- 格式
- abstract class 類名 {}
- public abstract void eat();
- 格式
-
抽象類
不一定有抽象方法
,有抽象方法
的類一定是抽象類
- 抽象類不能實例化(抽象類如何實例化呢?)
- 按照多態的方式,由具體的子類實例化。其實這也是多態的一種,抽象類多態。
- 抽象類有
構造方法
,其作用是為了用于子類訪問父類數據的初始化。
- 抽象類的
子類
- 要么是抽象類
- 要么重寫抽象類中的所有
抽象方法
//abstract class Animal //抽象類的聲明格式
abstract class Animal {
//抽象方法
//public abstract void eat(){} //空方法體,這個會報錯。抽象方法不能有主體
public abstract void eat();
public Animal(){}
}
//子類是抽象類
abstract class Dog extends Animal {}
//子類是具體類,重寫抽象方法
class Cat extends Animal {
public void eat() {
System.out.println("貓吃魚");
}
}
class AbstractDemo {
public static void main(String[] args) {
//創建對象
//Animal是抽象的; 無法實例化
//Animal a = new Animal();
//通過多態的方式
Animal a = new Cat();
a.eat();
}
}
抽象類的成員特點
- 成員變量
- 可以是變量
- 也可以是常量
- 構造方法
- 有構造方法,但是不能實例化
- 那么,構造方法的作用是什么呢?
- 用于子類訪問父類數據的初始化
- 成員方法
- 可以有抽象方法 作用:限定子類必須完成某些動作
- 也可以有非抽象方法 提高代碼復用性
- 抽象定義類練習:
//定義抽象的動物類
abstract class Animal {
//姓名
private String name;
//年齡
private int age;
public Animal() {}
public Animal(String name,int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
//定義一個抽象方法
public abstract void eat();
}
//定義具體的狗類
class Dog extends Animal {
public Dog() {}
public Dog(String name,int age) {
super(name,age); //重要知識點!!!
}
public void eat() {
System.out.println("狗吃肉");
}
}
//定義具體的貓類
class Cat extends Animal {
public Cat() {}
public Cat(String name,int age) {
super(name,age);
}
public void eat() {
System.out.println("貓吃魚");
}
}
//測試類
class AbstractTest {
public static void main(String[] args) {
//測試狗類
//具體類用法
//方式1:
Dog d = new Dog();
d.setName("旺財");
d.setAge(3);
System.out.println(d.getName()+"---"+d.getAge());
d.eat();
//方式2:
Dog d2 = new Dog("旺財",3);
System.out.println(d2.getName()+"---"+d2.getAge());
d2.eat();
System.out.println("---------------------------");
Animal a = new Dog();
a.setName("旺財");
a.setAge(3);
System.out.println(a.getName()+"---"+a.getAge());
a.eat();
Animal a2 = new Dog("旺財",3);
System.out.println(a2.getName()+"---"+a2.getAge());
a2.eat();
//練習:測試貓類
}
}
- 抽象教師類練習:
//定義抽象的老師類
abstract class Teacher {
//姓名
private String name;
//年齡
private int age;
public Teacher() {}
public Teacher(String name,int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
//抽象方法
public abstract void teach();
}
//基礎班老師類
class BasicTeacher extends Teacher {
public BasicTeacher(){}
public BasicTeacher(String name,int age) {
super(name,age);
}
public void teach() {
System.out.println("基礎班老師講解JavaSE");
}
}
//就業班老師類
class WorkTeacher extends Teacher {
public WorkTeacher(){}
public WorkTeacher(String name,int age) {
super(name,age);
}
public void teach() {
System.out.println("就業班老師講解JavaEE");
}
}
class AbstractTest2 {
public static void main(String[] args) {
//具體的類測試,自己玩
//測試(多態)
//基礎班老師
Teacher t = new BasicTeacher();
t.setName("劉意");
t.setAge(30);
System.out.println(t.getName()+"---"+t.getAge());
t.teach();
System.out.println("--------------");
t = new BasicTeacher("劉意",30);
System.out.println(t.getName()+"---"+t.getAge());
t.teach();
System.out.println("--------------");
//就業班老師
t = new WorkTeacher();
t.setName("林青霞");
t.setAge(27);
System.out.println(t.getName()+"---"+t.getAge());
t.teach();
System.out.println("--------------");
t = new WorkTeacher("林青霞",27);
System.out.println(t.getName()+"---"+t.getAge());
t.teach();
}
}
抽象類的幾個小問題
- 一個類如果沒有抽象方法,可以定義為抽象類?如果可以,有什么意義?
- 可以
- 禁止創建對象
-
abstract
不能和哪些關鍵字共存-
private
沖突 -
final
沖突 -
static
無意義(通過類名直接訪問沒有內容的方法體)
-
接口
接口概述
- 狗一般就是看門,貓一般就是作為寵物。但是,現在有很多的馴養員或者是馴獸師,可以訓練出:貓鉆火圈,狗跳高,狗做計算等。而這些額外的動作,并不是所有貓或者狗一開始就具備的,這應該屬于經過特殊的培訓訓練出來的。所以,這些額外的動作定義到動物類中就不合適,也不適合直接定義到貓或者狗中,因為只有部分貓狗具備這些功能。
所以,為了體現事物功能的擴展性,Java中就提供了接口
來定義這些額外功能,并不給出具體實現,將來哪些貓狗需要被培訓,只需要這部分貓狗把這些額外功能實現即可。
接口特點
-
接口用關鍵字
interface
表示- 格式:interface 接口名 {}
-
類實現接口用
implements
表示- 格式:class 類名 implements 接口名 {}
-
接口不能實例化(接口如何實例化呢?)
- 按照多態的方式,由具體的子類實例化。其實這也是多態的一種,接口多態。
-
接口的實現類(子類):
-
抽象類
:實現接口,但意義不大 -
具體類
:重寫接口中的所有抽象方法
-
-
補充:多態的三種形式
- 具體類多態(幾乎沒有)
- 抽象類多態(常用)
- 接口類多態(最常用 )
接口成員特點
-
成員變量
- 只能是
常量
- 默認修飾符 public static final
- 只能是
-
構造方法
- 沒有,因為接口主要是擴展功能的,而沒有具體存在。
- 所有的類都默認繼承自一個類:Object。(類Object 是類層次結構的根類。每個類都使用Object作為超類)
-
成員方法
- 只能是抽象方法
- 默認修飾符 public abstract
類與類,類與接口以及接口與接口的關系
- 類與類
- 繼承關系,只能單繼承,但是可以多層繼承
- 類與接口
-
實現關系,
- 可以單實現,也可以<font color = red>多實現</font>。
- 還可以在繼承一個類的同時實現多個接口。
-
實現關系,
- 接口與接口
- 繼承關系,可以單繼承,也可以<font color = red>多繼承</font>
抽象類和接口的區別
- 成員區別
- 抽象類
- 成員變量:變量,常量;
- 構造方法:可以有
- 成員方法:可以是抽象方法,也可以是非抽象方法;
- 接口
- 成員變量:只可以是常量;
- 構造方法:沒有
- 成員方法:只能是抽象方法
- 抽象類
- 關系區別
- 類與類 繼承,單繼承
- 類與接口 實現,單實現,多實現
- 接口與接口 繼承,單繼承,多繼承
- 設計理念區別
- 抽象類 被繼承體現的是:”is a”的關系。抽象類中定義的是該繼承體系的共性功能
- 接口 被實現體現的是:”like a”的關系。接口中定義的是該繼承體系的擴展功能
- 跳高貓練習:
/*
貓狗案例,加入跳高的額外功能
分析:從具體到抽象
貓:
姓名,年齡
吃飯,睡覺
狗:
姓名,年齡
吃飯,睡覺
由于有共性功能,所以,我們抽取出一個父類:
動物:
姓名,年齡
吃飯();
睡覺(){}
貓:繼承自動物
狗:繼承自動物
跳高的額外功能是一個新的擴展功能,所以我們要定義一個接口
接口:
跳高
部分貓:實現跳高
部分狗:實現跳高
實現;
從抽象到具體
使用:
使用具體類
*/
//定義跳高接口
interface Jumpping {
//跳高功能
public abstract void jump();
}
//定義抽象類
abstract class Animal {
//姓名
private String name;
//年齡
private int age;
public Animal() {}
public Animal(String name,int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
//吃飯();
public abstract void eat();
//睡覺(){}
public void sleep() {
System.out.println("睡覺覺了");
}
}
//具體貓類
class Cat extends Animal {
public Cat(){}
public Cat(String name,int age) {
super(name,age);
}
public void eat() {
System.out.println("貓吃魚");
}
}
//具體狗類
class Dog extends Animal {
public Dog(){}
public Dog(String name,int age) {
super(name,age);
}
public void eat() {
System.out.println("狗吃肉");
}
}
//有跳高功能的貓
class JumpCat extends Cat implements Jumpping {
public JumpCat() {}
public JumpCat(String name,int age) {
super(name,age);
}
public void jump() {
System.out.println("跳高貓");
}
}
//有跳高功能的狗
class JumpDog extends Dog implements Jumpping {
public JumpDog() {}
public JumpDog(String name,int age) {
super(name,age);
}
public void jump() {
System.out.println("跳高狗");
}
}
class InterfaceTest {
public static void main(String[] args) {
//定義跳高貓并測試
JumpCat jc = new JumpCat();
jc.setName("哆啦A夢");
jc.setAge(3);
System.out.println(jc.getName()+"---"+jc.getAge());
jc.eat();
jc.sleep();
jc.jump();
System.out.println("-----------------");
JumpCat jc2 = new JumpCat("加菲貓",2);
System.out.println(jc2.getName()+"---"+jc2.getAge());
jc2.eat();
jc2.sleep();
jc2.jump();
//定義跳高狗并進行測試的事情自己完成。
}
}
-
運行結果