Java封裝

在面向?qū)ο蟪淌皆O(shè)計方法中,封裝(Encapsulation)是指一種將抽象性函式接口的實現(xiàn)細節(jié)部分包裝、隱藏起來的方法。
封裝可以被認為是一個保護屏障、防止該類的代碼和數(shù)據(jù)被外部類定義的代碼隨機訪問。
要訪問該類的代碼和數(shù)據(jù),必須通過嚴格的接口控制。
封裝的主要的功能在于我們能修改自己的實現(xiàn)代碼,而不用修改那些調(diào)用我們代碼的程序片段。
適當(dāng)?shù)姆庋b可以讓程式碼更容易理解與維護,也將強了程式碼的安全性。

封裝的優(yōu)點

  • 良好的封裝能夠減少耦合
  • 類內(nèi)部的結(jié)構(gòu)可以自由修改
  • 可以對成員變量進行更精確的控制
  • 隱藏信息,實現(xiàn)細節(jié)

實現(xiàn)Java的封裝

  • 修改屬性的可見性來限制對屬性的訪問(一般限制為private),例如:
public class Person {
        private String name;
        private int age;
}

這段代碼中,將name和age屬性設(shè)置為私有的,只能本類才能訪問,其它類都訪問不了,如此就對信息進行了隱藏。

  • 對每個值屬性提供對外的公共方法訪問,也就是創(chuàng)建一對賦值方法,用于對私有屬性的訪問,例如:
public class Person{
    private String name;
    private int age;
?
    public int getAge(){
      return age;
    }
?
    public String getName(){
      return name;
    }
?
    public void setAge(int age){
      this.age = age;
    }
?
    public void setName(String name){
      this.name = name;
    }
}

采用this關(guān)鍵字是為了解決實例變量(private String name)和局部變量(setName(String name)中的name變量)之間發(fā)生的同名的沖突。

讓我們來看一個Java封裝類的例子:

/* 文件名: EncapTest.java */
public class EncapTest{
 
   private String name;
   private String idNum;
   private int age;
 
   public int getAge(){
      return age;
   }
 
   public String getName(){
      return name;
   }
 
   public String getIdNum(){
      return idNum;
   }
 
   public void setAge( int newAge){
      age = newAge;
   }
 
   public void setName(String newName){
      name = newName;
   }
 
   public void setIdNum( String newId){
      idNum = newId;
   }
}

以上實例中public方法是外部類訪問該類成員變量的入口。
通常情況下,這些方法被稱為getter和setter方法。
因此,任何要訪問類中私有成員變量的類都要通過這些getter和setter方法。
通過如下的例子說明EncapTest類的變量怎樣被訪問:

/* F文件名 : RunEncap.java */
public class RunEncap{
   public static void main(String args[]){
      EncapTest encap = new EncapTest();
      encap.setName("James");
      encap.setAge(20);
      encap.setIdNum("12343ms");
 
      System.out.print("Name : " + encap.getName()+ 
                             " Age : "+ encap.getAge());
    }
}

以上代碼編譯運行結(jié)果如下:

Name : James Age : 20

有時候在封裝的時候會遇到這樣的問題,就是我們的類名可能是重復(fù)的。為了更好地組織類,Java提供了包機制,用于區(qū)別類名的命名空間。

包的作用

  • 把功能相似或相關(guān)的類或接口組織在同一個包中,方便類的查找和使用。
  • 包采用了樹形目錄的存儲方式。同一個包中的類名字是不同,不同的包中的類的名字是可以相同的,當(dāng)同時調(diào)用兩個不同包中相同類名的類時,應(yīng)該加上包名加以區(qū)別。
  • 包也限定了訪問權(quán)限,擁有包訪問權(quán)限的類才能訪問某個包中的類。

定義包語法

package 包名
//注意:必須放在源程序的第一行,包名可用"."號隔開

例如:

//我們在定義文件夾的時候利用"/"來區(qū)分層次
//包中我們用"."來分層
package com.shiyanlou.Java 

不僅是我們這樣利用包名來區(qū)分類,系統(tǒng)也是這樣做的。

系統(tǒng)中的包
java.(功能).(類)
java.lang.(類) 包含java語言基礎(chǔ)的類
java.util.(類) 包含java語言中各種工具類
java.io.(類) 包含輸入、輸出相關(guān)功能的類

那我們怎么在不同包中使用另一個文件中的類呢?這時候就需要用到import關(guān)鍵字。比如我們要導(dǎo)入實驗樓下People這個類。import com.shiyanlou.People,同時如果import com.shiyanlou.*這是將包下的所有文件都導(dǎo)入進來,*是通配符。
這里要注意一點,包的命名規(guī)則是全小寫字母拼寫。

訪問修飾符

我們在前面的代碼中經(jīng)常用到privatepublic修飾符,這些修飾符的作用和意義是什么呢?接下來我們就來學(xué)習(xí)Java中的訪問修飾符。
訪問修飾符可以用來修飾屬性和方法的訪問范圍。

