回顧
一、面向?qū)ο蟮娜筇攸c(diǎn)
1.封裝的含義
2.繼承的含義
3.多態(tài)的含義
二、封裝的實(shí)現(xiàn)
1.Java訪問(wèn)權(quán)限修飾符
學(xué)習(xí)小結(jié)
2.封裝問(wèn)題引例
package com.Javastudy2;
/**
* @author Y.W.
* @date 2017年8月20日 上午10:49:26
* @Description TODO 類的封裝性使用引例
*/
public class P281_12_1 {
public static void main(String[] args) {
MyCat aCat = new MyCat();
aCat.weight = -10.0f; // 設(shè)置MyCat的屬性值
float temp = aCat.weight; // 獲取MyCat的屬性值
System.out.println("The weight of a cat is:" + temp);
}
}
class MyCat{
public float weight; // 通過(guò)public修飾符,開放MyCat的屬性給外界
MyCat(){} // 無(wú)參構(gòu)造方法,無(wú)實(shí)際含義
}
運(yùn)行結(jié)果:

引例把屬性(數(shù)據(jù))暴露出來(lái),讓外界可以任意接觸甚至改變它。運(yùn)行結(jié)果對(duì)于程序是沒(méi)有錯(cuò)誤的,賦值是合法的單精度浮點(diǎn)數(shù),但是現(xiàn)實(shí)中不可能有重量為負(fù)數(shù)的貓。
3.類的封裝實(shí)例
package com.Javastudy2;
/**
* @author Y.W.
* @date 2017年8月20日 上午11:04:25
* @Description TODO 類的封裝實(shí)例
*/
public class P282_12_2 {
public static void main(String[] args) {
MyCat2 aCat = new MyCat2();
aCat.weight = -10.0f; // 設(shè)置MyCat的屬性值
float temp = aCat.weight; // 獲取MyCat的屬性值
System.out.println("The weight of a cat is:" + temp);
}
}
class MyCat2 {
private float weight; // 通過(guò)private修飾符,封裝屬性
MyCat2() {} // 無(wú)參構(gòu)造方法,無(wú)實(shí)際含義
}
運(yùn)行結(jié)果:

可以看到IDE已經(jīng)有報(bào)錯(cuò)了,編譯后同樣有報(bào)錯(cuò)信息。封裝后,外界無(wú)法訪問(wèn)私有屬性,若需要給這些屬性賦值,就需要存取屬性的公共接口。
package com.Javastudy2;
/**
* @author Y.W.
* @date 2017年8月20日 上午11:15:40
* @Description TODO 類私有屬性的Setter和Getter方法
*/
public class P283_12_3 {
public static void main(String[] args) {
MyCat3 aCat = new MyCat3();
aCat.SetWeight(-10f); // 設(shè)置MyCat的屬性值
float temp = aCat.GetWeight(); // 獲取MyCat的屬性值
System.out.println("The weight of a cat is:" + temp);
}
}
class MyCat3 {
private float weight; // 通過(guò)private修飾符,封裝MyCat的屬性
public void SetWeight(float wt) {
if (wt > 0) {
weight = wt;
} else {
System.out.println("weight設(shè)置非法(應(yīng)該>0)。\n 采用默認(rèn)值");
weight = 10.0f;
}
}
public float GetWeight() {
return weight;
}
}
運(yùn)行結(jié)果:

通常,對(duì)屬性設(shè)置的方法被命名為SetXxx(),其中Xxx為任意有意義的名稱,這類方法可被統(tǒng)稱為Setter方法,而對(duì)屬性設(shè)置的方法被命名為GetYyy(),其中Xxx為任意有意義的名稱,這類方法可被統(tǒng)稱為Getter方法
注:見得多的還是setXxx()和getYyy()名稱。
封裝屬性:
private 屬性類型 屬性名;
封裝方法:
private 方法返回類型 方法名稱(參數(shù));
package com.Javastudy2;
/**
* @author Y.W.
* @date 2017年8月20日 上午11:40:55
* @Description TODO 方法的封裝使用
*/
public class P284_12_4 {
public static void main(String[] args) {
MyCat4 aCat = new MyCat4();
aCat.SetWeight(-10f); // 設(shè)置MyCat的屬性值
float temp = aCat.GetWeight(); // 獲取MyCat的屬性值
System.out.println("The weight of a cat is:" + temp);
aCat.MakeSound(); // 會(huì)報(bào)錯(cuò)
}
}
class MyCat4 {
private float weight; // 通過(guò)private修飾符,封裝MyCat的屬性
public void SetWeight(float wt) {
if (wt > 0) {
weight = wt;
} else {
System.out.println("weight設(shè)置非法(應(yīng)該>0)。\n 采用默認(rèn)值");
weight = 10.0f;
}
}
public float GetWeight() {
return weight;
}
private void MakeSound() {
System.out.println("Meow meow, my weight is " + weight);
}
}
運(yùn)行結(jié)果:

