面向對象02 7.==繼承== 繼承的本質是對某一批類的抽象,從而實現對現實世界更好地建模 extends的意思是“擴展”。子類是父類的擴展。 Java類中只有單繼承,沒有多繼承!(一個兒子只能有一個爸爸,一個爸爸可以有多個兒子) 繼承是類和類之間的一種關係。除此之外,類和類之間的關係還有依賴、組合 ...
面向對象02
7.繼承
- 繼承的本質是對某一批類的抽象,從而實現對現實世界更好地建模
- extends的意思是“擴展”。子類是父類的擴展。
- Java類中只有單繼承,沒有多繼承!(一個兒子只能有一個爸爸,一個爸爸可以有多個兒子)
- 繼承是類和類之間的一種關係。除此之外,類和類之間的關係還有依賴、組合、聚合等。
- 繼承關係的兩個類,一個為子類(派生類),一個為父類(基類)。子類繼承父類,使用關鍵字extends表示
- 子類和父類之間,從意義上講應該具有“is a”的關係
- object類
- super
- 方法重寫
子類繼承了父類,就會有父類的全部方法!(私有的東西無法被繼承)
例子1:
package li.oop.demo05;
//父類:Person 人
public class Person {
//public
//protected
//default
//private
public int money = 10_0000_0000;
public void say(){
System.out.println("說了一句話");
}
public int getMoney() {
return money;
}
public void setMoney(int money) {
this.money = money;
}
}
package li.oop.demo05;
//學生 is 人
//派生類(子類),子類繼承了父類,就會有父類的全部方法
public class Student extends Person{
}
package li.oop;
import li.oop.demo05.Student;
public class Application {
public static void main(String[] args) {
Student student = new Student();
student.say();//說了一句話
System.out.println(student.money);// 1000000000
}
}
![image-20220729214339154](https://liyuelian.oss-cn-shenzhen.aliyuncs.com/imgs/image-20220729214339154.png)
7.1Object類
在Java中,所有的類都預設直接或者間接繼承Object類
7.2Super關鍵字
-
super. 大部分情況下是可以省略的。
當父中類有,子類中又有,如果想在子中訪問“父的特征”,super. 不能省略。
在父和子中有同名的屬性,或者說有相同的方法,如果此時想在子類中訪問父中的數據,必須使用“super.”加以區分。-
super.屬性名 --->訪問父類的屬性
-
super.方法名(實參) --->訪問父類的方法
-
super(實參) ---->調用父類的構造方法
-
-
子類繼承父類,子類的構造方法必須調用super()即父類的構造方法,而且必須放在構造方法的第一行。
子類構造方法第一行都有調用父類無參的構造方法,如果你不顯示地寫出了,系統會自己加上;
但是如果你的父類重載了一個或多個構造方法,系統將不再預設加上無參的構造方法,必須自己加上。
- super調用父類的構造方法,必須在構造方法中的第一行
- super必須只能出現在子類的方法或者構造方法中
- super和this不能同時調用構造方法
- super&&this
- 代表的對象不同:
- this:代表本身調用者這個對象
- 代表當前類的父類對象的引用
- 前提:
- this:沒有繼承也可以使用
- super:只能在繼承條件下才可以使用
- 構造方法的區別:
- this(); 本類的構造
- super(); 父類的構造
- 代表的對象不同:
7.3方法重寫
例子1:
package li.oop.demo05;
//重寫都是方法的重寫,和屬性無關
public class B {
public static void test(){
System.out.println("B==>test");
}
}
package li.oop.demo05;
public class A extends B{
public static void test(){
System.out.println("A==>test");
}
}
package li.oop;
import li.oop.demo05.A;
import li.oop.demo05.B;
public class Application {
public static void main(String[] args) {
//靜態方法:方法的調用只和左邊定義的類型有關
A a = new A();
a.test();//調用的是A類方法
//父類的引用指向了子類
B b = new A();
b.test();//調用的是B類方法
}
}
![image-20220730150501414](https://liyuelian.oss-cn-shenzhen.aliyuncs.com/imgs/image-20220730150501414.png)
靜態方法:方法的調用只和左邊定義的類型有關
例子2:
package li.oop.demo05;
//重寫都是方法的重寫,和屬性無關
public class B {
public void test(){
System.out.println("B==>test");
}
}
package li.oop.demo05;
public class A extends B{
//Override 重寫
@Override // 註解:有功能的註解!
public void test(){
System.out.println("A==>test");
}
}
package li.oop;
import li.oop.demo05.A;
import li.oop.demo05.B;
//靜態方法和非靜態方法區別很大!
//靜態方法:方法的調用只和左邊定義的類型有關
//非靜態:重寫
public class Application {
public static void main(String[] args) {
A a = new A();
a.test();
//父類的引用指向了子類
B b = new A();//子類重寫了父類的方法
b.test();
}
}
![image-20220730151534644](https://liyuelian.oss-cn-shenzhen.aliyuncs.com/imgs/image-20220730151534644.png)
總結:
重寫 :子類的方法和父類的方法必須要一致,方法體不同
-- 重寫前提:需要有繼承關係,子類重寫父類的方法
- 方法名必須相同
- 參數列表必須相同
- 修飾符:範圍可擴大,但不能縮小:public>protected>default>private
- 拋出的異常:範圍可以被縮小,但不能擴大。例如:ClassNotFoundException(範圍小)-->Exception(範圍大)
為什麼需要重寫?:父類的功能,子類不一定需要,或者不一定滿足!
快捷鍵:Alt+insert:Override;
8.多態
8.1多態的定義和使用
-
即同一方法可以根據發送對象的不同而採取多種不同的行為方式
-
一個對象的實際類型是確定的,但可以指向對象的引用類型有很多
這裡的引用一般指父類或者有關係的類
-
多態存在的條件:
- 有繼承關係
- 子類重寫父類方法
- 父類引用指向子類對象
-
註意:多態是方法的多態,屬性沒有多態性
-
instanceof (類型轉換)引用類型
例子1:
package li.oop.demo06;
public class Person {
public void run(){
System.out.println("run");
}
}
package li.oop.demo06;
public class Student extends Person{
}
package li.oop;
import li.oop.demo06.Person;
import li.oop.demo06.Student;
public class Application {
public static void main(String[] args) {
//一個對象的實際類型是確定的
//new Student();
//new Person();
//但是可以指向的引用類型就不確定了
Student s1 = new Student();
Person s2 = new Student();//父類的引用指向子類
Object s3 = new Student();//父類的引用指向子類
s2.run();//這裡雖然new的是Student,但是是它依舊走的是父類的方法,因為子類繼承了父類的全部方法
}
}
![image-20220730154506673](https://liyuelian.oss-cn-shenzhen.aliyuncs.com/imgs/image-20220730154506673.png)
這裡的 s2 雖然new的是Student,但是是s2.run() 依舊走的是父類的方法,因為子類繼承了父類的全部方法
例子2
package li.oop.demo06;
public class Person {
public void run(){
System.out.println("run");
}
}
package li.oop.demo06;
public class Student extends Person{
@Override
public void run() {
System.out.println("son");
}
public void eat(){
System.out.println("eat");
}
}
package li.oop;
import li.oop.demo06.Person;
import li.oop.demo06.Student;
public class Application {
public static void main(String[] args) {
//一個對象的實際類型是確定的
//new Student();
//new Person();
//但是可以指向的引用類型就不確定了
//Sudent能調用的方法都是自己的或者繼承父類的
Student s1 = new Student();
//Person父類型:可以指向子類,但是不能調用子類獨有的方法
Person s2 = new Student();//父類的引用指向子類
Object s3 = new Student();//父類的引用指向子類
s2.run();//子類重寫了父類的方法,執行子類的方法
s1.run();
//s2.eat 不能調用 s2為Person父類型:可以指向子類,但是不能調用子類獨有的方法
((Student) s2).eat();//強制類型轉換後才可以使用
//對象能夠執行的方法主要看對象左邊的類型和右邊關係不大
}
}
對象能夠執行的方法主要看對象左邊的類型和右邊關係不大
如
//Person父類型:可以指向子類,但是不能調用子類獨有的方法
Person s2 = new Student();//父類的引用指向子類
//子類Sudent能調用的方法都是自己的或者繼承父類的
Student s1 = new Student();
![image-20220730155646033](https://liyuelian.oss-cn-shenzhen.aliyuncs.com/imgs/image-20220730155646033.png)
多態註意事項:
- 多態是方法的多態,屬性沒有多態
- 父類和子類,有聯繫
- 多態存在的必要條件:
- 有繼承關係
- 方法需要重寫
- 不能重寫的方法:
- 1.static 方法,屬於類,它不屬於實例
- final 常量
- private 方法
- 不能重寫的方法:
- 父類的引用指向子類對象
8.2instanceof
instanceof(類型轉換)引用類型,判斷一個對象是什麼類型
例子1:
package li.oop.demo06;
public class Person {
public void run(){
System.out.println("run");
}
}
package li.oop.demo06;
public class Student extends Person{
}
package li.oop.demo06;
public class Teacher extends Person{
}
package li.oop;
import li.oop.demo06.Person;
import li.oop.demo06.Student;
import li.oop.demo06.Teacher;
public class Application {
public static void main(String[] args) {
//Object > Person > Student
//Object > Person > Teacher
//Object > String
Object object = new Student();
System.out.println(object instanceof Student);//true
System.out.println(object instanceof Person);//true
System.out.println(object instanceof Object);//true
System.out.println(object instanceof Teacher);//false
System.out.println(object instanceof String);//false
System.out.println("==============");
Person person = new Student();
System.out.println(person instanceof Student);//true
System.out.println(person instanceof Person);//true
System.out.println(person instanceof Object);//true
System.out.println(person instanceof Teacher);//false
// 編譯就報錯了 System.out.println(person instanceof String);
System.out.println("==============");
Student student = new Student();
System.out.println(student instanceof Student);//true
System.out.println(student instanceof Person);//true
System.out.println(student instanceof Object);//true
// 編譯就報錯了 System.out.println(student instanceof Teacher);
//編譯就報錯了 System.out.println(student instanceof String);
}
}
總結:
System.out.println(X instanceof Y);
能不能編譯通過,取決於X與Y之間是否存在直系繼承關係
![image-20220730170759125](https://liyuelian.oss-cn-shenzhen.aliyuncs.com/imgs/image-20220730170759125.png)
8.3類的類型轉換
- 基本類型轉換
- 高容量轉換成低容量:強制類型轉換
- 低容量轉換成高容量:自動類型轉換
- 類之間的轉化:父類代表高的,子類代表低的
- 父轉子:強制轉換
- 子轉父:自動轉換
例子:
package li.oop.demo06;
public class Person {
}
package li.oop.demo06;
public class Student extends Person{
public void go(){
System.out.println("go");
}
}
package li.oop;
import li.oop.demo06.Person;
import li.oop.demo06.Student;
public class Application {
public static void main(String[] args) {
/*類型之間的轉換:
1.基本類型轉換-->高容量轉換成低容量:強制類型轉換
低容量轉換成高容量:自動類型轉換
2.類之間的轉化:父類代表高的,子類代表低的
*/
//高 <--- ---- --- 低
Person student = new Student();
//這裡只有在子類Student類中才有go()方法,
// 而student對象是Person類型的,因此不能直接調用,需要強制類型轉換成子類類型才能使用go()方法
//高 --- ---- --- > 低
((Student) student).go();//go
//或者
Person obj = new Student();
Student student1 = (Student) obj;//強制轉換
student1.go();//go
/*
子類轉換成父類可能會丟失自己本來的一些方法
*/
Student student2 = new Student();
student2.go();//go
Person person = student2;//自動轉換 低-->高
//這裡的 person對象就不能使用原本子類的go()方法了
}
}
![image-20220730172902824](https://liyuelian.oss-cn-shenzhen.aliyuncs.com/imgs/image-20220730172902824.png)
總結:
-
父類的引用指向子類的對象(子類的引用不能指向父類的對象)
-
把子類轉換為父類,向上轉型(自動類型轉換)
-
把父類轉換為子類,向下轉型(強制轉換)
基本數據類型的強制轉換可能會丟失精度,類的強制轉換可能會丟失一些方法
-
為什麼會存在類的類型轉換?方便方法的調用,減少重覆代碼,更簡潔
9.static關鍵字詳解
9.1靜態變數和靜態方法
例子1:靜態變數儘量使用類名來訪問
package li.oop.demo07;
//static
public class Student {
private static int age;//靜態的變數
private double score;//非靜態的變數
public static void main(String[] args) {
Student s1 = new Student();
//1.靜態變數儘量使用類名來訪問
//通過類來使用
System.out.println(Student.age);//0
//通過對象來使用
System.out.println(s1.age);//0
System.out.println(s1.score);//0.0
}
}
例子2:靜態方法
-
調用非靜態方法需要通過實例對象來調用
-
調用靜態方法可以直接通過類調用,如果如果靜態方法和main方法在同一個類中,甚至可以直接調用
-
非靜態方法可以去調用靜態方法里的所有東西,而靜態方法不能調非靜態方法
package li.oop.demo07;
//static
public class Student {
private static int age;//靜態的變數
private double score;//非靜態的變數
public void run(){
System.out.println("run");
}
public static void go(){
System.out.println("go");
}
public static void main(String[] args) {
//2.靜態方法
//調用非靜態方法需要通過實例對象來調用
Student s2 = new Student();
s2.run();
//調用靜態方法可以直接通過類調用,如果如果靜態方法和main方法在同一個類中,甚至可以直接調用
Student.go();
go();
//3.非靜態方法可以去調用靜態方法里的所有東西,而靜態方法不能調非靜態方法
//比如在靜態方法main()中不能直接調用非靜態方法run()
}
}
9.2靜態代碼塊
package li.oop.demo07;
public class Person {
{
//代碼塊(匿名代碼塊)
}
static{
//靜態代碼塊
}
}
-
如上所示,在類中用大括弧括起來的一段沒有名字的代碼塊稱為匿名代碼塊。在括弧前加上static關鍵字的代碼塊稱為靜態代碼塊。
-
匿名代碼塊沒有名字,程式在執行時並不能主動去調用這些模塊。在創建對象的時候匿名代碼塊自動創建,並且在構造器之前
-
靜態代碼塊是類載入的同時就直接執行,永久只執行一次
例子:匿名代碼塊、靜態代碼塊、構造方法的載入順序
package li.oop.demo07;
public class Person {
{
System.out.println("匿名代碼塊");//代碼塊(匿名代碼塊)
}
static{
System.out.println("靜態代碼塊");//靜態代碼塊
}
public Person() {
System.out.println("構造方法");
}
public static void main(String[] args) {
System.out.println("==========111");
Person person1 = new Person();
System.out.println("==========222");
Person person2 = new Person();
}
}
![image-20220730193306924](https://liyuelian.oss-cn-shenzhen.aliyuncs.com/imgs/image-20220730193306924.png)
載入順序:
靜態代碼塊>匿名代碼塊>構造函數
靜態代碼塊在person1實例化前就執行了,靜態代碼塊是在類載入的同時就執行了,並且只執行一次
9.3靜態導入包
package li.oop.demo07;
//靜態導入包~
import static java.lang.Math.random;
import static java.lang.Math.PI;
public class Test {
public static void main(String[] args) {
System.out.println(random());
System.out.println(PI);
}
}
![image-20220730194156371](https://liyuelian.oss-cn-shenzhen.aliyuncs.com/imgs/image-20220730194156371.png)
PS:被final修飾的類不能被其他類繼承
![image-20220730194358164](https://liyuelian.oss-cn-shenzhen.aliyuncs.com/imgs/image-20220730194358164.png)
![image-20220730194335674](https://liyuelian.oss-cn-shenzhen.aliyuncs.com/imgs/image-20220730194335674.png)