java-封裝

Java 封裝

在面向對象程式設計方法中,封裝(英語:Encapsulation)是指一種將抽象性函式接口的實現細節部份包裝、隱藏起來的方法。java

封裝能夠被認爲是一個保護屏障,防止該類的代碼和數據被外部類定義的代碼隨機訪問。shell

要訪問該類的代碼和數據,必須經過嚴格的接口控制。編程

封裝最主要的功能在於咱們能修改本身的實現代碼,而不用修改那些調用咱們代碼的程序片斷。windows

適當的封裝可讓程式碼更容易理解與維護,也增強了程式碼的安全性。安全

封裝的優勢

  • 1. 良好的封裝可以減小耦合。編程語言

  • 2. 類內部的結構能夠自由修改。ide

  • 3. 能夠對成員變量進行更精確的控制。函數

  • 4. 隱藏信息,實現細節。測試

實現Java封裝的步驟

1. 修改屬性的可見性來限制對屬性的訪問(通常限制爲private),例如:

public class Person {
    private String name;
    private int age;
}
這段代碼中,將 name 和 age 屬性設置爲私有的,只能本類才能訪問,其餘類都訪問不了,如此就對信息進行了隱藏。

2. 對每一個值屬性提供對外的公共方法訪問,也就是建立一對賦取值方法,用於對私有屬性的訪問,例如:

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 關鍵字是爲了解決實例變量(private String name)和局部變量(setName(String name)中的name變量)之間發生的同名的衝突。

 

實例

讓咱們來看一個java封裝類的例子:this

EncapTest.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類的變量怎樣被訪問:

RunEncap.java 文件代碼:
/* 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());
    }
}
以上代碼編譯運行結果以下:

Name : James Age : 20

 

Java 接口

接口(英文:Interface),在JAVA編程語言中是一個抽象類型,是抽象方法的集合,接口一般以interface來聲明。一個類經過繼承接口的方式,從而來繼承接口的抽象方法。

接口並非類,編寫接口的方式和類很類似,可是它們屬於不一樣的概念。類描述對象的屬性和方法。接口則包含類要實現的方法。

除非實現接口的類是抽象類,不然該類要定義接口中的全部方法。

接口沒法被實例化,可是能夠被實現。一個實現接口的類,必須實現接口內所描述的全部方法,不然就必須聲明爲抽象類。另外,在 Java 中,接口類型可用來聲明一個變量,他們能夠成爲一個空指針,或是被綁定在一個以此接口實現的對象。

接口與類類似點:

  • 一個接口能夠有多個方法。
  • 接口文件保存在 .java 結尾的文件中,文件名使用接口名。
  • 接口的字節碼文件保存在 .class 結尾的文件中。
  • 接口相應的字節碼文件必須在與包名稱相匹配的目錄結構中。

接口與類的區別:

  • 接口不能用於實例化對象。
  • 接口沒有構造方法。
  • 接口中全部的方法必須是抽象方法。
  • 接口不能包含成員變量,除了 static 和 final 變量。
  • 接口不是被類繼承了,而是要被類實現。
  • 接口支持多繼承。

接口特性

  • 接口中每個方法也是隱式抽象的,接口中的方法會被隱式的指定爲 public abstract(只能是 public abstract,其餘修飾符都會報錯)。
  • 接口中能夠含有變量,可是接口中的變量會被隱式的指定爲 public static final 變量(而且只能是 public,用 private 修飾會報編譯錯誤)。
  • 接口中的方法是不能在接口中實現的,只能由實現接口的類來實現接口中的方法。

抽象類和接口的區別

  • 1. 抽象類中的方法能夠有方法體,就是能實現方法的具體功能,可是接口中的方法不行。
  • 2. 抽象類中的成員變量能夠是各類類型的,而接口中的成員變量只能是 public static final 類型的。
  • 3. 接口中不能含有靜態代碼塊以及靜態方法(用 static 修飾的方法),而抽象類是能夠有靜態代碼塊和靜態方法。
  • 4. 一個類只能繼承一個抽象類,而一個類卻能夠實現多個接口。

接口的聲明

接口的聲明語法格式以下:

[可見度] interface 接口名稱 [extends 其餘的接口名名] {
        // 聲明變量
        // 抽象方法
}
Interface關鍵字用來聲明一個接口。下面是接口聲明的一個簡單例子。

NameOfInterface.java 文件代碼:
/* 文件名 : NameOfInterface.java */
import java.lang.*;
//引入包
 
