Java基礎(chǔ)-封裝和繼承
一. 封裝
那封裝是什么呢?
在面向?qū)ο蟪淌皆O(shè)計(jì)方法中,封裝(英語(yǔ):Encapsulation)是指一種將抽象性函式接口的實(shí)現(xiàn)細(xì)節(jié)部分包裝、隱藏起來的方法。
1.1 封裝的目的
- 直接通過操控類對(duì)象來達(dá)到目的,不需要對(duì)具體實(shí)現(xiàn)十分了解,使類屬性和方法的具體實(shí)現(xiàn)對(duì)外不可見。不但方便還起到了保護(hù)作用。
- 封裝最主要的功能在于我們能修改自己的實(shí)現(xiàn)代碼,而不用修改那些調(diào)用我們代碼的程序片段。
- 適當(dāng)?shù)姆庋b可以讓程式碼更容易理解與維護(hù),也加強(qiáng)了程式碼的安全性。
1.2 封裝的好處
- 良好的封裝能夠減少耦合。
- 類內(nèi)部的結(jié)構(gòu)可以自由修改。
- 可以對(duì)成員變量進(jìn)行更精確的控制。
- 隱藏信息,實(shí)現(xiàn)細(xì)節(jié)。
1.3 封裝的步驟
修改屬性的可見性來限制對(duì)屬性的訪問(一般限制為private),例如:
public class Person {
private String name ; // 姓名
private String gender ; // 性別
private int age; // 年齡
}
這段代碼中,將 name 、sex和 age 屬性設(shè)置為私有的,只能本類才能訪問,其他類都訪問不了,如此就對(duì)信息進(jìn)行了隱藏。
對(duì)每個(gè)值屬性提供對(duì)外的公共方法訪問,也就是創(chuàng)建一對(duì)賦取值方法,用于對(duì)私有屬性的訪問,例如:
public class Person {
private String name ; // 姓名
private String gender ; // 性別
private int age; // 年齡
public void setName(String name) {
this.name = name;
}
public String getName() {
return name;
}
public void setGender(String gender) {
this.gender = gender;
}
public String gender(){
return gender;
}
public void setAge(int age) {
this.age = age;
}
public int getAge() {
return age;
}
}
采用 this 關(guān)鍵字調(diào)用本類中的屬性,也就是類中的成員變量。主要為了解決實(shí)例變量(private String name)和局部變量(setName(String name)中的name變量)之間發(fā)生的同名的沖突。
1.4 封裝的例子
創(chuàng)建一個(gè)用戶類User:

- 代碼如下:
package com.nz.pojo;
public class User {
private String username; // 用戶名
private String password; // 密碼
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
}
- 編寫測(cè)試User的
demo:EncapsulationDemo

代碼如下:
package com.nz;
import com.nz.pojo.User;
public class EncapsulationDemo {
public static void main(String[] args) {
User user = new User();
user.setUsername("太子爺哪吒");
user.setPassword("520");
System.out.println("username: " + user.getUsername() + "-----------"
+ "password: " + user.getPassword());
}
}
執(zhí)行結(jié)果如下:
username:太子爺哪吒-----------password520
1.5 小結(jié)
封裝實(shí)際上是將類的某些信息隱藏在類的內(nèi)部,不允許外部程序直接訪問,而是通過該類提供的方法來實(shí)現(xiàn)對(duì)隱藏信息的訪問和操作。就是把我們想提供給外界的一些方法給暴露出來,以便外界能調(diào)用到我們。
二. 繼承
2.1 繼承的介紹
繼承是java面向?qū)ο缶幊碳夹g(shù)的一塊基石,因?yàn)樗试S創(chuàng)建分等級(jí)層次的類。描述的是事物之間的所屬關(guān)系,這種關(guān)系是:is-a 的關(guān)系。
繼承:就是子類繼承父類的屬性和行為,使得子類對(duì)象(實(shí)例)可以直接具有與父類相同的屬性、相同的行為。子類可以直接訪問父類中的非私有的屬性和行為。
2.2 生活中的繼承

