封裝

在描述對象時候,例如描述對象爲狗,可以設置Dog.age= 100;看上去語法沒有任何毛病,但是顯然這麼寫是不合理的。因此,java提供了封裝的機制,將類和對象的成員變量進行封裝。

案例1:

class FengZhuang
{
    publicstatic void main(String[] args){
        Dogjinmao = new Dog();
        jinmao.setAge(180);
        //jinmao.age= 100;
    }
}
class Dog
{
    private int age;
    public void setAge(intage){
        if(age > 20){
            System.out.println("滾犢子!");
            return;
        }
        System.out.println("設置成功");
        this.age = age;
    }
}
 


概念:

封裝是面向對象三大特徵之一,它指的是將對象的狀態信息隱藏在對象內部,不允許外部程序直接訪問對象內部信息,而是通過該類提供的方法來實現對內部信息的訪問。這樣,當我們設置屬性值的時候,可以判斷設置的屬性值是否合理。

//TODO
private int age;
    publicvoid setAge(int age){
        if(age> 20){
            System.out.println("滾犢子!");
            return;
        }
        System.out.println("設置成功");
        this.age= age;
    }
 


封裝是面向對象編程語言對客觀世界的模擬,在客觀世界裏,對象的信息都是被隱藏在對象內部,外界無法直接操作訪問和修改。就如對Dog.age設置屬性那樣,外界不能直接修改age屬性,只能隨着歲月的流逝(條件),age纔會增加。

封裝的目的:

1、  隱藏類的實現細節。

隱藏和封裝的區別:

隱藏就是將屬性私有化(private),不能被外界直接訪問。

封裝比隱藏多一步,另外提供公有的方法讓外界去操作該隱藏屬性。

如下:temp是內部實現功能的細節,只需要隱藏。而age是描述對象屬性,需要隱藏起來後提供公有方法對其進行訪問和設置。

class Dog
{
         //這個變量的業務邏輯只是在該對象方法中有一個記錄
         //臨時數據功能
         privateString temp;
         privateint age;
         publicvoid setAge(int age){
                   temp= "這個狗狗的年紀是"+age;
                   if(age> 20){
                            System.out.println("滾犢子!");
                            return;
                   }
                   System.out.println("設置成功");
                   this.age= age;
         }
         publicint getAge(){
         System.out.println(temp);
                   returnage;
         }
}


2、讓使用者只能通過預定義的方法來訪問數據,從而可以在該方法中添加控制邏輯,限制對成員變量的不合理的訪問。

3、可進行數據檢查,從而有利於保證對象完整性。

4、提高代碼的可維護性。

爲了實現良好的封裝,需要從兩個方面考慮:

1、將對象的成員變量和實現細節隱藏起來,不允許外部直接訪問。

2、將方法暴露出來,讓方法來控制對這些成員變量進行安全訪問和操作。

因此封裝實際上就是:將該隱藏的隱藏,將該暴露的暴露。而實現這一目的則是通過java提供的訪問控制符來實現。

 

訪問控制符(權限修飾符)

java提供3個訪問控制符關鍵字,private、protected、public分別代表三個訪問控制級別,另外還有一個默認訪問控制級別,一共4個訪問控制級別。

默認訪問控制即不寫權限修飾符(default)。

控制級別由小到大排序爲:

private->default->protected->public

使用4種權限類型控制的效果:

private:修飾的成員(變量、方法、構造器)只能在當前類內部訪問,外界是無法獲取該成員。顯然,使用這個修飾符可以達到隱藏成員變量的目的。

class FengZhuang
{
    public static void main(String[] args){
        Dog jinmao = new Dog();
        jinmao.age = 100;
    }
}
class Dog
{
    private int age;
 
}


default:默認修飾符,不適用任何修飾符關鍵字修飾。修飾的成員或類可以被相同包下的其他類訪問,不能被其他包下的類訪問。

案例:定義bao1. Bao1Class, bao1. Bao1Class2, bao2. Bao2Class,在bao2下的Bao2Class類無法訪問在bao1下的Bao1Class的name屬性。但是,bao1下的Bao1Class2類可以訪問在bao1下的Bao1Class的name屬性。

package bao1;
public class Bao1Class{
    staticString name;
}
 
package bao2;
import bao1.*;
public class Bao2Class{
    publicstatic void main(String[] args){
        Bao1Class.name= "小明";
    }
}
 
package bao1;
public class Bao1Class2{
    publicstatic void main(String[] args){
        Bao1Class.name= "小明";
    }
}


protected:子類訪問權限修飾符,修飾的成員可以被同包、不同包下的子類訪問。通常使用該修飾符修飾的方法,希望其子類能重寫這個方法。

