封裝
是指隱藏對象的不需要對外提供的屬性和實現細節,僅對外提供公共訪問方式。
具體封裝時,可以將需要隱藏的屬性和方法用private修飾,private修飾的成員變量和成員方法只在本類範圍內有效,類以外即使創建了對象了也不能直接訪問,因此對私有變量,需對外提供訪問方法,一般是get和set函數。
對外提供的訪問方式中,可以對訪問數據加入邏輯判斷等語句,有利於數據的安全使用,也提高了代碼的健壯性。
封裝不是私有,私有僅僅是封裝的一種表現形式,私有是最小權限,通過其它的權限設定也可以達到封裝。
這裏總結下類和類中成員的修飾符:
類的修飾符:
default 同包內可在其它類中訪問,同包類可在其子類中訪問;
public 擁有最大權限,繼承,可以其它任何地方訪問;
final 被final修飾的類不能被繼承。
類成員變量和成員函數的權限修飾符:
private 類訪問權限:本類內部可以訪問,不能繼承到子類,實例對象也不能訪問;
default 什麼都不寫,就是default權限,也叫包訪問權限,本類內部可以訪問,同包其他類也可以訪問,同包內可繼承;
protected 子類訪問權限,本類內部可以訪問,同包其他類也可以訪問, 可繼承,同包及不同包的子類都可以訪問;
public 公共訪問權限:任何地方都可以訪問,能繼承到子類。
通過下面這個例子演示類和類成員的權限問題:
package itcast.A;
public class Person{
public String name;
private int age;
protected int height;
String sex;
public Person(String name,int age,int height,String sex){
this.name=name;
this.age=age;
this.height=height;
this.sex=sex;
}
public int getAge(){ //對外提供訪問私有成員age的方法
return this.age;
}
}
class Student extends Person //Student類是default權限
{
public String birthday;
private int paiming;
double score;
Student(String name,int age,int height,String sex){
super(name, age,height,sex);
}
void show(){
System.out.println(name+" "+" "+height+" "+sex);/*子類中可以訪問default和protected變量,但是不能訪問private變量,所以此處不能打印年齡*/
}
}
package itcast.A;
public class QXDemoA {
public static void main(String[] args) {
Person p=new Person("lisi",21,170,"male");
/*System.out.println("lisi年齡:"+p.age);編譯不通過,private變量不能在對象中訪問*/
System.out.println("lisi身高,性別:"+p.height+","+p.sex);/*default和protected成員可由對象訪問*/
Student s=new Student("zhangsan",19,172,"female"); /*同包可以訪問default權限的Student類*/
s.show();//default成員函數可以在同包其它類中訪問
}
}
package itcast.B;
import itcast.A.Person;
class Worker extends Person{
public Worker(String name,int age,int height,String sex){
super(name,age,height,sex);
}
void display(){
System.out.println(name+" "+height);/*protected成員變量可以跨包在子類中訪問,但是default成員不能跨包在子類中繼承,此外不能打印sex*/
}
}
public class QXDemoB {
public static void main(String[] args) {
Person pp=new Person("wangwu",17,160,"male");/*Person類構造函數是public的,可以跨包訪問*/
/*System.out.println(pp.name+" "+pp.sex);編譯不通過,default成員變量不能跨包在其它類中訪問*/
/*System.out.println(pp.name+" "+pp.height);編譯不通過,protected成員變量不能跨包在非子類中訪問*/
}
}
繼承
類與類之間有is a的所屬關係時,可以讓子類繼承父類;繼承可以提高代碼的複用性。
子類繼承父類時,類中成員變量和成員函數都呈現出什麼特性呢?
先上一個簡單程序,繼承時子父類變量的特點都體現在代碼註釋中了:
class Fu{
int num=4;
Fu(){
System.out.println("Fu run");
}
Fu(int num){
this.num=num;
}
}
class Zi extends Fu{
int num=6;
Zi(){
System.out.println("Zi run");
System.out.println(num);/*此處num等價於this.num;
如果將Zi類中的num註釋掉,此處的num可以理解爲super.num,也可以理解爲this.num,
因爲Zi類中繼承了父類的num屬性,num也是Zi類的成員; */
}
}
public class ExtendDemo1 {
public static void main(String[] args) {
Zi zi=new Zi();/* 創建Zi對象時,先加載Fu.class文件,再加載Zi.class文件;
在zi對象所在的堆內存中會給父類的屬性num和子類的num都開闢空間,即使父類的num屬性是private的;
實際上,此時內存中只有Zi類對象,沒有Fu類對象,Zi類構造函數的super和this引用都是指向這個zi對象。
*/
}
}
該程序運行結果也說明了繼承時子父類構造函數的特點,運行結果是:
Fu run
Zi run
6
可見new Zi()時,父類的構造函數Fu()也會自動執行。實際上,父類中的數據子類可以直接獲取,所以子類對象在建立時,需要先查看父類中這些數據是如何進行初始化的,所以子類在對象初始化時,必須先訪問一下父類的構造函數。
構造函數繼承的特點:
子類的每一個構造函數內的第一行都有一句隱式super()語句;
當父類中沒有空參數的構造函數時,子類中必須通過super或this語句來指定要訪問的父類中的構造函數。
---之所以可以用this語句的原因:this語句代表調用子類的某個構造函數,該構造函數中如果沒有this語句時肯定有super語句,這樣也就訪問了父類的構造函數,而子類所有構造函數中肯定有一個構造函數中沒有this語句(否則成了構造函數間完全相互調用了,死循環),所以子類的每個構造函數中都會直接或間接調用父類構造函數;this語句和super語句都是放在構造函數第一行的,2者不能並存,只能2選1.
子父類函數繼承的特性:覆蓋(重寫)
當子父類中出現一模一要函數時,當子類對象調用此函數,會運行子類函數的內容,就像父類函數被覆蓋了一樣,這種情況就是覆蓋。
覆蓋注意事項:
子類覆蓋父類,必須保證子類函數權限大於父類函數權限,否則編譯失敗;父類的private函數對子類是不可見的,所以一般不覆蓋。
靜態只能覆蓋靜態。