一秧廉、面向?qū)ο筇卣饕唬悍庋b性
1.為什么要引入封裝性桃熄?
我們程序設(shè)計追求“高內(nèi)聚庆械,低耦合”犁享。
高內(nèi)聚?:類的內(nèi)部數(shù)據(jù)操作細節(jié)自己完成亏较,不允許外部干涉岸晦;
低耦合?:僅對外暴露少量的方法用于使用怔檩。
隱藏對象內(nèi)部的復(fù)雜性博个,只對外公開簡單的接口讹蘑。便于外界調(diào)用末盔,從而提高系統(tǒng)的可擴展性、可維護性座慰。通俗的說陨舱,把該隱藏的隱藏起來,該暴露的暴露出來版仔。這就是封裝性的設(shè)計思想游盲。
2.問題引入:
當我們創(chuàng)建一個類的對象以后,我們可以通過"對象.屬性"的方式蛮粮,對對象的屬性進行賦值益缎。這里,賦值操作要受到屬性的數(shù)據(jù)類型和存儲范圍的制約然想。除此之外莺奔,沒其他制約條件。但是变泄,在實際問題中令哟,我們往往需要給屬性賦值加入額外的限制條件。這個條件就不能在屬性聲明時體現(xiàn)妨蛹,我們只能通過方法進行限制條件的添加屏富。(比如:setLegs()同時,我們需要避免用戶再使用"對象.屬性"的方式對屬性進行賦值蛙卤。則需要將屬性聲明為私有的(private).
-->此時狠半,針對于屬性就體現(xiàn)了封裝性。
3.封裝性思想具體的代碼體現(xiàn):
體現(xiàn)一:將類的屬性xxx私有化(private),同時,提供公共的(public)方法來獲取getXxx()和設(shè)置setXxx()此屬性的值典予。
隱藏一個類中不需要對外提供的實現(xiàn)細節(jié)甜滨;
使用者只能通過事先定制好的方法來訪問數(shù)據(jù)乐严,可以方便地加入控制邏輯瘤袖, 限制對屬性的不合理操作;
便于修改昂验,增強代碼的可維護性捂敌;
private double radius;
public void setRadius(double radius){
? this.radius = radius;
}
public double getRadius(){
? return radius;
}
體現(xiàn)二:不對外暴露的私有的方法
體現(xiàn)三:單例模式(將構(gòu)造器私有化)
體現(xiàn)四:如果不希望類在包外被調(diào)用,可以將類設(shè)置為缺省的既琴。
4.Java規(guī)定的四種權(quán)限修飾符
Java權(quán)限修飾符public占婉、protected、(缺省)甫恩、private置于類的成員定義前逆济, 用來限定對象對該類成員的訪問權(quán)限。
4.1 權(quán)限從小到大順序為:private < 缺省 < protected < public
4.2 具體的修飾范圍:
package com.bcbd.java;
public class Order {
? private int orderPrivate;
? int orderDefault;
? public int orderPublic;
? private void methodPrivate(){
? ? orderPrivate = 1;
? ? orderDefault = 2;
? ? orderPublic = 3;
? }
? void methodDefault(){
? ? orderPrivate = 1;
? ? orderDefault = 2;
? ? orderPublic = 3;
? }
? public void methodPublic(){
? ? orderPrivate = 1;
? ? orderDefault = 2;
? ? orderPublic = 3;
? }
}
package com.bcbd.java;
public class OrderTest {
? public static void main(String[] args) {
? ? Order order = new Order();
? ? order.orderDefault = 1;
? ? order.orderPublic = 2;
? ? //出了Order類之后磺箕,私有的結(jié)構(gòu)就不可以調(diào)用了
// order.orderPrivate = 3;//The field Order.orderPrivate is not visible
? ? order.methodDefault();
? ? order.methodPublic();
? ? //出了Order類之后奖慌,私有的結(jié)構(gòu)就不可以調(diào)用了
// order.methodPrivate();//The method methodPrivate() from the type Order is not visible
? }
}
package com.bcbd.java1;
import com.bcbd.java.Order;
public class OrderTest {
? public static void main(String[] args) {
? ? Order order = new Order();
? ? order.orderPublic = 2;
? ? // 出了Order類所屬的包之后,私有的結(jié)構(gòu)松靡、缺省聲明的結(jié)構(gòu)就不可以調(diào)用了
// order.orderDefault = 1;
? ? // order.orderPrivate = 3;//The field Order.orderPrivate is not visible
? ? order.methodPublic();
? ? // 出了Order類所屬的包之后简僧,私有的結(jié)構(gòu)、缺省聲明的結(jié)構(gòu)就不可以調(diào)用了
// order.methodDefault();
? ? // order.methodPrivate();//The method methodPrivate() from the type Order is not visible
? }
}
4.3 權(quán)限修飾符可用來修飾的結(jié)構(gòu)說明:
4種權(quán)限都可以用來修飾類的內(nèi)部結(jié)構(gòu):屬性雕欺、方法岛马、構(gòu)造器、內(nèi)部類
對于class的權(quán)限修飾只可以用public和(default)缺省屠列。public類可以在任意地方被訪問啦逆。 default類只可以被同一個包內(nèi)部的類訪問。
總結(jié)封裝性:Java提供了4種權(quán)限修飾符來修飾類及類的內(nèi)部結(jié)構(gòu)笛洛,體現(xiàn)類及類的內(nèi)部結(jié)構(gòu)在被調(diào)用時的可見性的大小夏志。
二、面向?qū)ο筇卣鞫豪^承性
1.繼承性的作用:
繼承的出現(xiàn)減少了代碼冗余撞蜂,提高了代碼的復(fù)用性盲镶。
繼承的出現(xiàn),更有利于功能的擴展蝌诡。
繼承的出現(xiàn)讓類與類之間產(chǎn)生了關(guān)系溉贿,提供了多態(tài)的前提。
2.繼承性的格式:?class A extends B{}
A:子類浦旱、派生類宇色、subclass
B:父類、超類、基類宣蠕、superclass
2.1體現(xiàn):一旦子類A繼承父類B以后例隆,子類A中就獲取了父類B中聲明的所有的屬性和方法。
特別的抢蚀,父類中聲明為private的屬性或方法镀层,子類繼承父類以后,仍然認為獲取了父類中私有的結(jié)構(gòu)皿曲。
只有因為封裝性的影響唱逢,使得子類不能直接調(diào)用父類中私有(private)的結(jié)構(gòu)而已。
2.2 子類繼承父類以后屋休,還可以聲明自己特有的屬性或方法:實現(xiàn)功能的拓展坞古。
子類和父類的關(guān)系,不同于子集和集合的關(guān)系劫樟。
?extends:延展痪枫、擴展
3.繼承性的規(guī)定:
1.Java中類的多層繼承:一個類可以被多個子類繼承。
2.Java中類的單繼承性:一個類只能有一個父類叠艳。
3.子父類是相對的概念奶陈。
4.子類直接繼承的父類,稱為:直接父類虑绵。間接繼承的父類稱為:間接父類尿瞭。
5.子類繼承父類以后,就獲取了直接父類以及所有間接父類中聲明的屬性和方法翅睛。
6. 如果我們沒有顯式的聲明一個類的父類的話声搁,則此類繼承于java.lang.Object類。Object類是所有Java類的根父類?
7. 所有的java類(除java.lang.Object類之外)都直接或間接的繼承于java.lang.Object類捕发。
8. 意味著疏旨,所有的java類具有java.lang.Object類聲明的功能。
public class Creature {
? public void breath(){
? ? System.out.println("呼吸");
? }
}
public class ExtendsTest {
? ? ? Creature c = new Creature();
? ? ? c.toString();
? ? ? c.breath();
}
4.方法的重寫:
4.1重寫的定義:在子類中可以根據(jù)需要對從父類中繼承來的方法進行改造扎酷,也稱 為方法的重置檐涝、覆蓋。在程序執(zhí)行時法挨,子類的方法將覆蓋父類的方法谁榜。重寫以后,當創(chuàng)建子類對象以后凡纳,通過子類對象調(diào)用子父類中的同名同參數(shù)的方法時窃植,實際執(zhí)行的是子類重寫父類的方法。
4.2重寫的規(guī)定:
方法的聲明: 權(quán)限修飾符 返回值類型 方法名(形參列表) throws 異常的類型{?//方法體}
(1). 子類重寫的方法必須和父類被重寫的方法具有相同的方法名稱荐糜、參數(shù)列表巷怜。
(2). 子類重寫的方法使用的訪問權(quán)限不能小于父類被重寫的方法的訪問權(quán)限 葛超。子類不能重寫父類中聲明為private權(quán)限的方法。
(3). 子類方法拋出的異常不能大于父類被重寫方法的異常 延塑。
(4). 子類重寫的方法的返回值類型不能大于父類被重寫的方法的返回值類型绣张。
返回值類型:
>父類被重寫的方法的返回值類型是void,則子類重寫的方法的返回值類型只能是void
>父類被重寫的方法的返回值類型是A類型(引用數(shù)據(jù)類型)关带,則子類重寫的方法的返回值類型可以是A類或A類的子類
>父類被重寫的方法的返回值類型是基本數(shù)據(jù)類型(比如:double)侥涵,則子類重寫的方法的返回值類型必須是相同的基本數(shù)據(jù)類型(必須也是double)
4.3重寫的注意: 子類與父類中同名同參數(shù)的方法必須同時聲明為非static的(即為重寫),或者同時聲明為?static的(不是重寫)豫缨。因為static方法是屬于類的独令,子類無法覆蓋父類的方法端朵。
4.4區(qū)分方法的重載與重寫
① 二者的概念好芭。
(1)重載定義:在同一個類中,允許存在一個以上的同名方法冲呢,只要它們的參數(shù)個數(shù)或者參數(shù)類型不同即可舍败。
(2)重寫定義:在子類中可以根據(jù)需要對從父類中繼承來的方法進行改造,也稱 為方法的重置敬拓、覆蓋邻薯。
② 重載和重寫的具體規(guī)則。
(1)重載"兩同一不同":同一個類乘凸、相同方法名
參數(shù)列表不同:參數(shù)個數(shù)不同厕诡,參數(shù)類型不同
(2)子類重寫的方法必須和父類被重寫的方法具有相同的方法名稱、參數(shù)列表营勤。
③ 重載:不表現(xiàn)為多態(tài)性灵嫌。重寫:表現(xiàn)為多態(tài)性。
答:方法的重寫Overriding和重載Overloading是Java多態(tài)性的不同表現(xiàn)葛作。重寫Overriding是父類與子類之間多態(tài)性的一種表現(xiàn)寿羞,重載Overloading是一個類中多態(tài)性的一種表現(xiàn)。如果在子類中定義某方法與其父類有相同的名稱和參數(shù)赂蠢,我們說該方法被重寫 (Overriding)绪穆。子類的對象使用這個方法時,將調(diào)用子類中的定義虱岂,對它而言玖院,父類中的定義如同被"屏蔽"了。如果在一個類中定義了多個同名的方法第岖,它們或有不同的參數(shù)個數(shù)或有不同的參數(shù)類型难菌,則稱為方法的重載(Overloading)。
4.5四種訪問權(quán)限修飾符
public class OrderTest {//OrderTest類和Order類在同一個包下
? public static void main(String[] args) {
? ? Order order = new Order();
? ? order.orderDefault = 1;
? ? order.orderProtected = 2;
? ? order.orderPublic = 3;
? ? order.methodDefault();
? ? order.methodProtected();
? ? order.methodPublic();
? ? //同一個包中的其他類(OrderTest類)绍傲,不可以調(diào)用Order類中私有的屬性扔傅、方法
// order.orderPrivate = 4;
// order.methodPrivate();
? }
}
public class SubOrder extends Order {//SubOrder類與Order類在不同包
? public void method(){
? ? orderProtected = 1;
? ? orderPublic = 2;
? ? methodProtected();
? ? methodPublic();
? ? //在不同包的子類中耍共,不能調(diào)用Order類中聲明為private和缺省權(quán)限的屬性、方法
// orderDefault = 3;
// orderPrivate = 4;
//
// methodDefault();
// methodPrivate();
? }
}
public class OrderTest {//OrderTest類與Order類在不同包猎塞,且沒有父子類關(guān)系
? public static void main(String[] args) {
? ? Order order = new Order();
? ? order.orderPublic = 1;
? ? order.methodPublic();
? ? //不同包下的普通類(非子類)要使用Order類试读,不可以調(diào)用聲明為private、缺省荠耽、protected權(quán)限的屬性钩骇、方法
// order.orderPrivate = 2;
// order.orderDefault = 3;
// order.orderProtected = 4;
//
// order.methodPrivate();
// order.methodDefault();
// order.methodProtected();
? }
}
5.super關(guān)鍵字
super 關(guān)鍵字可以理解為:父類的
5.1在Java類中使用super來調(diào)用父類中的指定操作:
super可用于訪問父類中定義的屬性 。
super可用于調(diào)用父類中定義的成員方法铝量。
super可用于在子類構(gòu)造器中調(diào)用父類的構(gòu)造器倘屹。
5.2注意:
尤其當子父類出現(xiàn)同名成員時,可以用super表明調(diào)用的是父類中的成員慢叨。
super的追溯不僅限于直接父類纽匙,還要間接父類。
super和this的用法相像拍谐,this代表本類對象的引用烛缔,super代表父類的內(nèi)存 空間的標識。
5.3super的使用:調(diào)用屬性和方法
(1) 我們可以在子類的方法或構(gòu)造器中轩拨。通過使用"super.屬性"或"super.方法"的方式践瓷,顯式的調(diào)用父類中聲明的屬性或方法。但是亡蓉,通常情況下晕翠,我們習(xí)慣省略"super."
(2) 特殊情況:當子類和父類中定義了同名的屬性時,我們要想在子類中調(diào)用父類中聲明的屬性砍濒,則必須顯式的?使用"super.屬性"的方式淋肾,表明調(diào)用的是父類中聲明的屬性。
?(3)特殊情況:當子類重寫了父類中的方法以后梯影,我們想在子類的方法中調(diào)用父類中被重寫的方法時巫员,則必須顯式的使用"super.方法"的方式,表明調(diào)用的是父類中被重寫的方法甲棍。
5.4super調(diào)用構(gòu)造器
(1) 我們可以在子類的構(gòu)造器中顯式的使用"super(形參列表)"的方式简识,調(diào)用父類中聲明的指定的構(gòu)造器。
(2) "super(形參列表)"的使用感猛,必須聲明在子類構(gòu)造器的首行七扰!
(3)我們在類的構(gòu)造器中,針對于"this(形參列表)"或"super(形參列表)"只能二選一陪白,不能同時出現(xiàn)颈走。
(4)在構(gòu)造器的首行,沒有顯式的聲明"this(形參列表)"或"super(形參列表)"咱士,則默認調(diào)用的是父類中空參的構(gòu)造器:super()立由。
(5)在類的多個構(gòu)造器中轧钓,至少有一個類的構(gòu)造器中使用了"super(形參列表)",調(diào)用父類中的構(gòu)造器锐膜。
舉例
public class Person {
? private String name;
? private int age;
? private Date birthDate;
? public Person(String name, int age, Date d) {
? ? this.name = name;
? ? this.age = age;
? ? this.birthDate = d;
}
public Person(String name, int age) {
? ? this(name, age, null);
}
public Person(String name, Date d) {
? ? this(name, 30, d);
}
public Person(String name) {
? ? this(name, 30);
}}
public class Student extends Person {
? private String school;
? public Student(String name, int age, String s) {
? ? ? super(name, age);
? ? ? school = s;
? }
? public Student(String name, String s) {
? ? ? super(name); school = s;
? }
? // 編譯出錯: no super(),系統(tǒng)將調(diào)用父類無參數(shù)的構(gòu)造器毕箍。
? public Student(String s) {
? ? ? school = s;
? }
}
6.子類對象的實例化過程
6.1. 從結(jié)果上來看:(繼承性)
子類繼承父類以后,就獲取了父類中聲明的屬性或方法道盏。
創(chuàng)建子類的對象而柑,在堆空間中,就會加載所有父類(直接荷逞、間接父類)中聲明的屬性媒咳。
6.2. 從過程上來看:
當我們通過子類的構(gòu)造器創(chuàng)建子類對象時,我們一定會直接或間接的調(diào)用其父類的構(gòu)造器种远,進而調(diào)用父類的父類的構(gòu)造器涩澡,.....直到調(diào)用了java.lang.Object類中空參的構(gòu)造器為止。正因為加載過所有的父類的結(jié)構(gòu)院促,所以才可以看到內(nèi)存中父類中的結(jié)構(gòu)筏养,子類對象才可以考慮進行調(diào)用。
6.3.強調(diào)說明:
雖然創(chuàng)建子類對象時常拓,調(diào)用了父類的構(gòu)造器,但是自始至終就創(chuàng)建過一個對象辉浦,即為new的子類對象弄抬。
class Creature {
? ? public Creature() {
? ? ? System.out.println("Creature無參數(shù)的構(gòu)造器");
}}
class Animal extends Creature {
? ? public Animal(String name) {
? ? ? System.out.println("Animal帶一個參數(shù)的構(gòu)造器,該動物的name為" + name);
? ? ? ? }
? ? public Animal(String name, int age) {
? ? ? ? this(name);
? ? ? ? System.out.println("Animal帶兩個參數(shù)的構(gòu)造器宪郊,其age為" + age);
}}
public class Wolf extends Animal {
? ? public Wolf() {
? ? ? ? ? super("灰太狼", 3);
? ? ? ? ? System.out.println("Wolf無參數(shù)的構(gòu)造器");
}
? ? public static void main(String[] args) {
? ? ? ? ? new Wolf();
}}
三掂恕、面向?qū)ο筇卣魅憾鄳B(tài)性
1.理解多態(tài)性:可以理解為一個事物的多種形態(tài)。作用:提高了代碼的通用性弛槐,常稱作接口重用 懊亡。
2.何為多態(tài)性:
對象的多態(tài)性:父類的引用指向子類的對象(或子類的對象賦給父類的引用)------向上轉(zhuǎn)型『醮可以直接應(yīng)用在抽象類和接口上店枣。
3. 多態(tài)的使用:虛擬方法調(diào)用
有了對象的多態(tài)性以后,我們在編譯期叹誉,只能調(diào)用父類中聲明的方法鸯两,但在運行期,我們實際執(zhí)行的是子類重寫父類的方法长豁。
Java引用變量有兩個類型:編譯時類型和運行時類型钧唐。編譯時類型由聲明 該變量時使用的類型決定,運行時類型由實際賦給該變量的對象決定匠襟。簡稱:編譯钝侠,看左邊该园;運行,看右邊帅韧。
若編譯時類型和運行時類型不一致爬范,就出現(xiàn)了對象的多態(tài)性(Polymorphism)。
一個引用類型變量如果聲明為父類的類型弱匪,但實際引用的是子類
對象青瀑,那么該變量就不能再訪問子類中特有的屬性和方法。
Student m = new Student();
m.school = “pku”; //合法,Student類有school成員變量
Person e = new Student();
e.school = “pku”; //非法,Person類沒有school成員變量
//屬性是在編譯時確定的萧诫,編譯時e為Person類型斥难,沒有school成員變量,因而編
譯錯誤帘饶。
? 正常的方法調(diào)用
Person e = new Person();
e.getInfo();
Student e = new Student();
e.getInfo();
? 虛擬方法調(diào)用(多態(tài)情況下)
子類中定義了與父類同名同參數(shù)的方法哑诊,在多態(tài)情況下,將此時父類的方法稱為虛擬方法及刻,父 類根據(jù)賦給它的不同子類對象镀裤,動態(tài)調(diào)用屬于子類的該方法。這樣的方法調(diào)用在編譯期是無法 確定的(運行時行為)缴饭。
Person e = new Student();
e.getInfo(); //調(diào)用Student類的getInfo()方法
? 編譯時類型和運行時類型
編譯時e為Person類型暑劝,而方法的調(diào)用是在運行時確定的,所以調(diào)用的是Student類 的getInfo()方法颗搂。——動態(tài)綁定
4.多態(tài)性的使用前提:? ① 存在類的繼承關(guān)系或接口的實現(xiàn)關(guān)系? ? ? ? ? ② 有方法的重寫
多態(tài)情況下担猛,“看左邊”:看的是父類的引用(父類中不具備子類特有的方法)
“看右邊”:看的是子類的對象(實際運行的是子類重寫父類的方法)
5.對象的多態(tài)性,只適用于方法丢氢,不適用于屬性(編譯和運行都看左邊)傅联。
public class Person {
? String name;
? int age;
? int id = 1001;
}
public class Man extends Person{
? boolean isSmoking;
? int id = 1002;
}
public class PersonTest {
? public static void main(String[] args) {
? ? ? ? Person p2 = new Man();
? ? ? ? System.out.println(p2.id);//1001(調(diào)用屬性時編譯和運行都看左邊)
? ? }
}
6.多態(tài)性使用的舉例:
//多態(tài)性的使用舉例一:
public class AnimalTest {
? public static void main(String[] args) {
? ? AnimalTest test = new AnimalTest();
? ? test.func(new Dog());
? ? test.func(new Cat());
? }
? public void func(Animal animal){//Animal animal = new Dog();
? ? animal.eat();
? ? animal.shout();
? ? if(animal instanceof Dog){
? ? ? Dog d = (Dog)animal;
? ? ? d.watchDoor();
? ? }
? }
}
class Animal{
? public void eat(){
? ? System.out.println("動物:進食");
? }
? public void shout(){
? ? System.out.println("動物:叫");
? }
}
class Dog extends Animal{
? public void eat(){
? ? System.out.println("狗吃骨頭");
? }
? public void shout(){
? ? System.out.println("汪!汪疚察!汪蒸走!");
? }
? public void watchDoor(){
? ? System.out.println("看門");
? }
}
class Cat extends Animal{
? public void eat(){
? ? System.out.println("貓吃魚");
? }
? public void shout(){
? ? System.out.println("喵!喵貌嫡!喵比驻!");
? }
}
//舉例二:
class Order{
? public void method(Object obj){//object類是所有類的父類
? }
}
//舉例三:
class Driver{
? public void doData(Connection conn){//conn = new MySQlConnection(); / conn = new OracleConnection();
? ? //規(guī)范的步驟去操作數(shù)據(jù)(抽象化)
// conn.method1();
// conn.method2();
// conn.method3();
? }
}
//舉例四:方法聲明的形參類型為父類類型,可以使用子類的對象作為實參調(diào)用該方法
public class Test {
? ? public void method(Person e) {
? ? ? // ……
? ? ? e.getInfo();
? ? }
? ? public static void main(Stirng args[]) {
? ? ? Test t = new Test();
? ? ? Student m = new Student();
? ? ? t.method(m); // 子類的對象m傳送給父類類型的參數(shù)e
? ? }
}
7.多態(tài)是編譯時行為還是運行時行為衅枫?(證明如下代碼)
class Animal? {
? protected void eat() {
? ? System.out.println("animal eat food");
? }
}
class Cat? extends Animal? {
? protected void eat() {
? ? System.out.println("cat eat fish");
? }
}
class Dog? extends Animal? {
? public void eat() {
? ? System.out.println("Dog eat bone");
? }
}
class Sheep? extends Animal? {
? public void eat() {
? ? System.out.println("Sheep eat grass");
? }
}
public class InterviewTest {
? public static Animal? getInstance(int key) {
? ? switch (key) {
? ? case 0:
? ? ? return new Cat ();
? ? case 1:
? ? ? return new Dog ();
? ? default:
? ? ? return new Sheep ();
? ? }
? }
? public static void main(String[] args) {
? ? int key = new Random().nextInt(3);
? ? System.out.println(key);
? ? Animal? animal = getInstance(key);
? ? animal.eat();
? }
}
?
8.instanceof關(guān)鍵字
8.1有了對象的多態(tài)性以后嫁艇,內(nèi)存中實際上是加載了子類特有的屬性和方法的,但是由于變量聲明為父類類型弦撩,導(dǎo)致編譯時步咪,只能調(diào)用父類中聲明的屬性和方法。子類特有的屬性和方法不能調(diào)用益楼。
8.2如何才能調(diào)用子類特有的屬性和方法猾漫?
向下轉(zhuǎn)型:使用強制類型轉(zhuǎn)換符点晴。
Person p2 = new Man();
Man m1=p2;//這是錯誤的,因為Java中賦值符號兩邊數(shù)據(jù)類型應(yīng)該一樣悯周,或者是基本數(shù)據(jù)類型的自動類型提升粒督。
Man m1 = (Man)p2;//強制類型轉(zhuǎn)換。m1為Man類型禽翼,p2地址值賦值給了m1屠橄。
//使用強轉(zhuǎn)時,可能出現(xiàn)ClassCastException的異常闰挡。
Woman w1 = (Woman)p2;//運行時出現(xiàn)ClassCastException的異常锐墙。
基本數(shù)據(jù)類型的對象類型轉(zhuǎn)換(Casting):
(1)自動類型轉(zhuǎn)換:小的數(shù)據(jù)類型可以自動轉(zhuǎn)換成大的數(shù)據(jù)類型。 如long g=20; double d=12.0f
(2)強制類型轉(zhuǎn)換:可以把大的數(shù)據(jù)類型強制轉(zhuǎn)換(casting)成小的數(shù)據(jù)類型 长酗。如 float f=(float)12.0; int a=(int)1200L
對Java對象的強制類型轉(zhuǎn)換稱為造型
(1)從子類到父類的類型轉(zhuǎn)換可以自動進行溪北。
(2)從父類到子類的類型轉(zhuǎn)換必須通過造型(強制類型轉(zhuǎn)換)實現(xiàn)。
(3)無繼承關(guān)系的引用類型間的轉(zhuǎn)換是非法的夺脾。
(4)在造型前可以使用instanceof操作符測試一個對象的類型之拨。
public class ConversionTest {
? ? ? ? public static void main(String[] args) {
? ? ? ? ? ? ? double d = 13.4;
? ? ? ? ? ? ? long l = (long) d;
? ? ? ? ? ? ? System.out.println(l);
? ? ? ? ? ? ? int in = 5;
? ? ? ? ? ? ? // boolean b = (boolean)in;
? ? ? ? ? ? ? Object obj = "Hello";
? ? ? ? ? ? ? String objStr = (String) obj;
? ? ? ? ? ? ? System.out.println(objStr);
? ? ? ? ? ? ? Object objPri = new Integer(5);
? ? ? ? ? ? ? // 所以下面代碼運行時引發(fā)ClassCastException異常
? ? ? ? ? ? ? String str = (String) objPri;
? ? ? }
}
public class Test {//對象類型轉(zhuǎn)換舉例
public void method(Person e) { // 設(shè)Person類中沒有g(shù)etschool() 方法
// System.out.pritnln(e.getschool()); //非法,編譯時錯誤
if (e instanceof Student) {
Student me = (Student) e; // 將e強制轉(zhuǎn)換為Student類型
System.out.pritnln(me.getschool());
}
}
public static void main(String[] args){
Test t = new Test();
Student m = new Student();
t.method(m); }
}
8.3instanceof關(guān)鍵字的使用
a instanceof A:判斷對象a是否是類A的實例秘豹,返回值為boolean類型寺滚。如果是,返回true召边;如果不是佳簸,返回false乙墙。
要求a所屬的類與類A必須是子類和父類的關(guān)系,否則編譯錯誤生均。 如果a屬于類A的子類B,a instanceof A值也為true
為了避免在向下轉(zhuǎn)型時出現(xiàn)ClassCastException的異常腥刹,我們在向下轉(zhuǎn)型之前马胧,先進行instanceof的判斷,一旦返回true衔峰,就進行向下轉(zhuǎn)型佩脊。如果返回false,不進行向下轉(zhuǎn)型垫卤。
Person p2 = new Man();
Man m1 = (Man)p2;
if(p2 instanceof Woman){
? ? ? Woman w1 = (Woman)p2;
? ? ? w1.goShopping();
? ? ? System.out.println("******Woman******");不輸出System語句
? ? }
if(p2 instanceof Man){
? ? ? Man m2 = (Man)p2;
? ? ? m2.earnMoney();
? ? ? System.out.println("******Man******");//輸出System語句
? ? }
//如果 a instanceof A返回true,則 a instanceof B也返回true威彰。其中,類B是類A的父類穴肘。
if(p2 instanceof Person){
? ? ? System.out.println("******Person******");//輸出System語句
? ? }
if(p2 instanceof Object){
? ? ? System.out.println("******Object******");//輸出System語句
? ? }
向下轉(zhuǎn)型常見的問題
//問題一:編譯時通過歇盼,運行時不通過
? ? //舉例一:
// Person p3 = new Woman();
// Man m3 = (Man)p3;
? ? //舉例二:
// Person p4 = new Person();
// Man m4 = (Man)p4;
// Object o = new Date();
// String str1 = (String)o;//沒有意義
//問題二:編譯通過,運行時也通過
// Object obj = new Woman();//多態(tài)性
// Person p = (Person)obj;//Object類型向下轉(zhuǎn)型成Person類型
? ? //問題三:編譯不通過
// Man m5 = new Woman();//沒有子父類關(guān)系
// String str = new Date();//沒有子父類關(guān)系