本博文用于記載java進階中一些難點和易混淆的知識點,并不詳細,也不全面,适合有java基礎的朋友進行複習鞏固。
(部分内容為從PPT中拷貝,侵删)
裡面編号有點問題,以後再改吧,先湊合着看看
一、反射
反射中我們可以通過
Class
對象來反射出一個類的構造方法、方法、屬性、注釋以及内部類。
在通過反射擷取構造方法的适合,有四種不同的方法。
Constructor<T> getConstructor(Class<?>..ParameterType)
: 傳回此Class對象所表示的類的指定的public構造器
Constructor<?>[] getConstructors()
: 傳回此Class對象所表示的類的所有public構造器
Constructor<T> getDeclaredConstructor(Class<?>..ParameterType)
: 傳回此Class對象所表示的類的指定的public構造器,與構造器的級别沒有關系。
Constructor<?>[] getDeclaredConstructors()
: 傳回此Class對象所表示的類的所有構造器
而
getConstructor
和
getDeclaredConstructed
之間的差別,很簡單,就在于
getConstructor
隻能擷取用
public
申明的符合條件(參數清單比對)的構造函數,而
getDeclaredConstructed
可擷取所有的符合條件的的構造函數,不局限于
public
,也可以使
private
等。
用Class對象建立一個新對象的方式為
class.newInstance()
,或者
class.getConstructor(Class<?>..ParamterType).newInstance()
差別在于前者使用的是預設無參構造函數,而後者使用的是自己需要的構造函數,而需要選擇哪一個構造函數則是在
getContructor()
裡面的參數設定了
擷取類方法采用
getMethod()
,擷取類字段使用
getField()
.
如果是八大基本類型,可以使用
getxxx()
,這個xxx就是基本類型,當然同樣的有對應的set方法。
二、泛型
java泛型其實不難,講幾個易錯點吧。
- 子類繼承自帶泛型的父類時,可以不加泛型,但是如果加了泛型就不要寫成
,而應寫成一個具體的類型,比如<T>
<String>
- 系統沒有真正的泛型類,是以在類型判斷中使用
是錯誤的if( c instanceof ArrayList<String>)
- 定義泛型方法:
修飾符 <T,S> 傳回值類型 方法名(形參清單){
…….//方法體
}
- 泛型類型不具有父子關系:比如
和ArrayList<String>
之間不具有父子關系ArrayList<Object>
- 泛型中,如果通配符寫成了
,那麼不允許向該泛型集合中添加任何元素,除了null。比如:?
那麼List<?> list = new ArrayList();
是錯誤的。list.add(1);
-
的意義在于它可以控制傳入的參數類型:比如在方法參數申明中?
void foo(List<? extends Circle> list)
- 同樣可以用
設定下界,比如:?
,那麼x必須是(x super Student)
類或者其父類Student
- 泛型參數不适用于為靜态變量設定類型
三、多線程
- 并發與并行:經典問題,并發是同一時間段内多個程式執行,而并行是同一時刻。
- 多線程兩種方式,繼承自
,或者實作Thread
接口Runnable
- 重寫的是
方法,調用的是run()
方法,如調用start()
方法不能實作多線程,原因不詳述了。run()
- 不要對已死亡的線程調用
方法,也不要對同一個start()
調用兩次thread
,會抛異常的start()
- 實作Runnable接口的類可以作為多個線程的執行個體被調用,講人話就是其中公共字段會被公用。
-
yield
方法,就是退出運作狀态轉為就緒狀态,而下一個進入運作狀态的線程,可能仍然是該線程,也可能不是,這時要看CPU如何選擇了。清楚解析請看
可将目前線程設定為背景線程,而用Thread.setDaemon(true)
可以判斷是否為背景線程isDaemon()
- 線程同步常采用的方式有兩種,設定
或者 手動加鎖synchronized
-
同步代碼塊,必須要對某個對象加鎖,不然怎麼能叫同步呢。加鎖方式有兩種,當對某一個方法加鎖時,不需要手動設定加鎖的對象,因為加鎖的隻能(同時也預設)是synchronized
,寫法為:this
public synchronized void method(){
xxx
}
而如果是對某一個代碼塊設定
synchronized
同步鎖,則必須設定鎖的對象,比如:
public void method_1(){
sychronized(this){
// 這個是鎖目前對象;
}
public void method_2(People p){
synchronized(p){
// 這裡是對p這個對象加鎖;
}
}
}
- lock的用法:
-
volatile
關鍵字,可以在申明一個變量的時候加在前面進行修飾,其作用為讓這個變量的值一旦在某一個線程中被修改,會立刻存到記憶體。說起來很玄乎,其實反映到硬體層面,就是讓其緩存行失效。但是它隻能保證可見性,不保證原子性。想詳細了解的看部落格,從第四大點看起就好了
解決線程同步問題:ThreadLocal
修飾的變量會在每一個線程中建立一個副本,且隻能被目前線程通路,是以就保證了資料的線程安全性。ThreadLocal
- 線程通知機制有兩組,分别是
和 wait()、notify()、notifyAll()
。而await(),signal(),sianalAll()
和wait()
這兩個家夥貌似沒什麼差別,即便是在英文含義上也沒什麼差別,不過是wait是不及物動詞,而await是及物動詞,哈哈哈跑題了。相對而言,await()
常用于wait()
塊中,而synchronized
常見于await()
中,他們一定要在鎖裡面出現!!!lock
- 我們知道wait()和await()的signal()等方法都是随機通知的,這就容易産生亂子了,而如果要實作選擇性通知,那麼就需要采用Condition來實作了。其定義方法如下:
Condition condition = reentrantLock.newCondition();
//在代碼中則使用如下方式對指定的線程進行喚醒
condition.wait();
condition.signal();
-
和 Callable
, 相當于有參數的future
Runnable
從這個網站拷下來的一些代碼,看代碼就很清楚了,不細說
public class CallableAndFuture {
public static void main(String[] args) {
Callable<Integer> callable = new Callable<Integer>() {
public Integer call() throws Exception {
return new Random().nextInt(100);
}
};
FutureTask<Integer> future = new FutureTask<Integer>(callable);
new Thread(future).start();
try {
Thread.sleep(5000);// 可能做一些事情
System.out.println(future.get());
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
}
}
- 線程池。不細講了。
- 集合類是線程不安全的,線程安全的集合類有
、 ConcurrentHashMap
,分别代表了支援并發的通路的ConcurrentLinkedQueue
和支援并發通路的HashMap
Queue
四、JDBC
JDBC是java連接配接資料庫的方式,其需要對應資料庫提供商提供需要的驅動。
JDBC程式設計步驟
1. 加載并注冊資料庫驅動Driver
2. 建立連接配接Connection
3. 建立執行對象Statement
4. 執行語句
5. 處理執行結果(ResultSet)
6. 釋放資源
Class.forName(“com.mysql.jdbc.Driver”);
Connection conn =DriverManager.getConnection(url, user, password);
Statement st = conn.createStatement();
ResultSet rs =st.executeQuery(sql);
int flag = st.executeUpdate(sql);
rs.close();
st.close();
conn.close();