public interface NameOfInterface
{
   //任何類型 final, static 字段
   //抽象方法
}

接口有如下特性:

  • 接口是隱式抽象的,當聲明一個接口的時候,沒必要使用abstract關鍵字。
  • 接口中每個方法也是隱式抽象的,聲明時一樣不須要abstract關鍵字。
  • 接口中的方法都是公有的。
實例
Animal.java 文件代碼:
/* 文件名 : Animal.java */
interface Animal {
   public void eat();
   public void travel();
}

 

接口的實現

當類實現接口的時候,類要實現接口中全部的方法。不然,類必須聲明爲抽象的類。

類使用implements關鍵字實現接口。在類聲明中,Implements關鍵字放在class聲明後面。

實現一個接口的語法,可使用這個公式:...implements 接口名稱[, 其餘接口名稱, 其餘接口名稱..., ...] ...

實例
MammalInt.java 文件代碼:
/* 文件名 : MammalInt.java */
public class MammalInt implements Animal{
 
   public void eat(){
      System.out.println("Mammal eats");
   }
 
   public void travel(){
      System.out.println("Mammal travels");
   } 
 
   public int noOfLegs(){
      return 0;
   }
 
   public static void main(String args[]){
      MammalInt m = new MammalInt();
      m.eat();
      m.travel();
   }
}
以上實例編譯運行結果以下:

Mammal eats
Mammal travels

重寫接口中聲明的方法時,須要注意如下規則:

  • 類在實現接口的方法時,不能拋出強制性異常,只能在接口中,或者繼承接口的抽象類中拋出該強制性異常。
  • 類在重寫方法時要保持一致的方法名,而且應該保持相同或者相兼容的返回值類型。
  • 若是實現接口的類是抽象類,那麼就不必實現該接口的方法。

在實現接口的時候,也要注意一些規則:

  • 一個類能夠同時實現多個接口。
  • 一個類只能繼承一個類,可是能實現多個接口。
  • 一個接口能繼承另外一個接口,這和類之間的繼承比較類似。

接口的繼承

一個接口能繼承另外一個接口,和類之間的繼承方式比較類似。接口的繼承使用extends關鍵字,子接口繼承父接口的方法。

下面的Sports接口被Hockey和Football接口繼承:

// 文件名: Sports.java
public interface Sports
{
   public void setHomeTeam(String name);
   public void setVisitingTeam(String name);
}
 
// 文件名: Football.java
public interface Football extends Sports
{
   public void homeTeamScored(int points);
   public void visitingTeamScored(int points);
   public void endOfQuarter(int quarter);
}
 
// 文件名: Hockey.java
public interface Hockey extends Sports
{
   public void homeGoalScored();
   public void visitingGoalScored();
   public void endOfPeriod(int period);
   public void overtimePeriod(int ot);
}
Hockey接口本身聲明瞭四個方法,從Sports接口繼承了兩個方法,這樣,實現Hockey接口的類須要實現六個方法。

類似的,實現Football接口的類須要實現五個方法,其中兩個來自於Sports接口。

 

接口的多繼承

在Java中,類的多繼承是不合法,但接口容許多繼承。

在接口的多繼承中extends關鍵字只須要使用一次,在其後跟着繼承接口。 以下所示:

public interface Hockey extends Sports, Event

以上的程序片斷是合法定義的子接口,與類不一樣的是,接口容許多繼承,而 Sports及 Event 可能定義或是繼承相同的方法

標記接口

最經常使用的繼承接口是沒有包含任何方法的接口。

標記接口是沒有任何方法和屬性的接口.它僅僅代表它的類屬於一個特定的類型,供其餘代碼來測試容許作一些事情。

標記接口做用:簡單形象的說就是給某個對象打個標(蓋個戳),使對象擁有某個或某些特權。

例如:java.awt.event 包中的 MouseListener 接口繼承的 java.util.EventListener 接口定義以下:

package java.util;
public interface EventListener
{}

沒有任何方法的接口被稱爲標記接口。標記接口主要用於如下兩種目的:

  • 創建一個公共的父接口:

    正如EventListener接口,這是由幾十個其餘接口擴展的Java API,你可使用一個標記接口來創建一組接口的父接口。例如:當一個接口繼承了EventListener接口,Java虛擬機(JVM)就知道該接口將要被用於一個事件的代理方案。

  • 向一個類添加數據類型:

    這種狀況是標記接口最初的目的,實現標記接口的類不須要定義任何接口方法(由於標記接口根本就沒有方法),可是該類經過多態性變成一個接口類型。