兔子和長(zhǎng)頸鹿屬于食草動(dòng)物類,老虎和獅子屬于食肉動(dòng)物類。而食草動(dòng)物和食肉動(dòng)物又是屬于動(dòng)物類。
那是不是兔子、長(zhǎng)頸鹿、老虎、獅子都屬于動(dòng)物類呢?答案是沒錯(cuò)滴!雖然食草動(dòng)物和食肉動(dòng)物都是屬于動(dòng)物,但是兩者的屬性和行為上有差別,所以子類會(huì)具有父類的一般特性也會(huì)具有自身的特性。我們就可以再多個(gè)類中存在相同屬性和行為時(shí),我們可以將這些內(nèi)容抽取到單獨(dú)一個(gè)類中,那么多個(gè)類無需再定義這些屬性和行為,只要繼承那一個(gè)類即可。
2.3 繼承的好處
- 提高代碼的復(fù)用性(減少代碼冗余,相同代碼重復(fù)利用)。
- 使類與類之間產(chǎn)生了關(guān)系。
- 子類擁有父類非 private 的屬性、方法。
- 子類可以擁有自己的屬性和方法,即子類可以對(duì)父類進(jìn)行擴(kuò)展。
- 子類可以用自己的方式實(shí)現(xiàn)父類的方法。
- 提高了類之間的耦合性(繼承的缺點(diǎn),耦合度高就會(huì)造成代碼之間的聯(lián)系越緊密,代碼獨(dú)立性越差)。
- Java 的繼承是單繼承,但是可以多重繼承,單繼承就是一個(gè)子類只能繼承一個(gè)父類,多重繼承就是,例如 B 類繼承 A 類,C 類繼承 B 類,所以按照關(guān)系就是 B 類是 C 類的父類,A 類是 B 類的父類,這是 Java 繼承區(qū)別于 C++ 繼承的一個(gè)特性。
2.4 繼承的格式
在Java當(dāng)中會(huì)通過extends關(guān)鍵字可以申明一個(gè)類是從另外一個(gè)類繼承而來的,一般形式如下:
class 父類 {
}
class 子類 extends 父類 {
}
需要注意一點(diǎn): Java 不支持多繼承,但支持多重繼承。就如下:
class A {
}
class B extends A { (對(duì)的)
}
class C extends A, B { (錯(cuò)的)
}
class C extends B { (對(duì)的)
}

頂層父類是Object類。所有的類默認(rèn)繼承Object,作為父類。
2.5 繼承的demo
- 編寫一個(gè)父類極其對(duì)應(yīng)的子類信息
結(jié)構(gòu)如下:

