天天看點

java進階複習——常見易錯點總結

本博文用于記載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泛型其實不難,講幾個易錯點吧。

  1. 子類繼承自帶泛型的父類時,可以不加泛型,但是如果加了泛型就不要寫成​

    ​<T>​

    ​​ ,而應寫成一個具體的類型,比如​

    ​<String>​

  2. 系統沒有真正的泛型類,是以在類型判斷中使用​

    ​if( c instanceof ArrayList<String>)​

    ​ 是錯誤的
  3. 定義泛型方法:
修飾符  <T,S>  傳回值類型   方法名(形參清單){
   …….//方法體
}      
  1. 泛型類型不具有父子關系:比如​

    ​ArrayList<String>​

    ​​和​

    ​ArrayList<Object>​

    ​之間不具有父子關系
  2. 泛型中,如果通配符寫成了​

    ​?​

    ​​,那麼不允許向該泛型集合中添加任何元素,除了null。比如:​

    ​List<?> list = new ArrayList();​

    ​​那麼​

    ​list.add(1);​

    ​是錯誤的。
  3. ​?​

    ​​的意義在于它可以控制傳入的參數類型:比如在方法參數申明中​

    ​void foo(List<? extends Circle> list)​

  4. 同樣可以用​

    ​?​

    ​​設定下界,比如:​

    ​(x super Student)​

    ​​ ,那麼x必須是​

    ​Student​

    ​類或者其父類
  5. 泛型參數不适用于為靜态變量設定類型

三、多線程

  1. 并發與并行:經典問題,并發是同一時間段内多個程式執行,而并行是同一時刻。
  2. 多線程兩種方式,繼承自​

    ​Thread​

    ​​,或者實作​

    ​Runnable​

    ​接口
  3. 重寫的是​

    ​run()​

    ​​方法,調用的是​

    ​start()​

    ​​方法,如調用​

    ​run()​

    ​方法不能實作多線程,原因不詳述了。
  4. 不要對已死亡的線程調用​

    ​start()​

    ​​方法,也不要對同一個​

    ​thread​

    ​​調用兩次​

    ​start()​

    ​,會抛異常的
  5. 實作Runnable接口的類可以作為多個線程的執行個體被調用,講人話就是其中公共字段會被公用。
  6. ​yield​

    ​方法,就是退出運作狀态轉為就緒狀态,而下一個進入運作狀态的線程,可能仍然是該線程,也可能不是,這時要看CPU如何選擇了。清楚解析請看

    ​Thread.setDaemon(true)​

    ​​可将目前線程設定為背景線程,而用​

    ​isDaemon()​

    ​可以判斷是否為背景線程
  7. 線程同步常采用的方式有兩種,設定 ​

    ​synchronized​

    ​ 或者 手動加鎖
  8. ​synchronized​

    ​​ 同步代碼塊,必須要對某個對象加鎖,不然怎麼能叫同步呢。加鎖方式有兩種,當對某一個方法加鎖時,不需要手動設定加鎖的對象,因為加鎖的隻能(同時也預設)是​

    ​this​

    ​,寫法為:
public synchronized void method(){
xxx
}      

而如果是對某一個代碼塊設定​

​synchronized​

​同步鎖,則必須設定鎖的對象,比如:

public void method_1(){
    sychronized(this){
        // 這個是鎖目前對象;
     }

public void method_2(People p){
    synchronized(p){
        // 這裡是對p這個對象加鎖;
    }
}


}      
  1. lock的用法:
  2. ​volatile​

    ​​ 關鍵字,可以在申明一個變量的時候加在前面進行修飾,其作用為讓這個變量的值一旦在某一個線程中被修改,會立刻存到記憶體。說起來很玄乎,其實反映到硬體層面,就是讓其緩存行失效。但是它隻能保證可見性,不保證原子性。想詳細了解的看部落格,從第四大點看起就好了

    ​ThreadLocal​

    ​​ 解決線程同步問題:​

    ​ThreadLocal​

    ​修飾的變量會在每一個線程中建立一個副本,且隻能被目前線程通路,是以就保證了資料的線程安全性。
  3. 線程通知機制有兩組,分别是​

    ​wait()、notify()、notifyAll()​

    ​​ 和 ​

    ​await(),signal(),sianalAll()​

    ​​。而​

    ​wait()​

    ​​和​

    ​await()​

    ​​ 這兩個家夥貌似沒什麼差別,即便是在英文含義上也沒什麼差別,不過是wait是不及物動詞,而await是及物動詞,哈哈哈跑題了。相對而言,​

    ​wait()​

    ​​常用于​

    ​synchronized​

    ​​塊中,而​

    ​await()​

    ​​常見于​

    ​lock​

    ​中,他們一定要在鎖裡面出現!!!
  4. 我們知道wait()和await()的signal()等方法都是随機通知的,這就容易産生亂子了,而如果要實作選擇性通知,那麼就需要采用Condition來實作了。其定義方法如下:
Condition condition = reentrantLock.newCondition();

//在代碼中則使用如下方式對指定的線程進行喚醒
condition.wait();
condition.signal();      
  1. ​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();
        }
    }
}      
  1. 線程池。不細講了。
  2. 集合類是線程不安全的,線程安全的集合類有​

    ​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();