Java中容易混淆的基礎知識
面向對象
三大特性:
繼承,封裝,多態
封裝
3中修飾符:public,private,protected,給位于同一個或不同包中的對象賦予了不同的訪問權限
封裝的一些好處
通過隱藏對象的屬性來保護對象內部的狀態
提高代碼的可用性,可維護性
提高模塊化
繼承
給對象提供從基類獲取字段和方法的能力,基礎提高代碼的重用性,可以在不修改類的情況下添加新的特性
多態
多態就是同一函數在不同類中有不同的實現;
面向對象的多態性,即“一個接口,多個方法”。
多態性體現在基類中定義的屬性和方法被子類繼承后,可以具有不同的屬性或表現方式。
多態性允許一個接口被多個同類使用,彌補了單繼承的不足。
final,finally,finalize的區別
final
final可以修飾類、變量、方法,修飾類表示該類不能被繼承、修飾方法表示該方法不能被重寫、修飾變量表示該變量是一個 常量不能被重新賦值。
finally
finally一般作用在try-catch代碼塊中,在處理異常的時候,通常我們將一定要執行的代碼放入finally代碼塊中,表示不管是 否出現異常,該代碼塊都會執行,一般用來存放一些關閉資源的代碼。
finalize
finalize是一個方法,屬于Object類的一個方法,而Object類是所有類的父類,該方法一般由垃圾回收器來調用,當我們調 用System.gc() 方法的時候,由垃圾回收器調用finalize(),回收垃圾,一個對象是否可回收的最后判斷。
int和integer的區別
int
int是基本數據類型
integer
integer是其包裝類,是一個類
為了在各種類型中轉換,通過各種方法調用
int a = 0; String result = Integer.toString(a); //將int轉換為String
重載與重寫的區別
override重寫
overload重載
抽象類和接口的區別
接口時公開的,不能有私有的方法和變量,
抽象類可以有私有的方法或私有的變量
抽象類和接口的區別
反射的用途以及實現
反射機制所提供的功能
在運行時創造一個類的對象;
判斷一個類所具有的成員變量和方法
調用一個對象的方法
生成動態代理
Java反射的主要功能:
確定一個對象的類
取出類的modifiers,數據成員,方法,構造類,超類
在運行時刻調用動態對象的方法.
創建數組,數組大小和類型
反射機制的理解和應用
自定義注解的場景及實現
登陸、權限攔截、日志處理,以及各種Java 框架,如Spring,Hibernate,JUnit 提到注解就不能不說反射,Java自定義注解是通過運行時靠反射獲取注解。實際開發中,例如我們要獲取某個方法的調用日志,可以通過AOP(動態代理機制)給方法添加切面,通過反射來獲取方法包含的注解,如果包含日志 注解,就進行日志記錄。
http請求的get和post方式的區別
原理區別
一般我們在瀏覽器輸入一個網址訪問網站都是GET請求;再FORM表單中,可以通過設置Method指定提交方式為GET或者POST提交方式,默認為GET提交方式。
HTTP定義了與服務器交互的不同方法,其中最基本的四種:GET,POST,PUT,DELETE,HEAD,其中GET和HEAD被稱為安全方法,因為使用GET和HEAD的HTTP請求不會產生什么動作。不會產生動作意味著GET和HEAD的HTTP請求不會在服務器上產生任何結果。但是安全方法并不是什么動作都不產生,這里的安全方法僅僅指不會修改信息。
根據HTTP規范,POST可能會修改服務器上的資源的請求。比如CSDN的博客,用戶提交一篇文章或者一個讀者提交評論是通過POST請求來實現的,因為再提交文章或者評論提交后資源(即某個頁面)不同了,或者說資源被修改了,這些便是“不安全方法”。
請求的區別
GET方法會把名值對追加在請求的URL后面。因為URL對字符數目有限制,進而限制了用在 客戶端請求的參數值的數目。并且請求中的參數值是可見的,因此,敏感信息不能用這種方式傳遞。
POST方法通過把請求參數值放在請求體中來克服GET方法的限制,因此,可以發送的參數的數目是沒有限制的。最后,通過POST請求傳遞的敏感信息對外部客戶端是不可見的。
參考:get和post請求方式的區別
seesion與cookie的區別
cookie數據存放在客戶的瀏覽器上,session數據放在服務器上.
cookie不是很安全,別人可以分析存放在本地的COOKIE并進行COOKIE欺騙考慮到安全應當使用session。
設置cookie時間可以使cookie過期。但是使用session-destory(),我們將會銷毀會話。
session會在一定時間內保存在服務器上。當訪問增多,會比較占用你服務器的性能考慮到減輕服務器性能方面,應當使用cookie。
單個cookie保存的數據不能超過4K,很多瀏覽器都限制一個站點最多保存20個cookie。(Session對象沒有對存儲的數據量的限制,其中可以保存更為復雜的數據類型)
JDBC流程
加載JDBC驅動程序:
在連接數據庫之前,首先要加載想要連接的數據庫的驅動到JVM(Java虛擬機), 這通過java.lang.Class類的靜態方法forName(String className)實現。
例如:
try{ //加載MySql的驅動類 Class.forName("com.mysql.jdbc.Driver") ; }catch(ClassNotFoundException e){ System.out.println("找不到驅動程序類 ,加載驅動失敗!"); e.printStackTrace() ;
成功加載后,會將Driver類的實例注冊到DriverManager類中。
提供JDBC連接的URL
連接URL定義了連接數據庫時的協議、子協議、數據源標識。書寫形式:協議:子協議:數據源標識
協議:在JDBC中總是以jdbc開始 子協議:是橋連接的驅動程序或是數據庫管理系統名稱。數據源標識:標記找到數據庫來源的地址與連接端口。
例如:
jdbc:mysql://localhost:3306/test? useUnicode=true&characterEncoding=gbk;useUnicode=true;(MySql的連接URL)
表示使用Unicode字符集。如果characterEncoding設置為 gb2312或GBK,本參數必須設置
為true 。characterEncoding=gbk:字符編碼方式。
創建數據庫的連接
java.sql.DriverManager Connection
代表一個數據庫的連接。
使用DriverManager的getConnectin(String url , String username , String password )方法傳入指定的欲連接的數據庫的路徑、數據庫的用戶名和 密碼來獲得。
例如: //連接MySql數據庫,用戶名和密碼都是root
String url = "jdbc:mysql://localhost:3306/test" ; String username = "root" ; String password = "root" ; try{ Connection con = DriverManager.getConnection(url , username , password ) ; }catch(SQLException se){ System.out.println("數據庫連接失敗!"); se.printStackTrace() ;
? 要執行SQL語句,必須獲得java.sql.Statement實例,Statement實例分為以下3 種類型:
1、執行靜態SQL語句。通常通過Statement實例實現。
2、執行動態SQL語句。通常通過PreparedStatement實例實現。
3、執行數據庫存儲過程。通常通過CallableStatement實例實現。具體的實現方式:
Statement stmt = con.createStatement() ? PreparedStatement pstmt = con.prepareStatement(sql) ? CallableStatement cstmt = con.prepareCall("{CALL demoSp(? , ?)}") ?
執行SQL語句
Statement接口提供了三種執行SQL語句的方法:executeQuery 、executeUpdate 和execute
1、ResultSet executeQuery(String sqlString):執行查詢數據庫的SQL語句 ,返回一個結果集(ResultSet)對象。
2、int executeUpdate(String sqlString):用于執行INSERT、UPDATE或 DELETE語句以及SQL DDL語句,如:CREATE TABLE和DROP TABLE等
3、execute(sqlString):用于執行返回多個結果集、多個更新計數或二者組合的 語句。 具體實現的代碼:
ResultSet rs = stmt.executeQuery(“SELECT * FROM …”) ? int rows =
stmt.executeUpdate(“INSERT INTO …”) ? boolean flag = stmt.execute(String sql) ?
處理結果
兩種情況:
1、執行更新返回的是本次操作影響到的記錄數。
2、執行查詢返回的結果是一個ResultSet對象。
? ResultSet包含符合SQL語句中條件的所有行,并且它通過一套get方法提供了對這些 行中數據的訪問。
? 使用結果集(ResultSet)對象的訪問方法獲取數據:
while(rs.next()){
String name = rs.getString(“name”) ?
String pass = rs.getString(1) ? // 此方法比較高效
}
(列是從左到右編號的,并且從列1開始)
關閉JDBC對象
操作完成以后要把所有使用的JDBC對象全都關閉,以釋放JDBC資源,關閉順序和聲 明順序相反:
1、關閉記錄集
2、關閉聲明
3、關閉連接對象
if(rs!=null){ // 關閉記錄集 try{ rs.close(); }catch(SQLException e){e.printStackTrace(); } }try{ stmt.close(); } }catch(SQLException e){e.printStackTrace(); } if(conn!=null){ // 關閉連接對象 try{ conn.close(); }catch(SQLException e){ e.printStackTrace();20} }
MVC思想
M:Model 模型
V:View 視圖
C:Controller控制器
模型就是封裝業務邏輯和數據的一個一個的模塊,控制器就是調用這些模塊的(java中通常是 用Servlet來實現,框架的話很多是用Struts2來實現這一層),視圖就主要是你看到的,比如JSP 等.
當用戶發出請求的時候,控制器根據請求來選擇要處理的業務邏輯和要選擇的數據,再返回去 把結果輸出到視圖層,這里可能是進行重定向或轉發等.
equals 與 == 的區別
值類型(int,char,long,boolean等)都是用==判斷相等性。對象引用的話,判斷引用所指的對象 是否是同一個。equals是Object的成員函數,有些類會覆蓋(override)這個方法,用于判 斷對象的等價性。例如String類,兩個引用所指向的String都是"abc",但可能出現他們實際對應的對象并不是同一個(和jvm實現方式有關),因此用 ==判斷他們可能不相等,但用equals判斷一定是相等的。
線程
創建線程的方法及實現
Java中創建線程主要有三種方式:
一、繼承Thread類創建線程類
(1) 定義Thread類的子類,并重寫該類的run方法,該run方法的方法體就代表了線程要完成的任務。因此把run()方法稱為執行體。
(2) 創建Thread子類的實例,即創建了線程對象。
(3) 調用線程對象的start()方法來啟動該線程。
package com.thread; public class FirstThreadTest extends Thread{ int i = 0; //重寫run方法,run方法的方法體就是現場執行體public void run() { for(;i<100;i++){ System.out.println(getName()+" "+i); } } public static void main(String[] args) { for(int i = 0;i< 100;i++) { System.out.println(Thread.currentThread().getName()+" "+i): if(i==20) { new FirstThreadTest().start(); new FirstThreadTest().start(); } } }
二、通過Runnable接口創建線程類
(1) 定義runnable接口的實現類,并重寫該接口的run()方法,該run()方法的方法體同樣是該線程的線程執行體。
(2) 創建 Runnable實現類的實例的target來創建Thread對象,該
Thread對象才是真正的線程對象。
(3)調用線程對象的start()方法來啟動該線程
package com.thread; public class RunnableThreadTest implements Runnable { private int i; public void run() { for(i = 0;i <100;i++) { System.out.println(Thread.currentThread().getName()+" "+i); } } public static void main(String[] args) { for(int i = 0;i < 100;i++) { System.out.println(Thread.currentThread().getName()+" "+i); if(i==20) { RunnableThreadTest rtt = new RunnableThreadTest(); new Thread(rtt,"新線程1").start(); new Thread(rtt,"新線程2").start(); } } } }
三、通過Callable和Future創建線程
(1) 創建Callable接口的實現類,并實現call()方法,該call()方法將作為線程執行體,并且有返回值。
(2) 創建Callable實現類的實例,使用FutureTask類來包裝Callable對象,該FutureTask對象封裝了該Callable對象的call()方法的返回值。
(3) 使用FutureTask對象作為Thread對象的target創建并啟動新線程。
(4) 調用FutureTask對象的get()方法來獲得子線程執行結束后的返回值
package com.thread; import java.util.concurrent.Callable; import java.util.concurrent.ExecutionException; import java.util.concurrent.FutureTask; public class CallableThreadTest implements Callable
采用實現Runnable、Callable接口的方式創見多線程時,優勢是:
線程類只是實現了 接口或 接口,還可以繼承其他類。
在這種方式下,多個線程可以共享同一個target對象,所以非常適合多個相同線程來處理同 一份資源的情況,從而可以將CPU、代碼和數據分開,形成清晰的模型,較好地體現了面 向對象的思想。
劣勢是:
編程稍微復雜,如果要訪問當前線程,則必須使用Thread.currentThread()方法。
使用繼承Thread類的方式創建多線程時優勢是:
編寫簡單,如果需要訪問當前線程,則無需使用Thread.currentThread()方法,直接使用this 即可獲得當前線程。
劣勢是:
線程類已經繼承了Thread類,所以不能再繼承其他父類。
sleep() 、join()、yield()的區別
一、sleep()
在指定的毫秒數內讓當前正在執行的線程休眠(暫停執行),此操作受到系統計時器和調度 程序精度和準確性的影響。 讓其他線程有機會繼續執行,但它并不釋放對象鎖。也就是如 果有Synchronized同步塊,其他線程仍然不能訪問共享數據。注意該方法要捕獲異常
比如有兩個線程同時執行(沒有Synchronized),一個線程優先級為MAX_PRIORITY,另一 個為MIN_PRIORITY,如果沒有Sleep()方法,只有高優先級的線程執行完成后,低優先級 的線程才能執行;但當高優先級的線程sleep(5000)后,低優先級就有機會執行了。
總之,sleep()可以使低優先級的線程得到執行的機會,當然也可以讓同優先級、高優先級的 線程有執行的機會。
二、join()
Thread的非靜態方法join()讓一個線程B“加入”到另外一個線程A的尾部。在A執行完畢之前, B不能工作。
保證當前線程停止執行,直到該線程所加入的線程完成為止。然而,如果它加入的線程沒有 存活,則當前線程不需要停止。
三、yield()
yield()方法和sleep()方法類似,也不會釋放“鎖標志”,區別在于,它沒有參數,即yield()方 法只是使當前線程重新回到可執行狀態,所以執行yield()的線程有可能在進入到可執行狀態 后馬上又被執行,另外yield()方法只能使同優先級或者高優先級的線程得到執行機會,這也 和sleep()方法不同。
再給大家推薦一本書:Java并發編程想要電子版也可以私信我
線程池的幾種方式
newFixedThreadPool(int nThreads)
創建一個固定長度的線程池,每當提交一個任務就創建一個線程,直到達到線程池的最大數 量,這時線程規模將不再變化,當線程發生未預期的錯誤而結束時,線程池會補充一個新的線程
newCachedThreadPool()
創建一個可緩存的線程池,如果線程池的規模超過了處理需求,將自動回收空閑線程,而當 需求增加時,則可以自動添加新線程,線程池的規模不存在任何限制
newSingleThreadExecutor()
這是一個單線程的Executor,它創建單個工作線程來執行任務,如果這個線程異常結束,會 創建一個新的來替代它;它的特點是能確保依照任務在隊列
中的順序來串行執行
newScheduledThreadPool(int corePoolSize)
創建了一個固定長度的線程池,而且以延遲或定時的方式來執行任務,類似于Timer。
private static final Executor exec=Executors.newFixedThreadPool(50); Runnable runnable=new Runnable(){ public void run(){ ... } } exec.execute(runnable); Callable
線程的生命周期
新建(New)、就緒(Runnable)、運行(Running)、阻塞(Blocked)和死亡(Dead)5種狀態
(1)生命周期的五種狀態
新建(new Thread)
當創建Thread類的一個實例(對象)時,此線程進入新建狀態(未被啟動)。
例如:Thread t1=new Thread()?
就緒(runnable)
線程已經被啟動,正在等待被分配給CPU時間片,也就是說此時線程正在就緒隊列中排隊 等候得到CPU資源。例如:t1.start()?
運行(running)
線程獲得CPU資源正在執行任務(run()方法),此時除非此線程自動放棄CPU資源或者有 優先級更高的線程進入,線程將一直運行到結束。
死亡(dead)
當線程執行完畢或被其它線程殺死,線程就進入死亡狀態,這時線程不可能再進入就緒狀態 等待執行。
自然終止:正常運行run()方法后終止
異常終止:調用**stop()**方法讓一個線程終止運行
堵塞(blocked)
由于某種原因導致正在運行的線程讓出CPU并暫停自己的執行,即進入堵塞狀態。
正在睡眠:用sleep(long t) 方法可使線程進入睡眠方式。一個睡眠著的線程在指定的時間過去可進入就緒狀態。
正在等待:調用wait()方法。(調用motify()方法回到就緒狀態)
被另一個線程所阻塞:調用suspend()方法。(調用resume()方法恢復)
鎖機制
線程安全
線程安全是指要控制多個線程對某個資源的有序訪問或修改,而在這些線程之間沒有產生沖 突。
在Java里,線程安全一般體現在兩個方面:
1、多個thread對同一個java實例的訪問(read和modify)不會相互干擾,它主要體現在關 鍵字synchronized。如ArrayList和Vector,HashMap和Hashtable(后者每個方法前都有synchronized關鍵字)。如果你在interator一個List對象時,其它線程remove一個element, 問題就出現了。
2、每個線程都有自己的字段,而不會在多個線程之間共享。它主要體現在java.lang.ThreadLocal類,而沒有Java關鍵字支持,如像static、transient那樣。
volatle實現原理
深入分析 Volatile 的實現原理
悲觀鎖,樂觀鎖
是一種思想。可以用在很多方面。比如數據庫方面。
悲觀鎖就是for update(鎖定查詢的行)
樂觀鎖就是 version字段(比較跟上一次的版本號,如果一樣則更新,如果失敗則要重復讀-
比較-寫的操作。)
JDK方面:
悲觀鎖就是sync
樂觀鎖就是原子類(內部使用CAS實現)
本質來說,就是悲觀鎖認為總會有人搶我的。樂觀鎖就認為,基本沒人搶。
樂觀鎖是一種思想,即認為讀多寫少,遇到并發寫的可能性比較低,所以采取在寫時先讀出 當前版本號,然后加鎖操作(比較跟上一次的版本號,如果一樣則更新),如果失敗則要重 復讀-比較-寫的操作。
CAS是一種更新的原子操作,比較當前值跟傳入值是否一樣,一樣則更新,否則失敗。CAS頂多算是樂觀鎖寫那一步操作的一種實現方式罷了,不用CAS自己加鎖也是可以的。
樂觀鎖的業務場景及實現方式
每次獲取數據的時候,都不會擔心數據被修改,所以每次獲取數據的時候都不會進行加鎖, 但是在更新數據的時候需要判斷該數據是否被別人修改過。如果數據被其他線程修改,則不 進行數據更新,如果數據沒有被其他線程修改,則進行數據更新。由于數據沒有進行加鎖, 期間該數據可以被其他線程進行讀寫操作。
樂觀鎖:比較適合讀取操作比較頻繁的場景,如果出現大量的寫入操作,數據發生沖突的可 能性就會增大,為了保證數據的一致性,應用層需要不斷的重新獲取數據,這樣會增加大量 的查詢操作,降低了系統的吞吐量。
最后
都看到這了,給孩子一個三連支持一下吧,
Java對初學者很友好;
Java資源豐富,因為它可以解決不同的問題;
Java有一個龐大而友好的社區;
Java無處不在,因此更容易找到第一份工作;
Java開發人員缺口大,薪水很高。
只要你具備能力,薪資待遇你敢要公司就敢給。
Java 任務調度
版權聲明:本文內容由網絡用戶投稿,版權歸原作者所有,本站不擁有其著作權,亦不承擔相應法律責任。如果您發現本站中有涉嫌抄襲或描述失實的內容,請聯系我們jiasou666@gmail.com 處理,核實后本網站將在24小時內刪除侵權內容。