面向物件編程之繼承、多型、封裝、抽象類、介面、包-上
- 繼承
- 類的繼承格式
- 為什么要繼承
- 繼承的特點
- 繼承的種類及關鍵字
- 訪問權限
- 多型
- 向上轉型
- 動態系結
- 方法重寫
- 重寫和多載的區別比較
- 多型的優點
- 封裝
- 實作Java的封裝
- 封裝的優點
- 抽象類
- 抽象類及其實作
- 抽象方法
- 抽象類使用的注意事項
- 介面
- 介面的宣告
- 介面的特性
- 抽象類和介面的區別
- 介面與類的區別
- 包
- 包的語法格式和匯入
- 包的作用
- 歡迎指正😄
下篇👇
面向物件編程之繼承、多型、封裝、抽象類、介面、包-下(實戰圖書管理系統)
繼承
繼承就是子類繼承父類的特征和行為,使得子類物件(實體)具有父類的實體域和方法,或子類從父類繼承方法,使得子類具有父類相同的行為,
類的繼承格式
在 Java 中通過 extends 關鍵字可以申明一個類是從另外一個類繼承而來的,一般形式如下:
class 父類 {
}
class 子類 extends 父類 {
}
為什么要繼承
從這下面兩段代碼可以看出來,代碼存在重復了,導致后果就是代碼量大且臃腫,而且維護性不高(維護性主要是后期需要修改的時候,就需要修改很多的代碼,容易出錯)
/**
1. user:ypc;
2. date:2021-04-20;
3. time: 17:13;
*/
public class Dog {
private String name;
private int id;
public Dog(String myName, int myid) {
name = myName;
id = myid;
}
public void eat(){
System.out.println(name+"正在吃");
}
public void sleep(){
System.out.println(name+"正在睡");
}
public void introduction() {
System.out.println("大家好!我是" + id + "號" + name + ".");
}
}
/**
4. user:ypc;
5. date:2021-04-20;
6. time: 17:14;
*/
public class Cat {
private String name;
private int id;
public Cat(String myName, int myid) {
name = myName;
id = myid;
}
public void eat(){
System.out.println(name+"正在吃");
}
public void sleep(){
System.out.println(name+"正在睡");
}
public void introduction() {
System.out.println("大家好!我是" + id + "號" + name + ".");
}
}
所以要從根本上解決這兩段代碼的問題,就需要繼承,將兩段代碼中相同的部分提取出來組成 一個父類:
public class Animal {
private String name;
private int id;
public Animal(String myName, int myid) {
name = myName;
id = myid;
}
public void eat(){
System.out.println(name+"正在吃");
}
public void sleep(){
System.out.println(name+"正在睡");
}
public void introduction() {
System.out.println("大家好!我是" + id + "號" + name + ".");
}
}
這個Animal類就可以作為一個父類,然后狗類和貓類繼承這個類之后,就具有父類當中的屬性和方法,子類就不會存在重復的代碼,維護性也提高,代碼也更加簡潔,提高代碼的復用性(復用性主要是可以多次使用,不用再多次寫同樣的代碼) 繼承之后的代碼:
public class Dog extends Animal {
public Dog (String myName, int myid) {
super(myName, myid);
}
}
public class Cat extends Animal {
public Cat (String myName, int myid) {
super(myName, myid);
}
}
繼承的特點
🍟使用 extends 指定父類.
🍟Java 的繼承是單繼承,但是可以多重繼承,單繼承就是一個子類只能繼承一個父類,多重繼承就是,例如 B 類繼承 A 類,C 類繼承 B 類,所以按照關系就是 B 類是 C 類的父類,A 類是 B 類的父類,這是 Java 繼承區別于 C++ 繼承的一個特性
🍟子類會繼承父類的所有 public 的欄位和方法.
🍟對于父類的 private 的欄位和方法, 子類中是無法訪問的.
🍟子類的實體中, 也包含著父類的實體. 可以使用 super 關鍵字得到父類實體的參考
🍟提高了類之間的耦合性(繼承的缺點,耦合度高就會造成代碼之間的聯系越緊密,代碼獨立性越差),
🍟子類可以擁有自己的屬性和方法,即子類可以對父類進行擴展,
繼承的種類及關鍵字
🥚種類

