java-封装
Java 封裝
在面向對象程式設計方法中,封裝(英語:Encapsulation)是指一種將抽象性函式接口的實現細節部份包裝、隱藏起來的方法。
封裝可以被認為是一個保護屏障,防止該類的代碼和數據被外部類定義的代碼隨機訪問。
要訪問該類的代碼和數據,必須通過嚴格的接口控制。
封裝最主要的功能在于我們能修改自己的實現代碼,而不用修改那些調用我們代碼的程序片段。
適當的封裝可以讓程式碼更容易理解與維護,也加強了程式碼的安全性。
封裝的優點
1. 良好的封裝能夠減少耦合。
2. 類內部的結構可以自由修改。
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封裝類的例子:
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 提供了包機制,用于區別類名的命名空間。
包的作用
1、把功能相似或相關的類或接口組織在同一個包中,方便類的查找和使用。
2、如同文件夾一樣,包也采用了樹形目錄的存儲方式。同一個包中的類名字是不同的,不同的包中的類的名字是可以相同的,當同時調用兩個不同包中相同類名的類時,應該加上包名加以區別。因此,包可以避免名字沖突。
3、包也限定了訪問權限,擁有包訪問權限的類才能訪問某個包中的類。
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 {
// 類實現
}
接下來,把源文件放在一個目錄中,這個目錄要對應類所在包的名字。
....vehicleCar.java
現在,正確的類名和路徑將會是如下樣子:
類名 -> vehicle.Car
路徑名 -> vehicleCar.java (在 windows 系統中)
通常,一個公司使用它互聯網域名的顛倒形式來作為它的包名.例如:互聯網域名是 runoob.com,所有的包名都以 com.runoob 開頭。包名中的每一個部分對應一個子目錄。
例如:有一個 com.runoob.test 的包,這個包包含一個叫做 Runoob.java 的源文件,那么相應的,應該有如下面的一連串子目錄:
....comunoob estRunoob.java
編譯的時候,編譯器為包中定義的每個類、接口等類型各創建一個不同的輸出文件,輸出文件的名字就是這個類型的名字,并加上 .class 作為擴展后綴。 例如:
// 文件名: Runoob.java
package com.runoob.test;
public class Runoob {
}
class Google {
}
現在,我們用-d選項來編譯這個文件,如下:
$javac -d . Runoob.java
這樣會像下面這樣放置編譯了的文件:
.comunoob estRunoob.class
.comunoob estGoogle.class
你可以像下面這樣來導入所有 comunoob est 中定義的類、接口等:
import com.runoob.test.*;
編譯之后的 .class 文件應該和 .java 源文件一樣,它們放置的目錄應該跟包的名字對應起來。但是,并不要求 .class 文件的路徑跟相應的 .java 的路徑一樣。你可以分開來安排源碼和類的目錄。
<path-one>sourcescomunoob estRunoob.java
<path-two>classescomunoob estGoogle.class
這樣,你可以將你的類目錄分享給其他的編程人員,而不用透露自己的源碼。用這種方法管理源碼和類文件可以讓編譯器和java 虛擬機(JVM)可以找到你程序中使用的所有類型。
類目錄的絕對路徑叫做 class path。設置在系統變量 CLASSPATH 中。編譯器和 java 虛擬機通過將 package 名字加到 class path 后來構造 .class 文件的路徑。
<path- two>classes 是 class path,package 名字是 com.runoob.test,而編譯器和 JVM 會在 <path-two>classescomunoob est 中找 .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:usersjackjavaclasses
UNIX 平臺(Bourne shell 下):# CLASSPATH=/home/jack/java/classes; export CLASSPATH
逆風的方向最適合飛翔,我不怕千萬人阻擋,只怕自己投降。
總結
- 上一篇: 电脑桌面文件删除如何快速恢复电脑桌面如何
- 下一篇: Windows中禁止程序运行的几种方法电