繼承
繼承的實現
public class Fu {
public void show() {
System.out.println("show方法被呼叫");
}
}
public class Zi extends Fu {
public void method() {
System.out.println("method方法被呼叫");
}
}
public class Demo {
public static void main(String[] args) {
//建立物件,呼叫方法
Fu f = new Fu(); f.show();
Zi z = new Zi(); z.method();
z.show();
}
}
繼承的好處和弊端
繼承好處
提高了程式碼的複用性(多個類相同的成員可以放到同一個類中) 提高了程式碼的維護性(如果方法的程式碼需要修改,修改一處即可)繼承弊端
繼承讓類與類之間產生了關係,類的耦合性增強了,當父類發生變化時子類實現也不得不跟著變化,削弱了子類的獨立性
繼承的應用場景:
使用繼承,需要考慮類與類之間是否存在is..a的關係,不能盲目使用繼承is..a的關係:誰是誰的一種,例如:老師和學生是人的一種,那人就是父類,學生和老師就是子類
Java中繼承的特點
public class Granddad {
public void drink() {
System.out.println("爺爺愛喝酒");
}
}
public class Father extends Granddad {
public void smoke() {
System.out.println("爸爸愛抽菸");
}
}
public class Mother {
public void dance() {
System.out.println("媽媽愛跳舞");
}
}
public class Son extends Father {
// 此時,Son類中就同時擁有drink方法以及smoke方法
}
繼承中的成員訪問特點
繼承中變數的訪問特點
在子類方法中訪問一個變數,採用的是就近原則。
- 子類區域性範圍找
- 子類成員範圍找
- 父類成員範圍找
- 如果都沒有就報錯(不考慮父親的父親…)
class Fu {
int num = 10;
}
class Zi {
int num = 20; public void show(){
int num = 30;
System.out.println(num);
}
}
public class Demo1 {
public static void main(String[] args) {
Zi z = new Zi();
z.show(); // 輸出show方法中的區域性變數30
}
}
super
this&super關鍵字:
this:代表本類物件的引用
super:代表父類儲存空間的標識(可以理解為父類物件引用)
this和super的使用分別成員變數:
this.成員變數 - 訪問本類成員變數
super.成員變數 - 訪問父類成員變數
成員方法:
this.成員方法 - 訪問本類成員方法
super.成員方法 - 訪問父類成員方法
構造方法:
this(…) - 訪問本類構造方法
super(…) - 訪問父類構造方法
繼承中構造方法的訪問特點
注意:子類中所有的構造方法預設都會訪問父類中無參的構造方法
子類會繼承父類中的資料,可能還會使用父類的資料。所以,子類初始化之前,一定要先完成父類資料的初始化, 原因在於,每一個子類構造方法的第一條語句預設都是:super()
問題:如果父類中沒有無參構造方法,只有帶參構造方法,該怎麼辦呢?
繼承中成員方法的訪問特點
方法重寫
方法重寫的注意事項
public class Fu {
private void show() {
System.out.println("Fu中show()方法被呼叫");
}
void method() {
System.out.println("Fu中method()方法被呼叫");
}
}
public class Zi extends Fu {
/* 編譯【出錯】,子類不能重寫父類私有的方法*/
@Override
private void show() {
System.out.println("Zi中show()方法被呼叫");
}
/* 編譯【出錯】,子類重寫父類方法的時候,訪問許可權需要大於等於父類 */ @Override
private void method() {
System.out.println("Zi中method()方法被呼叫");
}
/* 編譯【通過】,子類重寫父類方法的時候,訪問許可權需要大於等於父類 */
@Override
public void method() {
System.out.println("Zi中method()方法被呼叫");
}
}
許可權修飾符
super記憶體圖
物件在堆記憶體中,會單獨存在一塊super區域,用來存放父類的資料(父類的空參建構函式必須寫)
父類沒有空參構造
1.在子類通過super呼叫父類有參建構函式
public Child(int age){
super(age);
this.age=age;
System.out.println("Child parameter constructor called");
}
2.子類通過this呼叫本類其他構造方法,本類其他構造方法再通過呼叫super去手動呼叫父類有參構造方法
public Child(){
this(10);
System.out.println("Child non_parameter constructor called");
}
public Child(int age){
super(age);
System.out.println("Child parameter constructor called");
}
注意this和super都必須放在構造方法第一行才能作為有效語句,並且二者不能共存
抽象類
抽象類的概述
當我們在做子類共性功能抽取時,有些方法在父類中並沒有具體的體現,這個時候就需要抽象類了!
在Java中,一個沒有方法體的方法應該定義為抽象方法,而類中如果有抽象方法,該類必須定義為抽象類!
抽象類的特點
//抽象類的定義
public abstract class 類 名 {}
//抽象方法的定義
public abstract void eat();
抽象類的案例
動物類
public abstract class Animal {
public void drink(){
System.out.println("喝水");
}
public Animal(){
}
public abstract void eat();
}
貓類
public class Cat extends Animal {
@Override
public void eat() {
System.out.println("貓吃魚");
}
}
狗類
public class Dog extends Animal { @Override public void eat() { System.out.println("狗吃肉"); } }
測試類
public static void main(String[] args) {
Dog d = new Dog();
d.eat();
d.drink();
Cat c = new Cat(); c.drink();
c.eat();
//Animal a = new Animal(); //抽象類不能例項話物件
//a.eat();
}
模板設計模式
設計模式
設計模式(Design pattern)是一套被反覆使用、多數人知曉的、經過分類編目的、程式碼設計經驗的總結。使用設計模式是為了可重用程式碼、讓程式碼更容易被他人理解、保證程式碼可靠性、程式的重用性。
模板設計模式
把抽象類整體就可以看做成一個模板,模板中不能決定的東西定義成抽象方法 讓使用模板的類(繼承抽象類的類)去重寫抽象方法實現需求
模板設計模式的優勢
模板已經定義了通用結構,使用者只需要關心自己需要實現的功能即可
示例程式碼
模板類
/*
作文模板類
*/
public abstract class CompositionTemplate {
public final void write(){
System.out.println("<<我的爸爸>>");
body();
System.out.println("啊~ 這就是我的爸爸");
}
public abstract void body();
}
實現類A
public class Tom extends CompositionTemplate {
@Override
public void body() {
System.out.println("那是一個秋天, 風兒那麼纏綿,記憶中, " +
"那天爸爸騎車接我放學回家,我的腳卡在了自行車鏈當中, 爸爸蹬不動,他就
站起來蹬...");
}
}
測試類
public class Test {
public static void main(String[] args) {
Tom t = new Tom();
t.write();
}
}
final
fianl關鍵字的作用
final代表最終的意思,可以修飾成員方法,成員變數,類final修飾類、方法、變數的效果
fianl修飾類:該類不能被繼承(不能有子類,但是可以有父類)
public final class Parent{};
final修飾方法:該方法不能被重寫
public final void show{};
final修飾變數:表明該變數是一個常量,不能再次賦值。變數是基本型別,不能改變值
final int a=10; //正確
a=20; //錯誤
變數是引用型別,不能改變的是地址值,但地址裡面的內容是可以改變的
public static void main(String[] args){
final Student s = new Student(23);
s = new Student(24); // 錯 誤
s.setAge(24); // 正 確
}
程式碼塊
程式碼塊概述
程式碼塊分類
public class Test {
/*
區域性程式碼塊
位置:方法中定義
作用:限定變數的生命週期,及早釋放,提高記憶體利用率
*/
public static void main(String[] args) {
{
int a = 10;
System.out.println(a);
}
// System.out.println(a);
}
}
構造程式碼塊
位置: 類中方法外定義
特點: 每次構造方法執行的時,都會執行該程式碼塊中的程式碼,並且在構造方法執行前執行作用: 將多個構造方法中相同的程式碼,抽取到構造程式碼塊中,提高程式碼的複用性
public static void main(String[] args) {
Student stu1 = new Student();
Student stu2 = new Student(10);
}
class Student {
{
System.out.println("好好學習");
}
public Student(){
System.out.println("空引數構造方法");
}
public Student(int a){
System.out.println("帶引數構造方法");
}
}
輸出:
好好學習
空引數構造方法
好好學習
帶引數構造方法
靜態程式碼塊
位置: 類中方法外定義
特點: 需要通過static關鍵字修飾,隨著類的載入而載入,並且只執行一次作用: 在類載入的時候做一些資料初始化的操作
public static void main(String[] args) {
Person p1 = new Person();
Person p2 = new Person(10);
}
class Person {
static {
System.out.println("我是靜態程式碼塊, 我執行了");
}
public Person(){
System.out.println("我是Person類的空引數構造方法");
}
public Person(int a){
System.out.println("我是Person類的帶引數構造方法");
}
}
輸出:
我是靜態程式碼塊, 我執行了
我是Person類的空引數構造方法
我是Person類的帶引數構造方法