🥚關鍵字
final 關鍵字
final 關鍵字也能修飾類, 此時表示被修飾的類就不能被繼承.
父類沒有final修飾子類可以正常繼承

有final關鍵字修飾父類子類不可以繼承,編譯會報錯

super 關鍵字
super關鍵字:
1.super()呼叫父類的構造方法,必需放在第一行

2.super.父類的成員變數,用super來呼叫父類的成員變數

3.呼叫父類的成員函式 super.func()

this關鍵字
指向自己的參考,

extends關鍵字
在 Java 中,類的繼承是單一繼承,也就是說,一個子類只能擁有一個父類,所以 extends 只能繼承一個類,
多繼承編譯會報錯👇

訪問權限
🍿private 修飾的方法和變數只可以在自己的類中訪問,子類也不可以訪問,
🍿default 就是不加private,protected,public修飾限定符修飾的方法或變數,在同一個包的同一類和不同類可以訪問default方法和變數
🍿protected相比于default,在不同包的子類可以訪問protected方法或變數,但這個類必需是它的父類,
🍿public可以在任一個類中訪問變數和方法,
🍿可以在任何一個類中使用public類
🍿不能用private和protected來修飾類
🍿訪問權限從高到低排列順序是:
public protected default private

多型
向上轉型
向上轉型,JAVA中的一種呼叫方式,向上轉型是對A的物件的方法的擴充,即A的物件可訪問B從A中繼承來的和B“重寫”A的方法,
例如:
public class Animal {
public String name;
public int age;
public Animal(String name, int age) {
this.age = age;
this.name = name;
}
public void eat() {
System.out.println(this.name+"在吃東西");
}
public void sleep() {
System.out.println(this.name+"在睡覺");
}
}
class Pig extends Animal{
public Pig(String name, int age){
super( name, age);
}
void funcPig(){
}
public void eat(){
System.out.println(this.name+"吃桃子");
}
void func(){
System.out.println(super.age);
this.eat();//呼叫自己的eat()fangfa
super.eat();//呼叫父類的eat()方法
this.funcPig();
}
}
class Test{
public static void main(String[] args) {
/*
正常使用
*/
Animal animal1 = new Animal("gougou",12);
animal1.eat();
Pig pig = new Pig("zhuzhu",8);
pig.eat();
/*
向上轉型
*/
Animal animal =new Pig("bajie",78);
animal.eat();
}
}
運行結果為:

動態系結
在 Java 中, 呼叫某個類的方法, 究竟執行了哪段代碼 (是父類方法的代碼還是子類方法的代碼) , 要看究竟這個引
用指向的是父類物件還是子類物件. 這個程序是程式運行時決定的(而不是編譯期), 因此稱為 動態系結.
上面的Animal animal =new Pig(“bajie”,78);
animal.eat();就發生了動態系結
構造方法也可以發生動態系結(也叫運行時系結)
動態系結的條件:
🎊一定有向上轉型
🎊子類重寫了父類的方法,發生了方法的重寫
🎊通過父類的參考來呼叫被重寫的方法
方法重寫
子類實作父類的同名方法, 并且引數的型別和個數完全相同, 這種情況稱為 覆寫/重寫/覆寫(Override)
比如剛才的eat()方法,在Pig子類中重寫了父類Animal的eat()方法
public class Animal {
public String name;
public int age;
public Animal(String name, int age) {
this.age = age;
this.name = name;
}
public void eat() {
System.out.println(this.name+"在吃東西");
}
public void sleep() {
System.out.println(this.name+"在睡覺");
}
}
class Pig extends Animal{
public Pig(String name, int age){
super( name, age);
}
void funcPig(){
}
public void eat(){//重寫父類的eat()方法
System.out.println(this.name+"吃桃子");
}
void func(){
System.out.println(super.age);
this.eat();//呼叫自己的eat()fangfa
super.eat();//呼叫父類的eat()方法
this.funcPig();
}
}
class Test{
public static void main(String[] args) {
/*
正常使用
*/
Animal animal1 = new Animal("gougou",12);
animal1.eat();
Pig pig = new Pig("zhuzhu",8);
pig.eat();
/*
向上轉型
*/
Animal animal =new Pig("bajie",78);
animal.eat();
}
}
針對重寫的方法, 可以使用 @Override 注解來顯式指定.