封裝的MakeSound() 是無(wú)法外部調(diào)用的。
若類中某些數(shù)據(jù)在初始化時(shí)不想再被外界修改,則可以使用構(gòu)造方法配合私有化的Setter函數(shù)來(lái)實(shí)現(xiàn)該數(shù)據(jù)的封裝,如下例所示。
package com.Javastudy2;
/**
* @author Y.W.
* @date 2017年8月20日 上午11:52:43
* @Description TODO 使用構(gòu)造方法實(shí)現(xiàn)數(shù)據(jù)的封裝
*/
public class P286_12_5 {
public static void main(String[] args) {
MyCat5 aCat = new MyCat5(12, -5); // 通過(guò)公有接口設(shè)置屬性值
float ht = aCat.GetHeight(); // 通過(guò)公有接口獲取屬性值height
float wt = aCat.GetWeight(); // 通過(guò)公有接口獲取屬性值weight
System.out.println("The height of cat is " + ht);
System.out.println("The weight of cat is " + wt);
}
}
class MyCat5 {
// 創(chuàng)建私有化屬性weight,height
private float weight;
private float height;
// 在構(gòu)造方法中初始化私有變量
public MyCat5(float height, float weight) {
SetHeight(height); // 調(diào)用私有方法設(shè)置height
SetWeight(weight); // 調(diào)用私有方法設(shè)置weight
}
// 通過(guò)private修飾符,封裝MyCat的SetWeight方法
private void SetWeight(float wt) {
if (wt > 0) {
weight = wt;
} else {
System.out.println("weight設(shè)置非法(應(yīng)該>0)。\n 采用默認(rèn)值10");
weight = 10.0f;
}
}
// 通過(guò)private修飾符,封裝MyCat的SetHeight方法
private void SetHeight(float ht) {
if (ht > 0) {
height = ht;
} else {
System.out.println("height設(shè)置非法(應(yīng)該>0)。\n 采用默認(rèn)值20");
height = 20.0f;
}
}
// 創(chuàng)建公有方法GetWeight()作為與外界的通信接口
public float GetWeight() {
return weight;
}
// 創(chuàng)建公有方法GetHeight()作為與外界的通信接口
public float GetHeight() {
return height;
}
}
運(yùn)行結(jié)果:

4.封裝問(wèn)題的總結(jié)
在Java中,最基本的封裝單元是類,類是基于面向?qū)ο笏枷刖幊陶Z(yǔ)言的基礎(chǔ),程序員可以把具有相同業(yè)務(wù)性質(zhì)的代碼封裝在一個(gè)類里,通過(guò)接口方法向外部提供服務(wù),同時(shí)向外部代碼屏蔽類里的服務(wù)的具體實(shí)現(xiàn)方法。
數(shù)據(jù)封裝的最重要的目的是在于實(shí)現(xiàn)“信息隱藏(Information Hidding)”。
封裝性是面向?qū)ο蟪绦蛟O(shè)計(jì)的原則之一,使程序達(dá)到強(qiáng)內(nèi)聚(許多功能盡量在類的內(nèi)部獨(dú)立完成,不讓外界干預(yù)),弱耦合(提供給外部盡量少的方法調(diào)用)的最終目標(biāo)。
5.實(shí)現(xiàn)封裝應(yīng)該注意的問(wèn)題
封裝的數(shù)據(jù)是引用數(shù)據(jù)時(shí),如下例。
package com.Javastudy2;
import java.util.ArrayList;
/**
* @author Y.W.
* @date 2017年8月20日 下午12:59:40
* @Description TODO 返回引用數(shù)據(jù)時(shí)應(yīng)該注意的問(wèn)題
*/
public class P288_12_6 {
public static void main(String[] args) {
TestReturn testReturn = new TestReturn();
// 得到該私有數(shù)據(jù),不是副本,而是引用
ArrayList<Integer> intArray = testReturn.getIntArray();
System.out.println(intArray.size());
intArray.add(4); // 修改其值
ArrayList<Integer> intArray2 = testReturn.getIntArray();
// 該類內(nèi)部的私有變量已經(jīng)被改變
System.out.println("在外部修改其私有變量以后其長(zhǎng)度為:" + intArray2.size());
}
}
class TestReturn {
// 定義一個(gè)私有的ArrayList
private ArrayList<Integer> intArray = new ArrayList<Integer>();
public TestReturn() {
// 通過(guò)構(gòu)造方法對(duì)其進(jìn)行初始化
intArray.add(1);
intArray.add(2);
intArray.add(3);
}
// 設(shè)置私有數(shù)據(jù)對(duì)應(yīng)的get函數(shù)
ArrayList<Integer> getIntArray() {
return intArray;
}
}
運(yùn)行結(jié)果:

封裝的變量被改變了。
解決辦法:
如果返回值是對(duì)數(shù)據(jù)的引用則顯示創(chuàng)建該數(shù)據(jù)的副本,然后返回該副本。
三、繼承的實(shí)現(xiàn)
1.繼承的基本概念
Java支持單繼承和多層繼承,但不支持多繼承。
格式:
class 子類名 extends 父類

語(yǔ)法:
class 父類{
// 定義父類
}
class 子類 extends 父類{
// 用extends關(guān)鍵字實(shí)現(xiàn)類的繼承
}
Java只繼承父類的公有屬性和公有方法,以及隱含(不可見)的私有屬性。
2.繼承問(wèn)題的引出
package com.Javastudy2;
/**
* @author Y.W.
* @date 2017年8月20日 下午2:28:12
* @Description TODO 繼承的引出
*/
public class P291_12_7 {
public static void main(String[] args) {
// 實(shí)例化一個(gè)Person對(duì)象
Person11 person = new Person11("張三", 21);
person.speak();
// 實(shí)例化一個(gè)Student對(duì)象
Student student = new Student("李四", 20, "HAUT");
student.speak();
student.study();
}
}
class Person11 {
String name;
int age;
Person11(String name, int age) {
this.age = age;
this.name = name;
}
void speak() {
System.out.println("我的名字叫:" + name + "我" + age + "歲");
}
}
class Student {
String name;
int age;
String school;
Student(String name, int age, String school) {
this.age = age;
this.name = name;
this.school = school;
}
void speak() {
System.out.println("我的名字叫:" + name + "我" + age + "歲");
}
void study() {
System.out.println("我在" + school + "讀書");
}
}
運(yùn)行結(jié)果:

3.實(shí)現(xiàn)繼承
上例代碼略顯臃腫,可以改造。
package com.Javastudy2;
/**
* @author Y.W.
* @date 2017年8月20日 下午2:50:21
* @Description TODO 實(shí)現(xiàn)繼承
*/
public class P293_12_8 {
public static void main(String[] args) {
// 實(shí)例化一個(gè)Student對(duì)象
Student1 s = new Student1("張三", 25, "工業(yè)大學(xué)");
s.speak();
s.study();
}
}
class Person12 {
String name;
int age;
Person12(String name, int age) {
this.age = age;
this.name = name;
}
void speak() {
System.out.println("我的名字叫:" + name + "我" + age + "歲");
}
}
class Student1 extends Person12 { // 繼承Person12
String school;
Student1(String name, int age, String school) {
super(name, age);
this.school = school;
}
void study() {
System.out.println("我在" + school + "讀書");
}
}

運(yùn)行結(jié)果:

4.繼承的限制
限制1
Java中不允許多重繼承,但是可以使用多層繼承。
多重繼承,指一個(gè)類同時(shí)繼承多個(gè)父類的行為和特征功能。
class A{
}
class B{
}
class C extends A,B{ // 錯(cuò)誤:多重繼承
}

多層繼承:指一個(gè)類B可以繼承來(lái)自類A,而另一個(gè)類C又繼承自B,像這樣在繼承層上單項(xiàng)繼承多個(gè)類。
class A{
}
class B extends A{
}
class C extends B{
}

注:編寫代碼時(shí),多層繼承最好不要超過(guò)三層。
限制2
從父類繼承的私有成員,不能被子類直接使用。
限制3
子類在進(jìn)行對(duì)象實(shí)例化時(shí),從父類繼承而來(lái)的數(shù)據(jù)成員需要先調(diào)用父類的構(gòu)造方法來(lái)初始化,然后再用子類的構(gòu)造方法來(lái)初始化本地的數(shù)據(jù)成員。
限制4
被final修飾的類不能再被繼承。
final在Java之中稱為終結(jié)器。
package com.Javastudy2;
/**
* @author Y.W.
* @date 2017年8月20日 下午3:33:43
* @Description TODO 繼承的final限制
*/
public class P296_12_9 {
public static void main(String[] args) {
SubClass subClass = new SubClass();
}
}
// 定義被final修飾的父類
final class SuperClass {
String name;
int age;
}
// 子類SubClass繼承SuperClass
class SubClass extends SuperClass {
// do something
}

思考
一下看了好幾頁(yè),絕對(duì)超出我的臨時(shí)緩存了,腦瓜子有點(diǎn)疼。繼承性還要繼續(xù)加強(qiáng)。
記于2017年8月20日