訪問修飾符 本類 同包 子類 其它
private
默認
protected
public

如圖所示,代表了不同的訪問能修飾符的訪問范圍,比如 private 修飾符的屬性或者方法,只能在當(dāng)前類中中訪問或者使用。默認是什么修飾符都不加,默認在當(dāng)前類中和同一包下都可以訪問和使用。protected修飾的屬性或者方法,對同一包內(nèi)的類和所有子類可見。public修飾的屬性或者方法,對所有類可見。
我們可以舉一個例子,比如 money,如果我們用private修飾代表著這是私有的,只能我自己可以使用。如果是protected代表著我可以使用,和我有關(guān)系的人,比如兒子也可以用。如果是public就代表了所有人都可以使用。

內(nèi)部類

可以將一個類的定義放在另一個類的定義內(nèi)部,這就是內(nèi)部類。而包含內(nèi)部類的類被稱為外部類。
內(nèi)部類的主要作用如下:

  • 內(nèi)部類提供了更好的封裝,可以把內(nèi)部類隱藏在外部類之內(nèi),不允許同一個包中的其它類訪問該類
  • 內(nèi)部類的方法可以直接訪問外部類的所有數(shù)據(jù),包括私有的數(shù)據(jù)
  • 內(nèi)部類所實現(xiàn)的功能使用外部類同樣可以實現(xiàn),只是有時使用內(nèi)部類更方便
  • 內(nèi)部類允許繼承多個非接口類型

注意:內(nèi)部類是編譯時的概念,一旦編譯成功,就會稱為完全不同的兩類。對于一個名為outer的外部類和其內(nèi)部定義的名為inner的內(nèi)部類。編譯完成后出現(xiàn)outer.class和outer$inner.class兩類。所以內(nèi)部類的成員變量/方法名可以和外部類的相同。

我們通過代碼來詳細學(xué)習(xí)以下內(nèi)部類把!

成員內(nèi)部類

ackage com.shiyanlou;

//外部類People
public class People {
    private String name = "LiLei";         //外部類的私有屬性
    //內(nèi)部類Student
    public class Student {
        String ID = "20151234";               //內(nèi)部類的成員屬性
        //內(nèi)部類的方法
        public void stuInfo(){
            System.out.println("訪問外部類中的name:" + name);
            System.out.println("訪問內(nèi)部類中的ID:" + ID);
        }
    }

    //測試成員內(nèi)部類
    public static void main(String[] args) {
        People a = new People();     //創(chuàng)建外部類對象,對象名為a
        Student b = a.new Student(); //使用外部類對象創(chuàng)建內(nèi)部類對象,對象名為b
        // 或者為 People.Student b = a.new Student();
        b.stuInfo();   //調(diào)用內(nèi)部對象的suInfo方法
    }
}

由此,我們可以直到,成員內(nèi)部類的使用方法:

  • Student 類相當(dāng)于 People 類的一個成員變量,所以 Student 類可以使用任意訪問修飾符。
  • Student 類在 People 類里,所以訪問范圍在類里的所有方法均可以訪問 People 的屬性(即內(nèi)部類里可以直接訪問外部類的方法和屬性,反之不行)
  • 定義成員內(nèi)部類后,必須使用外部類對象來創(chuàng)建內(nèi)部類對象,即內(nèi)部類 對象名 = 外部類對象.new 內(nèi)部類();
  • 如果外部類和內(nèi)部類具有相同的成員變量或方法,內(nèi)部類默認訪問自己的成員變量或方法,如果要訪問外部類的成員變量,可以使用 this 關(guān)鍵字 加上述代碼中:a.this

注:成員內(nèi)部類不能含有static的變量和方法,因為成員內(nèi)部類需要先創(chuàng)建了外部類,才能創(chuàng)建它自己的。

靜態(tài)內(nèi)部類

靜態(tài)內(nèi)部類通常被稱為嵌套類。

package com.shiyanlou;

//外部類People
public class People {
    private String name = "LiLei";         //外部類的私有屬性

/*外部類的靜態(tài)變量。
Java 中被 static 修飾的成員稱為靜態(tài)成員或類成員。它屬于整個類所有,而不是某個對象所有,即被類的所有對象所共享。靜態(tài)成員可以使用類名直接訪問,也可以使用對象名進行訪問。
*/
    static String ID = "510xxx199X0724XXXX"; 

    //靜態(tài)內(nèi)部類Student
    public static class Student {
        String ID = "20151234";               //內(nèi)部類的成員屬性
        //內(nèi)部類的方法
        public void stuInfo(){
            System.out.println("訪問外部類中的name:" + (new People().name));
            System.out.println("訪問外部類中的ID:" + People.ID);
            System.out.println("訪問內(nèi)部類中的ID:" + ID);
        }
    }

    //測試成員內(nèi)部類
    public static void main(String[] args) {
        Student b = new Student();   //直接創(chuàng)建內(nèi)部類對象,對象名為b
        b.stuInfo();                 //調(diào)用內(nèi)部對象的suInfo方法
    }
}

以上代碼編譯運行結(jié)果如下:

訪問內(nèi)外部類中的name:LiLei
訪問外部類中的ID:510xxx199X0724XXXX
訪問內(nèi)部類中的ID:20151234

靜態(tài)內(nèi)部類是static修飾的內(nèi)部類,這種內(nèi)部類的特點是:

  • 靜態(tài)內(nèi)部類不能直接訪問外部類的非靜態(tài)成員,但可以通過 new 外部類().成員的方式訪問
  • 如果外部類的靜態(tài)成員與內(nèi)部類的成員名稱相同,可通過類名.靜態(tài)成員訪問外部類的靜態(tài)成員;如果外部類的靜態(tài)成員與內(nèi)部類的成員名稱不相同,則可通過成員名直接調(diào)用外部類的靜態(tài)成員
  • 創(chuàng)建靜態(tài)內(nèi)部類的對象時,不需要外部類的對象,可以直接創(chuàng)建內(nèi)部類 對象名=new 內(nèi)部類();

局部內(nèi)部類

局部內(nèi)部類,是指內(nèi)部類定義在方法和作用域內(nèi)。
例如:

package com.shiyanlou;

//外部類People
public class People {    
    //定義在外部類中的方法內(nèi):
    public void peopleInfo() {
        final String sex = "man";  //外部類方法中的常量
        class Student {
            String ID = "20151234"; //內(nèi)部類中的常量
            public void print() {
                System.out.println("訪問外部類的方法中的常量sex:" + sex);
                System.out.println("訪問內(nèi)部類中的變量ID:" + ID);
            }
        }
        Student a = new Student();  //創(chuàng)建方法內(nèi)部類的對象
        a.print();//調(diào)用內(nèi)部類的方法
    }
    //定義在外部類中的作用域內(nèi)
    public void peopleInfo2(boolean b) {
        if(b){
            final String sex = "man";  //外部類方法中的常量
            class Student {
                String ID = "20151234"; //內(nèi)部類中的常量
                public void print() {
                    System.out.println("訪問外部類的方法中的常量sex:" + sex);
                    System.out.println("訪問內(nèi)部類中的變量ID:" + ID);
                }
            }
            Student a = new Student();  //創(chuàng)建方法內(nèi)部類的對象
            a.print();//調(diào)用內(nèi)部類的方法
        }
    }
    //測試方法內(nèi)部類
    public static void main(String[] args) {
        People b = new People(); //創(chuàng)建外部類的對象
        System.out.println("定義在方法內(nèi):===========");
        b.peopleInfo();  //調(diào)用外部類的方法
        System.out.println("定義在作用域內(nèi):===========");
        b.peopleInfo2(true);
    }
}

以上編譯運行結(jié)果如下:

定義在方法內(nèi):===========
訪問外部類的方法中的常量sex:man
訪問內(nèi)部類中的變量ID:20151234
定義在作用域內(nèi):===========
訪問外部類的方法中的常量sex:man
訪問內(nèi)部類中的變量ID:20151234

局部內(nèi)部類也像別的類一樣進行編譯,但只是作用域不同而已,只在該方法或條件的作用域內(nèi)才能使用,退出這些作用域后無法引用的。

匿名內(nèi)部類

匿名內(nèi)部類,顧名思義,就是沒有名字的內(nèi)部類。正因為沒有名字,所有匿名內(nèi)部類只能使用一次,它通常用來簡化代碼編寫。但使用匿名內(nèi)部類還有個前提條件:必須繼承一個父類或?qū)崿F(xiàn)一個接口。
例如:

public class Outer { 

    public Inner getInner(final String name, String city) { 
        return new Inner() { 
            private String nameStr = name; 
            public String getName() { 
                return nameStr; 
            } 
        };
    } 

    public static void main(String[] args) { 
        Outer outer = new Outer(); 
        Inner inner = outer.getInner("Inner", "NewYork"); 
        System.out.println(inner.getName()); 
    } 
} 
interface Inner { 
    String getName(); 
}

以上代碼編譯運行結(jié)果如下:

Inner

匿名內(nèi)部類是不能加訪問修飾符的。要注意的是,new 匿名類,這個類是要先定義的,如果不限定義,編譯時會報錯該類找不到。
同時,在上面的例子中,當(dāng)所在的方法的形參需要在內(nèi)部類里面使用時,該形參必須為final。這里可以看到形參 name 已經(jīng)定義為 final 了,而形參 city 沒有被使用則不用定義為 final。
然而,因為匿名內(nèi)部類沒名字,是用默認的構(gòu)造函數(shù)的,無參數(shù)的,如果需要該類有帶參數(shù)的構(gòu)造函數(shù),示例如下:

public Inner getInner(final String name, String city) { 
        return new Inner(name, city) { 
            private String nameStr = name; 

            public String getName() { 
                return nameStr; 
            } 
        }; 
    } 

注意這里的形參 city,由于它沒有被匿名內(nèi)部類直接使用,而是被抽象類 Inner 的構(gòu)造函數(shù)所使用,所以不必定義為 final。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容