Java笔记 - 黑马程序员_03(继承,修饰符,多态,抽象类,接口,内部类)
1. 繼承
1.1 繼承的概述
繼承是面向對象三大特征之一。可以使得子類具有父類元素的屬性和方法,還可以在子類中重新定義,追加屬性和方法。
繼承的格式:
-
格式:public class 子類名 extends 父類名
-
案例:public class ZI extends FU{}
-
FU類為父類(superclass),超類,基類
-
ZI類為子類(subclass),派生類,擴展類
繼承中子類的特點:
-
子類可以有父類的內容
-
子類也可以有自己特有的內容
1.2 繼承的好處和弊端
好處:
-
提高代碼的復用性(多個類相同的成員可以放到同一個類中)
-
提高代碼的維護性(如果方法的代碼需要修改,修改一處即可)
弊端:
-
繼承讓類與類之間產生了關系,類的耦合性增強,當父類發生變化時子類實現也不得不跟著變化,削弱了子類的獨立性。
什么時候使用繼承?
-
假設法:有兩個類A與B,如果他們之間滿足A是B的一種,或者B是A的一種,就說明他們之間存在著繼承關系,這個時候他們存在著繼承關系,可以考慮使用繼承,否則不能濫用繼承
-
例如:蘋果和水果,貓和動物(都可使用繼承),貓和狗(不能使用繼承)
1.3繼承中變量的訪問
在子類方法中訪問一個變量的訪問順序:
子類局部范圍找
子類成員范圍找
父類成員范圍找
如果都沒有就報錯(不考慮父類以上的)
1.4 super關鍵字
super關鍵字和this關鍵字的用法相似之處
-
this:代表本類對象的引用(this關鍵字指向調用該方法的對象)
-
super:代表父類存儲空間的標識(可以理解為父類引用對象)
| this | this.成員變量 訪問本類成員變量 | this(.....) 訪問本類構造方法 | this.成員方法(....) 訪問本類成員方法 |
| super | super.成員變量 訪問父類成員變量 | super(.....) 訪問父類構造方法 | super.成員方法(....) 訪問fu類成員方法 |
1.5 繼承中構造方法的訪問特點
子類中所有的構造方法默認都會訪問父類中無參的構造方法:
-
因為子類會繼承父類中的數據,可能還會使用父類的數據。所以,子類初始化之前,一定要先完成父類數據的初始化
-
每一個子類構造方法的第一條語句默認都是:super()
如果父類沒有無參構造方法,只有帶參構造方法,該怎么辦?
通過使用super關鍵字去 顯示的調用父類帶參構造方法
在父類中自己提供一個無參構造方法
推薦:自己給出無參構造方法
//1. package extendsDemo; ? public class Fu {/* public Fu(){System.out.println("fu中無參構造方法");}*/ ?public Fu(int age){System.out.println("fu中有參構造方法");} } ? //2. package extendsDemo; ? public class Zi extends Fu{public Zi(){ // ? super(); ? 系統默認調用父類無參構造方法super(20);System.out.println("zi中無參構造方法");} ?public Zi(int age){ // ? super(); ? 系統默認調用父類無參構造方法super(19);System.out.println("zi中有參構造方法");} } ? //3.測試類 package extendsDemo; ? public class Demo {public static void main(String[] args) {//創建對象,調用方法Zi z= new Zi();Zi z1 = new Zi(18);} } ? //運行結果 fu中有參構造方法 zi中無參構造方法 fu中有參構造方法 zi中有參構造方法1.6 繼承中成員方法的訪問特點
通過子類對象訪問一個方法:(就近原則)
子類成員范圍找
父類成員范圍找
如果沒有就報錯(不考慮父類以上)
1.7 super內存圖
點擊觀看視頻詳解
1.8 方法重寫
方法重寫概述:
-
子類中出現了和父類一摸一樣的方法聲明
方法重寫的應用:
-
當子類需要父類的功能,而主題子類有著自己特有的內容時,可以重寫父類方法,這樣,即沿襲了父類的功能,又定義了子類特有的內容
@Override
-
是一個注解
-
可以幫助我們檢查重寫的方法的 方法聲明的正確性
方法重寫注意事項:
-
私有方法不能被重寫(父類中private修飾 的不能在子類中 直接訪問。可以通過間接的手段來訪問。通過get方法來訪問)
-
子類方法的訪問權限不能低于父類(public > 默認 > 私有)
1.10 Java中繼承的注意事項
Java中類只支持單繼承,不支持多繼承
Java支持多層繼承(間接繼承)
????????例如:class C extends B,class B extends A,
????????也就 是說,C 直接繼承 B,其實 C 還間接繼承 A
1.11 案例
1. 老師和學生:
需求:定義老師類和學生類,找到老師類和學生類的共性內容,抽取一個父類,用繼承的方式改寫代碼,并進行測試
思路:
共性父類,定義人類(姓名, 年齡)
定義老師類,繼承人類,給出自己的方法:教書()
定義老師類,繼承人類,給出自己的方法:學習()
定義測試類,寫代碼測試
2.貓和狗
需求:采用繼承的思想實現貓和狗的案例,并在測試類中進行測試
共性:
成員變量:姓名,年齡;構造方法:無參,帶參;成員方法:get/set方法
//1. package catAndDog; ? public class Cat extends Animal {public Cat() {} ?public Cat(String name, int age) {super(name, age); //調用父} ?public static void show(){System.out.println("抓老鼠");} } ? //2.package catAndDog; ? public class Dog extends Animal {public Dog() {} ?public Dog(String name, int age) {super(name, age);} ?public static void method(){System.out.println("看家");} } ? //3. package catAndDog; ? public class Animal {private String name;private int age; ?public Animal() {}public Animal(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;} ?public static void fn(String dos){System.out.println(dos);} } ? //4. package catAndDog; ? public class Demo {public static void main(String[] args) {Dog an = new Dog("ww",2);System.out.println(an.getName()+", "+an.getAge());an.method();an.fn("看門"); ?Cat ca = new Cat("mm",1);System.out.println(ca.getName()+", "+ca.getAge());ca.show();ca.fn("抓小雞");} } ? //運行結果 ww, 2 看家 看門 mm, 1 抓老鼠 抓小雞2. 修飾符
2.1包的概述和使用
其實就是文件夾 作用:對類進行分類管理 包的定義格式
格式:package包名; (多級包用分開)
范例:package com.itheima; 帶包的)ava類編譯和執行
手動建包:
1.按照以前的格式編譯java文件???????????????? javac HelloWorld.java
2.手動創建包 ????????????????在E盤建立文件夾com,然后在com下建立文件夾theima
3.把class文件放到包的最里面 ????????????把HelloWorld.class文件放到com下的Jitheimai這個文件夾下
4.帶包執行 ????????????????java com.itheima.HelloWorld
自動建包:
javac-d,HelloWorld.java ????????????????java com.itheima.HelloWorld
2.2導包的概述和使用
使用不同包下的類時,使用的時候要寫類的全路徑,寫起來太麻煩了 為了簡化帶包的操作,Jva就提供了導包的功能
導包的格式:
1. 格試:import包名:
2. 范例:import cn.itcast..Teacher
為了簡化帶包的操作,Jva就提供了導包的功能
導包的格式
格試:import? 包名:
-
范例:importcn.itcast.Teacher
2.3 修飾符權限
| private | yes | no | no | no |
| 默認 | yes | yes | no | no |
| protected | yes | yes | yes | no |
| public | yes | yes | yes | yes |
2.4 final
final關鍵字是最終的意思,可以修飾成員方法,成員變量,類
final修飾的特點:
-
修飾方法:表明該方法是最終的方法,不能被重寫
-
修飾變量:表明該變量是常量,不能再次被賦值
-
修飾類:表明該類是最終類,不能被繼承
final修飾局部變量
-
變量是基本類型:final修飾指的是基本類型的數據值不能發生改變
-
變量是引用類型:final修飾指的是引用類型的地址值不能發生改變,但是地址里面的內容是可以改變的
代碼塊 -- new
代碼塊概述:
-
代碼塊是類的成分之一(成員變量、構造器,方法,代碼塊,內部類Java類中,使用{ }括起來的代碼被稱為代碼塊。
-
在Java類中,使用{}括起來的代碼被稱為代碼塊。
代碼塊分為:
-
構造代碼塊
-
格式:{}
-
特點:每次構造方法執行之前,都會先執行構造代碼塊的代碼。
-
使用場景:將多個構造方法中相同的代碼,抽取到構造代碼塊中,提高代碼的復用性。 靜態代碼塊
-
靜態的代碼塊
-
格式:static{}
-
特點:隨著類的加載而觸發執行,并且只會執行一次。
-
使用場景:在類加載的時候做一些靜態數據初始化的操作,以便后續對象可以使用。
2.5 static
static關鍵字是靜態的意思,可以修飾成員變量,成員方法
static修飾的特點:
-
被類的所有對象共享;這是判斷是否使用靜態關鍵字的條件
-
可以通過類名調用;也可以通過對象名調用;推薦使用類名調用
2.6 static訪問特點
非靜態成員方法:
-
能訪問靜態的成員變量
-
能訪問非靜態的成員變量
-
能訪問靜態的成員方法
-
能訪問非靜態的成員方法
靜態成員方法:
-
能訪問靜態成員變量
-
能訪問靜態成員方法
總結:靜態成員方法只能訪問靜態成員
3. 多態
3.1 多態的概述
-
同一個對象,在不同時刻表現出來的不同形態
-
多種形態,多種狀態,編譯和運行有兩個不同的狀態。
編譯期叫做靜態綁定。
運行期叫做動態綁定。
-
Animal a = new Cat();
? ? ? ? 1. a.eat();
? ? ? ? 2. 父類引用指向子類對象
????????3. 編譯的時候編譯器發現a的類型是Animal,所以編譯器會去Animal類中找eat()方法
? ? ? ? 4. 找到了,綁定,編譯通過。但是運行的時候和底層堆內存當中的實際對象有關
? ? ? ? 5.?真正執行的時候會自動調用“堆內存中真實對象”的相關方法。
多態在開發中的作用是: 降低程序的耦合度,提高程序的擴展力。
多態的前提和實現:
有繼承/實現關系
有方法重寫
有父類引用指向子類對象
3.2 多態中成員訪問特點
成員變量:編譯看左邊,執行看左邊
成員方法:編譯看左邊,執行看右邊
為什么成員變量和成員方法不一樣?
-
因為成員方法有重寫,成員變量沒有
3.3 多態的好處和弊端
-
多態的好處:提高程序的擴展性
具體體現:定義方法的時候,使用父類型作為參數,將來使用的時候,使用具體的子類型參與操作
-
多態的弊端:不能使用子類的特有功能
3.4 多態中的轉型
向上轉型:子--->父 (upcasting) 又被稱為自動類型轉換:Animal a = new Cat();
向下轉型:父--->子 (downcasting) 又被稱為強制類型轉換:Cat c = (Cat)a; 需要添加強制類型轉換符。
什么時候需要向下轉型?
1.需要調用或者執行子類對象中特有的方法。
2.必須進行向下轉型,才可以調用。
向下轉型有風險嗎?
1.容易出現ClassCastException(類型轉換異常)
怎么避免這個風險?
1. instanceof運算符,可以在程序運行階段動態的判斷某個引用指向的對象是否為某一種類型。
不管是向上轉型還是向下轉型,首先他們之間必須有繼承關系,這樣編譯器就不會報錯。
//1. package demo_01; ? public class Animal {public void eat(){System.out.println("吃東西");} } ? //2. package demo_01; ? public class Cat extends Animal{@Overridepublic void eat() {System.out.println("貓吃魚");}public void show(){System.out.println("貓捉老鼠");} } ? //3.測試類 package demo_01; ? public class AnimalDemo {public static void main(String[] args) {//父類引用指向子類對象Animal a = new Cat();a.eat(); // 報錯 ? ? ? a.show();//向下轉型Cat b = (Cat)a;b.eat();b.show();} } 3.5 貓和狗(多態版) //1. package catAndDog; ? public class Animal {private String name;private int age; ?public Animal() {} ?public Animal(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;} ?public void eat(){System.out.println("吃東西");} } ? //2. package catAndDog; ? public class Dog extends Animal{public Dog() {} ?public Dog(String name, int age) {super(name, age);} ?@Overridepublic void eat() {System.out.println("餓狗撲食");} ?public void show(){System.out.println("小狗玩耍");} } ? //3.測試類 package catAndDog; ? import demo_01.Cat; ? public class AnimalDemo {public static void main(String[] args) {//父類引用指向子類對象,創建對象Animal a = new Dog("小黃", 6);a.eat(); // ? ? ? a.show(); 報錯System.out.println("--------------"); ?//向下轉型Dog d = (Dog) a;d.eat();d.show();System.out.println("--------------"); ?/* Dog s = new Dog("小紅", 2);s.show();s.eat();*/} } ? //運行結果 餓狗撲食 -------------- 餓狗撲食 小狗玩耍 --------------4. 抽象類
4.1 抽象類的概念
在Java中,一個沒有方法體的方法應該定義為抽象方法,而類中的如果有抽象方法,該類必須定義為抽象類
package demo_01; ? public abstract class Animal { ?public abstract void eat(); ? }4.2 抽象類的特點
-
抽象類和抽象方法必須用abstract關鍵字修飾?
public abstract class 類名{}
public abstract void eat();
-
抽象類不一定有抽象方法,有抽象方法的類一定是抽象類
-
抽象類不能實例化
抽象類如何實例化呢?參照多態的形式,通過子類對象實例化,這叫抽象類多態
-
抽象的子類
1.要么重寫抽象類中的所有抽象方法
2.要么是抽象類
4.3 抽象類的成員特點
-
成員變量
可以是變量
也可以是常量
-
構造方法
有構造方法,但不能實例化
構造方法的作用是什么呢?用于子類訪問父類數據的初始化
-
成員方法
可以有抽象方法:限定子類必須完成某些動作
也可以有非抽象方法:提高代碼復用性
4.4 貓和狗(抽象類版)
需求:采用抽象類的思想實現貓和狗的案例,并在測試類中進行測試
//1.定義抽象類 package catAndDog; ? public abstract class Animal {private String name;private int age; ?public Animal() {} ?public Animal(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;} ?public abstract void eat(); } ? //2. package catAndDog; ? public class Cat extends Animal{public Cat() {} ?public Cat(String name, int age) {super(name, age);} ?@Overridepublic void eat() {System.out.println("小貓吃魚");} ?public void show(){System.out.println("66666666");} } ? //3.測試類 package catAndDog; ? public class AnimalDemo {public static void main(String[] args) {Animal a = new Cat();a.setName("大菊");a.setAge(2);System.out.println(a.getName() + ", " + a.getAge());a.eat();System.out.println("--------------"); ?a = new Cat("小黃", 3);System.out.println(a.getName() + ", " + a.getAge());a.eat();System.out.println("--------------"); ?Cat b = (Cat) a;b.show();} } ? //運行結果 大菊, 2 小貓吃魚 -------------- 小黃, 3 小貓吃魚 -------------- 666666665. 接口
5.1 接口概述
-
接口就是一種公共的規范標識,只要符合標準規范,大家可以共享
-
Java中的接口更多體現在對行為的抽象
5.2 接口的特點
-
接口用關鍵字interface修飾
public interface 接口名{}
-
類實現接口implements接口名{}
public class 類名 implements 接口名{}
-
接口不能實例化
1.接口如何實例化? 參照多態的方式,通過實現子類對象實例化,這叫接口實例化
2.多態的形式:具體類多態, 抽象類多態, 接口多態
-
接口實現類
1.要么重寫接口中的所有抽象方法
2.要么是抽象類
5.3 接口成員的特點
-
成員變量
只能是常量
默認修飾符:public static final(可省略)
-
構造方法
1. 接口沒有構造方法,因為接口主要是對行為進行抽象的,是沒有具體存在的
2. 一個類如果沒有父類,默認繼承Object
-
成員方法
-
只能是抽象方法
-
默認修飾符:public abstract
5.4 貓和狗(接口版)
需求:對貓和狗進行訓練,他們就可以調高,這里加入了調高功能,請采用抽象類和接口來實現貓和狗案例
//1.定義接口 package catAndDog; ? public interface Jumpping {public abstract void jump(); } ? //2.定義動物類 package catAndDog; ? public abstract class Animal {private String namne;private int age; ?public Animal() {} ?public Animal(String namne, int age) {this.namne = namne;this.age = age;} ?public String getNamne() {return namne;} ?public void setNamne(String namne) {this.namne = namne;} ?public int getAge() {return age;} ?public void setAge(int age) {this.age = age;} ?public abstract void eat(); } ? //3.定義貓類 package catAndDog; ? public class Cat extends Animal implements Jumpping{public Cat() {} ?public Cat(String namne, int age) {super(namne, age);} ?@Overridepublic void eat() {System.out.println("小貓吃魚");} ?@Overridepublic void jump() {System.out.println("小貓跳高");} } ? //4.測試類 package catAndDog; ? public class AnimalDemo {public static void main(String[] args) {Jumpping j = new Cat();j.jump();System.out.println("--------------"); ?Animal a = new Cat("加菲貓", 3);System.out.println(a.getNamne() + ", " + a.getAge());a.eat(); // ? ? ? a.jump(); ? ? 報錯System.out.println("--------------"); ?a = new Cat("大菊", 2);System.out.println(a.getNamne() + ", " + a.getAge());a.eat();} ? } ? //運行結果 小貓跳高 -------------- 加菲貓, 3 小貓吃魚 -------------- 大菊, 2 小貓吃魚5.5 類和接口的關系
-
類和類的關系
繼承關系,只能單繼承,但是可以多層繼承
-
類和接口的關系
實現關系,可以單實現,也可以多實現,還可以在繼承一個類的同時實現多個接口
-
接口和接口的關系
繼承關系,可以單繼承,也可以多繼承
//接口1 package Demo_02; ? public interface Inter1 { } ? //接口2 package Demo_02; ? public interface Inter2 { } ? //接口3 package Demo_02; ? public interface Inter3 extends Inter1, Inter2 {//接口和接口的關系 } ? //創建類 package Demo_02; ? public class Demo extends Object implements Inter1,Inter2{//類和接口的關系(繼承Object,體現Inter1,Inter2) }5.6 抽象類和接口的區別
-
成員區別
抽象類:變量,常量;有構造方法;有抽象方法,也有非抽象方法
接口:常量,抽象方法
-
關系區別
類與類:繼承,單繼承
類與接口:實現,可以單實現,也可以多實現
接口與接口:繼承,單繼承,多繼承
-
設計理念區別
抽象類:對類抽象,包括屬性和行為
接口:對行為抽象,主要是行為
//1.定義接口 package Demo_02; ? public interface Inter1 {void jump(); } ? //2.定義貓類 package Demo_02; ? public abstract class Cat {public abstract void eat(); } ? //3.測試類 package Demo_02; ? public class Demo extends Cat implements Inter1{@Overridepublic void jump() {//方法體} ?@Overridepublic void eat() {//方法體} }2.接口組成更新概述
2.1接口組成
常量?? ?public ?static final
?抽象方法 ? ?public abstract
默認方法(Java8)
靜態方法(Java8)
私有方法(Java9)
2.2接口中默認方法
接口中默認方法的定義格式:
- 格式:public default ?返回值類型方法名(參數列表){}
- 范例:public default void show(){}
接口中默認方法的注意事項:
- 默認方法不是抽象方法,所以不強制被重寫。但是可以被重寫,重寫的時候去掉default關鍵字
- public可以省略,default不能省略
2.3接口中靜態方法
接口中靜態方法的定義格式:
- 格式:public static ?返回值類型方法名(參數列表){}
- 范例:public static void show(){}
接口中靜態方法的注意事項:
- 靜態方法只能通過接口名調用,不能通過實現類名或者對象名調用
- public可以省略,static不能省略
2.4 接口中的私有方法
接口中私有方法的定義格式:
- 格式1:private返回值類型方法名(參數列表){}
- 范例1:private void show() {}
- 格式2:private static 返回值類型方法名(參數列表){}
- 范例2:private static void method(){}
接口中私有方法的注意事項:
- 默認方法可以調用私有的靜態方法和非靜態方法
- 靜態方法只能調用私有的靜態方法
6. 形參和返回值
6.1 類名作為形參和返回值
-
方法的形參是類名,其實需要的是該類的對象
-
方法的返回值類名,其實返回的是該類的對象
6.2 抽象類名作為形參和返回值
-
方法的形參是抽象類名,其實需要的是該抽象類的子類對象
-
方法的返回值是抽象類名,其實返回的是該抽象類的子類對象
6.3 接口名作為形參和返回值
-
方法的形參是接口名,其實需要的是該接口的實現類對象
-
方法的返回值是接口名,其實返回的是該接口的實現類對象
7. 內部類
7.1 內部類概述
-
內部類:就是在一個類中定義一個類。
-
舉例:在一個類A的內部定義一個類B,類B就被稱為內部類
-
內部類的定義格式
-
格式:
public class 類名{
修飾符 class 類名{
}
}
-
內部類的訪問特點:
內部類可以訪問外部類的成員,包括私有
外部類要訪問內部類的成員,必須創建對象
7.2 成員內部類
按照內部類在類中定義的位置不同,可以分為如下兩種形式:
-
在類的成員位置:成員內部類(在成員變量定義的類)
-
在類的局部位置:局部內部類(在方法中定義的類)
成員內部類,外界如何使用呢?
-
格式:外部類名.內部類名 對象明 = 外部類對象.內部類對象
-
范例:Outer.Inner oi = new Outer().new Inner();
局部內部類:
-
局部內部類是在方法中定義的類,所以外界是無法直接使用,需要在方法內部創建對象并使用,該類可以直接訪問外部類的成員,也可以訪問的方法內的局部變量
7.3 匿名內部類
前提:存在一個類或者接口,在這里類可以是具體的類也可以是抽象的類
-
格式:
new 類名或者接口名(){
重寫方法;
};
-
范例:
new Inter(){
public void show(){
}
};
-
本質:是一個繼承了該類或者實現了該接口的子類匿名對象
7.4 匿名內部類在開發中的使用
//1.跳高接口 package Demo_03; // public interface Jumpping {void jump(); } ? //2.接口操作類,里面有一個方法,方法的參數是接口名 package Demo_03; ? public class JumppingOpertor {public void method(Jumpping j){j.jump();} } ? //3.接口實現類 package Demo_03; ? public class Cat implements Jumpping{@Overridepublic void jump() {System.out.println("小貓跳高了");} } ? //4.測試類 package Demo_03; ? public class JumppingDemo {public static void main(String[] args) {//創建接口操作類對象,調用method方法JumppingOpertor s = new JumppingOpertor();Jumpping c = new Cat();s.method(c);System.out.println("-----------"); ?//匿名函數作為參數調用方法(好處:不需要在d接口實現類)s.method(new Jumpping() {@Overridepublic void jump() {System.out.println("小狗跳高");}}); ?} } ? //運行結果 小貓跳高了 ----------- 小狗跳高冒泡排序
排序:將一組數據按照固定的規則進行排列
-
冒泡排序:一種排序的方式,對要進行排序的數據中相鄰的數據進行兩兩比較,將較大的數據放在后面,依次對所有的數據進行操作,直至所有數據按要求完成排序
-
如果有n個數據進行排序,總共需要比較n-1次
-
每一次比較完畢,下一次的比較就會少一個數據參與
更多內容請訪問博主博客:逸樂的博客 - 今晚一起吃火鍋
文章如有紕漏請指出,整理不易多多包涵。
Java后續筆記將持續更新........
總結
以上是生活随笔為你收集整理的Java笔记 - 黑马程序员_03(继承,修饰符,多态,抽象类,接口,内部类)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 服务器自动关闭远程打印服务,实现远程打印
- 下一篇: 沈师 Java程序设计 PTA 填空题、