文章目錄
全部源碼:https://github.com/name365/JavaSE-30Day
轉載自atguigu.com視頻
第四章 面向對象(中)
繼承性的使用與理解
- Person 類
/*
* 爲描述和處理個人信息,定義類 Person
*/
public class Person {
String name;
private int age;
public Person(){
}
public Person(String name,int age){
this.name = name;
this.age = age;
}
public void eat(){
System.out.println("喫飯");
sleep();
}
private void sleep(){
System.out.println("睡覺");
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
- Student 類
/*
* 爲描述和處理學生信息,定義類 Student
*/
public class Student extends Person {
// String name;
// int age;
String major;
public Student(){
}
public Student(String name,int age,String major){
this.name = name;
// this.age = age;
setAge(age);
this.major = major;
}
// public void eat(){
// System.out.println("喫飯");
// }
//
// public void sleep(){
// System.out.println("睡覺");
// }
public void study(){
System.out.println("學習");
}
public void show(){
System.out.println("name:" + name + ",age = " + getAge());
}
}
- 測試類
/*
* 面向對象的特徵二:繼承性
*
* 爲什麼要有繼承?
* 多個類中存在相同屬性和行爲時,將這些內容抽取到單獨一個類中,
* 那麼多個類無需再定義這些屬性和行爲,只要繼承那個類即可。
* * 一、繼承性的好處
* ① 減少了代碼的冗餘,提高了代碼的複用性;
* ② 便於功能的擴展;
* ③ 爲之後多態性的使用,提供了前提。
*
* 二、繼承性的格式
* class A extends B{}
* A:子類、派生類、subclass
* B:父類、超類、基類、superclass
*
* 2.1 體現:一旦子類 A 繼承父類以後,子類 A 中就獲取了父類 B 中聲明的結構:屬性、方法
* 特別的,父類中聲明爲 private 的屬性或方法,子類繼承父類以後,仍然認爲獲取了父類中私有的結構。
* 只有因爲封裝性的影響,使得子類不能直接調用父類的結構而已。
* 2.2 子類繼承父類以後,還可以聲明自己特有的屬性或方法,實現功能的拓展。
* 子類和父類的關係:不同於子集與集合的關係。
* extends:延展、擴展
*
*/
public class ExtendsTest {
public static void main(String[] args) {
Person p1 = new Person();
// p1.age = 1;
p1.eat();
System.out.println("********************");
Student s1 = new Student();
s1.eat();
// s1.sleep();
s1.name = "Tom";
s1.setAge(10);
System.out.println(s1.getAge());
}
}
- Java 中關於繼承性的規定
/* 三、Java 中關於繼承性的規定:
* 1.一個類可以被多個類繼承
* 2.Java 中類的單繼承性:一個類只能有一個父類
* 3.子父類是相對的概念。
* 4.子類直接繼承的父類,稱爲:直接父類。間接繼承的父類,稱爲,間接父類。
* 5.子類繼承父類後,就獲取了直接父類以及所有間接父類中聲明的屬性和方法。
*
* 四、1.如果我們沒有顯式的聲明一個類的父類的話,則此類繼承於 java.lang.Object 類
* 2.所有的 java 類(除 java.long.Object 類之外)都直接或間接地繼承於 java.lang.Object 類;
* 3.意味着,所有的 java 類具有 java.lang.Object 類聲明的功能。
*/
public class ExtendsTest {
public static void main(String[] args) {
s1.brease();
Creature c = new Creature();
System.out.println(c.toString());
}
}
- 將上述 Person 類改爲如下
public class Person extends Creature {
...
}
- Creature 類
public class Creature {
public void brease(){
System.out.println("呼吸");
}
}
繼承性練習
- 練習1
/*
* 定義類Kids繼承ManKind,幷包括
* 成員變量int yearsOld;
* 方法printAge()打印yearsOld的值
*
*/
public class Kids extends ManKind{
private int yearsOld; //年限
public Kids() {
}
public Kids(int yearsOld) {
this.yearsOld = yearsOld;
}
public int getYearsOld() {
return yearsOld;
}
public void setYearsOld(int yearsOld) {
this.yearsOld = yearsOld;
}
public void printAge(){
System.out.println("I am " + yearsOld);
}
}
- ManKind類
/*
* 定義一個ManKind類,包括
* 成員變量int sex和int salary;
* 方法void manOrWoman():根據sex的值顯示“man”(sex==1)或者“woman”(sex==0);
* 方法void employeed():根據salary的值顯示“no job”(salary==0)或者“job”(salary!=0)。
*
*/
public class ManKind {
private int sex; //性別
private int salary; //薪資
public ManKind() {
}
public ManKind(int sex, int salary) {
this.sex = sex;
this.salary = salary;
}
public void manOrWoman(){
if(sex==1){
System.out.println("man");
}else if(sex==0){
System.out.println("woman");
}
}
public void employeed(){
if(salary==0){
System.out.println("no job");
}else if(salary!=0){
System.out.println("job");
}
}
public int getSex() {
return sex;
}
public void setSex(int sex) {
this.sex = sex;
}
public int getSalary() {
return salary;
}
public void setSalary(int salary) {
this.salary = salary;
}
}
- KidsTest
/*
* 定義類KidsTest,在類的main方法中實例化Kids的對象someKid,
* 用該對象訪問其父類的成員變量及方法。
*
*/
public class KidsTest {
public static void main(String[] args) {
Kids someKid = new Kids(12);
someKid.printAge();
someKid.setYearsOld(15);
someKid.setSalary(0);
someKid.setSex(1);
someKid.employeed();
someKid.manOrWoman();
}
}
- 練習2
public class Circle {
public double radius; //半徑
public Circle(){
radius = 1.0;
}
public double getRadius() {
return radius;
}
public void setRadius(double radius) {
this.radius = radius;
}
public double findArea(){ //計算圓的面積
return Math.PI * radius * radius;
}
}
- Cylinder類
public class Cylinder extends Circle{
private double length;
public Cylinder(){
length = 1.0;
}
public double getLength() {
return length;
}
public void setLength(double length) {
this.length = length;
}
public double findVolume(){ //計算圓柱體積
return findArea() * length;
}
}
- 測試類
public class CylinderTest {
public static void main(String[] args) {
Cylinder cy = new Cylinder();
cy.setRadius(2.1);
cy.setLength(3.4);
double volues = cy.findVolume();
System.out.println("圓柱的體積:" + volues);
double area = cy.findArea();
System.out.println("圓的面積: " + area);
}
}
方法的重寫(override/overwrite)
- Person類
public class Person {
String name;
int age;
public Person(){
}
public Person(String name,int age){
this.name = name;
this.age = age;
}
public void eat(){
System.out.println("喫飯");
}
public void walk(int distance){
System.out.println("走路,走的距離是:" + distance + "公里");
show();
}
private void show(){
System.out.println("我是一個人。");
}
public Object info(){
return null;
}
public double info1(){
return 1.0;
}
}
- Student類
public class Student extends Person{
String major;
public Student(){
}
public Student(String major){
this.major = major;
}
public void study(){
System.out.println("學習,專業是:" + major);
}
//對父類中的eat()進行了重寫
public void eat(){
System.out.println("學生應該多喫有營養的。");
}
public void show(){
System.out.println("我是一個學生。");
}
public String info(){
return null;
}
//不是一個類型,所以報錯。
// public int info1(){
// return 1;
// }
//可以直接將父類的方法的第一行粘過來,直接寫方法體
// public void walk(int distance){
// System.out.println("重寫的方法");
// }
//直接輸入父類的方法名,Alt + /,選擇即可生成
@Override
public void walk(int distance) {
System.out.println("自動生成");
}
}
- 測試類
/*
* 方法的重寫(override/overwrite)
*
* 1.重寫:子類繼承父類以後,可以對父類中的方法進行覆蓋操作。
* 2.應用:重寫以後,當創建子類對象以後,通過子類對象去調用子父類中同名同參數方法時,執行的是子類重寫父類的方法。
* 即在程序執行時,子類的方法將覆蓋父類的方法。
*
* 面試題:區分方法的重載與重寫(有的書也叫做“覆蓋”)
* 答:方法的重寫Overriding和重載Overloading是Java多態性的不同表現。
* 重寫Overriding是父類與子類之間多態性的一種表現,重載Overloading是一個類中多態性的一種表現。
* 如果在子類中定義某方法與其父類有相同的名稱和參數,我們說該方法被重寫 (Overriding)。
* 子類的對象使用這個方法時,將調用子類中的定義,對它而言,父類中的定義如同被"屏蔽"了。
* 如果在一個類中定義了多個同名的方法,它們或有不同的參數個數或有不同的參數類型,則稱爲方法的重載(Overloading)。
*
*/
public class PersonTest {
public static void main(String[] args) {
Student s = new Student("計算機科學與技術");
s.eat();
s.walk(10);
s.study();
}
}
方法重寫的細節
- Person類
public class Person {
String name;
int age;
public Person(){
}
public Person(String name,int age){
this.name = name;
this.age = age;
}
// public void eat(){
// System.out.println("喫飯");
// }
static void eat(){
System.out.println("喫飯");
}
public void walk(int distance){
System.out.println("走路,走的距離是:" + distance + "公里");
show();
}
private void show(){
System.out.println("我是一個人。");
}
public Object info(){
return null;
}
public double info1(){
return 1.0;
}
}
- Student類
public class Student extends Person{
String major;
public Student(){
}
public Student(String major){
this.major = major;
}
public void study(){
System.out.println("學習,專業是:" + major);
}
//對父類中的eat()進行了重寫
// public void eat(){
// System.out.println("學生應該多喫有營養的。");
// }
//這樣不會報錯,但已經不是重寫了!!
public static void eat(){
System.out.println("學生應該多喫有營養的。");
}
public void show(){
System.out.println("我是一個學生。");
}
public String info(){
return null;
}
//不是一個類型,所以報錯。
// public int info1(){
// return 1;
// }
//可以直接將父類的方法的第一行粘過來,直接寫方法體
// public void walk(int distance){
// System.out.println("重寫的方法");
// }
//直接輸入父類的方法名,Alt + /,選擇即可生成
@Override
public void walk(int distance) {
System.out.println("自動生成");
}
}
- 測試類
/*
* 3.重寫的規定:
* 方法的聲明:權限修飾符 返回值類型 方法名(形參列表){
* //方法體
* }
* 約定俗稱:子類中的叫重寫的方法,父類中的叫被重寫的方法。
* ① 子類重寫的方法的方法名和形參列表必須和父類被重寫的方法的方法名、形參列表相同;
* ② 子類重寫的方法使用的訪問權限不能小於父類被重寫的方法的訪問權限,
* 特殊情況: 子類不能重寫父類中聲明爲private權限的方法;
* ③ 返回值類型:
* > 父類被重寫的方法的返回值類型是void,則子類重寫的方法的返回值類型只能是void;
* > 父類被重寫的方法的返回值類型是A類型,則子類重寫的方法的返回值類型可以是A類或A類的子類;
* > 父類被重寫的方法的返回值類型如果是基本數據類型(比如:double),則子類重寫的方法的返回值類型必須是相同的基本數據類型(必須是:double)。
*
* ④ 子類方法拋出的異常不能大於父類被重寫的方法拋出的異常;
*
* 注意:子類與父類中同名同參數的方法必須同時聲明爲非static的(即爲重寫),或者同時聲明爲static的(不是重寫)。
* 因爲static方法是屬於類的,子類無法覆蓋父類的方法。
*/
public class PersonTest {
public static void main(String[] args) {
Student s = new Student("計算機科學與技術");
s.eat();
s.walk(10);
System.out.println("*******************");
s.study();
Person p1 = new Person();
p1.eat();
}
}
方法的練習
- 練習1
1.如果現在父類的一個方法定義成private訪問權限,在子類中將此方法聲明爲default訪問權限,那麼這樣還叫重寫嗎?(NO)
- 練習2
/*
* 2.修改練習1.2中定義的類Kids,在Kids中重新定義employeed()方法,
* 覆蓋父類ManKind中定義的employeed()方法,
* 輸出“Kids should study and no job.”
*/
public class Kids extends ManKind{
private int yearsOld; //年限
public Kids() {
}
public Kids(int yearsOld) {
this.yearsOld = yearsOld;
}
public int getYearsOld() {
return yearsOld;
}
public void setYearsOld(int yearsOld) {
this.yearsOld = yearsOld;
}
public void printAge(){
System.out.println("I am " + yearsOld);
}
public void employeed(){
System.out.println("Kids should study and no job.");
}
}
- MindKids類
public class ManKind {
private int sex; //性別
private int salary; //薪資
public ManKind() {
}
public ManKind(int sex, int salary) {
this.sex = sex;
this.salary = salary;
}
public void manOrWoman(){
if(sex==1){
System.out.println("man");
}else if(sex==0){
System.out.println("woman");
}
}
public void employeed(){
if(salary==0){
System.out.println("no job");
}else if(salary!=0){
System.out.println("job");
}
}
public int getSex() {
return sex;
}
public void setSex(int sex) {
this.sex = sex;
}
public int getSalary() {
return salary;
}
public void setSalary(int salary) {
this.salary = salary;
}
}
- 測試類
public class KidsTest {
public static void main(String[] args) {
Kids someKid = new Kids(12);
someKid.printAge();
someKid.setYearsOld(15);
someKid.setSalary(0);
someKid.setSex(1);
someKid.employeed();
someKid.manOrWoman();
}
}
四種訪問權限修飾符
對於之前的四種權限修飾符的補充
- Order類
package githubb;
/*
* 體會四種不同的權限修飾符
*
*
*/
public class Order {
private int orderPrivate;
int orderDefault;
protected int orderProtected;
public int orderPublic;
private void methodPrivate(){
orderPrivate = 1;
orderDefault = 2;
orderProtected = 3;
orderPublic = 4;
}
void methodDefault(){
orderPrivate = 1;
orderDefault = 2;
orderProtected = 3;
orderPublic = 4;
}
protected void methodProtected(){
orderPrivate = 1;
orderDefault = 2;
orderProtected = 3;
orderPublic = 4;
}
public void methodPublic(){
orderPrivate = 1;
orderDefault = 2;
orderProtected = 3;
orderPublic = 4;
}
}
- Ordertest類
package githubb;
public class OrderTest {
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();
//同一個包中的其它類,不可以調用Order類中私有的屬性
// order.orderPrivate = 4; //The field Order.orderPrivate is not visible
// order.methoPrivate();
}
}
- SubOrder類
package githubc;
import githubb.Order;
public class SubOrder extends Order{
public void method(){
orderProtected = 1;
orderPublic = 2;
methodProtected();
methodPublic();
//在不同包的子類中,不能調用Order類中聲明爲private和缺省的權限的屬性、方法
// orderDefault = 3;
// orderPrivate = 4;
//
// methodDefault();
// methodPrivate();
}
}
- OrderTest類
package githubc;
import githubb.Order;
public class OrderTest {
public static void main(String[] args) {
Order order = new Order();
order.orderPublic = 1;
order.methodPublic();
//不同包下的普通類(非子類)要使用Order類,不可以調用聲明爲private、缺省、protected權限的屬性、方法。
// order.orderPrivate = 2;
// order.orderProtected = 3;
// order.orderProtected = 4;
//
// order.methodPrivate();
// order.methodDefault();
// order.methodProtected();
}
public void show(Order order){
order.orderPublic = 1;
order.methodPublic();
//不同包下的普通類(非子類)要使用Order類,不可以調用聲明爲private、缺省、protected權限的屬性、方法。
// order.orderPrivate = 2;
// order.orderProtected = 3;
// order.orderProtected = 4;
//
// order.methodPrivate();
// order.methodDefault();
// order.methodProtected();
}
}
關鍵字:super
- Person類
public class Person {
String name;
int age;
int id = 1003; //身份證號
public Person(){
System.out.println("我無處不在");
}
public Person(String name){
this.name = name;
}
public Person(String name,int age){
this(name);
this.age = age;
}
public void eat(){
System.out.println("人,喫飯");
}
public void walk(){
System.out.println("人,走路");
}
}
- Student類
public class Student extends Person{
String major;
int id = 1002; //學號
public Student(){
}
public Student(String name,int age,String major){
// this.age = age;
// this.name = name;
super(name,age);
this.major = major;
}
public Student(String major){
this.major = major;
}
public void eat(){
System.out.println("學生多喫有營養的食物");
}
public void Study(){
System.out.println("學生,學習知識。");
this.eat();
//如果,想調用父類中被重寫的,不想調用子類中的方法,可以:
super.eat();
super.walk();//子父類中未重寫的方法,用"this."或"super."調用都可以
}
public void show(){
System.out.println("name = " + this.name + ",age = " + super.age);
System.out.println("id = " + this.id);
System.out.println("id = " + super.id);
}
}
- 測試類
/*
* super關鍵字的使用
* 1.super理解爲:父類的
* 2.super可以用來調用:屬性、方法、構造器
*
* 3.super的使用
* 3.1 我們可以在子類的方法或構造器中,通過"super.屬性"或"super.方法"的方式,顯式的調用
* 父類中聲明的屬性或方法。但是,通常情況下,我們習慣去省略這個"super."
* 3.2 特殊情況:當子類和父類中定義了同名的屬性時,我們要想在子類中調用父類中聲明的屬性,則必須顯式的
* 使用"super.屬性"的方式,表明調用的是父類中聲明的屬性。
* 3.3 特殊情況:當子類重寫了父類中的方法後,我們想在子類的方法中調用父類中被重寫的方法時,必須顯式的
* 使用"super.方法"的方式,表明調用的是父類中被重寫的方法。
*
* 4.super調用構造器
* 4.1 我們可以在子類的構造器中顯式的使用"super(形參列表)"的方式,調用父類中聲明的指定的構造器
* 4.2 "super(形參列表)"的使用,必須聲明在子類構造器的首行!
* 4.3 我們在類的構造器中,針對於"this(形參列表)"或"super(形參列表)"只能二選一,不能同時出現。
* 4.4 在構造器的首行,既沒有顯式的聲明"this(形參列表)"或"super(形參列表)",則默認的調用的是父類中的空參構造器。super()
* 4.5 在類的多個構造器中,至少有一個類的構造器使用了"super(形參列表)",調用父類中的構造器。
*
*/
public class SuperTest {
public static void main(String[] args) {
Student s = new Student();
s.show();
s.Study();
Student s1 = new Student("Ton",21,"IT" );
s1.show();
System.out.println("***********************");
Student s2 = new Student();
}
}
子類對象實例化過程(儘量理解!
!)
/*
* 子類對象實例化的全過程
*
* 1.從結果上看:
* 子類繼承父類以後,就獲取了父類中聲明的屬性或方法。
* 創建子類的對象中,在堆空間中,就會加載所有父類中聲明的屬性。
*
* 2.從過程上看:
* 當我們通過子類的構造器創建子類對象時,我們一定會直接或間接的調用其父類構造器,
* 直到調用了java.lang.Object類中空參的構造器爲止。正因爲加載過所有的父類結構,所以纔可以看到內存中有
* 父類中的結構,子類對象可以考慮進行調用。
*
* 明確:雖然創建子類對象時,調用了父類的構造器,但自始至終就創建過一個對象,即爲new的子類對象。
*/
public class InstanceTest {
}
- Account類
/*
* 寫一個名爲Account的類模擬賬戶。該類的屬性和方法如下圖所示。
* 該類包括的屬性:賬號id,餘額balance,年利率annualInterestRate;
* 包含的方法:訪問器方法(getter和setter方法),
* 返回月利率的方法getMonthlyInterest(),
* 取款方法withdraw(),存款方法deposit()。
*
*/
public class Account {
private int id; //賬號
private double balance; //餘額
private double annualInterestRate; //年利率
public Account(int id, double balance, double annualInterestRate) {
super();
this.id = id;
this.balance = balance;
this.annualInterestRate = annualInterestRate;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public double getBalance() {
return balance;
}
public void setBalance(double balance) {
this.balance = balance;
}
public double getAnnualInterestRate() {
return annualInterestRate;
}
public void setAnnualInterestRate(double annualInterestRate) {
this.annualInterestRate = annualInterestRate;
}
public double getMonthlyInterest(){ //返回月利率的方法
return annualInterestRate / 12;
}
public void withdraw (double amount){ //取款方法
if(balance >= amount){
balance -= amount;
return;
}
System.out.println("餘額不足");
}
public void deposit (double amount){ //存款方法
if(amount > 0){
balance += amount;
}
}
}
- AccountTest類
/*
* 寫一個用戶程序測試Account類。在用戶程序中,
* 創建一個賬號爲1122、餘額爲20000、年利率4.5%的Account對象。
* 使用withdraw方法提款30000元,並打印餘額。再使用withdraw方法提款2500元,
* 使用deposit方法存款3000元,然後打印餘額和月利率。
*/
public class AccountTest {
public static void main(String[] args) {
Account acct = new Account(1122,20000,0.045);
acct.withdraw(30000);
System.out.println("你的賬戶餘額爲:" + acct.getBalance());
acct.withdraw(2500);
System.out.println("你的賬戶餘額爲:" + acct.getBalance());
acct.deposit(3000);
System.out.println("你的賬戶餘額爲:" + acct.getBalance());
System.out.println("月利率爲: " + (acct.getAnnualInterestRate() * 100) + "%");
}
}
- CheckAccount類
/*
* 創建Account類的一個子類CheckAccount代表可透支的賬戶,該賬戶中定義一個屬性overdraft代表可透支限額。
* 在CheckAccount類中重寫withdraw方法,其算法如下:
* 如果(取款金額<賬戶餘額),
* 可直接取款
* 如果(取款金額>賬戶餘額),
* 計算需要透支的額度
* 判斷可透支額overdraft是否足夠支付本次透支需要,如果可以
* 將賬戶餘額修改爲0,衝減可透支金額
* 如果不可以
* 提示用戶超過可透支額的限額
*
*/
public class CheckAccount extends Account{
private double overdraft; //代表可透支限額
public CheckAccount(int id, double balance, double annualInterestRate,double overdraft){
super(id, balance, annualInterestRate);
this.overdraft = overdraft;
}
public double getOverdraft() {
return overdraft;
}
public void setOverdraft(double overdraft) {
this.overdraft = overdraft;
}
@Override
public void withdraw(double amount) {
if(getBalance() >= amount){ //餘額足夠消費
//方式一
// setBalance(getBalance() - amount);
//方式二
super.withdraw(amount);
}else if(overdraft >= amount - getBalance()){ //餘額不夠
overdraft -= (amount - getBalance());
// setBalance(0);
//或
super.withdraw(getBalance());
}else{ //超過可透支限額
System.out.println("超過可透支限額!");
}
}
}
- CheckAccountTest類
/*
* 寫一個用戶程序測試CheckAccount類。在用戶程序中,
* 創建一個賬號爲1122、餘額爲20000、年利率4.5%,
* 可透支限額爲5000元的CheckAccount對象。
* 使用withdraw方法提款5000元,並打印賬戶餘額和可透支額。
* 再使用withdraw方法提款18000元,並打印賬戶餘額和可透支額。
* 再使用withdraw方法提款3000元,並打印賬戶餘額和可透支額。
*
*/
public class CheckAccountTest {
public static void main(String[] args) {
CheckAccount cat = new CheckAccount(1122,20000,0.045,5000);
cat.withdraw(5000);
System.out.println("您的賬戶餘額爲: " + cat.getBalance());
System.out.println("您的可透支額度爲: " + cat.getOverdraft());
cat.withdraw(18000);
System.out.println("您的賬戶餘額爲: " + cat.getBalance());
System.out.println("您的可透支額度爲: " + cat.getOverdraft());
cat.withdraw(3000);
System.out.println("您的賬戶餘額爲: " + cat.getBalance());
System.out.println("您的可透支額度爲: " + cat.getOverdraft());
}
}
面向對象特徵之三:多態性
- Person類
public class Person {
String name;
int age;
public void eat(){
System.out.println("人,喫飯");
}
public void walk(){
System.out.println("人,走路");
}
}
- Woman類
public class Woman extends Person{
boolean isBeauty;
public void goShopping(){
System.out.println("女人喜歡購物");
}
public void eat(){
System.out.println("女人少喫,爲了減肥。");
}
public void walk(){
System.out.println("女人,窈窕的走路。");
}
}
- Man類
public class Man extends Person{
boolean isSmoking;
public void earnMoney(){
System.out.println("男人負責工作養家");
}
public void eat() {
System.out.println("男人多喫肉,長肌肉");
}
public void walk() {
System.out.println("男人霸氣的走路");
}
}
- 測試類
/*
* 面向對象之三:多態性
*
* 1.理解多態性:可以理解爲一個事物的多種態性。
* 2.何爲多態性:
* 對象的多態性:父類的引用指向子類的對象(或子類的對象賦值給父類的引用)
*
* 3.多態的使用:虛擬方法調用
* 有了對象多態性以後,我們在編譯期,只能調用父類聲明的方法,但在執行期實際執行的是子類重寫父類的方法
* 簡稱:編譯時,看左邊;運行時,看右邊。
*
* 若編譯時類型和運行時類型不一致,就出現了對象的多態性(Polymorphism)
* 多態情況下,
* “看左邊”:看的是父類的引用(父類中不具備子類特有的方法)
* “看右邊”:看的是子類的對象(實際運行的是子類重寫父類的方法)
*
* 4.多態性的使用前提:
* ① 類的繼承關係
* ② 方法的重寫
* 5.對象的多態性:只適用於方法,不適用於屬性(編譯和運行都看左邊)
*/
public class PersonTest {
public static void main(String[] args) {
Person p1 = new Person();
p1.eat();
Man man = new Man();
man.eat();
man.age = 25;
man.earnMoney();
//************************************
//對象的多態性,父類的引用指向子類的對象
Person p2 = new Man();
// Person p3 = new Woman();
//多態的使用:當調用子父類同名同參數方法時,實際調用的是子類重寫父類的方法---虛擬方法調用
p2.eat();
p2.walk();
// p2.earnMoney();
}
}
- 舉例
/*
* 多態性應用舉例
*/
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();
}
//如果沒有多態性,就會寫很多如下的方法,去調用
public void func(Dog dog){
dog.eat();
dog.shout();
}
public void func(Cat cat){
cat.eat();
cat.shout();
}
}
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("汪!汪!汪!");
}
}
class Cat extends Animal{
public void eat(){
System.out.println("貓喫魚");
}
public void shout() {
System.out.println("喵!喵!喵!");
}
}
虛擬方法的補充
import java.util.Random;
/*
* 2.從編譯和運行的角度看:
* 重載,是指允許存在多個同名方法,而這些方法的參數不同。
* 編譯器根據方法不同的參數表,對同名方法的名稱做修飾。
* 對於編譯器而言,這些同名方法就成了不同的方法。
* 它們的調用地址在編譯期就綁定了。Java的重載是可以包括父類和子類的,
* 即子類可以重載父類的同名不同參數的方法。所以:對於重載而言,在方法調用之前,
* 編譯器就已經確定了所要調用的方法,這稱爲“早綁定”或“靜態綁定”;
* 而對於多態,只有等到方法調用的那一刻,解釋運行器纔會確定所要調用的具體方法,
* 這稱爲“晚綁定”或“動態綁定”。
*
* 引用一句Bruce Eckel的話:“不要犯傻,如果它不是晚綁定,它就不是多態。”
*/
//面試題:多態是編譯時行爲還是運行時行爲?
//證明如下:
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();
}
}
整個Java全棧系列都是筆者自己敲的筆記。寫作不易,如果可以,點個讚唄!✌