代碼如下:
父類Person:
package com.nz.pojo;
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;
}
}
子類Student沒有額外的屬性和方法:
package com.nz.pojo;
/**
* 繼承了Person特有的name, age,
* 沒有額外的獨(dú)有屬性和方法
*/
public class Student extends Person{
}
子類Teacher多了一個(gè)工資的屬性和獨(dú)有的教書方法:
package com.nz.pojo;
/**
* 繼承了Person特有的name, age,
* 多了自己獨(dú)有的工資屬性還有獨(dú)有的教書方法
*/
public class Teacher extends Person{
// 工資
private double salary ;
// 特有方法
public void teach(){
System.out.println("老師在認(rèn)真教書!");
}
public double getSalary() {
return salary;
}
public void setSalary(double salary) {
this.salary = salary;
}
}
編寫測(cè)試代碼:
package com.nz;
import com.nz.pojo.Student;
import com.nz.pojo.Teacher;
public class InheritDemo {
public static void main(String[] args) {
Teacher teacher = new Teacher();
teacher.setName("太子爺哪吒");
teacher.setAge(18);
teacher.setSalary(1999.99);
System.out.println(teacher.getName());
System.out.println(teacher.getAge());
System.out.println(teacher.getSalary());
teacher.teach();
Student student = new Student();
student.setName("哪吒");
student.setAge(12);
//student.setSalary(1999.99); // student沒有工資屬性,報(bào)錯(cuò)!
System.out.println(student.getName());
System.out.println(student.getAge());
}
}
結(jié)果如下:
太子爺哪吒
18
1999.99
老師在認(rèn)真教書!
哪吒
12
從結(jié)果來看,子類繼承父類,就可以直接得到父類的成員變量和方法。而子類可以編寫一些特有的屬性和方法,但是是否可以繼承所有成分呢?
2.6 子類不能繼承的內(nèi)容
并不是父類的所有內(nèi)容都可以給子類繼承的:
2.6.1 super 與 this 關(guān)鍵字
這里先將這兩個(gè)關(guān)鍵字,super和this在繼承關(guān)系中,運(yùn)用比較頻繁。
- super關(guān)鍵字:我們可以通過super關(guān)鍵字來實(shí)現(xiàn)對(duì)父類成員的訪問,用來引用當(dāng)前對(duì)象的父類。
- this關(guān)鍵字:指向自己本類的引用。
super和this完整的用法如下:
this.成員變量 -- 本類的 super.成員變量 -- 父類的 this.成員方法名() -- 本類的 super.成員方法名() -- 父類的
具體演示,創(chuàng)建測(cè)試InheritDemo2:
package com.nz;
public class InheritDemo2 {
public static void main(String[] args) {
Animal a = new Animal();
a.eat();
Cat cat = new Cat();
cat.eatFish();
}
}
class Animal {
void eat() {
System.out.println("animal : eat");
}
}
class Cat extends Animal {
void eat() {
System.out.println("cat : eat");
}
void eatFish() {
this.eat(); // this 調(diào)用自己的方法
super.eat(); // super 調(diào)用父類方法
}
}
調(diào)用結(jié)果如下:
animal : eat
cat : eat
animal : eat
注意:
子類的每個(gè)構(gòu)造方法中均有默認(rèn)的super(),調(diào)用父類的空參構(gòu)造。手動(dòng)調(diào)用父類構(gòu)造會(huì)覆蓋默認(rèn)的super()。
super() 和 this() 都必須是在構(gòu)造方法的第一行,所以不能同時(shí)出現(xiàn)。
2.6.2 構(gòu)造器不能被繼承
- 子類不能繼承父類的構(gòu)造器(構(gòu)造方法或者構(gòu)造函數(shù)),它只是調(diào)用(隱式或顯式)。因?yàn)樽宇愑凶约旱臉?gòu)造器。值得注意的是子類可以繼承父類的私有成員(成員變量,方法),只是子類無法直接訪問而已,可以通過
getter/setter方法訪問父類的private成員變量。 - 如果父類的構(gòu)造器帶有參數(shù),則必須在子類的構(gòu)造器中顯式地通過
super關(guān)鍵字調(diào)用父類的構(gòu)造器并配以適當(dāng)?shù)膮?shù)列表。 - 如果父類構(gòu)造器沒有參數(shù),則在子類的構(gòu)造器中不需要使用
super關(guān)鍵字調(diào)用父類構(gòu)造器,系統(tǒng)會(huì)自動(dòng)調(diào)用父類的無參構(gòu)造器。
演示過程:
package com.nz;
public class InheritDemo3 {
public static void main(String[] args) {
System.out.println("------Teacher 類繼承------");
Teacher teacher = new Teacher();
Teacher teacher2 = new Teacher("張三");
System.out.println("------Student 類繼承------");
Student student = new Student();
Student student2 = new Student("張三三");
}
}
// 父類
class Person {
private String name;
Person(){
System.out.println("調(diào)用了父類的無參構(gòu)造器: Person()");
}
Person(String name) {
System.out.println("調(diào)用了父類的帶參構(gòu)造器: Person(String name)");
this.name = name;
}
}
// Teacher子類繼承Person
class Teacher extends Person{
private String name;
Teacher(){
// 自動(dòng)調(diào)用父類的無參數(shù)構(gòu)造器 因?yàn)闀?huì)有默認(rèn)super();
System.out.println("Teacher");
}
public Teacher(String name){
super("太子爺哪吒"); // 調(diào)用父類中帶有參數(shù)的構(gòu)造器
System.out.println("Teacher(String name):"+name);
this.name = name;
}
}
// Student子類繼承Person
class Student extends Person{
private String name;
Student(){
super("heihei"); // 調(diào)用父類中帶有參數(shù)的構(gòu)造器
System.out.println("SubClass2");
}
public Student(String name){ // 自動(dòng)調(diào)用父類的無參數(shù)構(gòu)造器
System.out.println("Student(String name):"+name);
this.name = name;
}
}
結(jié)果如下:
------Teacher 類繼承------
調(diào)用了父類的無參構(gòu)造器: Person()
Teacher
調(diào)用了父類的帶參構(gòu)造器: Person(String name)
Teacher(String name):張三
------Student 類繼承------
調(diào)用了父類的帶參構(gòu)造器: Person(String name)
SubClass2
調(diào)用了父類的無參構(gòu)造器: Person()
Student(String name):張三三
2.6.3 final修飾的類不能被繼承
final 關(guān)鍵字主要用在三個(gè)地方:變量、方法、類。
- 修飾類:表示該類不能被繼承;
- 修飾方法:表示方法不能被重寫;
- 修飾變量:表示變量只能一次賦值以后值不能被修改(常量)。
final 的特點(diǎn):
- 對(duì)于一個(gè) final 變量,如果是基本數(shù)據(jù)類型的變量,則其數(shù)值一旦在初始 化之后便不能更改;如果是引用類型的變量,則在對(duì)其初始化之后便不 能再讓其指向另一個(gè)對(duì)象。
- 當(dāng)用 final 修飾一個(gè)類時(shí),表明這個(gè)類不能被繼承。final 類中的所有成員 方法都會(huì)被隱式地指定為 final 方法。
- 使用 final 方法的原因有兩個(gè)。第一個(gè)原因是把方法鎖定,以防任何繼承 類修改它的含義;第二個(gè)原因是效率。在早期的 Java 實(shí)現(xiàn)版本中,會(huì)將 final 方法轉(zhuǎn)為內(nèi)嵌調(diào)用。但是如果方法過于龐大,可能看不到內(nèi)嵌調(diào)用 帶來的任何性能提升(現(xiàn)在的 Java 版本已經(jīng)不需要使用 final方法進(jìn)行這些優(yōu)化了)。類中所有的 private 方法都隱式地指定為 final。
我們測(cè)試下修飾類后到底能不能繼承:
package com.nz;
public class InheritDemo4 {
}
// 父類
final class Fu {
private String name;
}
//class Zi extends Fu{ // Cannot inherit from final 'com.nz.Fu' 會(huì)顯示沒辦法繼承Fu
//}
結(jié)果:可以看出來在被final修飾的Fu類沒辦法繼承,而且在編譯期間就會(huì)報(bào)錯(cuò)了,沒辦法通過運(yùn)行。
2.7 方法重寫
2.7.1 介紹
子類中出現(xiàn)與父類一模一樣的方法時(shí)(返回值類型,方法名和參數(shù)列表都相同),會(huì)出現(xiàn)覆蓋效果,也稱為重寫或者復(fù)寫。聲明不變,重新實(shí)現(xiàn)。
2.7.2 使用場(chǎng)景與案例
發(fā)生在子父類之間的關(guān)系。
子類繼承了父類的方法,但是子類覺得父類的這方法不足以滿足自己的需求,子類重新寫了一個(gè)與父類同名的方法,以便覆蓋父類的該方法。
寫個(gè)測(cè)試案例:
package com.nz;
public class InheritDemo5 {
public static void main(String[] args) {
// 創(chuàng)建子類對(duì)象
Cat lanMao = new Cat();
// 調(diào)用父類繼承而來的方法
lanMao.run();
// 調(diào)用子類重寫的方法
lanMao.sing();
}
}
class Animal{
public void sing(){
System.out.println("動(dòng)物都可以唱歌!");
}
public void run(){
System.out.println("動(dòng)物都可以跑!");
}
}
class Cat extends Animal {
public void sing(){
System.out.println("我們一起學(xué)貓叫,一起喵喵喵!讓我們一起撒個(gè)嬌");
}
}
運(yùn)行結(jié)果:
動(dòng)物都可以跑!
我們一起學(xué)貓叫,一起喵喵喵!讓我們一起撒個(gè)嬌
可以看出,藍(lán)貓調(diào)用了重寫后的sing方法。
2.7.2 @Override重寫注解
- @Override:注解,重寫注解校驗(yàn)!
- 這個(gè)注解標(biāo)記的方法,就說明這個(gè)方法必須是重寫父類的方法,否則編譯階段報(bào)錯(cuò)。
- 建議重寫都加上這個(gè)注解,一方面可以提高代碼的可讀性,一方面可以防止重寫出錯(cuò)!
加上后的子類代碼形式如下:
class Cat extends Animal {
// 聲明不變,重新實(shí)現(xiàn)
// 方法名稱與父類全部一樣,只是方法體中的功能重寫了!
@Override
public void sing(){
System.out.println("我們一起學(xué)貓叫,一起喵喵喵!讓我們一起撒個(gè)嬌");
}
}
2.7.3 注意事項(xiàng)
- 方法重寫是發(fā)生在子父類之間的關(guān)系。
- 子類方法覆蓋父類方法,必須要保證權(quán)限大于等于父類權(quán)限。
- 子類方法覆蓋父類方法,返回值類型、函數(shù)名和參數(shù)列表都要一模一樣。
總結(jié)
這篇文章就到這里了,如果這篇文章對(duì)你也有所幫助,希望您能多多關(guān)注腳本之家的更多內(nèi)容!
相關(guān)文章
基礎(chǔ)不牢,地動(dòng)山搖,Java基礎(chǔ)速來刷刷
基礎(chǔ)不牢,地動(dòng)山搖,快來一起學(xué)習(xí)一下基礎(chǔ)吧,不斷地學(xué)習(xí)就算是基礎(chǔ)也會(huì)有新的認(rèn)知和收獲,加油2021-08-08
AQS加鎖機(jī)制Synchronized相似點(diǎn)詳解
這篇文章主要為大家介紹了AQS加鎖機(jī)制Synchronized相似點(diǎn)詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-10-10
java統(tǒng)計(jì)字符串單詞個(gè)數(shù)的方法解析
在一些項(xiàng)目中可能需要對(duì)一段字符串中的單詞進(jìn)行統(tǒng)計(jì),本文在這里分享了一個(gè)簡(jiǎn)單的demo,有需要的朋友可以拿去看一下2017-01-01
Java設(shè)計(jì)模式之享元模式實(shí)例詳解
這篇文章主要介紹了Java設(shè)計(jì)模式之享元模式,結(jié)合實(shí)例形式詳細(xì)分析了享元模式的概念、功能、定義及使用方法,需要的朋友可以參考下2018-04-04
Java語(yǔ)言實(shí)現(xiàn)簡(jiǎn)單FTP軟件 FTP軟件遠(yuǎn)程窗口實(shí)現(xiàn)(6)
這篇文章主要為大家詳細(xì)介紹了Java語(yǔ)言實(shí)現(xiàn)簡(jiǎn)單FTP軟件,F(xiàn)TP軟件遠(yuǎn)程窗口的實(shí)現(xiàn)方法,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-03-03
Java中獲取類路徑classpath的簡(jiǎn)單方法(推薦)
下面小編就為大家?guī)硪黄狫ava中獲取類路徑classpath的簡(jiǎn)單方法(推薦)。小編覺得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2016-09-09
idea如何關(guān)閉頁(yè)面顯示的瀏覽器圖標(biāo)
這篇文章主要介紹了idea如何關(guān)閉頁(yè)面顯示的瀏覽器圖標(biāo)問題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-07-07

