Java程序運行
- Java程序的執行必須經過編輯、編譯和運行三個步驟
- 編輯指編寫代碼,最終形成后綴名為
.java
的Java源文件 - 編譯指使用Java編譯器(
javac
指令)將源文件翻譯為二進制代碼,編譯后生成后綴名為.class
的字節碼文件,該字節碼文件并不是一個可以直接運行的文件。Java編譯器會為每一個類生成一個字節碼文件 - 運行是指Java解釋器(
java
指令)將字節碼文件翻譯稱機器代碼執行并得到運行結果
- 編輯指編寫代碼,最終形成后綴名為
- JVM:Java Virtual Machine的縮寫,Java虛擬機,用于運行Java字節碼文件
- JRE:Java Runtime Environment的縮寫,Java運行環境,作用:運行Java程序所必須的環境的集合,包含JVM標準實現以及Java核心類庫
- JDK:Java Development Kit的縮寫,Java語言的軟件開發工具包 作用;JDK是整個Java開發的核心,他包含了Java的運行環境(JRE)和Java工具
三者的關系如下:詳見 傳送門
基礎
- Java常見類型精度:
byte(1)<short(2)<char(2)<int(4)<long(8)<float(4)<double(8)
,需要注意的是Java中的char類型占兩個字節,雖然和short一樣都只占兩個字節,但是無法將char類型自動轉換為short類型,char類型相當于無符號整數。 - 對于一個整數常量,系統自動認為是int類型的,若一個整數后綴字母l或L,則被定義為long類型的長整數。對于一個實數,系統默認為是雙精度型,即double類型,若需要把一個實數表示為單精度float類型,則需要在其實數后面加上字符f或F作標記。如2.54為雙精度型實數,而2.54f則為單精度型實數。
- 當兩個不同類型的操作數進行算術運算時,涉及到類型的轉換,被轉換為同一類型后再運算。類型轉換分為系統自動轉換和程序強制轉化兩種情況,從少字節的類型到多字節的類型、從整數類型到實數類型是自動轉換,相反則需要強制轉換。因此語句
float x=2.0;
會報錯,因為2.0默認是double類型的,賦值給float類型的需要強制類型轉換。(經測驗從long到float是可以自動轉換的) - 常用的數學函數被歸類到系統類java.lang.Math中,它們都是靜態(static)成員函數,通過類名和點運算符可以直接調用
- switch語句如果不break就會從上往下執行,如果遇到default任何條件都可以執行
- 類是對象的抽象,而對象則是類的特例,或者是類的具體表現形式
- 修飾類的修飾符只能為
public
final
abstract
和默認 - 封裝提高了可重用性
- Java中靜態變量可以不強制賦初值,如果要賦值可以在類體中完成。但是被
final
修飾的變量必須賦初值 - Java虛擬機中有一個
garbage collect
線程定期gc掉已經沒有引用的對象。(就算一直實例化對象也不會溢出)
繼承extends
- 使用
super
父類的構造函數只能在派生類構造函數的第一行調用(或者不調用,編譯器會自動調用super(),即父類的無參構造函數,如果沒有會報錯) - Java重寫條件比C++嚴格,在C++中只要和父類函數同名就會進行重寫,但是Java中必須要參數列表相同,返回類型必須可以和父類返回類型兼容。否則就會認為是重載
- 靜態方法不能被重寫,當派生類中含有和基類同名的靜態成員時將會進行覆蓋(原來的還在,如果使用基類引用指向派生類對象的話訪問到的還是原來的靜態成員)
- Java也支持用基類引用指向派生類對象,同C++一樣,基類引用只能訪問基類中存在的屬性
- Java重寫以后自動實現多態,不像C++需要
virtual
修飾才能真正實現多態。使用基類引用指向派生類對象時調用重寫函數將自動調用被重寫后的函數 - 如果派生類和基類中含有相同名字的數據成員,可以在派生類中使用
super
進行調用,對于派生類對象需要進行類型轉換才能訪問基類成員。例如:
class father
{int x=1;
}
class son extends father
{int x=2;
}
class Test
{public static void main(String[] args){son s=new son();System.out.println(((father)s).x);}
}
運行結束后結果應該為1,需要注意的時需要兩個括號。此時**重寫后的函數訪問這個同名成員x的時候訪問的是派生類的,即使使用基類引用訪問重寫函數仍然調用的是派生類中的x,但是如果訪問的是基類中沒有被重寫的函數修改的將會是基類中的成員屬性。**可能有些晦澀,可以理解一下下面我寫的測試樣例:
package Test;class xx
{int t=0;xx(int _t){t=_t;}void eat(){t=1;System.out.println(t);}void change(){t=11;}
}
class xxx extends xx
{int t;xxx(){super(10);System.out.println(t);}void eat(int z){t=z;System.out.println(t);}void eat(){t=2;System.out.println(t);}
}class Main
{public static void main(String[] args){xxx x=new xxx();x.eat();x.eat(3);System.out.println(x.t);System.out.println(((xx)x).t);x.change();System.out.println(((xx)x).t);xx y=new xxx();y.eat();System.out.println(y.t);y.change();System.out.println(y.t);}
}
運行結果為:
抽象abstract/接口interface
-
接口的所有方法都是抽象的,每個成員變量默認具有
public
static
final
,并且只能在定義時被初始化。接口中的每個成員方法默認具有public
abstract
,同抽象類一樣,接口不能被實例化。如果一個接口中沒有包含成員變量的定義稱這個接口為純接口。如果一個類引用了某個接口,就必須實現接口中的所有方法。 -
Java中不支持多繼承,但是支持實現多個接口
-
一個接口一個同時
extends
多個接口,即Java中的接口是支持多繼承的。 -
當一個類實現一些互相繼承的類的時候不用實現多次,每個方法都只用實現一次(默認就有C++中的
virtual
) -
經過測試,Java中接口中是可以含有非抽象方法的,不過方法需要是
private
修飾的。外部無法直接訪問。變量必須為public static final
類型的,而且必須初始化。 -
需要注意的是在實現接口的時候如果接口的方法是默認的訪問權限(
abstract public
)則在類中也必須為public
訪問權限,因為不能縮小重寫方法的訪問權限。但是如果方法在接口中使用private
修飾則不需要(不能使用protected
修飾)。只是使用private修飾以后相當于在類中是重寫而不是實現,而且接口中也必須實現private
方法 -
包聲明語句
package
必須是Java程序文件的第一條語句,引入包語句import
必須在包聲明語句和類定義模塊之間 -
抽象類和接口的區別:
- 抽象類要被子類繼承,接口要被類實現
- 接口只能做方法聲明,抽象類中可以作方法聲明,也可以進行方法實現
- 接口里定義的變量只能是公共的靜態的常量,抽象類中的變量是普通變量
- 接口式設計的結果,抽象類是重構的結果
- 抽象類和接口都是用來抽象具體對象的,但是接口的抽象級別更高
- 抽象類可以有具體的方法和屬性,接口中只能有抽象方法和不可變常量
- 抽象類主要用來抽象類別,接口主要用來抽象功能
異常Exception
- Throwable類是類庫java.lang包中的一個類,該類不能直接使用。它派生了兩個子類:Exception和Error。其中Error類表示恢復不是不可能但很困難的一種嚴重錯誤。所有的異常都繼承
java.lang.Throwable
- 異常類一般是
Exception
的子類,類名通常以Exception
結尾 - 如果一個方法會拋出異常而我們不想在這個方法內部處理這個異常,我們可以在方法頭后面加上
throws XXXException
,調用這個異常的方法必須處理這個異常,要么調用方也必須向上拋出異常。main函數的異常由JVM(java虛擬機)處理。 - 我們也可以自己定義自己的異常類,需要繼承
Exception
,然后通過父類的構造函數傳遞信息,再通過printStackTrace()
方法在命令行打印異常信息在程序中出錯的位置及原因,就會自動打印我們想要打印的信息(就是構造函數中的信息)。需要注意的是,我們在定義自己的異常類的時候必須定義一個private static final long serialVersionUID = 1L;
,可以參加下面這個例子:
package 實驗五;public class IllegalAgeException extends Exception
{private static final long serialVersionUID = 1L; public IllegalAgeException() {}public IllegalAgeException(String message){super(message);}
}
finally
中的內容一定會運行,例如:
public static void main(String[] args)
{try {return;}finally {System.out.println("Finally");}//運行結果為Finally//System.out.println("Not return");編譯錯誤,顯示Unreachable code
}
try catch finally
的使用- 將遇見可能引發異常的代碼包含在
try
語句塊中 - 如果發生異常,將對異常的處理放入
catch
finally
可以沒有也可以只有一個,無論沒有發生異常,他總會在這個異常處理結構的最后運行,即使在try
塊或者catch
塊中用return
返回了,在返回前finally
總是要執行。如果沒有catch
塊則finally
塊是必須的
- 將遇見可能引發異常的代碼包含在
String類
- String類對象的值和長度都不能改變,稱為常量字符串類
- Java中String沒有字符串結束符
- 如果直接使用給字符串賦值常量字符串而不調用構造函數的方式,如:
String s1="China";
則會將“China”
放入內存池中,如果在后面再定義String s2="China"
則s1和s2指向同一個位置,他們的指針值都是相同的,但是如果使用構造函數例如String s3=new String("China");
的話則s3的值和s1、s2不同 StringBuffer
類可以使用append
方法在末尾添加其它字符串(也可以是其他基本類型,將會自動轉換成字符串)
數組/Vector
- 對象數組在實例化以后相當于一個指針數組,每個元素仍然需要進行實例化。如果想要在數組創建的時候就進行實例化可以在后面加上花括號,里面是實例化的對象,但是這個時候我們不能指定數組的大小,需要編譯器自己判斷數組的大小。例如:
xx a[]=new xx[]{new xx(10),new xx(10),new xx(10)};//接上面的例子,xx是一個類
xx a[]={new xx(10),new xx(10),new xx(10)};//等價的寫法
- 數組長度就是數組中包含的元素個數,當定義和創建一個數組后,數組長度值被自動保存到數組對象的成員變量length中,它是一個常量成員變量,被創建數組時自動初始化后,以后不允許改變它的值,只允許通過點運算符讀取它的值。
char
類型的包裝類是character
- 包裝類常用的函數
boolean equals(Object obj)
,用于比較形參和當前對象是否相等String toString()
將當前包裝類的值轉換成字符串int compareTo(Object obj)
當調用對象大于參數對象時返回正數,小于時返回負數,相等時返回0
- 向量類
Vector
List
Set
等只允許保存對象類型,不允許保存基本數據類型 - Java 不支持重載運算符
- Java中for循環可以寫成簡化形式:
for(<元素類型> <變量名>:<數組或集合或向量>){<循環體>}//定義的變量將會遍歷整個數組或者向量
- 需要注意一個小細節就是
String
中的length
是一個方法,而數組中的length
是一個常量整型成員
多線程Thread
- 創建線程有兩種方法(想要了解更多可以戳 : 傳送門)
- 繼承
java.lang.Thread()
類,覆蓋run()
方法,在創建的子類中重寫run()
函數,加入線程所要執行的代碼。 - 在類中實現
java.lang.Runable
接口,并實現run()
方法。實例化這個類以后就可以使用這個類實例化其他線程。通過這種方法我們可以實例化多個相同的線程。 - 當類還要繼承其他類時使用第二種方法更加簡便。實現線程以后我們就可以在主函數中使用
start
方法開啟線程。 - Thread.start ()方法(native)啟動線程,使之進入就緒狀態,當CPU為該線程分配時間時,由JVM調度執行run()方法。
- 繼承
IO/文件流
- Java輸入流從結構上可以分為字節流和字符流(每個字符兩個字節)
- 字節流的基礎類是
InputStream
和OutputStream
這兩個抽象類 - 若輸入流對象創建失敗(如對應的文件不存在時),將會引發異常
FileNotFoundException
,在程序中需要對其捕獲和處理。創建輸出字節流對象時,若指定的文件不存在,將會自動創建一個新文件 - 盡量手動關閉文件流
- 通過
String
的getBytes
方法將字符串轉化為字符數組,可以用字符數組初始化字符串 - 文件類
File
的length
屬性保存文件的字節大小 - 文件中的
\
應該寫作\\
,否則會認為是轉義字符 - 可以使用文件流實例化數據文件流
DataInputStream
類和DataOutputStream
類,然后就可以使用在這個流對象直接輸入輸出。一般方法為readXXX
或者writeXXX
- 如果需要頻繁地讀寫磁盤,可以使用字節緩沖流
BufferedInputStream
和BufferedOutputStream
類讀寫文件。字節緩沖流對象將會建立一個內部緩沖區,當緩沖區滿或者關閉字節緩沖流的時候一次性輸出對應六,也可以使用flush
方法主動將緩沖區數據輸入到流對象 - 我們還可以只用
PrintStream
類進行輸出,同數據流DataOutputStream
一樣,PrintStream
需要文件流進行初始化,然后就可以直接使用print
和println
函數 - System類中的in將會實例化為
BufferedInputStream
對象(雖然它本身是一個InputStream
類) - 關于字符流內容可以戳我的另一篇博客:傳送門
GUI
- JPanel類的對象必須放在JFrame中才能可見
- 授權處理模型處理時間的一般方法:
- 對于某種類型的事件XXXEvent(例如點擊鼠標),想要接收并處理這類事件,必須定義相應的事件監聽器,該類需要實現與該時間相對應的接口
XXXListener
- 在該類中必須實現接口對應的方法(事件發生以后將會運行),不同的Listener有不同的方法
- 事件源實例化以后,必須進行授權注冊該類時間的監聽器,使用
addXXXListener
方法注冊監聽器
- 對于某種類型的事件XXXEvent(例如點擊鼠標),想要接收并處理這類事件,必須定義相應的事件監聽器,該類需要實現與該時間相對應的接口