如果不重寫eat()方法編譯就會報錯

重寫和多載的區別比較
重寫
重寫是子類對父類的允許訪問的方法的實作程序進行重新撰寫, 回傳值和形參都不能改變,即外殼不變,核心重寫!
重寫的好處在于子類可以根據需要,定義特定于自己的行為, 也就是說子類能夠根據需要實作父類的方法,
重寫規則:
🎈引數串列與被重寫方法的引數串列必須完全相同,
🎈回傳型別與被重寫方法的回傳型別可以不相同,但是必須是父類回傳值的派生類(java5 及更早版本回傳型別要一樣,java7 及更高版本可以不同),
🎈訪問權限不能比父類中被重寫的方法的訪問權限更低,例如:如果父類的一個方法被宣告為 public,那么在子類中重寫該方法就不能宣告為 protected,
🎈父類的成員方法只能被它的子類重寫,
🎈宣告為 final 的方法不能被重寫,
🎈宣告為 static 的方法不能被重寫,但是能夠被再次宣告,
🎈子類和父類在同一個包中,那么子類可以重寫父類所有方法,除了宣告為 private 和 final 的方法,
🎈子類和父類不在同一個包中,那么子類只能夠重寫父類的宣告為 public 和 protected 的非 final 方法,
🎈重寫的方法能夠拋出任何非強制例外,無論被重寫的方法是否拋出例外,但是,重寫的方法不能拋出新的強制性例外,或者比被重寫方法宣告的更廣泛的強制性例外,反之則可以,
🎈構造方法不能被重寫,
🎈如果不能繼承一個類,則不能重寫該類的方法
多載
多載(overloading) 是在一個類里面,方法名字相同,而引數不同,回傳型別可以相同也可以不同,
每個多載的方法(或者建構式)都必須有一個獨一無二的引數型別串列,
多載規則:
🎄被多載的方法必須改變引數串列(引數個數或型別不一樣);
🎄被多載的方法可以改變回傳型別;
🎄被多載的方法可以改變訪問修飾符;
🎄被多載的方法可以宣告新的或更廣的檢查例外;
🎄方法能夠在同一個類中或者在一個子類中被多載,
🎄無法以回傳值型別作為多載函式的區分標準,

多型的優點
🎁 消除型別之間的耦合關系
🎁可替換性
🎁可擴充性
🎁介面性
🎁靈活性
🎁簡化性
🎁多型存在的三個必要條件
1.繼承
2.重寫
3.父類參考指向子類物件:Parent p = new Child();
多型的實作方式
🚗方式一:重寫:
參見上文
🚗方式二:介面
java中的介面類似于生活中的介面,就是一些方法特征的集合,但沒有方法的實作,
參見下文
🚗方式三:抽象類和抽象方法
參見下文
封裝
在面向物件程式設計方法中,封裝(英語:Encapsulation)是指一種將抽象性函式介面的實作細節部分包裝、隱藏起來的方法,
封裝可以被認為是一個保護屏障,防止該類的代碼和資料被外部類定義的代碼隨機訪問,
要訪問該類的代碼和資料,必須通過嚴格的介面控制,
封裝最主要的功能在于我們能修改自己的實作代碼,而不用修改那些呼叫我們代碼的程式片段,
適當的封裝可以讓程式碼更容易理解與維護,也加強了程式碼的安全性,
實作Java的封裝
- 修改屬性的可見性來限制對屬性的訪問(一般限制為private)如:
/**
* user:ypc;
* date:2021-04-20;
* time: 19:15;
*/
public class Person {
private String name;
private int age;
}
這段代碼中,將 name 和 age 屬性設定為私有的,只能本類才能訪問.如此就對資訊進行了隱藏,
2. 對每個值屬性提供對外的公共方法訪問,也就是創建一對賦取值方法,用于對私有屬性的訪問如:get\set方法(idea快捷鍵alt+Ins插入)
/**
* user:ypc;
* date:2021-04-20;
* time: 19:15;
*/
public class Person {
private String name;
private int 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;
}
}

3.實體化
/**
* user:ypc;
* date:2021-04-20;
* time: 19:15;
*/
public class Person {
private String name;
private int 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;
}
}
class TestDemo{
public static void main(String[] args) {
Person person = new Person();
person.setAge(20);
person.setName("jack");
System.out.println(person.getName());
System.out.println(person.getAge());
}
}
結果