package bao1;
public class Bao1Class{
    staticprotected String name;
}
Bao2Class不可以訪問Bao1Class的name屬性
package bao2;
import bao1.*;
class Bao2Class {
    publicstatic void main(String[] args){
        Bao1Class.name= "小明";
    }
}
package bao1;
public class Bao1Class{
    staticprotected String name;
}
Bao2Class可以訪問Bao1Class的name屬性,因爲有繼承關係
package bao2;
import bao1.*;
class Bao2Class extends Bao1Class {
    publicstatic void main(String[] args){
        Bao1Class.name= "小明";
    }
}


public:公開訪問權限,這是最寬鬆的訪問權限級別,修飾的成員、類,那麼這個成員或者外部類可以被所有包下所有類訪問。

權限最大,在任意位置,都可以訪問(注意:導包)


 

修飾符修飾類:

注意:外部類只能用public 或者默認權限修飾,不能使用private、protected來修飾。

因爲被這兩個修飾的類不能被訪問,也就沒有任何意義。

//TODO代碼驗證權限修飾符

測試public修飾的類:

package bao1;
public class Bao1Class{
    staticpublic  String name;
}
 
package bao2;
import bao1.*;
class Bao2Class{
    publicstatic void main(String[] args){
        Bao1Class.name= "小明";
    }
}
 
默認修飾符(default):
package bao1;
class Bao1Class{
    staticpublic  String name;
}


這樣是無法訪問的,因爲Bao1Class權限僅限bao1包下,bao2中的類無法訪問。

package bao2;
import bao1.*;
class Bao2Class extends Bao1Class{
    publicstatic void main(String[] args){
        Bao1Class.name= "小明";
    }
}


這樣是可以訪問的,因爲Bao1Class2和Bao1Class在一個包下。

package bao1;
class Bao1Class2{
    publicstatic void main(String[] args){
        Bao1Class.name= "小明";
    }
}


不能使用private和protected修飾類


總結已學的修飾符。

static:靜態修飾符;

private:私有權限修飾符;

default:默認權限修飾符;

protected:子類權限修飾符;

public:公開的權限修飾符。

 

當使用private修飾構造器的時候,會出現什麼情況?

Private修飾的方法,作用範圍是:類本身,其他類不能調用。

 

那麼將對象的構造器方法都私有後,就無法創建對象了,那麼在實際應用中,還可以通過暴露一個公開的方法,讓外界獲取一個對象。

 

    classDuoTai
    {
        publicstatic void main(String[] args){
            Personperson = Person.getPerson();
            person.method();
        }
    }
    classPerson
    {
        privatePerson(){
            System.out.println("構造器方法執行");
        }
        publicstatic Person getPerson(){
            returnnew Person();
        }
        public  void method(){
            System.out.println("執行person中的方法");
        }
    }
 


單例設計模式

這種案例在實際開發中,我們以單例模式舉例。

當我們上網時候,發現顧客是多個,但是服務生是一個,並不是一個顧客有一個服務生。

那在這個時候,網管就是唯一的,那網管就是單例對象。

 

單例模式(Singleton Pattern)是 Java 中最簡單的設計模式之一。這種類型的設計模式屬於創建型模式,它提供了一種創建對象的最佳方式。

這種模式涉及到一個單一的類,該類負責創建自己的對象,同時確保只有單個對象被創建。這個類提供了一種訪問其唯一的對象的方式,可以直接訪問,不需要實例化該類的對象。

注意:

·        1、單例類只能有一個實例。

·        2、單例類必須自己創建自己的唯一實例。

·        3、單例類必須給所有其他對象提供這一實例。

意圖:保證一個類僅有一個實例,並提供一個訪問它的全局訪問點。

主要解決:一個全局使用的對象頻繁地創建與銷燬。

何時使用:當您想控制實例數目,節省系統資源的時候。

如何解決:判斷系統是否已經有這個單例,如果有則返回,如果沒有則創建。

關鍵代碼:構造函數是私有的。

更多相關資料請查閱:http://www.runoob.com/design-pattern/singleton-pattern.html

代碼實現:

class Singleton
{
    publicstatic  void main(String[] args){
        /*顯然,這種情況不符合常理
            實際中,一個網管,服務多個顧客,
            網管就是唯一的,我們把網管對象變爲唯一
            對象,就符合常理了。
        */
        Customerc1 = new Customer();
        c1.surfing();
        Customerc2 = new Customer();
        c2.surfing();
        Customerc3 = new Customer();
        c2.surfing();
    }
}
class Customer
{
    publicvoid surfing(){
        Waiterwaiter = Waiter.getWaiter();
        waiter.kaiji();
    }
}
class Waiter
{
    privateWaiter(){
   
    }
    privatestatic  Waiter waiter;
    publicstatic Waiter getWaiter(){
        //這個時候,我要保證每次獲取網管對象都是唯一的
        if(waiter== null){
            waiter= new Waiter();
            returnwaiter;
        }
        returnwaiter; 
    }
    int temp =0;
    publicvoid kaiji(){
        System.out.println("開機" + temp +"號電腦");
        temp++;
    }
}
 