java 包(package)

爲了更好地組織類,Java 提供了包機制,用於區別類名的命名空間。

包的做用

  • 一、把功能類似或相關的類或接口組織在同一個包中,方便類的查找和使用。

  • 二、如同文件夾同樣,包也採用了樹形目錄的存儲方式。同一個包中的類名字是不一樣的,不一樣的包中的類的名字是能夠相同的,當同時調用兩個不一樣包中相同類名的類時,應該加上包名加以區別。所以,包能夠避免名字衝突。

  • 三、包也限定了訪問權限,擁有包訪問權限的類才能訪問某個包中的類。

Java 使用包(package)這種機制是爲了防止命名衝突,訪問控制,提供搜索和定位類(class)、接口、枚舉(enumerations)和註釋(annotation)等。

包語句的語法格式爲:package pkg1[pkg2[pkg3]];

例如,一個Something.java 文件它的內容

package net.java.util;
public class Something{
   ...
}

那麼它的路徑應該是 net/java/util/Something.java 這樣保存的。 package(包) 的做用是把不一樣的 java 程序分類保存,更方便的被其餘 java 程序調用。

一個包(package)能夠定義爲一組相互聯繫的類型(類、接口、枚舉和註釋),爲這些類型提供訪問保護和命名空間管理的功能。

如下是一些 Java 中的包:

  • java.lang-打包基礎的類
  • java.io-包含輸入輸出功能的函數

開發者能夠本身把一組類和接口等打包,並定義本身的包。並且在實際開發中這樣作是值得提倡的,當你本身完成類的實現以後,將相關的類分組,可讓其餘的編程者更容易地肯定哪些類、接口、枚舉和註釋等是相關的。

因爲包建立了新的命名空間(namespace),因此不會跟其餘包中的任何名字產生命名衝突。使用包這種機制,更容易實現訪問控制,而且讓定位相關類更加簡單。

建立包

建立包的時候,你須要爲這個包取一個合適的名字。以後,若是其餘的一個源文件包含了這個包提供的類、接口、枚舉或者註釋類型的時候,都必須將這個包的聲明放在這個源文件的開頭。

包聲明應該在源文件的第一行,每一個源文件只能有一個包聲明,這個文件中的每一個類型都應用於它。

若是一個源文件中沒有使用包聲明,那麼其中的類,函數,枚舉,註釋等將被放在一個無名的包(unnamed package)中。

例子
讓咱們來看一個例子,這個例子建立了一個叫作animals的包。一般使用小寫的字母來命名避免與類、接口名字的衝突。

在 animals 包中加入一個接口(interface):

Animal.java 文件代碼:
/* 文件名: Animal.java */
package animals;
 
interface Animal {
   public void eat();
   public void travel();
}
接下來,在同一個包中加入該接口的實現:

MammalInt.java 文件代碼:
package animals;
 
/* 文件名 : MammalInt.java */
public class MammalInt implements Animal{
 
   public void eat(){
      System.out.println("Mammal eats");
   }
 
   public void travel(){
      System.out.println("Mammal travels");
   } 
 
   public int noOfLegs(){
      return 0;
   }
 
   public static void main(String args[]){
      MammalInt m = new MammalInt();
      m.eat();
      m.travel();
   }
}
而後,編譯這兩個文件,並把他們放在一個叫作animals的子目錄中。 用下面的命令來運行:

$ mkdir animals
$ cp Animal.class  MammalInt.class animals
$ java animals/MammalInt
Mammal eats
Mammal travel

 

import 關鍵字

爲了可以使用某一個包的成員,咱們須要在 Java 程序中明確導入該包。使用 "import" 語句可完成此功能。

在 java 源文件中 import 語句應位於 package 語句以後,全部類的定義以前,能夠沒有,也能夠有多條,其語法格式爲:

import package1[.package2].(classname|*);

若是在一個包中,一個類想要使用本包中的另外一個類,那麼該包名能夠省略。

例子
下面的 payroll 包已經包含了 Employee 類,接下來向 payroll 包中添加一個 Boss 類。Boss 類引用 Employee 類的時候能夠不用使用 payroll 前綴,Boss類的實例以下。

Boss.java 文件代碼:
package payroll;
 
