一、封裝(encapsulation)
封裝性就是把類(對象)的屬性和行為結合成一個獨立的相同單位,并盡可能隱蔽類(對象)的內部細節,對外形成一個邊界,只保留有限的對外接口使之與外部發生聯系。封裝的特性使得類(對象)以外的部分不能隨意存取類(對象)的內部數據(屬性),保證了程序和數據不受外部干擾且不被誤用。
這個怎么理解呢?首先來看一個列子。
已知一個類Animal,該類的屬性和方法如下表所示:
屬性 | 說明 | 方法 | 說明 |
String name | 名稱 | Animal() | 無參構造函數,為屬性設置初始值 |
Int age | 年齡 | Animal(String name,int age) | 有參構造函數,為屬性設置變量值 |
根據該類的定義,編寫一個程序,輸出該類的初始值以及通過變量設置的初始值,程序代碼如下
public class AnimalDemo{
public static void main(Stringargs[]){
Animal a=new Animal();
Animal b=new Animal("cat",5);
System.out.PRintln(a.name+"is "+a.age+" years old");
System.out.println(b.name+"is "+b.age+" years old");
}
}
程序執行結果:
Dog is 3 years oldcat is 5 years old
由此可以知道,類Animal的無參構造函數為name屬性賦值為“Dog”,為age屬性賦值為“3”。因此,可以寫出類Animal的代碼如下:
class Animal { String name; int age; Animal(){ name="Dog"; age=3; } Animal(Stringname,int age){ this.name=name; this.age=age; }}
實際上這就是上一篇文章中的例子,那么封裝在這里的含義如下:
l 類本身就實現了封裝功能,此處類Animal定義了兩個屬性,兩個構造函數,其只屬于Animal類。
l 通過訪問修飾符來限制對類的屬性和方法的訪問,各修飾符含義如下:
Private:成員變量和方法只能在類內被訪問,具有類可見性
默認: 成員變量和方法只能被同一個包里的類訪問,具有包可見性。
Protected:可以被同一個包中的類訪問,被同一個項目中不同包中的子類訪問
Public:可以被同一個項目中所有的類訪問,具有項目可見性,這是最大的訪問權限
l 只能通過類本身定義的方法來對該類所實例化的對象進行數據的訪問和處理。比如想對實例化的對象添加其它的一個方法和屬性是不可能的。這就體現的類的封裝性。這里也可以理解一下為什么類被稱之為模板或者藍圖。
二、繼承
1、繼承是面向對象的三大特征之一,也是實現代碼復用的重要手段。java的繼承具有單繼承的特點,即只能繼承自一個父類,每個子類只有一個直接父類,但是其父類又可以繼承于另一個類,從而實現了子類可以間接繼承多個父類,但其本質上劃分仍然是一個父類和子類的關系。
2、Java的繼承通過extends關鍵字來實現,實現繼承的類被稱為子類,被繼承的類稱為父類(有的也稱其為基類、超類),父類和子類的關系,是一種一般和特殊的關系。就像是水果和蘋果的關系,蘋果繼承了水果,蘋果是水果的子類,水果是蘋果的父類,則蘋果是一種特殊的水果。
3、Java使用extends作為繼承的關鍵字,extends關鍵字在英文是擴展的意思,而不是繼承。為什么國內把extends翻譯成繼承呢?除了與歷史原因有關外,把extends翻譯成為繼承也是有其道理的:子類擴展父類,將可以獲得父類的全部屬性和方法,這與漢語中得繼承(子輩從父輩那里獲得一筆財富成為繼承)具有很好的類似性。
值得指出的是:Java的子類不能獲得父類的構造器。
創建子類一般形式如下:
class 類名 extends 父類名{
子類體
}
4、子類與父類的變量、方法關系
子類可以繼承父類的所有特性,但其可見性,由父類成員變量、方法的修飾符決定。對于被private修飾的類成員變量或方法,其子類是不可見的,也即不可訪問;對于定義為默認訪問(沒有修飾符修飾)的類成員變量或方法,只有與父類同處于一個包中的子類可以訪問;對于定義為public或protected 的類成員變量或方法,所有子類都可以訪問。
子類中可以聲明與父類同名的成員變量,這時父類的成員變量就被隱藏起來了,在子類中直接訪問到的是子類中定義的成員變量。
子類中也可以聲明與父類相同的成員方法,包括返回值類型、方法名、形式參數都應保持一致,稱為方法的覆蓋。
如果在子類中需要訪問父類中定義的同名成員變量或方法,需要用的關鍵字super。Java中通過super來實現對被隱藏或被覆蓋的父類成員的訪問。super 的使用有三種情況:
l 訪問父類被隱藏的成員變量和成員方法;
super.成員變量名;
l 調用父類中被覆蓋的方法,如:
super.成員方法名([參數列]);
l 調用父類的構造函數,如:
super([參數列表]);
super( )只能在子類的構造函數中出現,并且永遠都是位于子類構造函數中的第一條語句。
舉例:
class BaseClass{
public double weight;
public void info(){
System.out.println("我的體重是"+weight+"千克");
}
}
public class ExtendsDemo001 extends BaseClass{
public static void main(String[]args) {
//創建ExtendsDemo001對象
ExtendsDemo001 ed = new ExtendsDemo001();
//ExtendsDemo001本身沒有weight屬性,但是ExtendsDemo001的父類有weight屬性,也可以訪問ExtendsDemo001對象的屬性
ed.weight = 56;
//調用ExtendsDemo001對象的info()方法
ed.info();
}
}
舉例二:
class Animal {
String name="animal";
int age;
void move(){
System.out.println("animalmove");
}
}
classDog extends Animal{
String name="dog"; //隱藏了父類的name屬性;
float weight; //子類新增成員變量
void move(){ //覆蓋了父類的方法move()
super.move(); //用super調用父類的方法
System.out.println("Dog Move");
}
}
publicclass InheritDemo{
public static void main(String args[]){
Dog d=new Dog();
d.age=5;
d.weight=6;
System.out.println(d.name+" is"+d.age+" years old");
System.out.println("weight:"+d.weight);
d.move();
}
}
程序運行結果:
dog is5 years old
weight:6.0
animalmove
DogMove
舉例三:
classSuperClass {
SuperClass() {
System.out.println("調用父類無參構造函數");
}
SuperClass(int n) {
System.out.println("調用父類有參構造函數:" + n );
}
}
classSubClass extends SuperClass{
SubClass(int n) {
System.out.println("調用子類有參構造函數:" + n );
}
SubClass(){
super(200);
System.out.println("調用子類無參構造函數");
}
}
publicclass InheritDemo2{
public static void main(String arg[]) {
SubClass s1 = new SubClass();
SubClass s2 = new SubClass(100);
}
}
程序運行結果:
調用父類有參構造函數:200
調用子類無參構造函數
調用父類無參構造函數
調用子類有參構造函數:100
請自行分析程序運行的結果,體會繼承的用法。
三、多態(Polymorphism)
多態性是指在繼承關系中的父類中定義的屬性或方法被子類繼承之后,可以具有不同的數據類型或表現出不同的行為。這使得同一個屬性或方法在父類及其各子類類中具有不同的含義。
Java引用變量有兩個類型:一個是編譯時類型,一個是運行時類型。編譯時的類型由聲明該變量時使用的類型決定,運行時的類型由實際賦給該變量的對象決定。如果編譯時類型和運行時類型不一致,就會出現所謂的多態(Polymorphism)
舉例1:
class Animal2 {
void eat(){
System.out.println("animal eat");
}
}
class Dog extends Animal2 {
void eat(){
System.out.println("Dog eat bone");
}
}
class Cat extends Animal2 {
void eat(){
System.out.println("Cat eat fish");
}
}
public class PloyDemo{
public static void main(String args[]){
Animal2 a;
a=newAnimal2 (); //編譯時類型和運行時類型完全一樣,因此不存在多態
a.eat();
a=new Dog(); //下面編譯時類型和運行時類型不一樣,多態發生
a.eat();
a=new Cat(); //下面編譯時類型和運行時類型不一樣,多態發生
a.eat();
}
}
程序運行結果:
animal eat
Dog eat bone
Cat eat fish
實例2:
class SuperClass{
public int book= 6;
public void base(){
System.out.println("父類的普通方法base()");
}
public void test(){
System.out.println("父類中將被子類覆蓋的方法");
}
}
public class PloymorphismTest001 extends SuperClass{
//重新定義一個book實例屬性,覆蓋父類的book實例屬性
public Stringbook = "Java瘋狂講義";
public void test(){
System.out.println("子類中覆蓋父類的方法");
}
private void Dmeo() {
System.out.println("子類中普通的方法");
}
//主方法
public static void main(String[]args) {
//下面編譯時類型和運行時類型完全一樣,因此不存在多態
SuperClass sc = new SuperClass();
System.out.println("book1= "+sc.book);//打印結果為:6
//下面兩次調用將執行SuperClass的方法
sc.base();
sc.test();
//下面編譯時類型和運行時類型完全一樣,因此不存在多態
PloymorphismTest001 pt = new PloymorphismTest001();
System.out.println("book2= "+pt.book);//打印結果為:Java瘋狂講義
//下面調用將執行從父類繼承到的base方法
pt.base();
//下面調用將執行當前類的test方法
pt.test();
//下面編譯時類型和運行時類型不一樣,多態發生
SuperClass sscc = new PloymorphismTest001();
//結果表明訪問的是父類屬性
System.out.println("book3= "+sscc.book);//打印結果為:6
//下面調用將執行從父類繼承到得base方法
sscc.base();
//下面調用將執行當前類的test方法
sscc.test();
//因為sscc的編譯類型是SuperClass,SuperClass類沒有提供Demo()方法
//所以下面代碼編譯時會出現錯誤
//sscc.Demo();
}
}
程序運行結果為:
book1=6
父類的普通方法base()
父類中將被子類覆蓋的方法
book2=Java瘋狂講義
父類的普通方法base()
子類中覆蓋父類的方法
book3=6
父類的普通方法base()
子類中覆蓋父類的方法
新聞熱點
疑難解答