1. 程式人生 > 實用技巧 >Java日誌第10天 2020.7.15

Java日誌第10天 2020.7.15

第五章 類的繼承和多型

5.1 Java中的繼承

子類繼承父類的屬性和方法,並根據需要增加它為自己的新的屬性和方法。由此而得到的類為子類,被繼承的類為父類,也叫超類。Java不支援多繼承(子類只能有一個父類)。

*5.1.1 Object類及其方法

Java中的所有類都預設繼承Object類,Object是Java所有類的父類。

定義:public class Object

*5.1.2 物件中的克隆

Java克隆是Java語言的特性之一,在實際中應用比較少見。但有時用方法會更方便、更有效率

(1)克隆的限制

  *被克隆的類必須自己實現Cloneable介面,以指示Object.clone()方法可以合法的對該類例項進行按欄位賦值。Cloneable介面實際上是個標識介面,沒有任何介面方法。

  *實現Cloneable介面的類應該使用公共方法重寫Object.clone(它是受保護的)。某個物件實現了此介面就克隆它是不可能的。

  *在Java.lang.Object類中克隆方法是這麼定義的。

  protected Object clone()

  throws CloneNotSupportedException

(2)淺層克隆和深層克隆

  *淺層克隆:主要複製基本物件的值

  *深層克隆:當類存在聚合關係是,克隆就必須考慮聚合物件的克隆。可以複製引用型別的欄位。

示例:淺層克隆

public class CloneDemo {
public static void main(String[] args) throws CloneNotSupportedException {
Person p = new Person("任我行", 35);
Person p2 = (Person)p.clone();
System.out.println("克隆前:"+p.getName()+","+p.getAge());
System.out.println("克隆後:"+p2.getName()+","+p2.getAge());
if(p == p2){
System.out.println("p和p2的地址相等!");
} else{
System.out.println("p和p2的地址不相等!!");
}

}
}
/*簡單類克隆實現
要實現克隆,必須實現Cloneable介面,這是一個標識介面,沒喲介面方法
實現了Cloneable介面,以指示Object.clone()方法
可以合法地對該類例項進行按欄位複製
按照慣例,實現此介面的類應該使用公共方法重寫Object.clone(它是受保護的)
*/
class Person implements Cloneable{
private String name;
private int age;
public Person(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;
}
@Override
protected Object clone() throws CloneNotSupportedException{
return super.clone();
}
}

示例:深層克隆

public class CloneDeepDemo {
public static void main(String[] args) throws CloneNotSupportedException{
Person per = new Person("令狐沖",20);
P p = new P(per);
P p2 =(P)p.clone();
System.out.println("克隆前:"+p.getPer().getName()+","+p.getPer().getAge());
System.out.println("克隆後:"+p2.getPer().getName()+","+p2.getPer().getAge());
if(p==p2)
System.out.println("p和p2的地址相等!");
else
System.out.println("p和p2的地址不相等!");
if(p.getPer()==p2.getPer())
System.out.println("p中的Person物件與p2中的Person物件相等!");
else
System.out.println("p中的Person物件與p2中的Person物件不相等!");
}
}
class P implements Cloneable{
Person per;
public P(Person per){
this.per = per;
}
public Person getPer(){
return per;
}
public void setPer(Person per){
this.per = per;
}
@Override
protected Object clone() throws CloneNotSupportedException{
P p = (P)super.clone();
p.per = (Person)this.per.clone();
return p;
}
}

5.1.3 Java的繼承

Java中的繼承使用關鍵字“extends”表示,

公式:class 子類 extennds 父類 {}

使用繼承子類可以擁有父類中的非私有屬性

示例:

定義一個Person類

public class Person {
public String name;
public String sex;
public int age;
public String getName(){
return name;
}
public void setName(String name){
this.name=name;
}
public String getSex(){
return sex;
}
public void setSex(String sex){
this.sex=sex;
}
public int getAge(){
return age;
}
public void setAge(int age){
this.age=age;
}

}

定義Student類繼承Person類
public class Student extends Person {
private String deparetment;//系別
private String specialty;//專業
}

public class day06 {
public static void main(String[] args) {
Student s = new Student();
//子類共享父類中的非私有屬性
String str=s.name;
//子類可以擁有父類中的非私有方法
s.setName("伍正雲");
s.setAge(25);
}
}

