Java基础-面向对象进阶-多态包final权限修饰符代码块
文章目錄
- 第一章 多態
- 1.1 多態的形式
- 1.2 多態的使用場景
- 1.3 多態的定義和前提
- 1.4 多態的運行特點
- 1.5 多態的弊端
- 1.6 引用類型轉換
- 1.6.1 為什么要轉型
- 1.6.2 向上轉型(自動轉換)
- 1.6.3 向下轉型(強制轉換)
- 1.6.4 案例演示
- 1.6.5 轉型的異常
- 1.6.6 instanceof關鍵字
- 1.6.7 instanceof新特性
- 1.7 綜合練習
- 第二章 包
- 2.1 包
- 2.2 導包
- 2.3 使用不同包下的相同類怎么辦?
- 第三章 權限修飾符
- 3.1 權限修飾符
- 3.2 不同權限的訪問能力
- 第四章 final關鍵字
- 4.1 概述
- 4.2 使用方式
- 4.2.1 修飾類
- 4.2.2 修飾方法
- 4.2.3 修飾變量-局部變量
- 4.2.4 修飾變量-成員變量
- 第五章 代碼塊
- 5.1 局部代碼塊
- 5.2 構造代碼塊
- 5.3 靜態代碼塊
第一章 多態
1.1 多態的形式
多態是繼封裝、繼承之后,面向對象的第三大特性。
多態是出現在繼承或者實現關系中的。
多態體現的格式:
父類類型 變量名 = new 子類/實現類構造器; 變量名.方法名();多態的前提:有繼承關系,子類對象是可以賦值給父類類型的變量。例如Animal是一個動物類型,而Cat是一個貓類型。Cat繼承了Animal,Cat對象也是Animal類型,自然可以賦值給父類類型的變量。
1.2 多態的使用場景
如果沒有多態,在下圖中register方法只能傳遞學生對象,其他的Teacher和administrator對象是無法傳遞給register方法方法的,在這種情況下,只能定義三個不同的register方法分別接收學生,老師和管理員。
有了多態之后,方法的形參就可以定義為共同的父類Person。
要注意的是:
- 當一個方法的形參是一個類,我們可以傳遞這個類所有的子類對象。
- 當一個方法的形參是一個接口,我們可以傳遞這個接口所有的實現類對象(后面會學)。
- 而且多態還可以根據傳遞的不同對象來調用不同類中的方法。
代碼示例:
父類: public class Person {private String name;private int age;空參構造帶全部參數的構造get和set方法public void show(){System.out.println(name + ", " + age);} }子類1: public class Administrator extends Person {@Overridepublic void show() {System.out.println("管理員的信息為:" + getName() + ", " + getAge());} }子類2: public class Student extends Person{@Overridepublic void show() {System.out.println("學生的信息為:" + getName() + ", " + getAge());} }子類3: public class Teacher extends Person{@Overridepublic void show() {System.out.println("老師的信息為:" + getName() + ", " + getAge());} }測試類: public class Test {public static void main(String[] args) {//創建三個對象,并調用register方法Student s = new Student();s.setName("張三");s.setAge(18);Teacher t = new Teacher();t.setName("王建國");t.setAge(30);Administrator admin = new Administrator();admin.setName("管理員");admin.setAge(35);register(s);register(t);register(admin);}//這個方法既能接收老師,又能接收學生,還能接收管理員//只能把參數寫成這三個類型的父類public static void register(Person p){p.show();} }1.3 多態的定義和前提
多態: 是指同一行為,具有多個不同表現形式。
從上面案例可以看出,Cat和Dog都是動物,都是吃這一行為,但是出現的效果(表現形式)是不一樣的。
前提【重點】
有繼承或者實現關系
方法的重寫【意義體現:不重寫,無意義】
父類引用指向子類對象【格式體現】
父類類型:指子類對象繼承的父類類型,或者實現的父接口類型。
1.4 多態的運行特點
調用成員變量時:編譯看左邊,運行看左邊
調用成員方法時:編譯看左邊,運行看右邊
代碼示例:
Fu f = new Zi(); //編譯看左邊的父類中有沒有name這個屬性,沒有就報錯 //在實際運行的時候,把父類name屬性的值打印出來 System.out.println(f.name); //編譯看左邊的父類中有沒有show這個方法,沒有就報錯 //在實際運行的時候,運行的是子類中的show方法 f.show();1.5 多態的弊端
我們已經知道多態編譯階段是看左邊父類類型的,如果子類有些獨有的功能,此時多態的寫法就無法訪問子類獨有功能了。
class Animal{public void eat(){System.out.println("動物吃東西!")} } class Cat extends Animal { public void eat() { System.out.println("吃魚"); } public void catchMouse() { System.out.println("抓老鼠"); } } class Dog extends Animal { public void eat() { System.out.println("吃骨頭"); } }class Test{public static void main(String[] args){Animal a = new Cat();a.eat();a.catchMouse();//編譯報錯,編譯看左邊,Animal沒有這個方法} }1.6 引用類型轉換
1.6.1 為什么要轉型
多態的寫法就無法訪問子類獨有功能了。
當使用多態方式調用方法時,首先檢查父類中是否有該方法,如果沒有,則編譯錯誤。也就是說,不能調用子類擁有,而父類沒有的方法。編譯都錯誤,更別說運行了。這也是多態給我們帶來的一點"小麻煩"。所以,想要調用子類特有的方法,必須做向下轉型。
回顧基本數據類型轉換
- 自動轉換: 范圍小的賦值給范圍大的.自動完成:double d = 5;
- 強制轉換: 范圍大的賦值給范圍小的,強制轉換:int i = (int)3.14
? 多態的轉型分為向上轉型(自動轉換)與向下轉型(強制轉換)兩種。
1.6.2 向上轉型(自動轉換)
- 向上轉型:多態本身是子類類型向父類類型向上轉換(自動轉換)的過程,這個過程是默認的。
當父類引用指向一個子類對象時,便是向上轉型。
使用格式:
**原因是:父類類型相對與子類來說是大范圍的類型,Animal是動物類,是父類類型。Cat是貓類,是子類類型。Animal類型的范圍當然很大,包含一切動物。**所以子類范圍小可以直接自動轉型給父類類型的變量。
1.6.3 向下轉型(強制轉換)
- 向下轉型:父類類型向子類類型向下轉換的過程,這個過程是強制的。
一個已經向上轉型的子類對象,將父類引用轉為子類引用,可以使用強制類型轉換的格式,便是向下轉型。
使用格式:
子類類型 變量名 = (子類類型) 父類變量名; 如:Aniaml a = new Cat();Cat c =(Cat) a;1.6.4 案例演示
當使用多態方式調用方法時,首先檢查父類中是否有該方法,如果沒有,則編譯錯誤。也就是說,不能調用子類擁有,而父類沒有的方法。編譯都錯誤,更別說運行了。這也是多態給我們帶來的一點"小麻煩"。所以,想要調用子類特有的方法,必須做向下轉型。
轉型演示,代碼如下:
定義類:
abstract class Animal { abstract void eat(); } class Cat extends Animal { public void eat() { System.out.println("吃魚"); } public void catchMouse() { System.out.println("抓老鼠"); } } class Dog extends Animal { public void eat() { System.out.println("吃骨頭"); } public void watchHouse() { System.out.println("看家"); } }定義測試類:
public class Test {public static void main(String[] args) {// 向上轉型 Animal a = new Cat(); a.eat(); // 調用的是 Cat 的 eat// 向下轉型 Cat c = (Cat)a; c.catchMouse(); // 調用的是 Cat 的 catchMouse} }1.6.5 轉型的異常
轉型的過程中,一不小心就會遇到這樣的問題,請看如下代碼:
public class Test {public static void main(String[] args) {// 向上轉型 Animal a = new Cat(); a.eat(); // 調用的是 Cat 的 eat// 向下轉型 Dog d = (Dog)a; d.watchHouse(); // 調用的是 Dog 的 watchHouse 【運行報錯】} }這段代碼可以通過編譯,但是運行時,卻報出了 ClassCastException ,類型轉換異常!這是因為,明明創建了Cat類型對象,運行時,當然不能轉換成Dog對象的。
1.6.6 instanceof關鍵字
為了避免ClassCastException的發生,Java提供了 instanceof 關鍵字,給引用變量做類型的校驗,格式如下:
變量名 instanceof 數據類型 如果變量屬于該數據類型或者其子類類型,返回true。 如果變量不屬于該數據類型或者其子類類型,返回false。所以,轉換前,我們最好先做一個判斷,代碼如下:
public class Test {public static void main(String[] args) {// 向上轉型 Animal a = new Cat(); a.eat(); // 調用的是 Cat 的 eat// 向下轉型 if (a instanceof Cat){Cat c = (Cat)a; c.catchMouse(); // 調用的是 Cat 的 catchMouse} else if (a instanceof Dog){Dog d = (Dog)a; d.watchHouse(); // 調用的是 Dog 的 watchHouse}} }1.6.7 instanceof新特性
JDK14的時候提出了新特性,把判斷和強轉合并成了一行
//新特性 //先判斷a是否為Dog類型,如果是,則強轉成Dog類型,轉換之后變量名為d //如果不是,則不強轉,結果直接是false if(a instanceof Dog d){d.lookHome(); }else if(a instanceof Cat c){c.catchMouse(); }else{System.out.println("沒有這個類型,無法轉換"); }1.7 綜合練習
需求:根據需求完成代碼:1.定義狗類屬性:年齡,顏色行為:eat(String something)(something表示吃的東西)看家lookHome方法(無參數) 2.定義貓類屬性:年齡,顏色行為:eat(String something)方法(something表示吃的東西)逮老鼠catchMouse方法(無參數) 3.定義Person類//飼養員屬性:姓名,年齡行為:keepPet(Dog dog,String something)方法功能:喂養寵物狗,something表示喂養的東西行為:keepPet(Cat cat,String something)方法功能:喂養寵物貓,something表示喂養的東西生成空參有參構造,set和get方法 4.定義測試類(完成以下打印效果):keepPet(Dog dog,String somethind)方法打印內容如下:年齡為30歲的老王養了一只黑顏色的2歲的狗2歲的黑顏色的狗兩只前腿死死的抱住骨頭猛吃keepPet(Cat cat,String somethind)方法打印內容如下:年齡為25歲的老李養了一只灰顏色的3歲的貓3歲的灰顏色的貓瞇著眼睛側著頭吃魚 5.思考: 1.Dog和Cat都是Animal的子類,以上案例中針對不同的動物,定義了不同的keepPet方法,過于繁瑣,能否簡化,并體會簡化后的好處?2.Dog和Cat雖然都是Animal的子類,但是都有其特有方法,能否想辦法在keepPet中調用特有方法?畫圖分析:
代碼示例:
//動物類(父類) public class Animal {private int age;private String color;public Animal() {}public Animal(int age, String color) {this.age = age;this.color = color;}public int getAge() {return age;}public void setAge(int age) {this.age = age;}public String getColor() {return color;}public void setColor(String color) {this.color = color;}public void eat(String something){System.out.println("動物在吃" + something);} }//貓類(子類) public class Cat extends Animal {public Cat() {}public Cat(int age, String color) {super(age, color);}@Overridepublic void eat(String something) {System.out.println(getAge() + "歲的" + getColor() + "顏色的貓瞇著眼睛側著頭吃" + something);}public void catchMouse(){System.out.println("貓抓老鼠");}}//狗類(子類) public class Dog extends Animal {public Dog() {}public Dog(int age, String color) {super(age, color);}//行為//eat(String something)(something表示吃的東西)//看家lookHome方法(無參數)@Overridepublic void eat(String something) {System.out.println(getAge() + "歲的" + getColor() + "顏色的狗兩只前腿死死的抱住" + something + "猛吃");}public void lookHome(){System.out.println("狗在看家");} }//飼養員類 public class Person {private String name;private int age;public Person() {}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;}//飼養狗/* public void keepPet(Dog dog, String something) {System.out.println("年齡為" + age + "歲的" + name + "養了一只" + dog.getColor() + "顏色的" + dog.getAge() + "歲的狗");dog.eat(something);}//飼養貓public void keepPet(Cat cat, String something) {System.out.println("年齡為" + age + "歲的" + name + "養了一只" + cat.getColor() + "顏色的" + cat.getAge() + "歲的貓");cat.eat(something);}*///想要一個方法,能接收所有的動物,包括貓,包括狗//方法的形參:可以寫這些類的父類 Animalpublic void keepPet(Animal a, String something) {if(a instanceof Dog d){System.out.println("年齡為" + age + "歲的" + name + "養了一只" + a.getColor() + "顏色的" + a.getAge() + "歲的狗");d.eat(something);}else if(a instanceof Cat c){System.out.println("年齡為" + age + "歲的" + name + "養了一只" + c.getColor() + "顏色的" + c.getAge() + "歲的貓");c.eat(something);}else{System.out.println("沒有這種動物");}} }//測試類 public class Test {public static void main(String[] args) {//創建對象并調用方法/* Person p1 = new Person("老王",30);Dog d = new Dog(2,"黑");p1.keepPet(d,"骨頭");Person p2 = new Person("老李",25);Cat c = new Cat(3,"灰");p2.keepPet(c,"魚");*///創建飼養員的對象Person p = new Person("老王",30);Dog d = new Dog(2,"黑");Cat c = new Cat(3,"灰");p.keepPet(d,"骨頭");p.keepPet(c,"魚");} }第二章 包
2.1 包
? 包在操作系統中其實就是一個文件夾。包是用來分門別類的管理技術,不同的技術類放在不同的包下,方便管理和維護。
在IDEA項目中,建包的操作如下:
包名的命名規范:
路徑名.路徑名.xxx.xxx // 例如:com.itheima.oa- 包名一般是公司域名的倒寫。例如:黑馬是www.itheima.com,包名就可以定義成com.itheima.技術名稱。
- 包名必須用”.“連接。
- 包名的每個路徑名必須是一個合法的標識符,而且不能是Java的關鍵字。
2.2 導包
什么時候需要導包?
? 情況一:在使用Java中提供的非核心包中的類時
? 情況二:使用自己寫的其他包中的類時
什么時候不需要導包?
? 情況一:在使用Java核心包(java.lang)中的類時
? 情況二:在使用自己寫的同一個包中的類時
2.3 使用不同包下的相同類怎么辦?
假設demo1和demo2中都有一個Student該如何使用?
代碼示例:
//使用全類名的形式即可。 //全類名:包名 + 類名 //拷貝全類名的快捷鍵:選中類名crtl + shift + alt + c 或者用鼠標點copy,再點擊copy Reference com.itheima.homework.demo1.Student s1 = new com.itheima.homework.demo1.Student(); com.itheima.homework.demo2.Student s2 = new com.itheima.homework.demo2.Student();第三章 權限修飾符
3.1 權限修飾符
? 在Java中提供了四種訪問權限,使用不同的訪問權限修飾符修飾時,被修飾的內容會有不同的訪問權限,我們之前已經學習過了public 和 private,接下來我們研究一下protected和默認修飾符的作用。
-
public:公共的,所有地方都可以訪問。
-
protected:本類 ,本包,其他包中的子類都可以訪問。
-
默認(沒有修飾符):本類 ,本包可以訪問。
注意:默認是空著不寫,不是default
-
private:私有的,當前類可以訪問。
public > protected > 默認 > private
3.2 不同權限的訪問能力
| 同一類中 | √ | √ | √ | √ |
| 同一包中的類 | √ | √ | √ | |
| 不同包的子類 | √ | √ | ||
| 不同包中的無關類 | √ |
可見,public具有最大權限。private則是最小權限。
編寫代碼時,如果沒有特殊的考慮,建議這樣使用權限:
- 成員變量使用private ,隱藏細節。
- 構造方法使用 public ,方便創建對象。
- 成員方法使用public ,方便調用方法。
小貼士:不加權限修飾符,就是默認權限
第四章 final關鍵字
4.1 概述
? 學習了繼承后,我們知道,子類可以在父類的基礎上改寫父類內容,比如,方法重寫。
如果有一個方法我不想別人去改寫里面內容,該怎么辦呢?
Java提供了final 關鍵字,表示修飾的內容不可變。
- final: 不可改變,最終的含義??梢杂糜谛揎楊?、方法和變量。
- 類:被修飾的類,不能被繼承。
- 方法:被修飾的方法,不能被重寫。
- 變量:被修飾的變量,有且僅能被賦值一次。
4.2 使用方式
4.2.1 修飾類
final修飾的類,不能被繼承。
格式如下:
final class 類名 { }代碼:
final class Fu { } // class Zi extends Fu {} // 報錯,不能繼承final的類查詢API發現像 public final class String 、public final class Math 、public final class Scanner 等,很多我們學習過的類,都是被final修飾的,目的就是供我們使用,而不讓我們所以改變其內容。
4.2.2 修飾方法
final修飾的方法,不能被重寫。
格式如下:
代碼:
class Fu2 {final public void show1() {System.out.println("Fu2 show1");}public void show2() {System.out.println("Fu2 show2");} }class Zi2 extends Fu2 { // @Override // public void show1() { // System.out.println("Zi2 show1"); // }@Overridepublic void show2() {System.out.println("Zi2 show2");} }4.2.3 修飾變量-局部變量
基本類型的局部變量,被final修飾后,只能賦值一次,不能再更改。代碼如下:
思考,下面兩種寫法,哪種可以通過編譯?
寫法1:
final int c = 0; for (int i = 0; i < 10; i++) {c = i;System.out.println(c); }寫法2:
for (int i = 0; i < 10; i++) {final int c = i;System.out.println(c); }根據 final 的定義,寫法1報錯!寫法2,為什么通過編譯呢?因為每次循環,都是一次新的變量c。這也是大家需要注意的地方。
4.2.4 修飾變量-成員變量
成員變量涉及到初始化的問題,初始化方式有顯示初始化和構造方法初始化,只能選擇其中一個:
- 顯示初始化(在定義成員變量的時候立馬賦值)(常用);
-
構造方法初始化(在構造方法中賦值一次)(不常用,了解即可)。
注意:每個構造方法中都要賦值一次!
被final修飾的常量名稱,一般都有書寫規范,所有字母都大寫。
第五章 代碼塊
-
局部代碼塊
-
構造代碼塊
-
靜態代碼塊
5.1 局部代碼塊
使代碼的變量提前結束,以前常用于回收局部變量的內存占用,現在漸漸的淘汰,因為現在的電腦與服務器內存較大,不用在乎這一點點了。
代碼如下:
public class CodeBlockDemo1 {public static void main(String[] args) {{int a = 10;}//因為當代碼執行到這里時,變量a就從內存中消失了System.out.println(a);//a變量會報錯} }5.2 構造代碼塊
- 1.寫在成員位置的代碼塊
- 2.作用:可以把多個構造方法中重復的代碼抽取出來
- 3.執行時機:我們在創建本類對象的時候會先執行構造代碼塊再執行構造方法
也是漸漸的淘汰了,因為不夠靈活,不如把重復代碼放在一個構造方法里,然后進行調用。
代碼如下:
//Student類 public class Student {private String name;private int age;//構造代碼塊:{System.out.println("開始創建對象了");}public Student() {System.out.println("空參構造");}public Student(String name, int age) {System.out.println("有參構造");this.name = name;this.age = age;}public Student(String name) {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 class CodeBlockDemo1 {public static void main(String[] args) {//創建對象Student s = new Student();Student s2 = new Student("zhangsan",23);Student s3 = new Student("zhangsan");} }5.3 靜態代碼塊
相比于構造代碼塊,靜態代碼塊隨著隨著類的加載而加載的,并且只執行一次,做類數據初始化的時候可以使用
//Student類 public class Student {private String name;private int age;//靜態代碼塊static {System.out.println("靜態代碼塊執行了");}public Student() {System.out.println("空參構造");}public Student(String name, int age) {System.out.println("有參構造");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;} }//測試類 package com.itheima.codeblockdemo2;public class Test {public static void main(String[] args) {//創建對象Student s1 = new Student();Student s2 = new Student("zhangsan",23);} }總結
以上是生活随笔為你收集整理的Java基础-面向对象进阶-多态包final权限修饰符代码块的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 计算机RRC是什么指令,srb0 srb
- 下一篇: Javac源码简单分析之解析和填充符号表