內部類和例外類
- 1 內部類
- 2 匿名類
- 2.1 和子類有關的匿名類
- 2.2 和介面有關的匿名類
- 3 例外類
- 3.1 try-catch陳述句
- 3.2 自定義例外類
- 4 斷言
- 5 綜合案例
1 內部類
Java支持在一個類中宣告另一個類,這樣的類稱作內部類,而包含內部類的類成為內部類的外嵌類,
內部類的類體中不可以宣告類變數和類方法,外嵌類的類體中可以用內部類宣告物件,作為外嵌類的成員,
內部類的使用規則:
(1)宣告內部類如同在類中宣告方法或變數一樣,一個類把內部類看作是自己的成員,
(2)外嵌類的類體中可以用內部類宣告的物件,作為外嵌類的成員,
(3)外嵌類的成員變數在內部類中仍然有效,內部類中的方法也可以呼叫外嵌類中的方法,
(4)內部類的類體中不可以宣告類變數和方法,
(5)外嵌類和內部類在編譯時,生成兩個.class檔案,
例如:某種型別的農場飼養了一種特殊種類的牛,但不希望其他農場飼養這種特殊種類的牛,那么這種型別的農場就可以將創建這種特殊種牛的類作為自己的內部類,
下面的例子1(Example1.1.java)中有一個RedCowForm(紅牛農場)類,該類中有一個名字為RedCow (紅牛)的內部類,
RedCowForm.java
public class RedCowForm {
static String formName;
RedCow cow; //內部類宣告物件
RedCowForm() {
}
RedCowForm(String s) {
cow = new RedCow(150, 112, 5000);
formName = s;
}
public void showCowMess() {
cow.speak();
}
class RedCow { //內部類的宣告
String cowName = "紅牛";
int height, weight, price;
RedCow(int h, int w, int p) {
height = h;
weight = w;
price = p;
}
void speak() {
System.out.println("偶是" + cowName + ",身高:" + height + "cm 體重:" + weight + "kg,生活在" + formName);
}
} //內部類結束
}
Example1.1.java
public class Example1_1 {
public static void main(String[] args) {
RedCowForm form = new RedCowForm("紅牛農場");
form.showCowMess();
form.cow.speak();
}
}
需要特別注意的是,Java編譯器生成的內部類的位元組碼檔案的名字和通常的類不同,內部類對應的位元組碼檔案的名字格式是“外嵌類名$ 內部類名”,例如,例子1中內部類的位元組碼檔案是RedCowForm$RedCow.class,因此,當需要把位元組碼檔案復制給其他開發人員時,不要忘記了內部類的位元組碼檔案,
內部類可以被修飾為static 內部類,例如,例子1中的內部類宣告可以是static classRedCow,類是一種資料型別,那么static內部類就是外嵌類中的一-種靜 態資料型別,這樣一來,程式就可以在其他類中使用static內部類來創建物件了,但需要注意的是,static 內部類不能操作外嵌類中的實體成員變數,
假如將例子1中的內部類RedCow更改成static內部類,就可以在例子1的Example1_ 1
主類的main方法中增加如下的代碼,
RedCowForm.RedCow redCow = new RedCowForm.RedCow(180,119,6000);
redCow.speak();
注意:非內部類不可以是static類
2 匿名類
2.1 和子類有關的匿名類
創建子類物件時,除了使用父類的構造方法外還有類體,此類體被認為是一個子類去掉類宣告后的類體,稱作匿名類,
假設Bank是類,那么下列代碼就是用Bank的一個子類(匿名類)創建物件:
new Bank() {
匿名類的類體
};
和子類有關的匿名類:
(1)匿名類是一個子類,由于無名可用,所以不可能用匿名類宣告物件,但卻可以直接用匿名類創建一個物件,
(2)匿名類可以繼承父類的方法也可以重寫父類的方法,
(3)使用匿名類時,必然是在某個類中直接用匿名類創建物件,以此,匿名類一定是內部類,
(4)匿名類可以訪問外嵌類中的成員變數和方法,匿名類的類體中不可以宣告static成員變數和static方法,
(5)由于匿名類是一個子類,但沒有類名,所以在用匿名類創建物件時,要直接使用父類的構造方法,
例子2:該類共有4個類: (Example2_1. java)、ShowBoard類、
OutputAlphabet型別、 OutputEnglish. java ,該匿名類的物件負責輸出希臘字母表,
OutputAlphabet.java
abstract class OutputAlphabet {
public abstract void output();
}
OutputAlphabet .java
public class OutputEnglish extends OutputAlphabet { //輸出英文字母子類
public void output(){
for (char c='a';c<='z';c++){
System.out.printf("%3c",c);
}
}
}
ShowBoard .java
public class ShowBoard {
void showMess(OutputAlphabet show) { //引數show是OutputAlphabet型別的物件
show.output();
}
}
Example2_1.java
public class Example2_1 {
public static void main(String[] args) {
ShowBoard board = new ShowBoard();
board.showMess(new OutputEnglish());//向引數傳遞OutputAlphabet的子類OutputEnglish的物件
board.showMess(new OutputAlphabet() { //向引數傳遞OutputAlphabet的匿名子類的物件
@Override
public void output() {
for (char c = 'α'; c <= 'ω'; c++) //輸出希臘字母
System.out.printf("%3c", c);
}
});//分號在這里
}
}