public class Boss
{
   public void payEmployee(Employee e)
   {
      e.mailCheck();
   }
}
若是 Boss 類不在 payroll 包中又會怎樣?Boss 類必須使用下面幾種方法之一來引用其餘包中的類。

使用類全名描述,例如:

payroll.Employee
用 import 關鍵字引入,使用通配符 "*"

import payroll.*;
使用 import 關鍵字引入 Employee 類:

import payroll.Employee;
注意:

類文件中能夠包含任意數量的 import 聲明。import 聲明必須在包聲明以後,類聲明以前。

package 的目錄結構

類放在包中會有兩種主要的結果:

  • 包名成爲類名的一部分,正如咱們前面討論的同樣。
  • 包名必須與相應的字節碼所在的目錄結構相吻合。
下面是管理你本身 java 中文件的一種簡單方式:

將類、接口等類型的源碼放在一個文本中,這個文件的名字就是這個類型的名字,並以.java做爲擴展名。例如:

// 文件名 :  Car.java
 
package vehicle;
 
public class Car {
   // 類實現  
}
接下來,把源文件放在一個目錄中,這個目錄要對應類所在包的名字。

....\vehicle\Car.java
如今,正確的類名和路徑將會是以下樣子:

類名 -> vehicle.Car

路徑名 -> vehicle\Car.java (在 windows 系統中)

一般,一個公司使用它互聯網域名的顛倒形式來做爲它的包名.例如:互聯網域名是 runoob.com,全部的包名都以 com.runoob 開頭。包名中的每個部分對應一個子目錄。

例如:有一個 com.runoob.test 的包,這個包包含一個叫作 Runoob.java 的源文件,那麼相應的,應該有以下面的一連串子目錄:

....\com\runoob\test\Runoob.java
編譯的時候,編譯器爲包中定義的每一個類、接口等類型各建立一個不一樣的輸出文件,輸出文件的名字就是這個類型的名字,並加上 .class 做爲擴展後綴。 例如:

// 文件名: Runoob.java
 
package com.runoob.test;
public class Runoob {
      
}
class Google {
      
}
如今,咱們用-d選項來編譯這個文件,以下:

$javac -d . Runoob.java
這樣會像下面這樣放置編譯了的文件:

.\com\runoob\test\Runoob.class
.\com\runoob\test\Google.class
你能夠像下面這樣來導入全部 \com\runoob\test\ 中定義的類、接口等:

import com.runoob.test.*;
編譯以後的 .class 文件應該和 .java 源文件同樣,它們放置的目錄應該跟包的名字對應起來。可是,並不要求 .class 文件的路徑跟相應的 .java 的路徑同樣。你能夠分開來安排源碼和類的目錄。

<path-one>\sources\com\runoob\test\Runoob.java
<path-two>\classes\com\runoob\test\Google.class
這樣,你能夠將你的類目錄分享給其餘的編程人員,而不用透露本身的源碼。用這種方法管理源碼和類文件可讓編譯器和java 虛擬機(JVM)能夠找到你程序中使用的全部類型。

類目錄的絕對路徑叫作 class path。設置在系統變量 CLASSPATH 中。編譯器和 java 虛擬機經過將 package 名字加到 class path 後來構造 .class 文件的路徑。

<path- two>\classes 是 class path,package 名字是 com.runoob.test,而編譯器和 JVM 會在 <path-two>\classes\com\runoob\test 中找 .class 文件。

一個 class path 可能會包含好幾個路徑,多路徑應該用分隔符分開。默認狀況下,編譯器和 JVM 查找當前目錄。JAR 文件按包含 Java 平臺相關的類,因此他們的目錄默認放在了 class path 中。

設置 CLASSPATH 系統變量

用下面的命令顯示當前的CLASSPATH變量:

  • Windows 平臺(DOS 命令行下):C:\> set CLASSPATH
  • UNIX 平臺(Bourne shell 下):# echo $CLASSPATH

刪除當前CLASSPATH變量內容:

  • Windows 平臺(DOS 命令行下):C:\> set CLASSPATH=
  • UNIX 平臺(Bourne shell 下):# unset CLASSPATH; export CLASSPATH

設置CLASSPATH變量:

    • Windows 平臺(DOS 命令行下): C:\> set CLASSPATH=C:\users\jack\java\classes
    • UNIX 平臺(Bourne shell 下):# CLASSPATH=/home/jack/java/classes; export CLASSPATH
相關文章
相關標籤/搜索