java-封装
Java 封裝
在面向?qū)ο蟪淌皆O(shè)計(jì)方法中,封裝(英語:Encapsulation)是指一種將抽象性函式接口的實(shí)現(xiàn)細(xì)節(jié)部份包裝、隱藏起來的方法。
封裝可以被認(rèn)為是一個(gè)保護(hù)屏障,防止該類的代碼和數(shù)據(jù)被外部類定義的代碼隨機(jī)訪問。
要訪問該類的代碼和數(shù)據(jù),必須通過嚴(yán)格的接口控制。
封裝最主要的功能在于我們能修改自己的實(shí)現(xiàn)代碼,而不用修改那些調(diào)用我們代碼的程序片段。
適當(dāng)?shù)姆庋b可以讓程式碼更容易理解與維護(hù),也加強(qiáng)了程式碼的安全性。
封裝的優(yōu)點(diǎn)
1. 良好的封裝能夠減少耦合。
2. 類內(nèi)部的結(jié)構(gòu)可以自由修改。
3. 可以對(duì)成員變量進(jìn)行更精確的控制。
4. 隱藏信息,實(shí)現(xiàn)細(xì)節(jié)。
實(shí)現(xiàn)Java封裝的步驟
1. 修改屬性的可見性來限制對(duì)屬性的訪問(一般限制為private),例如:
public class Person {
private String name;
private int age;
}
這段代碼中,將 name 和 age 屬性設(shè)置為私有的,只能本類才能訪問,其他類都訪問不了,如此就對(duì)信息進(jìn)行了隱藏。
2. 對(duì)每個(gè)值屬性提供對(duì)外的公共方法訪問,也就是創(chuàng)建一對(duì)賦取值方法,用于對(duì)私有屬性的訪問,例如:
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)鍵字是為了解決實(shí)例變量(private String name)和局部變量(setName(String name)中的name變量)之間發(fā)生的同名的沖突。
實(shí)例
讓我們來看一個(gè)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;
}
}
以上實(shí)例中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());
}
}
以上代碼編譯運(yùn)行結(jié)果如下:
Name : James Age : 20
Java 接口
接口(英文:Interface),在JAVA編程語言中是一個(gè)抽象類型,是抽象方法的集合,接口通常以interface來聲明。一個(gè)類通過繼承接口的方式,從而來繼承接口的抽象方法。
接口并不是類,編寫接口的方式和類很相似,但是它們屬于不同的概念。類描述對(duì)象的屬性和方法。接口則包含類要實(shí)現(xiàn)的方法。
除非實(shí)現(xiàn)接口的類是抽象類,否則該類要定義接口中的所有方法。
接口無法被實(shí)例化,但是可以被實(shí)現(xiàn)。一個(gè)實(shí)現(xiàn)接口的類,必須實(shí)現(xiàn)接口內(nèi)所描述的所有方法,否則就必須聲明為抽象類。另外,在 Java 中,接口類型可用來聲明一個(gè)變量,他們可以成為一個(gè)空指針,或是被綁定在一個(gè)以此接口實(shí)現(xiàn)的對(duì)象。
接口與類相似點(diǎn):
一個(gè)接口可以有多個(gè)方法。
接口文件保存在 .java 結(jié)尾的文件中,文件名使用接口名。
接口的字節(jié)碼文件保存在 .class 結(jié)尾的文件中。
接口相應(yīng)的字節(jié)碼文件必須在與包名稱相匹配的目錄結(jié)構(gòu)中。
接口與類的區(qū)別:
接口不能用于實(shí)例化對(duì)象。
接口沒有構(gòu)造方法。
接口中所有的方法必須是抽象方法。
接口不能包含成員變量,除了 static 和 final 變量。
接口不是被類繼承了,而是要被類實(shí)現(xiàn)。
接口支持多繼承。
接口特性
接口中每一個(gè)方法也是隱式抽象的,接口中的方法會(huì)被隱式的指定為public abstract(只能是 public abstract,其他修飾符都會(huì)報(bào)錯(cuò))。
接口中可以含有變量,但是接口中的變量會(huì)被隱式的指定為public static final變量(并且只能是 public,用 private 修飾會(huì)報(bào)編譯錯(cuò)誤)。
接口中的方法是不能在接口中實(shí)現(xiàn)的,只能由實(shí)現(xiàn)接口的類來實(shí)現(xiàn)接口中的方法。
抽象類和接口的區(qū)別
1. 抽象類中的方法可以有方法體,就是能實(shí)現(xiàn)方法的具體功能,但是接口中的方法不行。
2. 抽象類中的成員變量可以是各種類型的,而接口中的成員變量只能是public static final類型的。
3. 接口中不能含有靜態(tài)代碼塊以及靜態(tài)方法(用 static 修飾的方法),而抽象類是可以有靜態(tài)代碼塊和靜態(tài)方法。
4. 一個(gè)類只能繼承一個(gè)抽象類,而一個(gè)類卻可以實(shí)現(xiàn)多個(gè)接口。
接口的聲明
接口的聲明語法格式如下:
[可見度] interface 接口名稱 [extends 其他的接口名名] {
// 聲明變量
// 抽象方法
}
Interface關(guān)鍵字用來聲明一個(gè)接口。下面是接口聲明的一個(gè)簡單例子。
NameOfInterface.java 文件代碼:
/* 文件名 : NameOfInterface.java */
import java.lang.*;
//引入包
public interface NameOfInterface
{
//任何類型 final, static 字段
//抽象方法
}
接口有以下特性:
接口是隱式抽象的,當(dāng)聲明一個(gè)接口的時(shí)候,不必使用abstract關(guān)鍵字。
接口中每一個(gè)方法也是隱式抽象的,聲明時(shí)同樣不需要abstract關(guān)鍵字。
接口中的方法都是公有的。
實(shí)例
Animal.java 文件代碼:
/* 文件名 : Animal.java */
interface Animal {
public void eat();
public void travel();
}
接口的實(shí)現(xiàn)
當(dāng)類實(shí)現(xiàn)接口的時(shí)候,類要實(shí)現(xiàn)接口中所有的方法。否則,類必須聲明為抽象的類。
類使用implements關(guān)鍵字實(shí)現(xiàn)接口。在類聲明中,Implements關(guān)鍵字放在class聲明后面。
實(shí)現(xiàn)一個(gè)接口的語法,可以使用這個(gè)公式:...implements 接口名稱[, 其他接口名稱, 其他接口名稱..., ...] ...
實(shí)例
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();
}
}
以上實(shí)例編譯運(yùn)行結(jié)果如下:
Mammal eats
Mammal travels
重寫接口中聲明的方法時(shí),需要注意以下規(guī)則:
類在實(shí)現(xiàn)接口的方法時(shí),不能拋出強(qiáng)制性異常,只能在接口中,或者繼承接口的抽象類中拋出該強(qiáng)制性異常。
類在重寫方法時(shí)要保持一致的方法名,并且應(yīng)該保持相同或者相兼容的返回值類型。
如果實(shí)現(xiàn)接口的類是抽象類,那么就沒必要實(shí)現(xiàn)該接口的方法。
在實(shí)現(xiàn)接口的時(shí)候,也要注意一些規(guī)則:
一個(gè)類可以同時(shí)實(shí)現(xiàn)多個(gè)接口。
一個(gè)類只能繼承一個(gè)類,但是能實(shí)現(xiàn)多個(gè)接口。
一個(gè)接口能繼承另一個(gè)接口,這和類之間的繼承比較相似。
接口的繼承
一個(gè)接口能繼承另一個(gè)接口,和類之間的繼承方式比較相似。接口的繼承使用extends關(guān)鍵字,子接口繼承父接口的方法。
下面的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接口自己聲明了四個(gè)方法,從Sports接口繼承了兩個(gè)方法,這樣,實(shí)現(xiàn)Hockey接口的類需要實(shí)現(xiàn)六個(gè)方法。
相似的,實(shí)現(xiàn)Football接口的類需要實(shí)現(xiàn)五個(gè)方法,其中兩個(gè)來自于Sports接口。
接口的多繼承
在Java中,類的多繼承是不合法,但接口允許多繼承。
在接口的多繼承中extends關(guān)鍵字只需要使用一次,在其后跟著繼承接口。 如下所示:
public interface Hockey extends Sports, Event
以上的程序片段是合法定義的子接口,與類不同的是,接口允許多繼承,而 Sports及 Event 可能定義或是繼承相同的方法
標(biāo)記接口
最常用的繼承接口是沒有包含任何方法的接口。
標(biāo)記接口是沒有任何方法和屬性的接口.它僅僅表明它的類屬于一個(gè)特定的類型,供其他代碼來測(cè)試允許做一些事情。
標(biāo)記接口作用:簡單形象的說就是給某個(gè)對(duì)象打個(gè)標(biāo)(蓋個(gè)戳),使對(duì)象擁有某個(gè)或某些特權(quán)。
例如:java.awt.event 包中的 MouseListener 接口繼承的 java.util.EventListener 接口定義如下:
package java.util;
public interface EventListener
{}
沒有任何方法的接口被稱為標(biāo)記接口。標(biāo)記接口主要用于以下兩種目的:
建立一個(gè)公共的父接口:
正如EventListener接口,這是由幾十個(gè)其他接口擴(kuò)展的Java API,你可以使用一個(gè)標(biāo)記接口來建立一組接口的父接口。例如:當(dāng)一個(gè)接口繼承了EventListener接口,Java虛擬機(jī)(JVM)就知道該接口將要被用于一個(gè)事件的代理方案。
向一個(gè)類添加數(shù)據(jù)類型:
這種情況是標(biāo)記接口最初的目的,實(shí)現(xiàn)標(biāo)記接口的類不需要定義任何接口方法(因?yàn)闃?biāo)記接口根本就沒有方法),但是該類通過多態(tài)性變成一個(gè)接口類型。
java 包(package)
為了更好地組織類,Java 提供了包機(jī)制,用于區(qū)別類名的命名空間。
包的作用
1、把功能相似或相關(guān)的類或接口組織在同一個(gè)包中,方便類的查找和使用。
2、如同文件夾一樣,包也采用了樹形目錄的存儲(chǔ)方式。同一個(gè)包中的類名字是不同的,不同的包中的類的名字是可以相同的,當(dāng)同時(shí)調(diào)用兩個(gè)不同包中相同類名的類時(shí),應(yīng)該加上包名加以區(qū)別。因此,包可以避免名字沖突。
3、包也限定了訪問權(quán)限,擁有包訪問權(quán)限的類才能訪問某個(gè)包中的類。
Java 使用包(package)這種機(jī)制是為了防止命名沖突,訪問控制,提供搜索和定位類(class)、接口、枚舉(enumerations)和注釋(annotation)等。
包語句的語法格式為:package pkg1[.pkg2[.pkg3…]];
例如,一個(gè)Something.java 文件它的內(nèi)容
package net.java.util;
public class Something{
...
}
那么它的路徑應(yīng)該是net/java/util/Something.java這樣保存的。 package(包) 的作用是把不同的 java 程序分類保存,更方便的被其他 java 程序調(diào)用。
一個(gè)包(package)可以定義為一組相互聯(lián)系的類型(類、接口、枚舉和注釋),為這些類型提供訪問保護(hù)和命名空間管理的功能。
以下是一些 Java 中的包:
java.lang-打包基礎(chǔ)的類
java.io-包含輸入輸出功能的函數(shù)
開發(fā)者可以自己把一組類和接口等打包,并定義自己的包。而且在實(shí)際開發(fā)中這樣做是值得提倡的,當(dāng)你自己完成類的實(shí)現(xiàn)之后,將相關(guān)的類分組,可以讓其他的編程者更容易地確定哪些類、接口、枚舉和注釋等是相關(guān)的。
由于包創(chuàng)建了新的命名空間(namespace),所以不會(huì)跟其他包中的任何名字產(chǎn)生命名沖突。使用包這種機(jī)制,更容易實(shí)現(xiàn)訪問控制,并且讓定位相關(guān)類更加簡單。
創(chuàng)建包
創(chuàng)建包的時(shí)候,你需要為這個(gè)包取一個(gè)合適的名字。之后,如果其他的一個(gè)源文件包含了這個(gè)包提供的類、接口、枚舉或者注釋類型的時(shí)候,都必須將這個(gè)包的聲明放在這個(gè)源文件的開頭。
包聲明應(yīng)該在源文件的第一行,每個(gè)源文件只能有一個(gè)包聲明,這個(gè)文件中的每個(gè)類型都應(yīng)用于它。
如果一個(gè)源文件中沒有使用包聲明,那么其中的類,函數(shù),枚舉,注釋等將被放在一個(gè)無名的包(unnamed package)中。
例子
讓我們來看一個(gè)例子,這個(gè)例子創(chuàng)建了一個(gè)叫做animals的包。通常使用小寫的字母來命名避免與類、接口名字的沖突。
在 animals 包中加入一個(gè)接口(interface):
Animal.java 文件代碼:
/* 文件名: Animal.java */
package animals;
interface Animal {
public void eat();
public void travel();
}
接下來,在同一個(gè)包中加入該接口的實(shí)現(xiàn):
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();
}
}
然后,編譯這兩個(gè)文件,并把他們放在一個(gè)叫做animals的子目錄中。 用下面的命令來運(yùn)行:
$ mkdir animals
$ cp Animal.class MammalInt.class animals
$ java animals/MammalInt
Mammal eats
Mammal travel
import 關(guān)鍵字
為了能夠使用某一個(gè)包的成員,我們需要在 Java 程序中明確導(dǎo)入該包。使用 "import" 語句可完成此功能。
在 java 源文件中 import 語句應(yīng)位于 package 語句之后,所有類的定義之前,可以沒有,也可以有多條,其語法格式為:
import package1[.package2…].(classname|*);
如果在一個(gè)包中,一個(gè)類想要使用本包中的另一個(gè)類,那么該包名可以省略。
例子
下面的 payroll 包已經(jīng)包含了 Employee 類,接下來向 payroll 包中添加一個(gè) Boss 類。Boss 類引用 Employee 類的時(shí)候可以不用使用 payroll 前綴,Boss類的實(shí)例如下。
Boss.java 文件代碼:
package payroll;
public class Boss
{
public void payEmployee(Employee e)
{
e.mailCheck();
}
}
如果 Boss 類不在 payroll 包中又會(huì)怎樣?Boss 類必須使用下面幾種方法之一來引用其他包中的類。
使用類全名描述,例如:
payroll.Employee
用 import 關(guān)鍵字引入,使用通配符 "*"
import payroll.*;
使用 import 關(guān)鍵字引入 Employee 類:
import payroll.Employee;
注意:
類文件中可以包含任意數(shù)量的 import 聲明。import 聲明必須在包聲明之后,類聲明之前。
package 的目錄結(jié)構(gòu)
類放在包中會(huì)有兩種主要的結(jié)果:
包名成為類名的一部分,正如我們前面討論的一樣。
包名必須與相應(yīng)的字節(jié)碼所在的目錄結(jié)構(gòu)相吻合。
下面是管理你自己 java 中文件的一種簡單方式:
將類、接口等類型的源碼放在一個(gè)文本中,這個(gè)文件的名字就是這個(gè)類型的名字,并以.java作為擴(kuò)展名。例如:
// 文件名 : Car.java
package vehicle;
public class Car {
// 類實(shí)現(xiàn)
}
接下來,把源文件放在一個(gè)目錄中,這個(gè)目錄要對(duì)應(yīng)類所在包的名字。
....vehicleCar.java
現(xiàn)在,正確的類名和路徑將會(huì)是如下樣子:
類名 -> vehicle.Car
路徑名 -> vehicleCar.java (在 windows 系統(tǒng)中)
通常,一個(gè)公司使用它互聯(lián)網(wǎng)域名的顛倒形式來作為它的包名.例如:互聯(lián)網(wǎng)域名是 runoob.com,所有的包名都以 com.runoob 開頭。包名中的每一個(gè)部分對(duì)應(yīng)一個(gè)子目錄。
例如:有一個(gè) com.runoob.test 的包,這個(gè)包包含一個(gè)叫做 Runoob.java 的源文件,那么相應(yīng)的,應(yīng)該有如下面的一連串子目錄:
....comunoob estRunoob.java
編譯的時(shí)候,編譯器為包中定義的每個(gè)類、接口等類型各創(chuàng)建一個(gè)不同的輸出文件,輸出文件的名字就是這個(gè)類型的名字,并加上 .class 作為擴(kuò)展后綴。 例如:
// 文件名: Runoob.java
package com.runoob.test;
public class Runoob {
}
class Google {
}
現(xiàn)在,我們用-d選項(xiàng)來編譯這個(gè)文件,如下:
$javac -d . Runoob.java
這樣會(huì)像下面這樣放置編譯了的文件:
.comunoob estRunoob.class
.comunoob estGoogle.class
你可以像下面這樣來導(dǎo)入所有 comunoob est 中定義的類、接口等:
import com.runoob.test.*;
編譯之后的 .class 文件應(yīng)該和 .java 源文件一樣,它們放置的目錄應(yīng)該跟包的名字對(duì)應(yīng)起來。但是,并不要求 .class 文件的路徑跟相應(yīng)的 .java 的路徑一樣。你可以分開來安排源碼和類的目錄。
<path-one>sourcescomunoob estRunoob.java
<path-two>classescomunoob estGoogle.class
這樣,你可以將你的類目錄分享給其他的編程人員,而不用透露自己的源碼。用這種方法管理源碼和類文件可以讓編譯器和java 虛擬機(jī)(JVM)可以找到你程序中使用的所有類型。
類目錄的絕對(duì)路徑叫做 class path。設(shè)置在系統(tǒng)變量 CLASSPATH 中。編譯器和 java 虛擬機(jī)通過將 package 名字加到 class path 后來構(gòu)造 .class 文件的路徑。
<path- two>classes 是 class path,package 名字是 com.runoob.test,而編譯器和 JVM 會(huì)在 <path-two>classescomunoob est 中找 .class 文件。
一個(gè) class path 可能會(huì)包含好幾個(gè)路徑,多路徑應(yīng)該用分隔符分開。默認(rèn)情況下,編譯器和 JVM 查找當(dāng)前目錄。JAR 文件按包含 Java 平臺(tái)相關(guān)的類,所以他們的目錄默認(rèn)放在了 class path 中。
設(shè)置 CLASSPATH 系統(tǒng)變量
用下面的命令顯示當(dāng)前的CLASSPATH變量:
Windows 平臺(tái)(DOS 命令行下):C:> set CLASSPATH
UNIX 平臺(tái)(Bourne shell 下):# echo $CLASSPATH
刪除當(dāng)前CLASSPATH變量內(nèi)容:
Windows 平臺(tái)(DOS 命令行下):C:> set CLASSPATH=
UNIX 平臺(tái)(Bourne shell 下):# unset CLASSPATH; export CLASSPATH
設(shè)置CLASSPATH變量:
Windows 平臺(tái)(DOS 命令行下): C:> set CLASSPATH=C:usersjackjavaclasses
UNIX 平臺(tái)(Bourne shell 下):# CLASSPATH=/home/jack/java/classes; export CLASSPATH
逆風(fēng)的方向最適合飛翔,我不怕千萬人阻擋,只怕自己投降。
總結(jié)
- 上一篇: 电脑桌面文件删除如何快速恢复电脑桌面如何
- 下一篇: Windows中禁止程序运行的几种方法电