2.2 和介面有關的匿名類
和介面有關的匿名類
假設Computable是一個介面,那么,Java允許直接用介面名和一個類體創建一個匿名物件,此類體被認為是實作了Computable介面的類去掉類宣告后的類體,稱作匿名類,
下列代碼就是用實作了Computable介面的類(匿名類)創建物件:
new Computable(){
實作介面的匿名類的類體
};
下面例子演示了和介面有關的匿名類的用法:
interface SpeakHello {
void speak();
}
class HelloMachine {
public void turnOn(SpeakHello hello) {
hello.speak();
}
}
public class Example7_3 {
public static void main(String[] args) {
HelloMachine machine = new HelloMachine();
machine.turnOn(new SpeakHello() {
@Override
public void speak() {
System.out.println("hello,you are welcome!");
}
});
machine.turnOn(new SpeakHello() {
@Override
public void speak() {
System.out.println("你好,歡迎光臨!");
}
});
}
}

3 例外類
所謂例外就是程式運行時可能出現一些錯誤,比如試圖打開一個根本不存在的檔案等,例外處理將會改變程式的控制流程,讓程式有機會對錯誤作出處理,程式運行出現例外時,Java運行環境就用例外類Exception的相應子類創建一個例外物件,并等待處理,例外物件可以呼叫如下方法得到或輸出有關例外的資訊:
例外物件可以呼叫如下方法得到或輸出有關例外的資訊:
public String getMessage();
public void printStackTrace();
public String toString();
3.1 try-catch陳述句
Java使用try-catch陳述句來處理例外,將可能出現的例外操作放在try-catch陳述句的try部分,將發生例外后的處理放在catch部分,
try-catch陳述句的格式如下:
try{
包含可能發生例外的陳述句
}
catch(ExceptionSubClass1 e){
...
}
catch(ExceptionSubClass2 e){
...
}
下面一個例子給出了try-catch陳述句的用法:
public class Example3_1 {
public static void main(String[] args) {
int n = 0, m = 0, t = 1000;
try {
m = Integer.parseInt("8888");
n = Integer.parseInt("ab89"); //發生例外,轉向catch
t = 7777; //t沒有機會被賦值
} catch (NumberFormatException e) {
System.out.println("發生例外:" + e.getMessage());
}
System.out.println("n=" + n + ",m=" + m + ",t=" + t);
try {
System.out.println("故意拋出I/O例外!");
throw new java.io.IOException("我是故意的");
//System.out.println("這個輸出陳述句肯定沒有機會執行,所以必須注釋掉,否則編譯出錯");
} catch (java.io.IOException e) {
System.out.println("發生例外:" + e.getMessage());
}
}
}

