- 判斷是不是奇數的方法:
i % 2 != 0 或者 (i & 1) != 0
,不能用i % 2 == 1
,因爲存在負數
- 精確計算的時候不要用小數計算,例如“錢”,乘以100用整數代替小數計算。
long aa = 24 * 60 * 60 * 1000 * 1000
會造成精度損失,是因爲等號右邊本身是按照int
進行計算的,完成之後纔將值轉成long
,解決辦法只需要將其中一個常亮後面加L
使其成爲長整型。
- 多重轉型:
- 如果最初的數值是有符號的,那麼就執行符號擴展,
- 如果是
char
類型,那麼不管被轉成什麼類型,都執行0擴展
- 如果目標小於源長度,則直接截取就行了
- 謎題9:不要將複合操作符用於
byte,short,char
上,當用於Int
時 ,要確保右側不是double,float,long
類型,避免強制轉換,導致精度損失。
+
號操作符當且僅當它的操作數中至少有一個是String
類型時,才執行字符串鏈接操作。
- 謎題13,只要是常量表達式組成的字符串相等,
hello world = hello + world
,那麼引用相等,但是如果其中一個是變量就不行了,因爲靜態常量在編譯期就轉換了,而如果帶了變量,就只有在運行期才知道該變量是什麼東西了。
new String(char[])
時,儘量都指明字符集,不要依賴默認的字符集
j = j++
相當於temp = j;j=j+1;j = temp;
for(int i = start;i<= start + 1;i++){}
當start
是Integer.max_value
時,可以無限循環
while(i == i + 1)
當i = Double.POSITIVE_INFINITY
,也就是無窮大時,可以無限循環
while(i != i)
,當i = Double.NaN(不是數字的數量)
時,爲true
while(i != i + 0)
當i
爲一個字符串時,就可以true
,無限循環
- 移位運算符只能是整數
- 謎題31,所有的算術操作都會對
short,byte,char
類型先提升爲int
類型。
while(i<=j && j<=i&& i!=j){}
,當i,j
等於同一個數的包裝類時滿足爲true
,包裝類在比較運算符時自動拆包了,但是== ,!=
這些時是引用。
int
有31位精度,而float
只有24位精度
- 謎題37,不能隨便拋出
try
中不存在的受檢查異常,也就是基本上不能隨便加cache
但是可以隨便捕獲Exception
異常
- 一個方法可以拋出的被檢查異常集合是它繼承的父類中方法拋出異常的交集,而不是合集
- 要確定一個程序是否可以不止一次的對一個空
final
類型進行賦值是一個很困難的問題,比如,第一次通過方法賦值,出現錯誤了,那麼第二次是否還可以再賦值?所以編輯器採用了保守方法:一個空final
變量只有在它是明確未賦過值得地方纔可以被賦值,也就是隻有第一次,就算失敗了,第二次也不能賦值了。
- 當調用一個構造器時,實例變量的初始化操作(也就是屬性)將先於構造器的程序體運行。
- 對於一個對象包含與它自己類相同的實例時,例如,鏈表列表節點,樹節點和圖節點,需要避免造成棧滿異常(stackOverfloatError),儘量就不要屬性是該類,除非是單例,通過
static
修飾一下
- 實例初始化操作拋出的任何異常都會傳播給構造器。
- 令人混淆的構造器案例:
Java
的重載解析過程是以兩個階段運行的,第一個階段選取所有可獲得並且可以應用的方法或者構造器;第二個階段是在第一個階段選取的方法或構造器中選取最精確的一個。如果第一個的參數類型可以傳遞給第二個,那麼就說,第一個精確點,eg:double[]
可以傳遞給Object
,所以double[]
精確。
public class Confusing{
private Confusing(Object o){
System.out.println("Object");
}
private Confusing(double[] dArray){
System.out.println("array");
}
public static void main(String[] args){
new Confusing(null);
}
}
- 啊呀!我的貓變成狗了
- 非靜態方法可以直接訪問靜態方法,不加類名。
final
類不可繼承;final
方法能繼承,但不能被子類重寫;final
變量是常量
- 靜態方法被繼承到子類中,那麼也可以直接通過
SubClass.staticMethod()
調用;
- 我所得到的都是靜態的
class Dog{
public static void bark(){System.out.println("woof");}
}
class BaseJi extends Dog{
public static void bark(){}
}
public static viod main(String[] args){
Dog woofer = new Dog();
Dog nipper = new BaseJi();
woofer.bark();
nipper.bark();
}
- 對靜態方法的調用不存在任何動態的分派機制,在編譯時刻已經確定,因爲他們都被聲明爲Dog類型的,所以都會調用
Dog
類型的靜態方法,輸出woof
;
- 更改方法:去掉
static
,因爲靜態的東西是在編譯期就定了,去掉的話,就是重寫,而不是隱藏了。
- 謎題49:比生命更大
public class Elvis{
public static final Elvis INSTANCE = new Elvis();
private final int beltSize;
private static final int current_year = Calendar.getInstance().get(Calendar.YEAR);
private Elvis(){
beltSize = current_year - 1930;
}
public int beltSize(){
return beltSize;
}
public static void main(String[] args){
System.out.println(INSTANCE.beltSize());
}
}
- 謎題50,不是你的類型:
null
對於每一個引用類型來說都是子類型,但是當instanceof
操作符左側爲null
時返回false
new Type() instanceof String instanceof
操作符要求:如果兩個操作數的類型都是類,其中一個必須是另一個子類型,會在編譯器就檢測出來。
Type type = (Type) new Object()
會在運行期報錯,但是可以編譯通過。
- 不要在構造器中調用被子類重寫過的方法。
- 助手方法(靜態方法)通常都優於靜態代碼塊,因爲方法可以命名。
- Null和Void
public class Type{
public static void greet(){
System.out.println("hello word");
}
public static void main(String[] args){
((Type)null).greet();
}
}
Java
語言規範不允許本地變量聲明語句作爲一條語句在for,while,do
循環中while Type type = new Type()
需要加{}
括起來。
BigInteger,BigDecimal,包裝類,String
都是不可變的,改動之後需要用新的接受String aa = "aa"; aa = aa + "bb"
;
equal
方法重寫,可以先用instanceof
判斷一下類型,相同不,再比較值。比較兩個實例是否相等時,可以先判斷引用是否相等
split
接受的是一個正則表達式;
- 對於陌生的數組,可以使用
Arrays.deepToString()
打印出來
Math.abs(Integer.MIN_VALUE)
是Integer.MIN_VALUE
;
- 謎題66:一件私事:重寫(方法)和隱藏(屬性)的區別,重寫除非在子類中通過
super
可以調用到父類的方法,否則調不到了,而隱藏可以轉型到父類,就可以訪問到了;當聲明“屬性”,“靜態方法”,“內部類”時,如果和父類的名稱相同了,會發生隱藏。
final
修飾方法時,對於實例方法表示不能“重寫”,對於靜態方法來說,不能“隱藏”
- 隱藏一個成員將阻止其被繼承。
- 謎題77:搞亂鎖的妖怪:
public class Worker extends Thread{
private volatile boolean flag = false;
public void run(){
while(!flag){
pretendToWork();
}
System.out.print("beer is good");
}
private void pretendToWork(){
try{
Thread.sleep(300);
}catch(InterruptedException e){}
}
synchronized void quit(){
flag = true;
join();
}
synchronized void keepWorking(){
flag = false;
}
public static void main(String[] args){
Worker worker = new Worker();
worker.start();
Timer t = new Timer(true);
t.schedule(new TimerTask(){
public void run(){worker.keepWorking()}
},500);
Threed.sleep(400);
worker.quit();
}
}
private final Object lock = new Object();
public void quit(){
synchronized(lock){
flag = true;
join();
}
}
- 謎題85,:不要在類初始化的時候啓動任何線程,也就是靜態代碼塊中
- 謎題89:泛型迷藥
- 非靜態成員類可以訪問外部類的泛型,所以該類是不需要自己的泛型的;
- 靜態成員類需要自己的泛型;
- 優先考慮用靜態成員類代替非靜態成員類;