第二十四章 封裝
作者:張子默
一、封裝概述
1、概述
面向對象編程語言是對客觀世界的模擬,客觀世界裏成員變量都是隱藏在對象內部的,外界無法直接操作和修改。封裝可以被認爲是一個屏障,防止該類的代碼和數據被其他類隨意訪問。要訪問該類的數據,必須通過指定的方式。適當的封裝可以讓代碼更容易理解與維護,也加強了代碼的安全性。
2、原則
將屬性隱藏起來,若需要訪問某個屬性,提供公共方法對其訪問。
3、實例
/*
面向對象三大特徵:封裝、繼承、多態
封裝在Java當中的表現
1、方法就是一種封裝
2、關鍵字private也是一種封裝
封裝就是將一些細節信息隱藏起來,對於外界不可見
*/
public class Demo01Methed {
public static void main(String[] args) {
int[] array = {5, 15, 25, 20 ,100};
int result = getMax(array);
System.out.println("最大值:" + result);
}
//給我一個數組,我還給你一個最大值
public static int getMax(int[] array) {
int max = array[0];
for(int i=1; i<array.length; i++) {
if(array[i]>max) {
max = array[i];
}
}
return max;
}
}
二、封裝的步驟
-
使用
private
關鍵字來修飾成員變量。 -
對需要訪問的成員變量,提供對應的一對
getXxx
方法、SetXxx
方法。
1、實例
/*
問題描述:定義Person的年齡時,無法阻止不合理的數值被設置進來。
解決方案:用private關鍵字將需要保護的成員變量進行修飾。
一旦使用了private進行修飾,那麼本類當中仍然可以隨意。但是!超出了本類範圍之外就不能再直接訪問了。
間接訪問private成員變量,就是定義一對兒Getter/Setter方法
命名規則:必須叫setXXX或者是getXxx
對於Getter來說,不能有參數,返回值類型和成員變量對應
對於Setter來說,不能有返回值,參數類型和成員變量對應
*/
public class Person {
String name; //姓名
private int age; //年齡
public void show() {
System.out.println("我叫:" + name + ",年齡:" + age);
}
//這個成員方法,專門用於向age設置數據
public void setAge(int num) {
if(num<100 && num>=9) {
age = num;
}else {
System.out.println("數據不合理!");
}
}
//這個成員方法,專門獲取age數據
public int getAge() {
return age;
}
}
public class Demo02Person {
public static void main(String[] args) {
Person person = new Person();
person.show();
person.name = "趙麗穎";
//person.age = 18; //直接訪問private內容,錯誤寫法!
person.setAge(-20);
person.show();
}
}
三、封裝的操作——private關鍵字
1、private的含義
-
private是一個權限修飾符,代表最小權限。
-
可以修飾成員變量和成員方法。
-
被private修飾後的成員變量和成員方法,只能在本類中才能訪問。
2、private的使用格式
private 數據類型 變量名;
-
使用
private
修飾成員變量,代碼如下:public class Student { private String name; private int age; }
-
提供
getXxx
方法/setXxx
方法,可以訪問成員變量,代碼如下:public class Student { private String name; private int age; public void setName(String n) { name = n; } public String getName() { return name; } public void setAge(int a) { age = a; } public int getAge() { return age; } }
3、實例
/*
對於基本類型當中的boolean值,Getter方法一定要寫成isXxx的形式,而setXxx規則不變。
*/
public class Student {
private String name; //姓名
private int age; //年齡
private boolean male; //是不是爺們兒
public void setMale(boolean b) {
male = b;
}
public boolean isMale() {
return male;
}
public void setName(String str) {
name = str;
}
public String getName() {
return name;
}
public void setAge(int num) {
age = num;
}
public int getAge() {
return age;
}
}
public class Demo03Student {
public static void main(String[] args) {
Student stu = new Student();
stu.setName("鹿晗");
stu.setAge(20);
stu.setMale(true);
System.out.println("姓名:" + stu.getName());
System.out.println("年齡:" + stu.getAge());
System.out.println("是不是爺們兒:" + stu.isMale());
}
}
四、封裝優化——this關鍵字
我們發現setXxx
方法中的形參名字並不符合見名知意的規定,那麼如果修改與成員變量名一致,是否就見名知意了呢?代碼如下:
public class Student {
private String name;
private int age;
public void setName(String name) {
name = name;
}
public void setAge(int age) {
age = age;
}
}
經過修改和測試,我們發現了新的問題,成員變量賦值失敗了。也就是說,在修改了setXxx()
的形參變量名後,方法並沒有給成員變量賦值!這是由於形參名與成員變量名重名,導致成員變量名被隱藏,方法無法訪問到成員變量從而賦值失敗。所以,我們只能使用this關鍵字來解決這個重名問題。
1、this的含義
this代表所在類的當前對象的引用(地址值),即對象自己的引用。
記住:方法被那個對象調用,方法中的this就代表那個對象。即誰在調用,this就代表誰。
2、this使用格式
this.成員變量名;
-
使用
this
修飾方法中的變量,解決成員變量被隱藏的問題,代碼如下:public class Student { private String name; private int age; public void setName(String name) { //name = name; this.name = name; } public String getName() { return name; } public void setAge(int age) { //age = age; this.age = age; } public int getAge() { return age; } }
小貼士:方法中只有一個變量名時,默認也是使用
this
修飾,可以省略不寫。
3、實例
/*
當方法的局部變量和類的成員變量重名的時候,根據"就近原則"優先使用局部變量。
如果需要訪問本類中的成員變量,需要使用格式:this.變量名
"通過誰調用的方法,誰就是this"
*/
public class Person1 {
String name; //我自己的名字
//參數who是對方的名字
//成員變量name是自己的名字
public void sayHello(String name) {
System.out.println(name + "你好!我是" + this.name);
System.out.println(this);
}
}
public class Demo04Person1 {
public static void main(String[] args) {
Person1 person = new Person1();
//設置我自己的名字
person.name = "王健林";
person.sayHello("王思聰");
System.out.println(person); //地址值
}
}
五、封裝優化——構造方法
當一個對象被創建的時候,構造方法用來初始化該對象,給對象的成員變量賦初始值。
小貼士:無論是否自定義構造方法,所有的類都有構造方法,因爲Java自動提供了一個無參數構造方法,一旦自己定義了構造方法,Java自動提供的默認無參數構造方法就會失效。
1、構造方法的定義格式
修飾符 構造方法名(參數列表) {
//方法體
}
構造方法的寫法上,方法名與它所在的類名相同。它沒有返回值,所以不需要返回值類型,甚至不需要void。使用構造方法後,代碼如下:
public class Student {
private String name;
private int age;
// 無參數構造方法
public Student() {}
// 有參數構造方法
public Student(String name,int age) {
this.name = name;
this.age = age;
}
}
2、注意事項
-
如果你不提供構造方法,系統會給出無參數構造方法。
-
如果你提供了構造方法,系統將不再提供無參數的構造方法。
-
構造方法是可以重載的,既可以定義參數,也可以不定義參數。
3、實例
/*
構造方法是專門用來創建對象的方法,當我們通過關鍵字new來創建對象時,其實就是在調用構造方法。
格式:
public 類名稱(參數類型 參數名稱) {
方法體
}
注意事項:
1、構造方法的名稱必須和所在的類名稱完全一樣,就連大小寫也要一樣
2、構造方法不要寫返回值類型,連void都不寫
3、構造方法不能return一個具體的返回值
4、如果沒有編寫任何構造方法,那麼編譯器將會默認贈送一個構造方法,沒有參數、方法體什麼事情都不做。
public Student1() {}
5、一旦編寫了至少一個構造方法,那麼編譯器將不再贈送。
6、構造方法也是可以重載的
重載:方法名稱相同,參數列表不同
*/
public class Student1 {
//成員變量
private String name;
private int age;
//無參數的構造方法
public Student1() {
System.out.println("無參構造方法執行啦!");
}
//全參數的構造方法
public Student1(String name, int age) {
this.name = name;
this.age = age;
System.out.println("全參構造方法執行啦!");
}
public void setName(String name) {
this.name = name;
}
public String getName() {
return name;
}
public void setAge(int age) {
this.age = age;
}
public int getAge() {
return age;
}
}
public class Demo05Student1 {
public static void main(String[] args) {
Student1 stu = new Student1(); //無參構造
System.out.println("==============");
Student1 stu1 = new Student1("趙麗穎", 20); //全參構造
System.out.println("姓名:" + stu1.getName() + ",年齡:" + stu1.getAge());
//如果需要改變對象當中的成員變量數據內容,仍然還需要使用setXxx方法
stu1.setAge(21); //改變年齡
System.out.println("姓名:" + stu1.getName() + ",年齡:" + stu1.getAge());
}
}
六、標準代碼——JavaBean
JavaBean
是Java語言編寫類的一種規範。符合JavaBean
的類,要求類必須是具體的和公共的,並且具有無參數的構造方法,提供用來操作成員變量的set
和get
方法。
public class ClassName{
//成員變量
//構造方法
//無參構造方法【必須】
//有參構造方法【建議】
//成員方法
//getXxx()
//setXxx()
}
編寫符合JavaBean
規範的類,以學生類爲例,標準代碼如下:
public class Student {
//成員變量
private String name;
private int age;
//構造方法
public Student() {}
public Student(String name,int age) {
this.name = name;
this.age = age;
}
//成員方法
publicvoid setName(String name) {
this.name = name;
}
public String getName() {
return name;
}
publicvoid setAge(int age) {
this.age = age;
}
publicint getAge() {
return age;
}
}
測試類,代碼如下:
public class TestStudent {
public static void main(String[] args) {
//無參構造使用
Student s= new Student();
s.setName("柳巖");
s.setAge(18);
System.out.println(s.getName()+"‐‐‐"+s.getAge());
//帶參構造使用
Student s2= new Student("趙麗穎",18);
System.out.println(s2.getName()+"‐‐‐"+s2.getAge());
}
}
1、實例
/*
一個標準的類通常要擁有下面四個組成部分:
1、所有的成員變量都要使用private關鍵字修飾
2、爲每一個成員變量編寫一對兒Getter/Setter方法
3、編寫一個無參數的構造方法
4、編寫一個全參數的構造方法
這樣標準的類也叫作Java Bean
*/
public class Student2 {
private String name; //姓名
private int age; //年齡
public Student2() {
}
public Student2(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 class Demo06Student2 {
public static void main(String[] args) {
Student2 stu = new Student2();
stu.setName("迪麗熱巴");
stu.setAge(20);
System.out.println("姓名:" + stu.getName() + ",年齡:" + stu.getAge());
System.out.println("===================");
Student2 stu1 = new Student2("古力娜扎", 21);
System.out.println("姓名:" + stu1.getName() + ",年齡:" + stu1.getAge());
stu1.setAge(22);
System.out.println("姓名:" + stu1.getName() + ",年齡:" + stu1.getAge());
}
}