工作原理
1)編寫.java文本文件;
2)通過編譯器編譯為.class二進制文件;
3)使用JAVA虛擬機執行.class文件,不同平臺對應不同虛擬機;
System.exit:main方法結束不等于整個程序的真正結束,可能還有線程在運行著,調用System.exit()才達到程序的真正結束。
面向對象原理
單繼承,多接口實現;一般,繼承主要用在一個系列的對象抽象;接口主要針對功能的抽象;
JAVA語言中,并非所有的變量都是對象,基本的數值類型(char,short,int,long,float,double,boolean)除外,可能是為了運行速度,編譯器沒有將這些類型編譯為對象;
對象Object是所有對象的祖宗;
對象Class保存一個對象的類型信息,也可以是基本的數值類型;
數據類型
int 4B
short 2B
long 8B
byte 1B
float 4B (后綴f,F)
double 8B (后綴d,D)
char 2B
boolean 1B
前綴:
0x:十六進制 (指數用p,十進制用e)
0:八進制
變量命名
字母(a-zA-Z)、下劃線(_)開頭,后續字母可以是字母、數字、下劃線,不能是關鍵字或者保留字。
關鍵字
abstract, assert, boolean, break, byte, case, catch, char, class, const, continue, default, do, double, else, extends, final, finally, float, for, goto, if,
implements, import, instanceof, int, interface, long, native, new, null, package, private, protected, public, return, short, static, strictfp, super, switch,
synchronized, this, throw, throws, transient, try, void, volatile, while
其中,const和goto是保留關鍵字。
注釋
//行注釋
運算符
算術運算:+、-、*、/、%;++、--、+=、-=;
關系運算:>、<、==、>=、<=、!=、!、&&、||;
位運算:&、|、^、~、>>、>>>、<<、<<<;
流程控制
if ... else ...
(...) ? ... : ...;
switch 只能接受byte、short、char、int四種,不能接受long類型。
for
for each
while
do...while
參數傳遞
基本數據類型按照值傳遞,對象按照引用傳遞;String對象沒有修改該對象的方法,如果要通過引用修改可以使用StringBuilder或StringBuffer;
面向對象
類加載:static字段、一般字段、構造函數字段;(注意:static成員是類加載器加載的,是線程安全的;)
繼承;
接口;
內部類、匿名內部類用途:使用一個對象去做任務處理,但是該對象以后也不需要用到;這樣在一個類A內部定義一個內部類B,這樣類B可以訪問類A的數據,外界并不知道有類B的存在;
異常繼承時候,父類與子類的異常聲明可以不同,但是子類的異常必須在父類的異常范圍之內,也就是父類的異常必須可以引用子類的異常;
方法繼承時候,如果需要覆蓋,方法名稱、形參類型、返回類型必須相同;
訪問修飾符
當前對象 同一個包中子類/非子類 其它包中子類/非子類
private yes no/no no/no
protected yes yes/yes yes/no
默認 yes yes/yes no/no
public yes yes/yes yes/yes
對象比較
使用==比較的是引用;使用equals默認比較的也是對象的引用,但是,經過重載的equals可以按照我們需要去比較特點字段;
String類重載了equals與hashCode,而StringBuilder與StringBuffer沒有經過重載,因此使用equals比較StringBuilder與StringBuffer實際比較的是引用;
注意:重載equals必須同時重載hashCode,這兩個方法必須保持同步,即equals與hashCode同真假;
對象序列化
繼承接口Serializable即可以實現對象序列化,默認是序列化與反序列化的結果是相同的(引用被序列化后再反序列化回來還是跟之前相同的);
一般序列化后,要定義字段serialVersionUID,eclipse自動可以生成;作用是保持序列化與反序列化時候的版本兼容,如果不定義該字段,當出現反序列化時候內容不同時,可能會報錯;
transient關鍵字可以使該字段不進行序列化;
對象克隆
繼承接口Cloneable,然后覆蓋Object類的clone()方法進行克隆的聲明;默認是淺拷貝,若字段是引用類型,則需要手動在clone()方法里面人工進行new一個對象;
數組默認支持克隆,但是數組的數組(二維數組以上)不支持直接使用克隆;
異常
異常的結構
Throwable
| |
Error Exception
| |
IOException等 RuntimeException
異常的分類
1)未檢查異常
RuntimeException和Error及其子類。
這類異常不需要顯式捕捉,一旦發生,它自動會拋出來,然后程序終止;當然,你也可以進行捕捉,這樣程序就可以繼續運行;
2)已檢查異常
Exception及其子類
由于Exception派生的子類及Exception類多是已檢查異常,所以,Throwable類也屬于已檢查異常;這類異常必須進行捕捉,否則編譯不能通過。
聲明已檢查異常
例:public FileInputStream(String name) throws FileNotFoundException
拋出已檢查異常
例:throw new Exception("message");
捕獲異常
如果不捕獲的話,程序就會終止。有些時候,出現了異常,但是,我們不需要終止程序,那么就需要捕獲異常。
try {
// 可能拋出異常的代碼
} catch(異常類型 e) {
// e.printStackTrace(); // 打印異常堆棧
// 處理
}
// catch語句是從上到下執行的,具體的異常應該放在上面;
傳遞異常
將異常傳遞下去,這樣才能不會被覆蓋;
try {
// access the database
} catch(SQLException e) {
throw new ServletException("database error.", e);
}
finally子句
finally子句是一定會執行的,該子句主要用于回收一些資源。
泛型(屬于底層代碼,不常用)
JAVA虛擬機中沒有泛型,只有普通類與方法,使用泛型主要是為了方便類型轉換;還有泛型可以限定對象引用的使用;所有,泛型了解使用即可,不需要深究;
泛型包含兩種:泛型類、泛型方法;泛型類主要用于對某個不確定類型的字段進行操作;泛型方法是指static方法中使用了泛型參數;
泛型的翻譯
翻譯泛型表達式
A a = new A();
a.setT("generic programming.");
String str = a.getT(); // 翻譯為:String str = (String) a.getT();
翻譯泛型方法
public static T getMiddle(T[] a) // 翻譯為:public static Object getMiddle(Object[] objects)
public static T getMiddle(T[] a) // 翻譯為:public static Comparable getMiddle(Comparable[] a)
// 默認是轉化為左邊第一個類型,所有盡量將范圍大的類型放到前面;
復雜一點的橋方法:
class A {
private T t;
public void setT(T t) {
this.t = t;
}
public T getT() {
return t;
}
}
class B extends A {
public void setT(String t) {
super.setT(t);
}
}
// 翻譯后:
class A { // 父類翻譯后肯定是Object
private Object t;
public void setT(Object object) {
t = object;
}
public Object getT() {
return t;
}
}
class B extends A {
public void setT(String string) { // 子類肯定它的父類是String
super.setT(string);
}
public volatile void setT(Object object) { // 橋方法,外界還是認為是Object
setT((String) object);
}
}
// 調用:
A a = new B();
a.setT("generic programming."); // 翻譯為:b.setT((Object) "generic programming.");
不能使用泛型的情況
不能使用泛型繼承異常。
例如:public class Problem extends Exception {...}。
不能在catch(...)中,使用catch(T t)。
異常聲明中可以使用泛型。
例如:public static void doWork(T t) throws T {...}。
不能用泛型數組
A[] arr = new A[5]; // 擦除后為:A[] arr = new A[5];
不能將泛型類型實例化。
class A {
a = new T(); // 擦除后是a = new Object();我們本意卻不是這個。
...
}
類的靜態字段不能使用泛型;
當泛型類型擦除后,創建條件不能產出沖突。
例如:public boolean equals(T t) {...}
類型限定
子類型限定<? extends Employee>,可以讀,不能寫。
Pair<? extends Employee> pair1 = null; // ?是Employee的子類,子類可能很多,不確定有幾個。
Pair<Manager> pair2 = new Pair<Manager>();
pair1 = pair2;
pair1.getFirst(); // 操作成功,因為是“(? extends Employee) pair1.getFirst();”,
// 相當于是“(Employee) pair1.getFirst();”。
pair1.setFirst(new Manager()); // 編譯通不過,因為是“pair1.setFirst(? extends Employee);”
// 相當于是“pair1.setFirst(?);” 不確定的類型。
超類型限定<? super Employee>,可以寫,不能讀;剛好和上面相反。
無限定通配符<?>,可以讀,不能寫;讀的時候直接轉型為Object。
反射(屬于底層代碼,不常用)
對象產生于類,而在JAVA虛擬機里面還保存著對類的描述,這個描述是一個Class的對象;類信息被加載到虛擬機,就會產生一個Class對象,用以描述這個類的信息;
通過這個Class對象可以解析類的結構,這個Class對象可以從類信息來(例如:Employee.class),也可以從對象來(例如:emp.getClass());
通過這個Class對象可以引用具體對象的字段、方法、構造器,可以完全操作一個對象;
.class: 應該是一個指向類的Class對象的指針。
forName(): 會調用當前線程所在的ClassLoader來裝載一個類的Class實例。
注意:基礎類型也可以這樣使用“int.class”;
類加載器(屬于底層代碼,不常用)
java中的類是動態加載的,即引用到了才會被加載;
// 三種加載方式示例
class A{}
class B{}
class C{}
public class Loader{
public static void main(String[] args) throws Exception{
Class aa=A.class;
Class bb=Class.forName("B");
Class cc=ClassLoader.getSystemClassLoader().loadClass("C");
}
}
系統內默認的類加載器
Bootstrap ClassLoader (加載rt.jar)
|
ExtClassLoader (加載jre/lib/ext/)
|
AppClassLoader (加載claspath)
//ClassLoader實現:查找類,從父加載器向上遍歷,找不到就調用當前自定義的加載器;
protected ClassLoader() {
SecurityManager security = System.getSecurityManager();
if (security != null) {
security.checkCreateClassLoader();
}
// 自己實現的類加載器,默認是用系統類加載器的。
this.parent = getSystemClassLoader();
initialized = true;
}
protected ClassLoader(ClassLoader parent) {
SecurityManager security = System.getSecurityManager();
if (security != null) {
security.checkCreateClassLoader();
}
// 傳入一個父加載器
// 如果parent=null,那么啟動類加載器就是父親。
this.parent = parent;
initialized = true;
}
// 雙親委派加載的實現
public Class<?> loadClass(String name) throws ClassNotFoundException {
return loadClass(name, false);
}
protected synchronized Class<?> loadClass(String name, boolean resolve)
throws ClassNotFoundException {
// 先檢查該類是否已經被裝載過
Class c = findLoadedClass(name);
if (c == null) {
try {
// 向父加載器委托(加載不到拋ClassNotFoundException)
if (parent != null) {
c = parent.loadClass(name, false);
// 最終到啟動類加載器(加載不到拋ClassNotFoundException)
} else {
c = findBootstrapClass0(name);
}
} catch (ClassNotFoundException e) {
// 父加載器加載不到,調用我們自己設定的findClass(name)進行查找
// 對于API提供的ClassLoader,findClass()是直接拋ClassNotFoundException
c = findClass(name);
}
}
// 是否要解析(解析符號引用為直接地址引用)
// 一般我們用false。
// 我的理解是使用false的話,程序啟動速度應該會有一點點提升,但是第一次執行的時候應該會慢一點點。
// 當然,這個我們人是感覺不出來的。
if (resolve) {
resolveClass(c);
}
return c;
}
=====
from
http://blog.sina.com.cn/s/blog_667ac0360102e8ii.html