1. 程式人生 > >DAY12-Java中的類--接DAY10

DAY12-Java中的類--接DAY10

區分 返回值 員工 方式 ... 頂部 date類 gets 工作

一、用戶自定義類

1、寫先出一個簡單的Employee類作為例子說明。

代碼如下:

 1 import java.time.LocalDate;
 2 
 3 /**
 4  * 自定義方法練習--測試 這個程序中包含了兩個類Employee類和帶有public修飾的EmployeeTest類
 5  * 
 6  * @author:Archer-LCY
 7  * @date:2018年2月3日下午8:08:51
 8  */
 9 public class EmployeeTest {
10     public static void main(String[] args) {
11         //
定義Employee類得數組並賦值 12 Employee staff[] = new Employee[3]; 13 System.out.println("加薪前"); 14 staff[0] = new Employee("Herry", 70000, 1988, 12, 3); 15 staff[1] = new Employee("Marry", 20000, 1990, 1, 31); 16 staff[2] = new Employee("Amy", 10000, 1989, 11, 23); 17 18 // 給每個人加薪5%,並打印
19 System.out.println("\n加薪後"); 20 for (Employee em : staff) { 21 em.raiseSalary(5); 22 System.out.println("姓名:" + em.getname() + "\t薪水:" + em.getSalary() + "\t入職時間:" + em.getHireDay()); 23 } 24 } 25 } 26 27 /** 28 * 員工類 29 * 30 * @author:Archer-LCY
31 * @date:2018年2月3日下午8:28:40 32 */ 33 class Employee { 34 private String name; 35 private double salary; 36 private LocalDate hireDay;// LocalDate需要導入包java.time.LocalDate; 37 38 public Employee(String name, double salary, int year, int month, int day) { 39 super(); 40 this.name = name; 41 this.salary = salary; 42 this.hireDay = LocalDate.of(year, month, day); 43 output(); 44 } 45 46 // 輸出 47 public void output() { 48 System.out.println("姓名:" + name + "\t薪水:" + salary + "\t入職時間:" + hireDay); 49 } 50 51 public String getname() { 52 return name; 53 } 54 55 public double getSalary() { 56 return salary; 57 } 58 59 public LocalDate getHireDay() { 60 return hireDay; 61 } 62 63 public void raiseSalary(double byPercent) { 64 double raise = this.salary * byPercent / 100; 65 salary += raise; 66 } 67 }

註意:

(1)在這個示例中包含兩個類,一個是Employee類,一個是帶有public訪問修飾符的EmployeeTest類。其中EmployeeTest類中包含了main方法。

(2)源文件名是EmployeeTest.java ,這是因為文件名必須與public類的名字相匹配。在一個源文件中,只能有一個共有類,但非共有類的數目可以任意。

(3)當編譯這段源代碼時,編譯器將在目錄下創建兩個類文件:EmployeeTest.class和Employee.class。

(4)程序中包含main方法的類名提供字節碼解釋器,以便啟動這個程序:java EmployeeTest ,字節碼解釋器開始運行EmployeeTest類的main方法的代碼。在這段代碼中,定義了Employee類的數組,裏面有三組,先後構造了三個新的Employee對象,並顯示它們的狀態。

2、多個文件的使用

在EmployeeTest.java一個源文件中包含了兩個類。但一般情況下,我們習慣於每一個類放在一個單獨的源文件中。例如,將EmployeeTest類放在EmployeeTest.java中,而將Employee類放在Employee.java中。

如果習慣上述所說的分開組織文件的方法,可以采用下面三種編譯源程序的方法:

註:每次在命令提示符窗口使用前記得先用dir,查看當前目錄,這樣可以避免不必要的尷尬錯誤。還需要註意的一點是javac和java時必須是在文件所在目錄,如下圖:

技術分享圖片

(1)使用通配符調用java編譯器:javac EmployeeTest*.java,此時,所有的與通配符匹配的源文件都將被翻譯成類文件。編譯成功結果如下:

技術分享圖片

(2)第二種是使用:javac EmployeeTest.java,編譯成功結果如下:

技術分享圖片

(3)第三種:如果想獨立測試使用:java EmployeeTest 這種方法可以將結果打印在命令提示符窗口,結果如下圖:

技術分享圖片

一個更大應用程序的一部分,可以用):java Application