*Java不支援不支援多繼承,一個類只能繼承一個類,即子類只能繼承一個父類,但是一個父類可以被多個子類繼承。

5.1.4 super關鍵字
在Java繼承中,子類可以使用super富案件自呼叫父類的非私有屬性和非私有方法,還可以呼叫父類的非私有構造方法。
(1)使用super關鍵字呼叫父類屬性
public class Person {
public String name;
public String sex;
public int age;
public String getName(){
return name;
}
public void setName(String name){
this.name=name;
}
public String getSex(){
return sex;
}
public void setSex(String sex){
this.sex=sex;
}
public int getAge(){
return age;
}
public void setAge(int age){
this.age=age;
}

}

public class Student extends Person {
private String deparetment;//系別
private String specialty;//專業
String name1 = super.name; //呼叫父類的屬性name
public void test(){
super.getAge(); //呼叫父類方法
}
}

*super關鍵字可以省略
public class Student extends Person {
private String deparetment;//系別
private String specialty;//專業
String name1 = name; //呼叫父類的屬性name
public void test(){
getAge(); //呼叫父類方法
}
}

(2)使用super呼叫父類的構造方法
public class Person {
private String name;
private int age;
public Person(){

}
public Person(String name, int age){
this.name = name;
this.age = age;
}
}
class Student extends Person{
public Student(){
super("sky",26);
}
}

(3)子類和父類構造方法的執行順序
*子類預設呼叫父類的無參構造方法,也就是說,子類的構造方法中會預設呼叫super(),並且在構造方法的第一行。
*如果子類只提供有參的構造方法,則必須在子類的構造剛發中呼叫父類的構造方法。
*執行父類的構造方法後,在呼叫本類中的構造方法。
public class Person {
private String name;
private int age;
public Person(){
System.out.println("父類無參構造方法");
}
public Person(String name, int age){
this.name = name;
this.age = age;
System.out.println("父類有參構造方法");
}
public static void main(String[] args){
Student stu = new Student();
}
}
class Student extends Person{
public Student(){
super("sky",26);
System.out.println("子類有參構造方法");
}
}

5.2 多型變化

5.2.1 Java中多型的實現

覆蓋:子類重寫父類中的方法

public class Father {
public void say(){
System.out.println("Father say()");
}

public static void main(String[] args) {
Son son = new Son();
son.say();
}
}
class Son extends Father{
public void say(){
System.out.println("Son say()");
}
}

5.2.2 型別檢測——向上轉型/向下轉型

向上轉型是指父類物件的引用指向子類物件。向下轉型是指在向上轉型的基礎上再次指向子類物件。

(1)向上轉型

語法:父類 物件 = new 子類()

public class Father {
public void say(){
System.out.println("Father say()");
}

public static void main(String[] args) {
//向上轉型
Father son = new Son();
son.say();
}
}
class Son extends Father{
public void say(){
System.out.println("Son say()");
}
}

有時使用向上轉型會丟失掉子類特有的方法

public class Father {
public void say(){
System.out.println("Father say()");
}

public static void main(String[] args) {
//向上轉型
Father son = new Son();
son.sayMe();//報錯
}
}
class Son extends Father{
public void say(){
System.out.println("Son say()");
}
public void sayMe(){
System.out.println("Son sayMe()");
}
}
(2)向下轉型
語法: 父類 物件1 = new 子類()
    子類 物件2 = (子類)物件1

public class Father {
public void say(){
System.out.println("Father say()");
}

public static void main(String[] args) {
//向上轉型
Father son = new Son();
//向下轉型
Son son2 = (Son)son;
son2.sayMe();//報錯
}
}
class Son extends Father{
public void say(){
System.out.println("Son say()");
}
public void sayMe(){
System.out.println("Son sayMe()");
}
}

如果直接將父類強轉成子類物件會報錯
public class Father {
public void say(){
System.out.println("Father say()");
}

public static void main(String[] args) {
Father f = new Father();
Son son = (Son)f;
}
}
class Son extends Father{
public void say(){
System.out.println("Son say()");
}
public void sayMe(){
System.out.println("Son sayMe()");
}
}

5.2.3 動態繫結
*動態繫結
會基於物件實際的型別(只能在執行時得知)來選擇所呼叫的方法
*靜態繫結
在程式編譯時就繫結的,在Java中的變數都是靜態繫結的,只有private、static和final是靜態繫結的。