接下來介紹單例模式的兩種實現方式:

1、  懶漢式,顧名思義,獲取單例對象的操作採用偷懶的方式。

在代碼中,那就是說:你什麼時候需要用到該對象,那麼什麼時候再創建。

如下代碼:當調用getWaiter方法獲取對象時,纔會創建對象。而不調用getWaiter方法的話,是不會創建對象的。

 

class Waiter
{
    private Waiter(){
   
    }
    privatestatic  Waiter waiter;
    publicstatic Waiter getWaiter(){
        //這個時候,我要保證每次獲取網管對象都是唯一的
        if(waiter== null){
            waiter= new Waiter();
            returnwaiter;
        }
        returnwaiter; 
    }
    int temp =0;
    publicvoid kaiji(){
        System.out.println("開機" + temp +"號電腦");
        temp++;
    }
}
 

2、  餓漢式

和懶漢式相反,在類存在的時候,該類型對象就存在了!即便你沒有調用getWaiter方法,該對象也存在!

class Waiter
{
    privateWaiter(){   }
    privatestatic  Waiter waiter = new Waiter();
    publicstatic Waiter getWaiter(){
        /*這個時候,不管有沒有調用該方法,
        返回的對象就已經存在了!而且該對象
            屬於類,所以每次調用該方法,返回
            的就是唯一的Waiter*/
        returnwaiter; 
    }
    int temp =0;
    publicvoid kaiji(){
        System.out.println("開機" + temp +"號電腦");
        temp++;
    }
}
 


其實這兩種單例模式在開發中也並不是非常完美,但是作爲現階段,我們只需熟練編寫上面兩個案例即可,如果還有興趣,可以參考下面鏈接的文章,還有其他創建單例對象的方式(按住ctrl鍵單擊)。

http://www.runoob.com/design-pattern/singleton-pattern.html

 

 

 

 

 

思考案例:

情況1:

定義Person類,定義Man類,兩個類不在同一個包下

package bao1;
public class Person{
    protectedint age;
}
 
import bao1.Person;
public class Man
{
    Person p = new Person();
    publicvoid setAge(){
        p.age= 12;
    }
}


編譯Man類會報錯,因爲age屬性是protected修飾,必須是Person本包下或它的子類纔可以訪問,這裏Man即不在同一個包下,也不是Person子類!

情況2:

定義Person類,定義Man類,兩個類不在同一個包下

package bao1;
public class Person{
    protectedint age;
}


 

 

 

 

import bao1.Person;
public class Man extends Person
{
    Person p = new Person();
    publicvoid setAge(){
        p.age= 12;
    }
}


這種情況還是會報錯,因爲雖然Man繼承了Person,但是,實際上訪問age屬性的還是Person對象,這裏並不滿足Man類和Person類在同一包下,也不滿足調用age屬性的對象是Person對象的子類。這裏的p指的是Person類型對象,不是他的子類對象。

情況3:

正確的情況:

定義Person類,定義Man類,兩個類不在同一個包下

package bao1;
public class Person{
    protectedint age;
}
 


 

 

 

import bao1.Person;
public class Man extends Person
{
    Man p =new Man();
    publicvoid setAge(){
        p.age= 12;
    }
}


 

這裏,p.age是可以的,雖然Man不和Person在同一個包下,但是,創建出來訪問age屬性的對象是Person類型對象的子類對象,符合protected權限修飾符的訪問範圍,所以不報錯!

 

情況4:

編寫測試類TestPro,測試並思考:

package bao1;
public class Person{
    protectedint age;
}


 

import bao1.Person;
public class Man extends Person
{
    public intgetAge(){
        returnthis.age;
    }
    publicvoid setAge(int age){
        this.age= age;
    }
}


 

 

class TestPro{
    publicstatic void main(String[] args){
        Manman = new Man();   
        man.setAge(123);
        intage = man.getAge();
        System.out.println(age);
    }
}


 

這裏通過測試類創建man對象,然後調用Man對象的age屬性。

在man對象中,this代表的是當前對象,這個當前對象又是Person類的子類對象,所以是可以訪問protected修飾的age屬性,所以不會報錯!!

 

 

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