封裝的優點
🎨良好的封裝能夠減少耦合,
🎨類內部的結構可以自由修改,
🎨可以對成員變數進行更精確的控制,
🎨隱藏資訊,實作細節
抽象類
抽象類及其實作
在面向物件的概念中,所有的物件都是通過類來描繪的,但是反過來,并不是所有的類都是用來描繪物件的,如果一個類中沒有包含足夠的資訊來描繪一個具體的物件,這樣的類就是抽象類,
由于抽象類不能實體化物件,所以抽象類必須被繼承,才能被使用,
父類包含了子類集合的常見的方法,但是由于父類本身是抽象的,所以不能使用這些方法,
例如:Person就是一個抽象類
public abstract class Person {
private String name;
private int 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 Work(){}
}
class Teacher extends Person{
public void Work(){
System.out.println(this.getName()+"的作業是教書");
}
}
class Student extends Person{
public void Work(){
System.out.println(this.getName()+"的作業學習");
}
}
class TestDemo{
public static void main(String[] args) {
// Person person = new Person();不能實體化否則編譯就會報錯
person.setAge(20);
person.setName("jack");
System.out.println(person.getName());
System.out.println(person.getAge());
}
}

抽象方法
如果你想設計這樣一個類,該類包含一個特別的成員方法,該方法的具體實作由它的子類確定,那么你可以在父類中宣告該方法為抽象方法,
Abstract 關鍵字同樣可以用來宣告抽象方法,抽象方法只包含一個方法名,而沒有方法體,
抽象方法沒有定義,方法名后面直接跟一個分號,而不是花括號,
如:Pereon類中的Work()方法

抽象方法必需被重寫否則就會報錯
/**
* user:ypc;
* date:2021-04-20;
* time: 19:15;
*/
public abstract class Person {
private String name;
private int 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 Work(){}
public abstract void Work();
}
class Teacher extends Person{//抽象方法必需被重寫否則就會報錯
public void Work(){
System.out.println(this.getName()+"的作業是教書");
}
}
class Student extends Person{
public void Work(){
System.out.println(this.getName()+"的作業是學習");
}
}
class TestDemo{
public static void main(String[] args) {
Person person = new Student();
person.setName("Steven");
person.Work();
// Person person = new Person();
// person.setAge(20);
// person.setName("jack");
// System.out.println(person.getName());
// System.out.println(person.getAge());
}
}

抽象類使用的注意事項
👧如果一個類包含抽象方法,那么該類必須是抽象類,
任何子類必須重寫父類的抽象方法,或者宣告自身為抽象類,
👧繼承抽象方法的子類必須重寫該方法,否則,該子類也必須宣告為抽象類,最終,必須有子類實作該抽象方法,否則,從最初的父類到最終的子類都不能用來實體化物件,
👧抽象類可以發生向上轉型,可以被繼承,可以動態系結
👧抽象類不能被實體化
👧抽象類被繼承時方法一定要重寫
👧抽象類存在的意義就是為了被繼承
👧抽象方法不能是private
👧抽象類可以有非抽象方法
介面
介面是抽象類的更進一步. 抽象類中還可以包含非抽象方法, 和欄位. 而介面中包含的方法都是抽象方法, 欄位只能包含
靜態常量.
介面(英文:Interface),在JAVA編程語言中是一個抽象型別,是抽象方法的集合,介面通常以interface來宣告,一個類通過繼承介面的方式,從而來繼承介面的抽象方法,
介面并不是類,撰寫介面的方式和類很相似,但是它們屬于不同的概念,類描述物件的屬性和方法,介面則包含類要實作的方法,
除非實作介面的類是抽象類,否則該類要定義介面中的所有方法,
介面無法被實體化,但是可以被實作,一個實作介面的類,必須實作介面內所描述的所有方法,否則就必須宣告為抽象類,另外,在 Java 中,介面型別可用來宣告一個變數,他們可以成為一個空指標,或是被系結在一個以此介面實作的物件
介面的宣告
[可見度] interface 介面名稱 [extends 其他的介面名] {
// 宣告變數
// 抽象方法
}
例如:IShape就是一個介面
interface IShape {
void draw();
}
class Rect implements IShape{
public void draw(){
System.out.println("?");
}
}
class Cycle implements IShape {
public void draw() {
System.out.println("○");
}
}
class TestDemo2 {
public static void main(String[] args) {
IShape shape = new Rect();
shape.draw();
}
}
介面的特性
🎦介面是隱式抽象的,當宣告一個介面的時候,不必使用abstract關鍵字,
🎦介面中每一個方法也是隱式抽象的,宣告時同樣不需要abstract關鍵字,
🎦介面中的方法都是公有的,
也就是說interface IShape{}中的方法默認都是從public abstrat的,并且不能有具體實作
變數默認都是public abstrat final的
🎦介面可以向上轉型,可以發生運行時系結即動態系結
🎦介面中的方法可以具體實作但必須是這樣的:default void function(){…}
🎦一個類可以實作多個介面
🎦介面的實作就是為了滿足繼承
🎦介面可以拓展
🎦一個類可以實作一個介面也可以繼承一個類
如下:

