java面向對象四大特徵(上)


java面向對象有4大特徵,按出現順序分別是,封裝、繼承、抽象、和多態。本文講述封裝和繼承的特性及代碼演示。

封裝
是指隱藏對象的不需要對外提供的屬性和實現細節,僅對外提供公共訪問方式。

具體封裝時,可以將需要隱藏的屬性和方法用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()語句;
當父類中沒有空參數的構造函數時,子類中必須通過superthis語句來指定要訪問的父類中的構造函數
---之所以可以用this語句的原因:this語句代表調用子類的某個構造函數,該構造函數中如果沒有this語句時肯定有super語句,這樣也就訪問了父類的構造函數,而子類所有構造函數中肯定有一個構造函數中沒有this語句(否則成了構造函數間完全相互調用了,死循環),所以子類的每個構造函數中都會直接或間接調用父類構造函數;this語句和super語句都是放在構造函數第一行的,2者不能並存,只能2選1.

子父類函數繼承的特性:覆蓋(重寫)
當子父類中出現一模一要函數時,當子類對象調用此函數,會運行子類函數的內容,就像父類函數被覆蓋了一樣,這種情況就是覆蓋。
覆蓋注意事項:
子類覆蓋父類,必須保證子類函數權限大於父類函數權限,否則編譯失敗;父類的private函數對子類是不可見的,所以一般不覆蓋。
靜態只能覆蓋靜態。






發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章