3、對Employee類剖析

(1)這個類裏面有一個構造器和5方法:

/**構造器*/

public Employee(String name, double salary, int year, int month, int day)

/**5個方法*/

public void output()

public String getname()

public double getSalary()

public LocalDate getHireDay()

public void raiseSalary(double byPercent)

(2)所有方法都被public標記。關鍵字public意味著任何類的任何方法都可以調用這些方法。

(3)在Employee類中有3個示例域用來存放將要操作的數據:

private String name;

private double salary;

private LocalDate hireDay;

(4)關鍵字private確保只有Employee類自身才能訪問這些實例域,而其他類的方法不可以。

(5)註:可以有public來標記實例域,但是,這是一張極不為提倡的方法。public數據域允許程序中的任何方法都能對其進行讀取和修改,這就破壞了封裝。任何類任何方法都可以修改public與,這意味著某些代碼將可以使用這種存取權限,這是我們不希望看到的。

(6)註:有兩個實例域本身就是對象:name域是String類的對象,hireDay域是LocalDate類的對象。其實,這種情形十分常見:類通常包括類型屬於某個類類型的實例域。

4、構造函數的使用

A.從Employee類的構造器開始分析

public Employee(String name, double salary, int year, int month, int day) {

super();

this.name = name;

this.salary = salary;

this.hireDay = LocalDate.of(year, month, day);

output();

}

(1)可以看到構造器與類名相同,在構造Employ類的對象時,構造器會運行,以便將實例域初始化為希望的狀態。

(2)例如:new Employee("Herry", 70000, 1988, 12, 3);這條代碼在創建Employee類實例時,將會把實例域設置為:name=”Herry”;salary=70000;hireDay=LocalDate.of(1988,12,3);

(3)構造與其他方法不一樣的是,構造器總是會伴隨著New操作符的執行而被調用,而對一個已存在的對象不能調用構造器來達到從新調用的目的。例如:Herry.Employee("Herry", 70000, 1988, 12, 3); 會產生編譯錯誤。

4、隱式參數與顯式參數

隱式參數:出現在方法名之前的。

顯式參數:位於方法名後面的括號中的。

方法用於操作對象以及存取它們的實例域。將調用這個方法的對象的salary實例域設置為新值。例如:方法:

public void raiseSalary(double byPercent) {

double raise =salary *byPercent / 100;

salary +=raise;

}

在每一個方法中,關鍵字this表示隱式參數。可以用下面方式編寫上面的方法:(這樣的優點:這樣可以將實例域與局部變量區分開來)

public void raiseSalary(double byPercent) {

double raise =this.salary *byPercent / 100;

salary +=raise;

}

註意隱式構造和參數化構造不能共存:盡量把帶參構造和默認構造都寫出來,當你不把默認構造顯示出來時,帶參構造會將其覆蓋,後面第二次使用時就會出錯。

如下圖:左邊兩組是帶默認參數,不會報錯;右邊是不帶默認參數,會報錯(紅色波浪線部分)

技術分享圖片技術分享圖片

技術分享圖片技術分享圖片

在Java中,所有的方法都必須在類的內部定義,但並不是內聯(inline)方法。是否將某個變量設置為內聯方法是Java虛擬機的任務

5、封裝

封裝(Encapsulation)是面向對象方法的重要原則,就是把對象的屬性和操作(或服務)結合為一個獨立的整體,並盡可能隱藏對象的內部實現細節。

封裝是把過程和數據包圍起來,對數據的訪問只能通過已定義的接口。面向對象計算始於這個基本概念,即現實世界可以被描繪成一系列完全自治、封裝的對象,這些對象通過一個受保護的接口訪問其他對象。封裝是一種信息隱藏技術,在java中通過關鍵字private,protected和public實現封裝。

優點:(1)一旦在構造器中設定完畢,就沒有任何一個辦法可以對其修改,這樣確保其不會被破壞,安全系數增加。

(2)更改器可以執行錯誤檢查,而直接對域進行賦值就不會有這些處理。

6、靜態方法

下面的情況適合使用靜態方法:

(1)一個方法不需要訪問對象狀態,其所需參數都是通過顯式參數提供(例如:Math.pow)

(2)一個方法只需要訪問類的靜態域

