java的知識點12——==和equals方法、 super關鍵字、 繼承樹追溯、封裝的作用和含義、封裝的實現—使用訪問控制符、封裝的使用細節
==和equals方法
“==”代表比較雙方是否相同。如果是基本型別則表示值相等,如果是引用型別則表示地址相等即是同一個物件。
Object 的 equals 方法預設就是比較兩個物件的hashcode,是同一個物件的引用時返回 true 否則返回 false。但是,我們可以根據我們自己的要求重寫equals方法。
equals方法測試和自定義類重寫equals方法
JDK提供的一些類,如String、Date、包裝類等,重寫了Object的equals方法,呼叫這些類的equals方法, x.equals (y) ,當x和y所引用的物件是同一類物件且屬性內容相等時(並不一定是相同物件)
package cn.dym.cl; class Person{ int id; String name; public Person(int id, String name) { super(); this.id = id; this.name = name; } public boolean equals(Object obj) { if(obj==null) { return false; }else { if(obj instanceof Person) { Person c=(Person) obj; if(c.id==this.id) { return true; } } } return false; } } public class TestEquals { public static void main(String[] args) { Person p1=new Person(123,"止小兮"); Person p2=new Person(123,"止兮"); System.out.println(p1==p2); System.out.println(p1.equals(p2)); String s1=new String("蒼小凌"); String s2=new String("蒼小凌"); System.out.println(s1==s2); System.out.println(s1.equals(s2)); } }
super關鍵字
super是直接父類物件的引用。可以通過super來訪問父類中被子類覆蓋的方法或屬性。
使用super呼叫普通方法,語句沒有位置限制,可以在子類中隨便呼叫。
若是構造方法的第一行程式碼沒有顯式的呼叫super(...)或者this(...);那麼Java預設都會呼叫super(),含義是呼叫父類的無引數構造方法。這裡的super()可以省略。super()永遠位於構造器的第一句
注: ctrl+T 快捷鍵為檢視繼承樹
super關鍵字的使用
package cn.dym.cl; class FatherClass{ public int value; public void f() { value=100; System.out.println("FatherClass.value="+value); } } class ChildClass extends FatherClass{ public int value; public void f() { super.f(); value=200; System.out.println("ChildClass.value="+value); System.out.println(value); System.out.println(super.value); } } public class TestSuper01 { public static void main(String[] args) { new ChildClass().f(); } }
繼承樹追溯
屬性/方法查詢順序:(比如:查詢變數h)
1. 查詢當前類中有沒有屬性h
2. 依次上溯每個父類,檢視每個父類中是否有h,直到Object
3. 如果沒找到,則出現編譯錯誤。
4. 上面步驟,只要找到h變數,則這個過程終止。
構造方法呼叫順序:
構造方法第一句總是:super(…)來呼叫父類對應的構造方法。所以,流程就是:先向上追溯到Object,然後再依次向下執行類的初始化塊和構造方法,直到當前子類為止。
注:靜態初始化塊呼叫順序,與構造方法呼叫順序一樣,不再重複。
構造方法向上追溯執行測試
package cn.dym.cl;
class FatherClass1{
public FatherClass1() {
System.out.println("建立FatherClass");
}
}
class ChildClass1 extends FatherClass1{
public ChildClass1() {
System.out.println("建立ChildClass");
}
}
public class TestSuper02 {
public static void main(String[] args) {
System.out.println("開始建立一個ChildClass物件……");
new ChildClass1();
}
}
封裝的作用和含義
程式設計要追求“高內聚,低耦合”。 高內聚就是類的內部資料操作細節自己完成,不允許外部干涉;低耦合是僅暴露少量的方法給外部使用,儘量方便外部呼叫。
程式設計中封裝的具體優點:
1. 提高程式碼的安全性。
2. 提高程式碼的複用性。
3. “高內聚”:封裝細節,便於修改內部程式碼,提高可維護性。
4. “低耦合”:簡化外部呼叫,便於呼叫者使用,便於擴充套件和協作。
沒有封裝的程式碼會出現一些問題
package cn.dym01;
class Person{
String name;
int age;
@Override
public String toString() {
return "Person [name="+name+",age="+age+"]";
}
}
public class Test {
public static void main(String[] args) {
Person p=new Person();
p.name="小紅";
p.age=-45; //年齡可以通過這種方式隨意賦值,沒有任何限制
System.out.println(p);
}
}
注:我們都知道,年齡不可能是負數,也不可能超過130歲,但是如果沒有使用封裝的話,便可以給年齡賦值成任意的整數,這顯然不符合我們的正常邏輯思維。
如果使用封裝,我們只需要稍微修改下Person類的setAge()方法即可,而無需修改使用了該類的客戶程式碼。
封裝的實現—使用訪問控制符
Java是使用“訪問控制符”來控制哪些細節需要封裝,哪些細節需要暴露的。Java中4種“訪問控制符”分別為private、default、protected、public,它們說明了面向物件的封裝性,所以我們要利用它們儘可能的讓訪問許可權降到最低,從而提高安全性。
訪問許可權修飾符
1. private 表示私有,只有自己類能訪問
2. default表示沒有修飾符修飾,只有同一個包的類能訪問
3. protected表示可以被同一個包的類以及其他包中的子類訪問
4. public表示可以被該專案的所有包中的所有類訪問
封裝的使用細節
類的屬性的處理:
1. 一般使用private訪問許可權。
2. 提供相應的get/set方法來訪問相關屬性,這些方法通常是public修飾的,以提供對屬性的賦值與讀取操作(注意:boolean變數的get方法是is開頭!)。
3. 一些只用於本類的輔助性方法可以用private修飾,希望其他類呼叫的方法用public修飾。
JavaBean的封裝例項
package cn.dym02;
public class Person {
//屬性一般使用private修飾
private String name;
private int age;
private boolean flag;
//為屬性提供public修飾的set/get方法
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 boolean isFlag() { //注:boolean型別的屬性get方法是is開頭的
return flag;
}
public void setFlag(boolean flag) {
this.flag=flag;
}
}
封裝的使用
package cn.dym02;
class Person{
private String name;
private int age;
public Person() {
}
public Person(String name, int age) {
super();
this.name = name;
//this.age = age; //age不能在構造方法中直接賦值,應該呼叫setAge方法
setAge(age);
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
//在賦值前先判斷年齡是否合法
if(age>130||age<0) {
this.age=18;//不合法賦預設值為18
}else {
this.age = age;
}
}
@Override
public String toString() {
return "Person [name="+name+",age="+age+"]";
}
}
public class Test2 {
public static void main(String [] args) {
Person p1=new Person();
//p.name="小兮"; //編譯錯誤//因為是私有屬性,不能直接訪問
p1.setName("小兮");
p1.setAge(-45);
System.out.println(p1);
Person p2=new Person("小凌",300);
System.out.println(p2);
}
}