帶finally子陳述句的try~catch陳述句,語法格式如下:
try{ }
catch(ExceptionSubClass e){ }
finally{}
其執行機制是在執行try~catch陳述句后,執行finally 子陳述句,也就是說,無論在try部分是否發生過例外,finally 子陳述句都會被執行
3.2 自定義例外類
(1)例外的宣告
?一個方法不處理它產生的例外,而是沿著呼叫層次向上傳遞,由呼叫它的方法來處理這些例外,叫宣告例外.
?宣告例外的方法:
在產生例外的方法名后面加上要拋出(throws)的例外的串列:
如: void compute(int x) throwsAri thmeticException
{//這里有例外發生,但是并沒有處理…}
(2)我們也可以擴展Exception類定義自己的例外類,然后規定哪些方法產生這樣的例外,一個方法在宣告時可以使用throws關鍵字宣告要產生的若干個例外,并在該方法的方法體中具體給出產生例外的操
作,即用相應的例外類創建物件,并使用throw關鍵字拋出該例外物件,導致該方法結束執行,
(3)通常情況下,計算兩個整數之和的方法不應當有任何例外放出,但是,對某些特殊應程式,可能不允許同號的整數做求和運算,比如當一個整數代表收入,一個整數代表支出時,這兩個整數就不能是同號,
例子 (Example3_2. java)中,Bank類中有一個income(int in, int out)方法,物件呼叫該方法時,必須向引數in傳遞正整數、向引數out傳遞負數,并且int+out必須大于等于0,否則該方法就拋出例外( BankException. java ),因此,Bank類在宣告income(int in, int out)方法時,使用throws關鍵字宣告要產生的例外,
BankException.java
public class BankException extends Exception {
String message;
public BankException(int m, int n) {
message = "入賬資金" + m + "是負數或支出" + n + "是正數,不符合系統要求.";
}
public String warnMess() {
return message;
}
}
Bank.java
public class Bank {
private int money;
public void income(int in, int out) throws BankException {
if (in <= 0 || out >= 0 || in + out <= 0) {
throw new BankException(in, out); //方法拋出例外,導致方法結束
}
int netIncome = in + out;
System.out.printf("本次計算出的純收入是:%d元\n", netIncome);
money = money + netIncome;
}
public int getMoney() {
return money;
}
}
Example3_2.java
public class Example3_2 {
public static void main(String[] args) {
Bank bank = new Bank();
try {
bank.income(200, -100);
bank.income(300, -100);
bank.income(400, -100);
System.out.printf("銀行目前有%d元\n", bank.getMoney());
bank.income(200, 100);
bank.income(99999, -100);
} catch (BankException e) {
System.out.println("計算收益的程序出現如下問題:");
System.out.println(e.warnMess());
}
System.out.printf("銀行目前有%d元\n", bank.getMoney());
}
}

4 斷言
?斷言陳述句用于除錯代碼階段,在除錯代碼階段讓斷言陳述句發揮作用,這樣就可以發現一些致命的錯誤,當程式正式運行時就可以關閉斷言陳述句,但仍把斷言陳述句保留在源代碼中,如果以后應用程又需要除錯,可以重新啟用斷言陳述句,
?使用關鍵字assert宣告一條斷言陳述句,斷言陳述句有以下兩種格式:
assert booleanExpression;
assert booleanExpression:messagelException;
?啟用與關閉斷言陳述句
當使用Java解釋器直接運行應用程式時,默認地關閉斷言陳述句,在除錯程式時可以使用-ea啟用斷言陳述句,例如:
java -ea mainClass
例子4中,使用一個陣列放著某學生5門課程的成績,程式準備計算學生的成績的總和,在除錯程式時使用了斷言陳述句,如果發現成績有負數,程式立刻結束執行,程式除錯開啟斷言陳述句運行效果如圖4.1,關閉斷言陳述句運行效果如圖4.2,
import java.util.Scanner;
public class Example4 {
public static void main (String args[ ]) {
int [] score={-120,98,89,120,99};
int sum=0;
for(int number:score) {
assert number>0:"負數不能是成績";
sum=sum+number;
}
System.out.println("總成績:"+sum);
}
}
圖4.1

圖4.2

5 綜合案例
下面的例子5中模擬向貨船上裝載集裝箱,如果貨船超重,那么貨船認為這是一個例外將拒絕裝載集裝箱,但無論是否發生例外,貨船都需要正點啟航
DangerException.java
public class DangerException extends Exception {
final String message = "超重";
public String warnMess() {
return message;
}
}
CargoBoat.java
public class CargoBoat {
int realContent; //裝載的重量
int maxContent; //最大裝載量
public void setMaxContent(int c) {
maxContent = c;
}
public void loading(int m) throws DangerException {
realContent += m;
if(realContent>maxContent) {
throw new DangerException();
}
System.out.println("目前裝載了"+realContent+"噸貨物");
}
}
Example5.java
public class Example5 {
public static void main(String[] args) {
CargoBoat ship = new CargoBoat();
ship.setMaxContent(1000);
int m =600;
try{
ship.loading(m);
m = 400;
ship.loading(m);
m = 367;
ship.loading(m);
m = 555;
ship.loading(m);
}
catch(DangerException e) {
System.out.println(e.warnMess());
System.out.println("無法再裝載重量是"+m+"噸的集裝箱");
}
finally {
System.out.printf("貨船將正點啟航");
}
}
}

轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/274717.html
標籤:java
上一篇:JVM類加載器(詳解)