Java中的靜態域和靜態方法在功能上與c++相同,不同的是語法書寫上不一樣。Java中用. 如:Math.pow;而c++中是用::操作符訪問,如:Math::PI。

關於“static”:起初,C引入關鍵字 static是為了表示退出一個塊後依然存在的局部變量在這種情況下, 術語“ static” 是有意義的;變量一直存在,當再次進入該塊時仍然存在。隨後,static 在C 中有了第二種含義, 表示不能被其他文件 訪問的全局變量和函數。 為了避免引入一個新的關鍵字, 關鍵字static 被重用了。最後,C++ 第三次重用了這個關鍵字,與前面賦予的含義完全不一樣, 這裏將其解釋為:屬於類且不屬於類對象的變量和函數。這個含義與 Java相同。

-------摘自《Java核心技術》

二、對象構造

構造器:

(1)特點:沒有返回值(void不是)、方法名和類名一致(方法名一樣,參數不一樣,參數可以有0個或者1個或者多個構造方法的重載)、每個類可以有一個以上的構造器、構造器總是伴隨著new操作一起調用

(2)可以指定參數及實現重載

(3)註:java構造器的工作方式和C++一樣。但是,所有java對象都是在堆中構造的,構造器總是伴隨著new操作符一起使用。Employee number("Herry", 70000, 1988, 12, 3);//在c++中是正確的

(4)警告!!:不要在構造器中定義和實例域重名的局部變量。例如

public Employee(String n, double s, . . ){

String name = n;

double salary = s;

}//是錯誤的

在上述錯例中,在這個構造器中聲明了局部變量name和salary。這些變量只能在構造器內部訪問。這些變量屏蔽了同名的實例域。

在構造器內調用同一個類的構造器,可以用到this關鍵字,this(...),如:

技術分享圖片

構造器小結註意事項:

(1)一個類中可以有多個構造器,這些構造與類名相同,當存在多個構造方法時,這些方法傳遞的參數不一樣。

(2)如果一個類中沒有構造器也沒有main方法,這時候會默認一個無參構造;這個構造器會將所有實例域設置為默認值,即實例域裏,數值型為0,布爾型為false,對象變量為null。

(3)如果類中至少有一個構造器,並且這個構造器不帶有參數,這時,如果在構造對象時沒有提供參數就會視為不合法的。

(4)如果構造器中沒有顯示地給實例域賦值,這時會自動地賦為默認值:數值為0,布爾值為false,對象引用為null。這樣,會影響代碼的可讀性。

(5)註:在c++中,不能直接初始化類的實例域,所有的域都必須在構造器裏面設置。

三、包

使用包的主要原因是保證類名的唯一性,當兩個程序員各自建立了兩個類名相同的類時,只要將類放在不同的包中,就不會產生沖突。

為保證包的絕對唯一性,sun公司建議將公司的因特網域名(這是獨一無二的)以逆序形式作為包名。例如:banana.com,逆序變為com.banana。

從編譯器角度來看,嵌套的包之間沒有任何聯系。

一個類可以使用包中的所有類,以及其他包中的公有類(public class)。訪問另一個包中的公有類的兩種方法:

(1)每個類名之前添加完整的包名(繁瑣),例如:java.time.LocalDate today =java.time.LocalDate.now();

(2)我們常用的方法是使用import導入包,import語句應位於源文件的頂部(位於package語句後面),這樣就無需在前面加前綴了。例如:import java.time.LocalDate;這時候就可以使用:LocalDatetoday=LocalDate.now();

技術分享圖片

當兩個包中含有相同的類名時,在使用時,編譯器無法識別要使用哪個類,這時候我們可以在使用的語句加前綴。例如,兩個不同的類中都含有Date類時,可以這樣表示:

技術分享圖片

註:在 C-H■ 中, 與 包 機 制 類 似 的 是 命 名 空 間(namespace)。 在Java 中,package 與import 語句類似於C+H■ 中的namespace 和using 指令。

靜態導入:如:import static java.lang.System.*;這時候就可以這樣寫了out.println();但是,這樣降低了程序的可讀性。

四、類設計的技巧

1、保證數據的私有。

2、數據一定要初始化。

3、不要在類中使用過多的私有類型。

4、一個類的職責不應該太多或者太少。

5、類名和方法名盡可能體現其職責。

6、優先使用不可變的類。

DAY12-Java中的類--接DAY10