class A{
}
interface IShape {
void draw();
}
/*
🎦一個類可以實作多個介面
🎦介面的實作就是為了滿足繼承
🎦介面可以拓展
🎦一個類可以實作一個介面也可以繼承一個類
*/
interface IShape2 extends IShape {
void draw();
}
class Rect extends A implements IShape,IShape2{
public void draw(){
System.out.println("?");
}
}
class Cycle implements IShape {
public void draw() {
System.out.println("○");
}
}
class TestDemo2 {
public static void main(String[] args) {
IShape shape = new Rect();
shape.draw();
}
}
抽象類和介面的區別
🎅抽象類中的方法可以有方法體,就是能實作方法的具體功能,但是介面中的方法不行,
🎅 抽象類中的成員變數可以是各種型別的,而介面中的成員變數只能是 public static final 型別的,
🎅介面中不能含有靜態代碼塊以及靜態方法(用 static 修飾的方法),而抽象類是可以有靜態代碼塊和靜態方法,
🎅 一個類只能繼承一個抽象類,而一個類卻可以實作多個介面,
介面與類的區別
🤶介面不能用于實體化物件,
🤶介面沒有構造方法,
🤶介面中所有的方法必須是抽象方法,
🤶介面不能包含成員變數,除了 static 和 final 變數,
🤶介面不是被類繼承了,而是要被類實作,
🤶介面支持多繼承
包
為了更好地組織類,Java 提供了包機制,用于區別類名的命名空間,
包的語法格式和匯入
包的語法格式
package pkg1[.pkg2[.pkg3…]];
包的匯入
import package1[.package2…].(classname|*);
例如:Demo6匯入了B包中的Demo5類并在主函式中實列化了Demo5類,使用了Demo5類的func函式
同時也繼承了A介面(不能實作A介面(不能使用implements介面),只能繼承)


包B中的Demo5類的代碼
package B;
/**
* user:ypc;
* date:2021-04-20;
* time: 20:46;
*/
interface A{
public void test();
}
public class Demo5 {
public void func(){
System.out.println("匯入了B包中的Demo5類的func()方法");
}
}
包外類Demo6的代碼
import B.Demo5;
/**
* user:ypc;
* date:2021-04-20;
* time: 20:46;
*/
class B extends A {
public void test(){
System.out.println("繼承了B包中的A介面的test方法");
}
}
public class Demo6 {
public static void main(String[] args) {
B b = new B();
b.test();
Demo5 demo5 = new Demo5();
demo5.func();
}
}
包的作用
📆把功能相似或相關的類或介面組織在同一個包中,方便類的查找和使用,
📆如同檔案夾一樣,包也采用了樹形目錄的存盤方式,同一個包中的類名字是不同的,不同的包中的類的名字是可以相同的,當同時呼叫兩個不同包中相同類名的類時,應該加上包名加以區別,因此,包可以避免名字沖突,
📆包也限定了訪問權限,擁有包訪問權限的類才能訪問某個包中的類,
Java 使用包(package)這種機制是為了防止命名沖突,訪問控制,提供搜索和定位類(class)、介面、列舉(enumerations)和注釋(annotation)等,
歡迎指正😄
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/279382.html
標籤:java
下一篇:用python爬取酷狗音樂
