多態(tài)
概念:
意味著允許不同類的對象對同一消息做出不同的響應(yīng)
必要條件:
1遵倦、滿足繼承關(guān)系
2尽超、父類引用指向子類
編譯時多態(tài)(設(shè)計時多態(tài))
運行時多態(tài)(運行時多態(tài))
向上轉(zhuǎn)型(隱式轉(zhuǎn)型、自動轉(zhuǎn)型):
父類引用指向子類實例梧躺,可以調(diào)用子類重寫父類的方法以及父類派生的方法似谁,無法調(diào)用子類獨有的方法,是小類轉(zhuǎn)大類
Animal one = new Animal();
Animal two = new Cat();
Animal three = new Dog();
one.eat();
two.eat();
three.eat();
結(jié)果:
動物都有吃東西的能力
貓吃魚~~
狗吃肉~~
向下轉(zhuǎn)型(強制類型轉(zhuǎn)換)
子類引用指向父類對象掠哥,此處必須進行強轉(zhuǎn)巩踏。可以調(diào)用子類特有的方法续搀,必須滿足轉(zhuǎn)型條件才能轉(zhuǎn)換
Cat temp = (Cat)two;
temp.eat();
temp.run();
結(jié)果:
貓吃魚~~
小貓在快樂的奔跑
instanceof運算符:
作用:判斷對象是否滿足某個特定類型塞琼,判斷左邊的對象是否是右邊類型的實例
返回true或false
if(two instanceof Cat){
Cat temp = (Cat)two;
System.out.println("two可以轉(zhuǎn)換為Cat類型");
}
if(two instanceof Dog){
Dog temp2 = (Dog)two;
System.out.println("two可以轉(zhuǎn)換為Dog類型");
}
if(two instanceof Animal){
System.out.println("Animal");
}
if(two instanceof Object){
System.out.println("Object");
}
結(jié)果:
two可以轉(zhuǎn)換為Cat類型
Animal
Object
由此結(jié)果我們可知two滿足Cat的類型的特征禁舷,也滿足Cat類型的父類Animal和Object類型的特征
Master案例:
需求:
- 喂寵物
- 喂貓咪:吃完東西后彪杉,主人會帶著去玩線球
- 喂狗狗:吃完東西后,主人會帶著狗狗去睡覺
- 主人時間充足的條件下養(yǎng)狗狗
- 主人時間不充足的條件下養(yǎng)貓咪
Cat.java
//方法:吃東西(重寫父類方法)
@Override
public void eat() {
System.out.println("貓吃魚~~");
}
//方法:玩線球
public void playBall() {
// TODO Auto-generated method stub
System.out.println("小貓喜歡玩線球");
}
Dog.java
//方法:吃東西(重寫父類方法)
@Override
public void eat() {
System.out.println("狗吃肉~~");
}
//方法:睡覺
public void sleep(){
System.out.println("小狗有午睡的習(xí)慣");
}
Master.java
//方案:編寫方法傳入動物的父類牵咙,方法中通過類型轉(zhuǎn)換派近,調(diào)用指定子類的方法
public void feed(Animal obj){
obj.eat();
if(obj instanceof Cat){
Cat temp=(Cat)obj;
temp.playBall();
}else if(obj instanceof Dog){
Dog temp=(Dog)obj;
temp.sleep();
}
}
//
public Animal raise(boolean isManyTime){
if(isManyTime){
System.out.println("主人休閑時間比較充足,適合養(yǎng)狗狗");
return new Dog();
}else{
System.out.println("主人平時比較忙碌洁桌,適合養(yǎng)貓咪");
return new Cat();
}
}
MasterTest.java
Master master=new Master();
Cat one=new Cat();
Dog two=new Dog();
master.feed(one);
master.feed(two);
System.out.println("=============");
boolean isManyTime=false;
Animal temp=master.raise(isManyTime);
System.out.println(temp);
結(jié)果:
貓吃魚~~
小貓喜歡玩線球
狗吃肉~~
小狗有午睡的習(xí)慣
=============
主人平時比較忙碌渴丸,適合養(yǎng)貓咪
com.imooc.animal.Cat@15db9742
接口:
定義接口:interface
package com.imooc.tel;
/**
* 具有照相能力的接口
* @author imooc
*
*/
public interface IPhoto {
//具有拍照的能力
public void photo();
}
// void network();
}
實現(xiàn)接口:implements
一個類去實現(xiàn)一個接口使用到的關(guān)鍵字是implements
一個類去實現(xiàn)一個接口的時候需要去實現(xiàn)這個接口當(dāng)中的方法
Camera.java
package com.imooc.tel;
public class Camera implements IPhoto{
@Override
public void photo() {
// TODO Auto-generated method stub
System.out.println("相機可以拍照");
}
FourthPhone.java
package com.imooc.tel;
public class FourthPhone extends ThirdPhone implements IPhoto,INet{
public void game(){
System.out.println("手機可以玩游戲");
}
@Override
public void photo() {
// TODO Auto-generated method stub
System.out.println("手機可以拍照");
}
PhoneTest.java
package com.imooc.test;
import com.imooc.tel.Camera;
import com.imooc.tel.FourthPhone;
import com.imooc.tel.INet;
import com.imooc.tel.IPhoto;
import com.imooc.tel.SmartWatch;
public class PhoneTest {
public static void main(String[] args) {
IPhoto ip=new FourthPhone();
ip.photo();
ip=new Camera();
ip.photo();
}
}
結(jié)果:
相機可以拍照
手機可以拍照
default:默認方法,可以帶方法體
//default:默認方法 可以帶方法體 jdk1.8后新增
//可以在實現(xiàn)類中重寫另凌,并可以通過接口的引用調(diào)用
default void connection(){
System.out.println("我是接口中的默認鏈接");
}
default實現(xiàn)類的重寫:
系統(tǒng)自動加上public訪問權(quán)限
INet.super.connection();//接調(diào)用接口中默認的方法
如果不填super的話谱轨,通過接口名打點調(diào)用的是當(dāng)前接口的靜態(tài)成員
static:靜態(tài)方法 可以帶方法體 ,通過接口名去調(diào)用
INet.java
//static:靜態(tài)方法 可以帶方法體 jdk1.8后新增
//不可以在實現(xiàn)類中重寫,可以同接口名調(diào)用
static void stop(){
System.out.println("我是接口中的靜態(tài)方法");
}
PhoneText.java
INet.stop();
一個類可以實現(xiàn)多個接口吠谢,但注意去實現(xiàn)接口中待重寫的方法土童,否則這個類也會變成抽象類
當(dāng)一個類實現(xiàn)多個接口,接口中有多個同名的方法時工坊,實現(xiàn)類必須要重寫一個滿足自己特征的同名方法娜扇,如果這個實現(xiàn)類中的父類有同名方法時错沃,默認情況下會調(diào)用父類的同名方法, 但屬性則不同雀瓢,父類沒有優(yōu)先權(quán)
接口的繼承:
1、Java中的接口也可以實現(xiàn)接口玉掸,且可以有多個父接口
2刃麸、當(dāng)父接口中存在同名方法時,需要在自己的接口李創(chuàng)建自己的同名方法司浪,不用任何一個父接口里的方法
內(nèi)部類:
定義:
在Java中泊业,可以將一個類定義在另一個類里面或者一個方法里面,這樣的類稱為內(nèi)部類
分類:
- 成員內(nèi)部類(普通內(nèi)部類)
- 靜態(tài)內(nèi)部類
- 方法內(nèi)部類(局部內(nèi)部類)
- 匿名內(nèi)部類
成員內(nèi)部類:
* 內(nèi)部類在外部使用時啊易,無法直接實例化吁伺,需要借由外部類信息才能完成實例化
* 內(nèi)部類的訪問修飾符,可以任意租谈,但是訪問范圍會受到影響
* 內(nèi)部類可以直接訪問外部類的成員篮奄;如果出現(xiàn)同名屬性,優(yōu)先訪問內(nèi)部類中定義的
* 可以使用外部類.this.成員的方式割去,訪問外部類中同名的信息
* 外部類訪問內(nèi)部類信息窟却,需要通過內(nèi)部類實例,無法直接訪問
* 內(nèi)部類編譯后.class文件命名:外部類$內(nèi)部類.class
* 內(nèi)部類中是否可以包含與外部類相同方法簽名的方法呻逆?以及如何調(diào)用夸赫?
如何獲取內(nèi)部類實例對象:
方法一:
//獲取成員內(nèi)部類對象實例,方式1:new 外部類.new 內(nèi)部類
Person.Heart myHeart=new Person().new Heart();
System.out.println(myHeart.beat());
方法二:
//獲取成員內(nèi)部類對象實例咖城,方式2:外部類對象.new 內(nèi)部類
myHeart=lili.new Heart();
System.out.println(myHeart.beat());
方法三:
//獲取成員內(nèi)部類對象實例茬腿,方式3:外部類對象.獲取方法
myHeart=lili.getHeart();
System.out.println(myHeart.beat());
靜態(tài)內(nèi)部類:
-
靜態(tài)內(nèi)部類中,只能直接訪問外部類的靜態(tài)成員宜雀,如果需要調(diào)用非靜態(tài)成員切平,可以通過對象實例
static class Heart { int age = 13; int temp = 22; public String beat() { //對象實例 new Person().eat(); return new Person.age + "歲的心臟在跳動"; } }
靜態(tài)內(nèi)部類對象實例時,可以不依賴于外部類對象
可以通過外部類.內(nèi)部類.靜態(tài)成員的方式州袒,訪問內(nèi)部類中的靜態(tài)成員
當(dāng)內(nèi)部類屬性與外部類屬性同名時揭绑,默認直接調(diào)用內(nèi)部類中的成員;
如果需要訪問外部類中的靜態(tài)屬性郎哭,則可以通過 外部類.屬性 的方式他匪;
如果需要訪問外部類中的非靜態(tài)屬性,則可以通過 new 外部類().屬性的方式夸研;
獲取靜態(tài)內(nèi)部類對象實例方法:
Person.Heart myHeart=new Person.Heart();
System.out.println(myHeart.beat());
方法內(nèi)部類:
- 定義在方法內(nèi)部邦蜜,作用范圍也在方法內(nèi)
- 和方法內(nèi)部成員使用規(guī)則一樣,class前面不可以添加public亥至、private悼沈、protected贱迟、static
- 類中不能包含靜態(tài)成員
- 類中可以包含final、abstract修飾的成員
public Object getHeart() {
class Heart {
public final int age = 13;
int temp = 22;
public final void say() {
System.out.println("hello");
}
public void eat() {
}
public String beat() {
new Person().eat();
return Person.age + "歲的心臟在跳動";
}
}
return new Heart().beat();
// new Heart().temp=12;
//// temp=33;
// return new Heart();
}
##### 匿名內(nèi)部類:
定義:
對某個類的實例只會使用一次絮供,這個類的名字對于整個程序而言就可有可無了衣吠,這時我們將類的定義與累的創(chuàng)建放到一起 完成
- 匿名內(nèi)部類沒有類型名稱、實例對象名稱
- 編譯后的文件命名:外部類$數(shù)字.class
- 無法使用private壤靶、public缚俏、protected、abstract贮乳、static修飾
- 無法編寫構(gòu)造方法忧换,可以添加構(gòu)造代碼塊
- 不能出現(xiàn)靜態(tài)成員
- 匿名內(nèi)部類可以實現(xiàn)接口也可以繼承父類,但不可兼得
test.getRead(new Person(){
{
//構(gòu)造代碼塊
}
// public static int age=12;
@Override
public void read() {
// TODO Auto-generated method stub
System.out.println("男生喜歡看科幻類書籍");
}
});
test.getRead(new Person(){
@Override
public void read() {
// TODO Auto-generated method stub
System.out.println("女生喜歡讀言情小說");
}
});
單例模式:
要點:
1向拆、某個類只能有一個實例
2亚茬、必須自行創(chuàng)建實例
3、必須自行向整個系統(tǒng)提供這個實例
實現(xiàn):
1浓恳、只提供私有的構(gòu)造方法
2刹缝、含有一個該類的靜態(tài)私有對象
3、提供一個靜態(tài)的公有方法用于創(chuàng)建奖蔓、獲取靜態(tài)私有對象
餓漢式:對象創(chuàng)建過程中實例化
package com.imooc.singleton;
//餓漢式:創(chuàng)建對象實例的時候直接初始化 空間換時間
public class SingletonOne {
//1赞草、創(chuàng)建類中私有構(gòu)造
private SingletonOne(){
}
//2、創(chuàng)建該類型的私有靜態(tài)實例
private static SingletonOne instance=new SingletonOne();
//3吆鹤、創(chuàng)建公有靜態(tài)方法返回靜態(tài)實例對象
public static SingletonOne getInstance(){
return instance;
}
}
懶漢式:靜態(tài)公有方法中實例化
package com.imooc.singleton;
//懶漢式:類內(nèi)實例對象創(chuàng)建時并不直接初始化厨疙,直到第一次調(diào)用get方法時,才完成初始化操作
//時間換空間
public class SingletonTwo {
//1疑务、創(chuàng)建私有構(gòu)造方法
private SingletonTwo(){
}
//2沾凄、創(chuàng)建靜態(tài)的該類實例對象
private static SingletonTwo instance=null;
//3、創(chuàng)建開放的靜態(tài)方法提供實例對象
public static SingletonTwo getInstance(){
if(instance==null)
instance=new SingletonTwo();
return instance;
}
}
優(yōu)點:
1知允、在內(nèi)存中只有一個對象撒蟀,節(jié)省內(nèi)存空間
2、避免頻繁的創(chuàng)建銷毀對象温鸽,提高性能
3保屯、避免對共享資源的多重占用
缺點:
1、擴展比較困難
2涤垫、如果實例化后的對象長期不利用姑尺,系統(tǒng)將默認為垃圾進行回收,造成對象狀態(tài)丟失
使用場景:
1蝠猬、創(chuàng)建對象時占用資源過多切蟋,單同時有需要用到該類對象
2、系統(tǒng)內(nèi)資源要求同一讀寫榆芦,如讀寫配置信息
3柄粹、當(dāng)多個實例存在可能引起程序邏輯錯誤喘鸟,如號碼生成器