主要是對一個Java開發(fā)的注意點和易忘點做個小總結,不少地方?jīng)]有詳細分析存捺,讀者見諒。另外,對一些特殊的示例程序做一些筆記捌治。
一岗钩、Integer 內部的IntegerCache類對象,緩存了從-128~127的整數(shù)(因為這些小的整數(shù)可能較為常用肖油,所以提前緩存在內存中)兼吓,也是常量池的一種運用。
Class cache = Integer.class.getDeclaredClasses()[0];//IntegerCache.java 這個類的類類型
Field myCache = cache.getDeclaredField("cache");//通過這個類類型反射獲取到類對象
myCache.setAccessible(true);///將該類對象的所有屬性和方法的訪問權限都變?yōu)閜ublic
Integer[] newCache = (Integer[]) myCache.get(cache);///調用這個反射獲得者的方法
System.out.printf("看一下這個newCache 緩存數(shù)組的首元素森枪,是不是 -128视搏? newCache[0]=%d\n",newCache[0]);
System.out.printf("所以,newCache[128]=%d\n",newCache[(0+128)]);
newCache[132] = newCache[133];// 這個數(shù)組的第133個元素, 值為: 5
int a =2;
int b =a+a;//實際指向了 cache數(shù)組的
System.out.printf("%d + %d = %d\n" , a,a,b);
System.out.println(newCache[128+3]);
////看看大整數(shù)和小整數(shù)的區(qū)別
Integer big1 = 1000;
Integer big2 = 1000;
Integer sm1 = 127;
Integer sm2 = 127;
System.out.println(big1==big2);///這里可以看出疲恢,比127大的數(shù)凶朗,會在堆中新建一個Integer類對象,所以显拳,兩個Integer對象引用指向兩個不同位置的Integer類對象
System.out.println(sm1==sm2);///而在Integer類中棚愤,[-128,127]區(qū)間里的整數(shù),都會先在IntegerCache類中的常量池里查找杂数,并索引之宛畦,所以,sm1和sm2指向同一個位置
///這里揍移,由于上述的代碼"newCache[132]==newCache[133]"的緣故次和,即newCache[sm1+128]== newCache[sm2+128],而newCache[sm1+128]=newCache[sm2+128]= -128+128+5 = 5
///所以,sm1 和 sm2 的指向的常量池下標對應的值都是5那伐,于是踏施,sm1 == sm2
sm1 = 4;
sm2 = 5;
System.out.printf("sm1=%d,sm2=%d罕邀,sm1=sm2嗎畅形?%b\n",sm1,sm2,sm1==sm2);
//而這里,就是正常的情況
sm2 = 6;
System.out.printf("sm1=%d诉探,sm2=%d日熬,sm1=sm2嗎?%b\n",sm1,sm2,sm1==sm2);
運行結果如下:
看一下這個newCache 緩存數(shù)組的首元素肾胯,是不是 -128竖席? newCache[0]=-128
所以,newCache[128]=0
2 + 2 = 5
3
false
true
sm1=5敬肚,sm2=5毕荐,sm1=sm2嗎?true
sm1=5艳馒,sm2=6憎亚,sm1=sm2嗎?false
二、泛型注意點:通配符+邊界虽填,List<? super X>
只能添加X
類及其子類對象元素(因為? super X
表示:X及其父類,存在一定的不確定性)
List<? super Mother> list = new ArrayList<Mother>();
Me me = new Me();///Me extends Mother
Sister sister = new Sister();//Sister extends Mother
Mother mother = new Mother();//Mother extends Grandpa
Grandpa grandpa = new Grandpa();
Son son = new Son();
list.add(me);
list.add(son);
list.add(sister);
list.add(mother);
// list.add(grandpa); //不合法
三曹动、Java常用注解與自定義注解
- 常用注解:
@Deprecated///表示這個Person類是過時的類
class Person{
@SuppressWarnings(value = "unused")///無須拋出 未使用警告
private String name;
@Deprecated///表示過時的方法
public void speak(){
}
@Override///表示重載的方法
public String toString() {
return super.toString();
}
@SuppressWarnings("unused")
public void working(){
@SuppressWarnings({"unchecked", "unused"})///無須拋出檢測警告和未使用警告
List list=new ArrayList();
}
}
- 自定義注解的基礎--元注解(@Target斋日,@Retention,@Document墓陈,@Inherited)
- @Target:表明自定義注解的作用域(枚舉類型ElementType中找)
-
ElementType.ANNOTATION_TYPE
:作用在注解類型上的注解 -
ElementType.CONSTRUCTOR
:作用在構造方法上 -
ElementType.FIELD
:作用在屬性上 -
ElementType.LOCAL_VARIABLE
:作用在本地變量上 -
ElementType.METHOD
:方法上 -
ElementType.PACKAGE
:包上 -
ElementType.PARAMETER
:參數(shù)上 -
ElementType.Type
:類恶守、接口、枚舉上
-
- @Retention:用于聲明注解方法的保留策略(枚舉類型RetentionPolicy中找)
-
RetentionPolicy.SOURCE
:【源代碼】注解信息僅保留在源文件中贡必,編譯時將丟棄注解信息兔港。 -
RetentionPolicy.CLASS
:【源代碼-->編譯后】注解信息保留到編譯后的class文件中。 -
RetentionPolicy.RUNTIME
:【源代碼-->編譯后-->運行時】注解信息保留到運行時仔拟,可通過反射來讀取該注解信息衫樊。
-
- @Documented:【注解信息添加到文檔】表明制作Javadoc時,是否將注解信息加入文檔利花。
- @Inherited:【修飾注解科侈,表明讓子類繼承該注解】表明注解是否會被子類繼承,默認情況是不繼承的炒事。
- @Target:表明自定義注解的作用域(枚舉類型ElementType中找)
- 自定義注解
- 類型是
@interface
臀栈。 - 注解參數(shù)的類型只能是:所有基本類型(int、float挠乳、double)权薯、String、Class睡扬、enum盟蚣、Annotation 以及以上類型的數(shù)組。
- 快捷賦值參數(shù)
value
威蕉,詳見以下例子刁俭。
- 類型是
@Target(ElementType.FIELD)///注解@JP用于修飾方法
@Retention(RetentionPolicy.RUNTIME)//注解@JP能夠保留到運行時
public @interface ID {
public String value();///快捷參數(shù)value,可用于快捷賦值
public String description() default "";
}
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@SuppressWarnings("unused")
public @interface Entity {
String name() default "用戶";
ID id() default @ID("007");///①Entity內部可擁有@ID注解參數(shù) ②快捷賦值給value為007:@ID("007")
}
- 注解處理器【需自定義】
- 相關接口:
AnnotationProcessor
- 接口的實現(xiàn)類:
ExtractProcessor
- 處理步驟:① 獲取@ExtractInterface 注解【獲取失敗后結束】② 構建StringBuilder對象作為臨時代碼存儲器 ③ 按順序添加:包信息韧涨、接口信息牍戚、方法信息 ④ 生成接口文件
- 相關接口:
- Apt工具
- Sun公司開發(fā)的一款用于處理注解的工具。
- 能快速構建復雜的注解處理器虑粥。
- 深度優(yōu)先檢查新產生的類如孝,并對新生的文件進行編譯【Apt一般包含javac功能】。
- 容易將我們編寫的多個注解處理器(都必須實現(xiàn)了AnnotationProcessor接口)組合起來娩贷,以處理一或多個注解第晰。
- Apt處理源代碼的Annotation時,會調用特定的AnnotationProcessor(開發(fā)人員自己定義的),一個Processor處理一個或多個Annotation茁瘦。Apt是通過AnnotationProcessorFactory來獲取處理具體Annotation的Processor的品抽。
- 使用Apt的條件:①實現(xiàn)AnnotationProcessor接口 ②實現(xiàn)AnnotationProcessorFactory接口
- Apt的實現(xiàn)在
com.sun.tools.apt
及其子包中【此包 包含:用于處理Java代碼文件的com.sun.mirror
包,內部是Visitor模式進行代碼維護的甜熔,每個Declaration接口的子類都都有一個accept方法圆恤,用于接受一個DeclarationVisitor接口實現(xiàn)類,并調用該接口的相應方法(設計模式中的訪問者模式的思想)】
- 注解示例demo【實現(xiàn).class文件到sql建表語句的轉換過程】
四腔稀、Java網(wǎng)絡編程
- 網(wǎng)絡協(xié)議:
- OSI(開放系統(tǒng)互聯(lián)模型)【7層】:物理層盆昙、數(shù)據(jù)鏈路層、網(wǎng)絡層焊虏、運輸層淡喜、會話層、表示層诵闭、應用層
- TCP/IP模型【4層】:網(wǎng)絡接口層悦污、網(wǎng)際層朦蕴、運輸層陷猫、應用層
- 五層協(xié)議體系【5層】參考文章:物理層硝逢、數(shù)據(jù)鏈路層、網(wǎng)絡層润歉、傳輸層模狭、應用層
- IP地址:
- IPv4:32位二進制數(shù)表示(8x4)
- IPv6:128位二進制數(shù)表示(8x16)
- InetAddress以及實現(xiàn)類是Java對IP地址的封裝。作用:IP與主機地址(網(wǎng)址)互轉踩衩。實現(xiàn)原理是:使用本地及其配置或DNS(域名系統(tǒng))嚼鹉、NIS(網(wǎng)絡信息服務)來對域名進行解析。提高效率的方法:對于DNS來說驱富,通過本地緩存一些主機名與IP地址的映射锚赤,避免重復發(fā)送DNS請求。
- TCP通信:
- 主要兩個類:ServerSocket 和 Socket
- ServerSocket.accept() throws IOException 此方法一直處于阻塞狀態(tài)褐鸥,知道有新的連接接入线脚,建立連接后,此方法返回一個套接字叫榕,用于操作讀寫浑侥。
- UDP通信:
- 特點:不像TCP每次通信都建立一條特定的連接通道,進行傳輸控制晰绎,UDP本身數(shù)據(jù)就自帶傳輸控制信息寓落,所以UDP傳輸能節(jié)省系統(tǒng)開銷,數(shù)據(jù)傳輸效率高于TCP荞下。
- 主要類:DatagramPacket(數(shù)據(jù)包伶选,'郵件')史飞,DatagramSocket(數(shù)據(jù)包收發(fā)套接字,‘郵箱’)
- 工作過程:接收方會一直監(jiān)聽是否有數(shù)據(jù)包到達仰税,當有數(shù)據(jù)包到達時构资,會創(chuàng)建一個DatagramPacket對象,來接收存儲這個報文陨簇,接收的報文中存儲了發(fā)送者的地址和端口蚯窥。
- HTTP通信:
- HTTP作用:用于從WWW服務器傳輸超文本到本地瀏覽器的傳送協(xié)議,可以使瀏覽器更高效塞帐,是網(wǎng)絡傳輸減少。
- HTTP是基于TCP的應用層協(xié)議巍沙,有時承載著TLS或SSL協(xié)議層【TLS:安全傳輸層協(xié)議葵姥,用于兩個通信應用之間提供保密性和數(shù)據(jù)完整性;SSL:Netscape研發(fā)的用于保障Internet上數(shù)據(jù)傳輸?shù)陌踩湫脭?shù)據(jù)加密(Encryption)技術榔幸,確保數(shù)據(jù)在網(wǎng)絡上的傳輸過程中不被截取、竊聽】
- HTTP永遠是:客戶端發(fā)請求矮嫉,服務端響應削咆。
- HTTP格式:
- 請求消息格式:
Method【GET/POST等】
+空格+Request-URI【請求訪問的地址(相對地址,"/"開頭)】
+空格+HTTP/Version【HTTP版本】
+換行+消息頭【客戶端運行環(huán)境信息+消息體信息等】
+換行+消息體
- 響應消息格式:
HTTP/Version
+空格+Status【響應狀態(tài)碼】
+空格+Description【響應描述】
+換行+消息頭
+換行+消息體
- 請求消息格式:
五蠢笋、多線程
- 線程操作相關基礎:
- Thread.sleep():【休眠】當前線程休眠拨齐;不占CPU時間;休眠結束后昨寞,線程繼續(xù)運行瞻惋;線程休眠時間精確性與系統(tǒng)時鐘有關。
- Thread.interrupt():【中斷】設置線程的中斷狀態(tài)為true援岩;不直接強制線程的執(zhí)行或中止歼狼,線程自己決定是否運行;
- 注意點一:線程處于阻塞狀態(tài)享怀,線程沒有執(zhí)行羽峰,所以沒機會檢查中斷狀態(tài)。(線程阻塞狀態(tài):由于某種原因線程暫停運行的狀態(tài)添瓷,包括可中斷阻塞和不可中斷阻塞)
- 可中斷阻塞:線程上調用了sleep()梅屉、wait()、join()導致鳞贷。
- 不可中斷阻塞:獲取對象鎖 導致的阻塞履植。
- 注意點二:如果線程處于可中斷阻塞狀態(tài),另一個線程對它提出中斷請求悄晃,線程將拋出InterruptedException異趁钓或ClosedByInterruptException異常凿滤,并跳出阻塞狀態(tài);如果線程處于不可中斷狀態(tài)庶近,則對中斷請求不會做出響應翁脆。
- 注意點一:線程處于阻塞狀態(tài)享怀,線程沒有執(zhí)行羽峰,所以沒機會檢查中斷狀態(tài)。(線程阻塞狀態(tài):由于某種原因線程暫停運行的狀態(tài)添瓷,包括可中斷阻塞和不可中斷阻塞)
- Object.wait():導致本線程等待,并釋放本線程擁有的該對象的鎖鼻种;只有本線程被別的線程調用nofity()或notifyAll()并搶到對象鎖時反番,才重新回到運行態(tài)。
- Object.notify() 和 Object.notifyAll():前者只通知本線程以外的其他等待此對象鎖的線程中的一個叉钥,后者是則通知其他所有的等待線程并讓隨機一個線程獲取對象鎖罢缸。
- Condition.await():【類似于:Object.wait()】讓本線程等待。
- Condition.signal()和signalAll():【類似于:Object.notify()】通知等待的線程投队,并結束等待線程的等待狀態(tài)枫疆。
- 例子:線程的run()方法中對中斷做出響應的正確寫法:
while(還有工作沒完成){
if(Thread.currentThread().isInterrupted())
{///如果中斷狀態(tài)被設為true(別人叫我中斷了)
///響應中斷請求。首先決定是否終止線程敷鸦,如果要終止息楔,需要完成必須完成的結束工作
///例如關閉資源占用等,然后退出run()方法
}
///處理未完成工作
}
- 未捕獲異常扒披,用
Thread.UncaughtExceptionHandler
來解決值依。
- 出現(xiàn)未捕獲異常的情況:子線程的run()方法執(zhí)行過程中拋出異常并終止,但是主線程無法獲取到這個異常碟案≡赶眨【因為主線程與子線程是完全不同的兩個指令序列】
- 解決方法:
Thread.setDefaultUncaughtExceptionHandler(new 自定義UncaughtExceptionHandler實現(xiàn)類);
- Lock的用法
- Lock是接口,常用實現(xiàn)類是ReentrantLock价说。
- 正確寫法實例:
class X{ private ReentrantLock lock = new ReentrantLock(); public void readOrWriteSharedData(){ if(lock.tryLock()){///嘗試獲取對象鎖 try{ ///對共享資源進行處理 } finally{ lock.unlock(); } } } }
- 如果一個鎖被另一個線程保持拯啦,那么,處于線程調度目的熔任, 阻塞當前線程褒链,當前線程處于休眠狀態(tài),直到:
- 鎖由當前線程獲得
- 其他某個線程中斷當前線程
- 已超過指定的等待時間
- 線程的六個狀態(tài)
- 新生:new出了Thread對象疑苔,還沒執(zhí)行start()甫匹。
- 可運行:調用start()后的狀態(tài)〉敕眩【注意:此狀態(tài)下兵迅,線程不一定被線程調度器加載到CPU上執(zhí)行】
- 阻塞:受阻塞并正在等待鎖的線程狀態(tài),沒有CPU時間片薪贫。兩種方法進入阻塞態(tài):①線程進入synchronized方法或代碼塊(或調用Lock對象的lock()或tryLock()等方法)恍箭,并試圖獲取其他線程已經(jīng)占用的鎖時;②退出等待狀態(tài)瞧省、并試圖重新獲得在等待狀態(tài)時擁有的鎖但此鎖已被其他線程占用時扯夭。
- 等待:此狀態(tài)下的線程正在等待另一個線程鳍贾,以執(zhí)行特定操作。不占CPU時間片交洗。
- 計時等待:具有指定等待時間的某一等待線程的線程狀態(tài)骑科。與等待狀態(tài)相似,區(qū)別是:過了等待時間构拳,也會退出等待狀態(tài)咆爽。
- 終止:線程結束執(zhí)行。進入此狀態(tài)的兩種可能:① run()方法執(zhí)行完畢并返回置森; ② 在執(zhí)行run()過程中拋出未處理異常斗埂。
- 示例:Condition.await()和Condition.signal()的應用:多個轉賬交易可以被多個線程調用,而遇到轉賬金額過大的情況凫海,就選擇等待其他交易完成呛凶。
Condition相對于對象鎖的優(yōu)勢:能夠在一個鎖對象上創(chuàng)建多個Condition對象,每個Condition對象代表一種不同的等待類型盐碱。
private Account[] accounts;
private Lock dealLock = new ReentrantLock();
private Condition moneyCondition = dealLock.newCondition();///資金不足的情況
public void deal(int fromAccount,int toAccount,Long money){
if (this.dealLock.tryLock()){
try {
while(accounts[fromAccount].money<money){
///如果存款不足,就不能轉這么多帳了
try {
moneyCondition.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
///到有了存款了沪伙,那么瓮顽,就可以繼續(xù)執(zhí)行轉賬
accounts[fromAccount].money -= money;
accounts[toAccount].money += money;
/////轉賬完畢,可以喚醒其他需要轉賬的線程了
moneyCondition.signalAll();
} finally {
this.dealLock.unlock();
}
}
}
以上代碼的功能于一下使用synchronized同步關鍵字的一樣:
public synchronized void deal(int fromAccount, int toAccount, Long money) {
while (accounts[fromAccount].money < money) {
///如果存款不足围橡,就不能轉這么多帳了
try {
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
///到有了存款了暖混,那么,就可以繼續(xù)執(zhí)行轉賬
accounts[fromAccount].money -= money;
accounts[toAccount].money += money;
this.notifyAll();//轉賬完畢翁授,可以喚醒其他需要轉賬的線程了
}
- 同步器之---信號量(Semaphore)
信號量的作用是限制對共享資源讀寫的線程的最大并發(fā)數(shù)拣播。它一般配合具有同步能力的資源接口方法一起使用。而信號量本身的阻塞過多線程的能力與共享數(shù)據(jù)的同步操作之間收擦,是不同的處理贮配,也就是說:能夠被信號量允許的線程,也還得需要經(jīng)過同步方法的同步過程塞赂,才能真的達到共享資源的同步讀寫泪勒。
///例子:10個線程 ,同時對共享數(shù)據(jù)進行讀取宴猾,通過信號量限制每次最多5個線程異步運行圆存。
///,剩下的線程被阻塞仇哆,而運行的5個線程沦辙,如果要做同步操作,也必須遵循先后的原則讹剔。
public class PoolSemaphoreDemo {
private static final int max =5;
private final Semaphore semaphore = new Semaphore(max,true);
public static void main(String[] args){
final PoolSemaphoreDemo pool = new PoolSemaphoreDemo();
Runnable runnable = new Runnable() {
@Override
public void run() {
try {
Object obj;
obj = pool.getItem();///讀寫數(shù)據(jù)油讯,設置數(shù)據(jù)狀態(tài)為"被占用"
if (obj!=null)
System.out.println("線程:"+Thread.currentThread().getName()+"讀取了數(shù)據(jù):"+obj.toString());
else
System.out.println("線程:"+Thread.currentThread().getName()+"沒有數(shù)據(jù)");
Thread.sleep(1000);
pool.putItem(obj);//讀寫數(shù)據(jù)完畢详民,設置數(shù)據(jù)為"空閑"狀態(tài),并容許后續(xù)的等待線程調用
} catch (InterruptedException e) {
e.printStackTrace();
}
}
};
for (int i=0;i<10;i++){
Thread t = new Thread(runnable,"thread"+i);
t.start();
}
}
public Object getItem() throws InterruptedException {
System.out.println(Thread.currentThread().getName()+"正在被信號量檢查撞羽。阐斜。。");
semaphore.acquire();
System.out.println(Thread.currentThread().getName()+"被允許執(zhí)行同步方法");
return getNextAvailableItem();
}
public void putItem(Object x){
if (markAsUnused(x)){
semaphore.release();
System.out.println("線程:"+Thread.currentThread().getName()+"釋放了資源:"+x.toString());
}
}
protected Object[] items = {"11","22","33"};
protected boolean[] useds = new boolean[3];
private synchronized Object getNextAvailableItem() {
for (int i=0;i<3;i++){
if (!useds[i]){
useds[i] = true;
return items[i];
}
}
return null;
}
private synchronized boolean markAsUnused(Object item){
for (int i=0;i<3;i++){
if (item == items[i]){
if (useds[i]) {///正在被使用
useds[i] = false;
return true;
}else///沒有被使用
return false;
}
}
return false;
}
}
- 同步器之---倒計時門栓(CountDownLatch)
是一個同步輔助器诀紊。下面通過一個例子谒出,說明他的用法:
public class LatchDriverDemo {
public static void main(String[] args) throws InterruptedException {
CountDownLatch startSignal = new CountDownLatch(1);
CountDownLatch doneSignal = new CountDownLatch(5);
//主線程運行
for (int i=0;i<5;i++){
new Thread(new Worker(startSignal,doneSignal),"t"+i).start();
}
//此時,5個子線程都執(zhí)行了CountDownLatch.await()從而等待主線程開門邻奠,主線程繼續(xù)運行
///此時笤喳,5個子線程處于等待狀態(tài),主線程休眠4s
Thread.sleep(4000);
// 此時碌宴,主線程執(zhí)行CountDownLatch.countDown()杀狡,使得由于startSignal的值已經(jīng)減為0從而解放5個子線程,子線程開始繼續(xù)往下執(zhí)行贰镣,主線程繼續(xù)執(zhí)行
startSignal.countDown();///startSignal變成0呜象,所有線程開始工作
///此時,子線程繼續(xù)執(zhí)行中碑隆,主線程調用了await()恭陡,所以主線程阻塞了,等待doneSignal的值變?yōu)?上煤,才被允許繼續(xù)執(zhí)行
doneSignal.await();
////然后休玩,子線程開始做。劫狠。拴疤。。独泞。呐矾。。
System.out.println("所有任務完成懦砂!");
}
}
class Worker implements Runnable{
private final CountDownLatch startSignal;
private final CountDownLatch doneSignal;
public Worker(CountDownLatch startSignal, CountDownLatch doneSignal) {
this.startSignal = startSignal;
this.doneSignal = doneSignal;
}
@Override
public void run() {
try {
//上門栓凫佛,等待主線程的開門(startSignal減為0)
startSignal.await();
/*
do sth
*/
//完成任務,doneSignal減一(減到0孕惜,主線程才會被喚醒)
doneSignal.countDown();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
- 同步器之---障柵(CyclicBarrier)
?允許一組線程相互等待愧薛,直到到達某個公共屏障點。優(yōu)點:能夠循環(huán)多次地進行(等待--運行)的狀態(tài)切換衫画,從而實現(xiàn)線程間的復雜協(xié)作過程毫炉。
?例子說明一切:快的線程,會等待慢的線程執(zhí)行完削罩,每次達到同一個進度瞄勾,就再次解放所有線程费奸,繼續(xù)往下執(zhí)行。
public class CyclicBarrierTest {
public static void main(String[] args){
CyclicBarrier barrier = new CyclicBarrier(2, new Runnable() {
@Override
public void run() {
System.out.println("人齊了=浮愿阐!");
}
});
new Thread(new Tour(barrier,"小明走路",1)).start();
new Thread(new Tour(barrier,"小花開車",2)).start();
}
static class Tour implements Runnable{
///走路到:廣州、深圳趾疚、珠海的時間
private int walkTime[] = {5,5,5};
//開車到:廣州缨历、深圳、珠海的時間
private int driveTime[] = {3,3,3};
private CyclicBarrier barrier;
private String name;
private int way;
public Tour(CyclicBarrier barrier,String name,int way) {
this.barrier = barrier;
this.name = name;
this.way = way;
}
@Override
public void run() {
try{
Thread.sleep(1000*((way==1)?walkTime[0]:driveTime[0]));
System.out.println(this.name+"到廣州了");
barrier.await();
Thread.sleep(1000*((way==1)?walkTime[1]:driveTime[1]));
System.out.println(this.name+"到深圳了");
barrier.await();
Thread.sleep(1000*((way==1)?walkTime[2]:driveTime[2]));
System.out.println(this.name+"到珠海了");
barrier.await();
} catch (InterruptedException e) {
e.printStackTrace();
} catch (BrokenBarrierException e) {
e.printStackTrace();
}
}
}
}
- 同步器之--交換器(Exchanger)
?顧名思義糙麦, 就是進行線程間數(shù)據(jù)交換的辛孵。實現(xiàn)方法為:Exchanger.exchange(Object obj):Object
六、序列化
- 注意點:
- 靜態(tài)變量和所有方法都不必序列化
- 使用
transient
關鍵字赡磅,可以修飾不想被序列化的屬性魄缚。 - 要實現(xiàn)序列化接口的類,都必須聲明一個
serialVersionUID
靜態(tài)Long屬性焚廊,默認JVM也會自動聲明該屬性并為之賦值冶匹。只有類的序列化標識完全相同,Java才會進行反序列化工作咆瘟。
- Serializable 接口的擴展:
這里面的兩個方法:public class Person implements Serializable{ private static final Long serialVersionUID= 1L; private String name; ///getter and setter 方法 private void writeObject(ObjectOutputStream out) throws IOException{ out.defaultWriteObject(); Date date = new Date(); } private void readObject(ObjectInputStream in) throws IOException,ClassNotFoundException{ in.defaultReadObject(); Date date = (Date)in.readObject();///序列化時的時刻 Date now = new Date();///當前時刻 long offset = now.getTime() - date.getTime();///求得時間差 ///后續(xù)的自定義操作等嚼隘。。搞疗。 } }
writeObject()
和readObject()
嗓蘑,分別能夠給到我們在序列化和反序列化過程時添加自定義的邏輯须肆,例如添加想要序列化的數(shù)據(jù)匿乃,如上述代碼。 - 解決單例模式的類在序列化后豌汇,被多次反序列出不同的類對象的情況:
主要加入兩個方法:public class Earth implements Serializable{ private static Earth sInstance; private Earth(){ } public static Earth getInstance(){ if(instance==null) instance=new Earth(); return instance; } private Object readResolve(){ return getInstance(); } private Object writeReplace(){ return getInstance(); } }
readResolve()
和writeResolve()
即可幢炸。 - Externalizable接口
- 優(yōu)點:靈活,可部分序列化拒贱,可提高序列化效率
- 缺點:較為復雜宛徊,需要重寫方法
- 重寫方法:
-
readExternal()
:自定義哪些屬性需要反序列化 -
writeExternal()
:自定義哪些屬性需要序列化
-
- 例子:
class Person implements Externalizable{ public String name; public int age; @Override public void writeExternal(ObjectOutput out) throws IOException { out.write(name.getBytes());///只序列化name } @Override public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException { this.name = in.readLine();///反序列化name }
}
```
- 對XML的解析
- DOM:
- 采用建立樹形接口的方式訪問XML文檔,直接解析整個文檔逻澳,生成一棵樹并對樹遍歷闸天。
- 優(yōu)點:JDK自帶,編程容易斜做,容易添加或修改樹中的元素苞氮。
- 缺點:需要處理整個XML文檔,對性能和內存要求比較高瓤逼。
- DOM解析器常用于XML文檔需要頻繁改變的服務中笼吟。
- SAX:
- 采用事件模型库物,找到對應的tag時,激活回調方法贷帮。
- 優(yōu)點:JDK自帶戚揭,對內容要求低,不需要整個文檔處理撵枢,效率提高民晒。
- 缺點:編碼較復雜,難以同時訪問同一個文檔中的多處不同數(shù)據(jù)诲侮。
- JDOM:
- 與DOM的區(qū)別:JDOM使用具體類镀虐,而不是接口,限制了靈活性沟绪。
- 需要導入jdom.jar包刮便。
- DOM4J:
- 特點:API更復雜,但提供更大的靈活性绽慈。
- 需要導入dom4.jar包恨旱。
- DOM:
- 對JSON的解析
可以參考本人的這篇文章《JSON數(shù)據(jù)通信--org.json和Gson基本用法》
七、JDBC
JDBC生命周期:
【開始】 --> 加載數(shù)據(jù)庫驅動 --> 注冊數(shù)據(jù)庫驅動 --> 獲取連接會話 --> 進行數(shù)據(jù)庫操作 --> 關閉并釋放連接 --> 【結束】-
三個重要接口:
-
java.sql.Connection
:負責維護Java開發(fā)者與數(shù)據(jù)庫之間的會話 -
java.sql.Driver
:數(shù)據(jù)庫提供商提供的驅動類必須實現(xiàn)的接口 -
java.sql.DriverManager
:用戶需要將數(shù)據(jù)庫驅動(Driver實現(xiàn)類)注冊到DriverManagerService中坝疼,才能訪問數(shù)據(jù)庫搜贤。
-
-
數(shù)據(jù)庫操作類相關:
-
java.sql.Statement
:會話類,用于執(zhí)行sql語句钝凶。 -
java.sql.PreparedStatement
:會話類仪芒,相對于Statement
,能夠識別sql語句中的?
問號耕陷,并進行動態(tài)賦值等操作掂名。 -
java.sql.ResultSet
:執(zhí)行結果類,用于讀取query返回的數(shù)據(jù)庫查詢結果哟沫。
-
MySql的Connection驅動包下載:http://dev.mysql.com/downloads/connector/j/3.1.html
-
例子:自定義的簡易數(shù)據(jù)庫連接池
具體思路:MyCon封裝由MySqlDAO工具類中獲取的新建Connection對象饺蔑,而ConPool則管理所有的MyCon連接封裝對象。- MyCon.java【Connection數(shù)據(jù)庫連接對象封裝類】
public class MyCon {
public static final int FREE = 100;///空閑
public static final int BUZY = 101;///繁忙
public static final int CLOSED = 102;///連接關閉
private Connection connection;//持有Connection對象的引用
private int state= FREE;///當前的連接狀態(tài)
public MyCon(Connection connection) {
this.connection = connection;
}
/**
* @return 返回數(shù)據(jù)庫連接嗜诀,用于操作
/
public Connection getConnection() {
return connection;
}
/*
* @return 當前狀態(tài)
*/
public int getState() {
return state;
}
/**
* @param state 設置當前狀態(tài)
*/
public void setState(int state) {
this.state = state;
}
}
* ConPool.java 【數(shù)據(jù)庫連接池】
public class ConPool {
private List<MyCon> freeCons = new ArrayList<>();
private List<MyCon> buzyCons = new ArrayList<>();
private int max = 10;
private int min = 2;
private int current = 0;
private static ConPool sInstance;
private ConPool(){
while(this.min > this.current){
this.freeCons.add(this.createCon());
}
}
public static ConPool getInstance(){
if (sInstance==null){
synchronized (ConPool.class){
if (sInstance==null)
sInstance = new ConPool();
}
}
return sInstance;
}
/**
* 獲取數(shù)據(jù)庫連接
* @return 數(shù)據(jù)庫連接
*/
public MyCon getCon() {
MyCon myCon = this.getFreeCon();
if (myCon!=null)
return myCon;
return this.getNewCon();
}
/**
* 設置連接為空閑狀態(tài)
* @param con 連接
*/
public void setFree(MyCon con){
this.buzyCons.remove(con);
con.setState(MyCon.FREE);
this.freeCons.add(con);
}
/**
* @return 返回當前連接池的連接狀態(tài)
*/
public String toString(){
return "當前連接數(shù):"+ this.current + "猾警,空閑連接數(shù):"+this.freeCons.size()+",繁忙連接數(shù):"+this.buzyCons.size();
}
//=================================================================================
private MyCon getNewCon() {
if (this.current>=this.max)
return null;
MyCon myCon = this.createCon();
assert myCon != null;
myCon.setState(MyCon.BUZY);
this.buzyCons.add(myCon);
return myCon;
}
private MyCon createCon() {
try{
Connection connection = MySqlDAO.getConnection();
MyCon myCon = new MyCon(connection);
this.current++;
return myCon;
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
private MyCon getFreeCon() {
if (freeCons.size()>0){
MyCon con =freeCons.remove(0);
con.setState(MyCon.BUZY);
this.buzyCons.add(con);
return con;
}
return null;
}
}
* MySqlDAO.java【MySql的連接驅動操作工具類】
public class MySqlDAO {
public static String database = null;
public static Connection getConnection() throws Exception{
String driverName="com.mysql.jdbc.Driver";
String url = "jdbc:mysql://localhost:3306/"+(database==null?"":database);///連接協(xié)議 + 數(shù)據(jù)庫地址+ 數(shù)據(jù)庫名稱
String user = "root";
String password="110120130140";
Class.forName(driverName);///加載數(shù)據(jù)庫驅動隆敢,此過程會自動調用DriverManager中的registerDriver(Driver driver)方法发皿,注冊到管理器中
Connection con = DriverManager.getConnection(url,user,password);////創(chuàng)建并獲取連接
return con;//等待并最終返回連接信息
}
//。拂蝎。穴墅。。。封救。拇涤。。誉结。鹅士。
}
#### 八、IntelliJ IDEA上第一個后端項目的創(chuàng)建過程惩坑。
關于eclipse或MyEclipse上新建Web工程掉盅,網(wǎng)上比較全,這里不多介紹以舒,而IDEA上創(chuàng)建web項目的過程趾痘,可以參考[這篇文章](http://blog.csdn.net/u012532559/article/details/51013400),親測成功蔓钟。
由于篇幅問題永票,關于Servlet注意點與Java Web開發(fā)規(guī)范等,將后續(xù)更新滥沫,謝謝閱讀~