1.導(dǎo)包
ctrl+shift+字母o ,回車
2.保留指定位數(shù)的小數(shù)
(1)保留幾位小數(shù)??“%.nf” ,n保留的小數(shù)位數(shù) ,保留2位小數(shù) "%.2f"
(2)//借助 java.text.DecimalFormat類 炭晒,格式化數(shù)字??保留幾位小數(shù),就留幾個(gè)“0”
????????DecimalFormat df = new DecimalFormat(".000");
????????//借助df格式化pi????str="3.142" ,是一個(gè)字符串???
????????//format()方法筒严,將 double 按指定格式 輸出成字符串
????????String str = df.format(pi);
????????System.out.println("str="+str);
????????// 將字符串 轉(zhuǎn)換成 double類型的浮點(diǎn)數(shù)
????????double result = Double.parseDouble(str);
3.Math.round(a)
4.多重if
范圍打亂闸昨,順序?qū)Y(jié)果又影響 ,要么從大往小寫箫攀,要么從小往大寫磁餐,對于順序打亂违崇,解決辦法:加上邏輯限制條件。
5.隨機(jī)數(shù)
[min, max) 整數(shù)???(int)(Math.random()*(max-min)+min);
Random??ra??= new Random();
[min, max)????整數(shù):???ra.nextInt(max-min)+min
6.冒泡排序
????int[] arr = {5,4,3,2,1};
????????????//聲明中間變量诊霹,用于交換
????????????int temp=0;
????????????//控制輪數(shù)
????????????for(int k=0;k<arr.length-1;k++){
????????????????System.out.println("\n\n第"+(k+1)+"輪開始時(shí):"+Arrays.toString(arr));
????????????????//內(nèi)層控制的每一輪比較的次數(shù)羞延,要保證比較次數(shù)在減少, 取值畅哑,4肴楷,3水由,2荠呐,1
????????????????for(int i=0;i<arr.length-1-k;i++){
????????????????????//如果前一個(gè)比后一個(gè)大需要交換
????????????????????if(arr[i]>arr[i+1]){
????????????????????????temp=arr[i];
????????????????????????arr[i]= arr[i+1];
????????????????????????arr[i+1]=temp;
????????????????????}
????????????????????System.out.println("第"+(k+1)+"輪第"+(i+1)+"次比較:"+Arrays.toString(arr));
????????????????}
????????????????System.out.println("第"+(k+1)+"輪結(jié)束后:"+Arrays.toString(arr)+"\n\n");
????????????}
選擇排序
????public static void main(String[] args) {
?????int [] arr=new int [] {45,65,32,33,12,1};
?????for(int i=0;i<arr.length-1;i++) {
????????int index=i;
????????for(int j=i+1;j<arr.length;j++) {
????????????if(arr[j]<arr[index]) {
????????????????int temp=arr[index];
????????????????arr[index]=arr[j];
????????????????arr[j]=temp;
????????????}
????????}
?????}
?????System.out.println(Arrays.toString(arr));
????}
快速排序
????public static void main(String[] args) {
????????int[] arr = new int[] { 1, 2, 4, 5, 7, 4, 5, 3, 9, 0 };
?????//System.out.println(Arrays.toString(arr));
????????quickSort(arr);
????????System.out.println(Arrays.toString(arr));
????}
????private static void quickSort(int[] arr) {
????????if (arr.length > 0) {
????????????quickSort(arr, 0, arr.length - 1);
????????}
????}
????private static void quickSort(int[] arr, int low, int high) {
????????// 1.遞歸算法出口
????????if (low > high) { // 放在key之前,防止下標(biāo)越界
????????????return;
????????}
????????// 2. 存
????????int i = low;
????????int j = high;
????????// key
????????int key = arr[i];
????????// 3.完成一趟排序
????????while (i < j) {
????????????// 從右往左找到第一個(gè)小于key的數(shù)
????????????while (i < j && arr[j] > key) {
????????????????j--;
????????????}
????????????// 從左往右找第一個(gè)大于key的數(shù)
????????????while (i < j && arr[i] <= key) {
????????????????i++;
????????????}
????????????// 交換
????????????if (i < j) {
????????????????int temp = arr[i];
????????????????arr[i] = arr[j];
????????????????arr[j] = temp;
????????????}
????????}
????????// 當(dāng)i==j時(shí)砂客,調(diào)整key的位置
????????int p = arr[i];
????????arr[i] = arr[low];
????????arr[low] = p;
????????// 對key左邊的數(shù)快排
????????quickSort(arr, low, i - 1);
????????// 對key右邊的數(shù)快排
????????quickSort(arr, i + 1, high);
????}
http://developer.51cto.com/art/201403/430986.htm
7.數(shù)組拷貝
???????(1) int[] arr = {10,12,13,14,15};
???????int[] brr = arr.clone();??//clone()
???????(2)System.arraycopy(要拷貝的原始數(shù)組arr,原始數(shù)組中元素的起始下標(biāo)從0開始srcfrom泥张,目標(biāo)數(shù)組brr,目標(biāo)數(shù)組中起始位置destfrom,要拷貝的元素個(gè)數(shù)num)?
?????*?需要滿足的條件:
?????*?srcfrom>=0
?????*?destfrom>=0
?????*?srcfrom +num <= arr.length
?????*?destfrom+num<=brr.length
???????(3)copyOf(int[] original, int newLength)?
??????*?copyOf(要拷貝的原始數(shù)組鞠值,要拷貝的元素個(gè)數(shù)num)
???????(4)copyOfRange(要拷貝的原始數(shù)組媚创,拷貝的起始索引從0開始from ,結(jié)束索引to)
??????*?拷貝的索引范圍:[from, to) 左閉右開 ,拷貝的元素個(gè)數(shù) to-from
8 .??字符串轉(zhuǎn)數(shù)組
(1)使用Java split() 方法
????split() 方法根據(jù)匹配給定的正則表達(dá)式來拆分字符串彤恶。
????注意: . 钞钙、 | 和 * 等轉(zhuǎn)義字符鳄橘,必須得加 \\。多個(gè)分隔符芒炼,可以用 | 作為連字符瘫怜。????
????String str = "0,1,2,3,4,5";
????String[] arr = str.split(","); // 用,分割
????System.out.println(Arrays.toString(arr));
` int a=Integer.parseInt(arr[]) String類型轉(zhuǎn)int型`
9。數(shù)組轉(zhuǎn)字符串
?????String str2 = ArrayUtils.toString(arr, ","); // 數(shù)組轉(zhuǎn)字符串(逗號分隔,首尾加大括號)
????String str4 = StringUtils.join(arr, ","); //StringUtils的join方法
10.charAt(2) 取出指定位置的字符
lastIndexOf()最后一個(gè)索引的位置
endWith() /startsWith("aa")判斷是否以aa開頭本刽,返回布爾值
trim() 去掉兩邊空格
11鲸湃。 int---》String??Int型轉(zhuǎn)字符串型
????String s1 = String.valueOf(num);
String---》 int???字符串型轉(zhuǎn)int型
????int num2 = Integer.parseInt(s2);
????double num3 =Double.parseDouble(s2);
12 . 截取字符串
//取出10??subString(from,to)??[from,to) 左閉右開
???????String num1Str = s.substring(s.indexOf("從")+1, s.indexOf("數(shù)到"));
???????String num1Str = s.substring(s.indexOf("從")+1, s.indexOf("數(shù)到"));
13.//靜態(tài)變量??,可以類名.屬性名 ,也可以對象名.屬性名
//非static變量/普通變量??,只能通過對象名.屬性名來訪問
//靜態(tài)方法ceshi4(),只能調(diào)用靜態(tài)方法ceshi1(),不能調(diào)用普通方法ceshi2();
14.//1個(gè)類:靜態(tài)成員變量子寓,實(shí)例成員變量(普通的成員變量)暗挑,靜態(tài)代碼塊,普通代碼塊 斜友,構(gòu)造
//執(zhí)行順序: 靜態(tài)成員----》靜態(tài)代碼塊 ----》實(shí)例成員----》普通代碼塊----》構(gòu)造
/
//1.父類的靜態(tài)成員
//???父類的靜態(tài)代碼塊
// 2.子類的靜態(tài)成員
// 子類的靜態(tài)代碼塊
// 3.父類的實(shí)例成員
//???父類的普通代碼塊(非static代碼塊)
//4.父類的構(gòu)造Father()
// 5.子類的實(shí)例成員
//???子類的普通代碼塊(非static代碼塊)
// 6.子類的構(gòu)造Son()
15.this() :表示調(diào)用本類的無參構(gòu)造
?*?this(屬性名):表示調(diào)用本類的帶參構(gòu)造??,this(屬性1炸裆,屬性2....) 可以構(gòu)造的調(diào)用,需要放到第1句
16.基本數(shù)據(jù)類型---》包裝類
//直接裝箱??int類型的變量蝙寨,直接賦值給Integer類型的變量 num2
????????Integer num2 = num1;
????//int--->Integer
????int num1=10;
????Integer num2 = new Integer(num1);
????Integer num7 = Integer.valueOf(num1);
????//String--->Integer
????????String s="10";?
????????Integer num3 = new Integer(s);????
????????Integer num8 = Integer.valueOf(s);
17.包裝類----》基本數(shù)據(jù)類型
//直接拆箱???Integer類型變量num2,直接賦值給int類型的變量num3
????int num3 = num2;
?????//Integer---》int
?????Integer num1 = new Integer(10);
?????int num2 = num1.intValue();
????//String--->int
????????String s="123";
????????int num5=Integer.parseInt(s);
**封裝**(降低耦合
將類的信息隱藏在類的內(nèi)部晒衩,對外提供公有的方法,實(shí)現(xiàn)對該成員屬性的存取操作
封裝的好處:隱藏類的實(shí)現(xiàn)細(xì)節(jié)墙歪,讓使用者使用提供的方法來訪問數(shù)據(jù)听系,可以方便的加入存取操作,限制不合理的操作
**繼承**
一個(gè)類可以由其他類派生虹菲,子類繼承父類特征和方法靠胜。
只支持單繼承
子類可以繼承父類Public和protected修飾的屬性和方法
在同一個(gè)包中可以繼承除private以外的所有修飾的屬性和方法
子類無法繼承父類的構(gòu)造方法
子類不能拋出 比父類更多的異常
父類的靜態(tài)方法不能被子類覆蓋為非靜態(tài)方法,同樣父類的非靜態(tài)方法不能被子類覆蓋為靜態(tài)方法
**繼承下構(gòu)造方法的執(zhí)行過程**
注意:加載順序:啟動(dòng)類(java虛擬機(jī)啟動(dòng)時(shí)毕源,被標(biāo)明為啟動(dòng)類的類)的static block 最先加載(父類靜態(tài)成員浪漠,靜態(tài)代碼塊----子類靜態(tài)成員,靜態(tài)代碼塊---父類實(shí)例成員霎褐,代碼塊-----父類構(gòu)造函數(shù)------子類實(shí)例成員址愿,代碼塊---子類構(gòu)造函數(shù))
*重寫*
方法名相同 參數(shù)列表相同 返回值類型相同或是其子類 不能縮小被重寫方法的訪問權(quán)限
**final關(guān)鍵字**
final 修飾成員變量,則成為實(shí)例常量
final修飾類冻璃,類不能被繼承
final修飾成員方法响谓,則該方法不能被子類重寫。
**super關(guān)鍵字**
在子類構(gòu)造方法中調(diào)用且必須為第一句(調(diào)用父類的帶參構(gòu)造方法)super(屬性1省艳,屬性2..)
使用super關(guān)鍵字 直接調(diào)用父類的方法
**多態(tài)**
同一引用類型娘纷,使用不同的實(shí)例而執(zhí)行不同的操作。
舉例說明多態(tài):動(dòng)物類父類??有“叫”的這樣一個(gè)動(dòng)作跋炕,??繼承它的都是普通類貓 狗等??每個(gè)子類叫的方法實(shí)現(xiàn)都不一樣??赖晶,現(xiàn)在要實(shí)現(xiàn)各種動(dòng)物的叫聲??,如何動(dòng)態(tài)實(shí)現(xiàn)??寫一個(gè)方法把父類做形參傳進(jìn)去
????主人類始終要修改辐烂,只要新增寵物子類遏插,主人類就需要添加具體動(dòng)物看病的方式捂贿,子類寫不盡的,Host類始終需要修改胳嘲,不合理?
?????*??解決辦法:多態(tài)來來解決
?????*??1.創(chuàng)建Cat子類眷蜓,extends Pet父類,Cat類中是Cat特有的屬性
?????*??2. Host類胎围,不需要修改的吁系,只提供一個(gè)空方法,帶寵物看病
?????*?public void cure(Pet pet){
?????*???????pet.toHospital();
?????*?}
?????*??3.父類Pet中白魂,提供1個(gè)空方法 汽纤,public??void toHospital(){}
?????*??4.每個(gè)子類,看病的方式不同福荸,就把各自子類看病的方式蕴坪,放到各自的子類中去完成
?????*???每個(gè)子類,去重寫父類的toHospital()方法
?????*???
?????*??5.調(diào)用的時(shí)候敬锐,父類引用背传,指向子類對象,執(zhí)行的是各自不同的子類對應(yīng)的操作
**abstract抽象**
抽象方法(只有方法聲明台夺,沒有方法實(shí)現(xiàn))*abstract void fun()径玖;*
抽象類 :包含抽象方法的類是抽象類;
抽象類不能實(shí)例化颤介,可以實(shí)例化子類來實(shí)現(xiàn)父類的方法
??*?子類必須重寫所有抽象方法才能實(shí)例化梳星,否則子類還是一個(gè)抽象類*
抽象類有構(gòu)造方法,可以被本類其他構(gòu)造方法調(diào)用滚朵,如果不是private修飾冤灾,可以被其子類中的構(gòu)造方法調(diào)用。
abstract修飾類和方法辕近,不能修飾屬性和構(gòu)造方法
**接口**
接口中不能定義變量??可以定義常量??自動(dòng)用public static final修飾??全局靜態(tài)常量
接口中所有方法都是抽象方法 自動(dòng)public abstract 修飾
接口不能實(shí)例化 不能有構(gòu)造方法
接口的實(shí)現(xiàn)類必須要實(shí)現(xiàn)接口的全部方法韵吨,除非這個(gè)類是抽象類
一個(gè)接口不能實(shí)現(xiàn)另一個(gè)接口,但可以繼承多個(gè)其他接口
**Date類**
????Date??date=new??Date()移宅;
????System.out.println("date="+date);
3個(gè)子類構(gòu)造
????//java.sql.Date??,默認(rèn)格式“yyyy-MM-dd"
????????Date date = new Date(System.currentTimeMillis());
????????// date=2019-03-25
????//java.sql.Time???归粉,默認(rèn)格式:“HH:mm:ss”
????????Time date2 = new Time(System.currentTimeMillis());
????????//date2=11:53:09?
????//java.sql.Timestamp??默認(rèn)格式“ yyyy-MM-dd HH:mm:ss.SSS" 精確到毫秒
????????//1s = 1000ms ,毫秒的范圍[000,999]
????????Timestamp date3 = new Timestamp(System.currentTimeMillis());
????????//date3=2019-03-25 11:54:20.097
DateFormat:日期格式化類吞杭。抽象類無法使用
SimpleDateFormat是其子類可以使用
(1 格式化java.util.Date對象??盏浇,讓其按指定的格式來顯式
?????將Date對象 ----format()方法-----》字符串String 來顯式
(2 public static String getStrFromDate(Date date,String pattern){
????DateFormat df = new SimpleDateFormat("yyyy-MM-dd");
????Date date = new Date();????
????String result = df.format(date);
????System.out.println("date="+date+",格式化后="+DateUtil.getStrFromDate(date, "yyyy-MM-dd"));
**Calendar類**
Calendar:抽象類变丧,不能直接實(shí)例化 芽狗,可以使用其子類 GregorianCalendar
????Calendar cal = new GregorianCalendar();
獲取時(shí)間
????Calendar cal = Calendar.getInstance();
設(shè)置時(shí)間
Calendar cal = Calendar.getInstance();
????// 如果想設(shè)置為某個(gè)日期,可以一次設(shè)置年月日時(shí)分秒痒蓬,由于月份下標(biāo)從0開始賦值月份要-1
????// cal.set(year, month, date, hourOfDay, minute, second);
???????cal.set(2018, 1, 15, 23, 59, 59);
**異常**
*??error與exceptionde 區(qū)別*
error表示不可處理的異常??通常為內(nèi)存溢出??jvm崩潰等童擎。
exception表示需要捕捉或者處理的異常
*??throw和throws的區(qū)別*
throw在程序中拋出異常滴劲,出現(xiàn)在方法體內(nèi),如果執(zhí)行則一定拋出某種異常對象顾复,且只能拋出一個(gè)班挖。
throws表示拋出異常的聲明,出現(xiàn)在方法頭芯砸,聲明拋出異常的一種可能性萧芙,throws后面可以跟多個(gè)異常類。
*?try catch finally*
try塊必須???catch??finally必須出現(xiàn)一個(gè)
finally一定會執(zhí)行假丧,除非System.exit(n)
try塊中有return語句双揪,finally語句也會執(zhí)行,執(zhí)行return語句會記下返回值包帚,待finally執(zhí)行結(jié)束后渔期,再向調(diào)用者返回其值。
*常見的5種RunTimeException*
NullPointerException渴邦,空指針異常疯趟。
NumberFormatException,數(shù)據(jù)格式轉(zhuǎn)換錯(cuò)誤谋梭。
ClassCastException信峻,強(qiáng)制類型轉(zhuǎn)換異常。
IndexOutOfBoundsException,越界異常瓮床。
ArithmeticException 算術(shù)異常站欺。
除RuntimeException及其子類其他所有的異常都是檢查型異常(可查異常)
運(yùn)行時(shí)異常的特點(diǎn)是Java編譯器不會檢查它,也就是說纤垂,當(dāng)程序中可能出現(xiàn)這類異常矾策,即使沒有用try-catch語句捕獲它,也沒有用throws子句聲明拋出它峭沦,也會編譯通過贾虽。
使用自定義異常的步驟:
1.定義異常類(繼承 Throwable 類,Exception類 RuntimeException)吼鱼。
2.編寫構(gòu)造方法蓬豁,繼承父類的實(shí)現(xiàn)。
3.實(shí)例化自定義異常對象菇肃。
4.使用throw 拋出地粪。
**String、StringBuffer與StringBuilder之間的區(qū)別**
1.String含義為引用數(shù)據(jù)類型,是字符串常量.是不可變的對象,(顯然線程安全)在每次對string類型進(jìn)行改變的時(shí)候其實(shí)都等同與生成了一個(gè)新的String對象.然后指針指向新的String對象,所以經(jīng)常改變內(nèi)容的字符串最好不使用String,因?yàn)槊看紊蓪ο蠖紩ο到y(tǒng)性能產(chǎn)生影響,特別當(dāng)內(nèi)存中無引用對象多了之后.JVM的垃圾回收(GC)就會開始工作,對系統(tǒng)的性能會產(chǎn)生影響
2.StringBuffer ?線程安全的可變字符序列:對StringBuffer對象本身進(jìn)行操作,而不是生成新的對象.所所以在改變對象引用條件下,一般推薦使用StringBuffer.同時(shí)主要是使用append和insert方法,
3.StringBuilder?線程不安全的可變字符序列.提供一個(gè)與StringBuffer兼容的API,但不同步.設(shè)計(jì)作為StringBuffer的一個(gè)簡易替換,用在字符緩沖區(qū)被單個(gè)線程使用的時(shí)候.效率比StringBuffer更快
區(qū)別:
a.執(zhí)行速度:StringBuilder > StringBuffer > String
b.線程安全:StringBuffer線程安全.StringBuilder線程不安全
c.String適用與少量字符串操作
StringBuilder適用單線程下在字符緩沖區(qū)下進(jìn)行大量操作的情況
StringBuffer使用多線程下在字符緩沖區(qū)進(jìn)行大量操作的情況
**集合**
????Collection 接口存儲一組不唯一琐谤,無序的對象蚪腐。
????List接口存儲一組不唯一惰蜜,有序憔鬼,可重復(fù)的對象喉磁。ArrayList、LinkedList和Vector(淘汰)是主要的實(shí)現(xiàn)類
????Set接口存儲唯一,無序的對象。HashSet和TreeSet是主要的實(shí)現(xiàn)類。
????Map接口存儲一組鍵—值對象砰粹,提供Key—Value的映射。其中key列就是一個(gè)集合造挽,key不能重復(fù)碱璃,但是value可以重復(fù)。 HashMap饭入、TreeMap和Hashtable是Map的主要實(shí)現(xiàn)類厘贼。
**Vector擴(kuò)容機(jī)制**
vector 默認(rèn)的擴(kuò)容機(jī)制是按照容器現(xiàn)有容量的一倍進(jìn)行增長。由于 Vector 容器分配的是一塊連續(xù)的內(nèi)存空間, 每次容器的增長并不是在原有連續(xù)的內(nèi)容空間后進(jìn)行簡單的疊加, 而是重新申請一塊更大的新內(nèi)存, 并把現(xiàn)有容器中的元素逐個(gè)復(fù)制過去, 然后銷毀原有內(nèi)存圣拄。
舉例:vector 初始化時(shí)申請的空間大小為 6 , 存入了 6 個(gè)元素, 當(dāng)向 vector 中插入第 7 個(gè)元素“ 6” 時(shí), vector 會利用自己的擴(kuò)容機(jī)制重新申請空間, 數(shù)據(jù)存放結(jié)構(gòu)如圖 1 所示(_First 指向使用空間的頭部,_Last 指向使用空間大小(size)的尾部,_End 指向使用空間容量(capacity)的尾部)嘴秸。

**ArrayList底層實(shí)現(xiàn)原理**
ArrayList的底層數(shù)據(jù)結(jié)構(gòu)就是一個(gè)數(shù)組,數(shù)組元素的類型為Object類型庇谆,對ArrayList的所有操作底層都是基于數(shù)組的
ArrayList繼承AbstractList抽象父類岳掐,實(shí)現(xiàn)了List接口(規(guī)定了List的操作規(guī)范)、RandomAccess(可隨機(jī)訪問)饭耳、Cloneable(可拷貝)串述、Serializable(可序列化)。
ArrayList是List接口的可變數(shù)組非同步實(shí)現(xiàn)寞肖,并允許包括null在內(nèi)的所有元素纲酗。
底層使用數(shù)組實(shí)現(xiàn)
該集合是可變長度數(shù)組,數(shù)組擴(kuò)容時(shí)新蟆,會將老數(shù)組中的元素重新拷貝一份到新的數(shù)組中觅赊,每次數(shù)組容量增長大約是其容量的1.5倍,這種操作的代價(jià)很高琼稻。
采用了Fail-Fast機(jī)制吮螺,面對并發(fā)的修改時(shí),迭代器很快就會完全失敗帕翻,而不是冒著在將來某個(gè)不確定時(shí)間發(fā)生任意不確定行為的風(fēng)險(xiǎn)
remove方法會讓下標(biāo)到數(shù)組末尾的元素向前移動(dòng)一個(gè)單位鸠补,并把最后一位的值置空,方便GC
(補(bǔ)充)
**LinkedList底層實(shí)現(xiàn)原理**
LinkedList是List接口的雙向鏈表非同步實(shí)現(xiàn)嘀掸,并允許包括null在內(nèi)的所有元素紫岩。
底層的數(shù)據(jù)結(jié)構(gòu)是基于雙向鏈表的,該數(shù)據(jù)結(jié)構(gòu)我們稱為節(jié)點(diǎn)
雙向鏈表節(jié)點(diǎn)對應(yīng)的類Node的實(shí)例睬塌,Node中包含成員變量:prev泉蝌,next歇万,item。其中梨与,prev是該節(jié)點(diǎn)的上一個(gè)節(jié)點(diǎn),next是該節(jié)點(diǎn)的下一個(gè)節(jié)點(diǎn)文狱,item是該節(jié)點(diǎn)所包含的值粥鞋。
它的查找是分兩半查找,先判斷index是在鏈表的哪一半瞄崇,然后再去對應(yīng)區(qū)域查找呻粹,這樣最多只要遍歷鏈表的一半節(jié)點(diǎn)即可找到
**HashMap底層實(shí)現(xiàn)原理(jdk1.8)**
從結(jié)構(gòu)上講,hashmap是位桶(Node數(shù)組)+鏈表+紅黑樹實(shí)現(xiàn)的苏研,鏈表是為了解決hash沖突的等浊,當(dāng)鏈表長度超過閾值(8)時(shí),將鏈表轉(zhuǎn)換為紅黑樹摹蘑,大大減少查找時(shí)間筹燕。
主干是Node數(shù)組,包含一個(gè)鍵值對衅鹿,實(shí)現(xiàn)了Map.entry接口撒踪,它的初始容量為16, 當(dāng)鏈表數(shù)組的容量超過初始容量的0.75時(shí)大渤,再散列將鏈表數(shù)組擴(kuò)大2倍制妄,把原鏈表數(shù)組的搬移到新的數(shù)組中
*如何getValue*
get方法時(shí)獲取key的Hash值,通過計(jì)算hash&(n-1)得到在鏈表數(shù)組中的位置泵三,判斷計(jì)算的key與參數(shù)key是否相等耕捞,不等集遍歷后面的鏈表找到相同的key值返回對應(yīng)的Value值即可。
*如何put<K烫幕,V>*
判斷鍵值對數(shù)組tab[]是否為空或?yàn)閚ull俺抽,否則以默認(rèn)大小resize();
根據(jù)鍵值key計(jì)算hash值得到插入的數(shù)組索引i较曼,如果tab[i]==null凌埂,直接新建節(jié)點(diǎn)添加
判斷當(dāng)前數(shù)組中處理hash沖突的方式為鏈表還是紅黑樹(check第一個(gè)節(jié)點(diǎn)類型即可),分別處理
*HasMap的擴(kuò)容機(jī)制resize();*
構(gòu)造hash表時(shí),如果不指明初始大小诗芜,默認(rèn)大小為16(即Node數(shù)組大小16)瞳抓,如果Node[]數(shù)組中的元素達(dá)到(填充比*Node.length)重新調(diào)整HashMap大小 變?yōu)樵瓉?倍大小,擴(kuò)容很耗時(shí)
**Hashtable實(shí)現(xiàn)原理**
不允許出現(xiàn)null值null鍵,線程同步伏恐,et/put所有相關(guān)操作都是synchronized的孩哑,這相當(dāng)于給整個(gè)哈希表加了一把大鎖,多線程訪問時(shí)候翠桦,只要有一個(gè)線程訪問或操作該對象横蜒,那其他線程只能阻塞胳蛮,相當(dāng)于將所有的操作串行化。??????線程安全丛晌。
**ConcurrentHashMap實(shí)現(xiàn)原理**
ConcurrentHashMap是Java并發(fā)包中提供的一個(gè)線程安全且高效的HashMap實(shí)現(xiàn)仅炊。
ConcurrentHashMap采用了非常精妙的"分段鎖"策略,ConcurrentHashMap的主干是個(gè)Segment數(shù)組澎蛛。
?????final Segment<K,V>[] segments;
ConcurrentHashMap完全允許多個(gè)讀操作并發(fā)進(jìn)行抚垄,讀操作并不需要加鎖。如果使用傳統(tǒng)的技術(shù)谋逻,如HashMap中的實(shí)現(xiàn)呆馁,如果允許可以在hash鏈的中間添加或刪除元素,讀操作不加鎖將得到不一致的數(shù)據(jù)毁兆。ConcurrentHashMap實(shí)現(xiàn)技術(shù)是保證HashEntry幾乎是不可變的浙滤。HashEntry代表每個(gè)hash鏈中的一個(gè)節(jié)點(diǎn),其結(jié)構(gòu)如下所示
?????tatic final class HashEntry<K,V> {??
?????final K key;??
?????final int hash;??
?????volatile V value;??
?????final HashEntry<K,V> next;??
????}?
可以看到除了value不是final的气堕,其它值都是final的纺腊,這意味著不能從hash鏈的中間或尾部添加或刪除節(jié)點(diǎn),因?yàn)檫@需要修改next 引用值茎芭,所有的節(jié)點(diǎn)的修改只能從頭部開始摹菠。對于put操作,可以一律添加到Hash鏈的頭部骗爆。但是對于remove操作次氨,可能需要從中間刪除一個(gè)節(jié)點(diǎn),這就需要將要?jiǎng)h除節(jié)點(diǎn)的前面所有節(jié)點(diǎn)整個(gè)復(fù)制一遍摘投,最后一個(gè)節(jié)點(diǎn)指向要?jiǎng)h除結(jié)點(diǎn)的下一個(gè)結(jié)點(diǎn)煮寡。這在講解刪除操作時(shí)還會詳述。為了確保讀操作能夠看到最新的值犀呼,將value設(shè)置成volatile幸撕,這避免了加鎖。
**IO操作**
*?1.刪除文件及其下面的子目錄外臂,子文件坐儿,不包括最外層的父文件夾
????????public static void delAllFileExceptOuter(File dir){
????????????if(dir.exists() && dir.isDirectory()){
????????????????//獲取子文件列表
????????????????File[] arr = dir.listFiles();
????????????????//遍歷
????????????????for(File f:arr){
????????????????????//遞歸調(diào)用自身方法,繼續(xù)內(nèi)層的刪除
????????????????????delAllFileExceptOuter(f);
????????????????????f.delete();
????????????????}
????????????}
????????}
*?2.刪除文件及其下面的子目錄宋光,子文件貌矿,包括最外層的父文件夾
*?
???????????public static void delAllFileIncludeOuter(File dir){
????????????if(dir.exists() && dir.isDirectory()){
????????????????//獲取子文件列表
????????????????File[] arr = dir.listFiles();
????????????????//遍歷
????????????????for(File f:arr){
????????????????????//遞歸調(diào)用自身方法,繼續(xù)內(nèi)層的刪除
????????????????????delAllFileIncludeOuter(f);
????????????????????f.delete();
????????????????}
????????????????dir.delete();
????????????}
????????}
*?3.拷貝所有的子文件夾罪佳,不拷貝子文件
????????public static void copyAllDir(File src,File dest){
????????????if(src.isDirectory()){
????????????????if(!dest.exists()){
????????????????????dest.mkdirs();
????????????????}
????????????????//獲取src的子文件列表?
????????????????File[] arr = src.listFiles();
????????????????//遍歷
????????????????for(File f:arr){
????????????????????//構(gòu)建新的子文件對象??subSrc=new File("E:/others/", c);
????????????????????// subDest = new File("D:/others", c);
????????????????????File subSrc = new File(src,f.getName());
????????????????????File subDest = new File(dest,f.getName());
????????????????????System.out.println("###subSrc="+subSrc+",subDest="+subDest);
????????????????????//遞歸調(diào)用自身方法
????????????????????copyAllDir(subSrc, subDest);
????????????????}
????????????}
????????}
*?4.拷貝單個(gè)子文件
????????public static void copySingleFile(File src,File dest){
????????????if(src.isDirectory()){
????????????????System.out.println("只能拷貝文件逛漫!");
????????????????return;
????????????}
????????//
????????if(dest.isDirectory()){
????????????System.out.println("要拷貝的文件和父目錄中的文件夾重名,不能拷貝赘艳!");
????????????return;
????????}
????????//聲明輸入流對象酌毡,輸出流對象
????????FileInputStream fis=??null;
????????FileOutputStream fos = null;
????????try {
????????????//建立輸入流和源文件之間的聯(lián)系?
????????????fis = new FileInputStream(src);
????????????//建立輸出流和目標(biāo)文件之間的聯(lián)系
????????????fos = new FileOutputStream(dest);
????????????//聲明byte[]數(shù)組克握,用來存儲讀取的內(nèi)容??,數(shù)組的容量 n:整數(shù)值,任意定枷踏,項(xiàng)目中一般用1024
????????????byte[] buffer = new byte[3];?
????????????//聲明int變量菩暗,用來存儲read()方法的返回值,實(shí)際上存儲就是實(shí)際讀取到的字節(jié)個(gè)數(shù)?
????????????int len=fis.read(buffer);
????????????while(len!=-1){
????????????????//讀取的內(nèi)容報(bào)錯(cuò)在byte數(shù)組中??旭蠕,需要轉(zhuǎn)換成String停团,才能打印輸出
//????????????String data = new String(buffer,0,len);
//????????????????System.out.println("len="+len+"data="+data);
????????????????//讀多少,寫多少出去
????????????????fos.write(buffer, 0, len);
????????????????//刷新
????????????????fos.flush();
????????????????//接著讀
????????????????len=fis.read(buffer);
????????????}
????????} catch (FileNotFoundException e) {
????????????e.printStackTrace();
????????} catch (IOException e) {
????????????e.printStackTrace();
????????} finally{
????????????//釋放資源 下梢、關(guān)閉流?
????????????//先打開的后關(guān)閉客蹋,先創(chuàng)建的后關(guān)閉
????????????if(null!=fos){
????????????????try {
????????????????????fos.close();
????????????????} catch (IOException e) {
????????????????????e.printStackTrace();
????????????????}
????????????}
????????????if(null!=fis){
????????????????try {
????????????????????fis.close();
????????????????} catch (IOException e) {
????????????????????e.printStackTrace();
????????????????}
????????????}
????????}
????}
*?5.拷貝所有的子文件塞蹭,子目錄
????????public static void copyAllFiles(File src,File dest){
????????if(src.getParent()==null && dest.getParent()==null){
????????????//證明相對路徑下孽江,同級之間的拷貝,允許通過
????????}else if((src.getParent()==null && dest.getParent()!=null) && (dest.getAbsolutePath().contains(src.getAbsolutePath()))){
????????????System.out.println("***父目錄不能拷貝到子目錄中番电!");
????????????return;
????????}else if(dest.getAbsolutePath().contains(src.getAbsolutePath()) &&??!src.getParent().equals(dest.getParent())){
????????????//src的parent()和dest的parent()不同
????????????System.out.println("父目錄不能拷貝到子目錄中岗屏!");
????????????return;
????????}
????????if(src.isDirectory()){//如果是目錄,拷貝對應(yīng)的目錄
????????????if(!dest.exists()){
????????????????dest.mkdirs();
????????????}
????????????//獲取src的子文件列表?
????????????File[] arr = src.listFiles();
????????????//遍歷
????????????for(File f:arr){
????????????????//構(gòu)建新的子文件對象?
????????????????File subDest = new File(dest,f.getName());
????????????????//遞歸調(diào)用自身方法
????????????????copyAllFiles(f, subDest);
????????????}
????????}else if(src.isFile()){ //如果是文件漱办,拷貝文件
????????????copySingleFile(src, dest);
????????}
????}
**IO流**
????????* 面試題: 字符串和字節(jié)數(shù)組这刷,字符串和字符數(shù)組之間的相互轉(zhuǎn)換??
?????????*??String??s---->byte[]??buffer?
?????????*??String s="asd";
?????????*??byte[] buffer=new byte[1024];
?????????*???buffer = s.getBytes();??
?????????*??
?????????*???byte[] buffer ---->String s??
?????????*s = new String(buffer);?
?????????*s = new String(buffer,int from, int len);??
?????????*from:buffer數(shù)組的起始索引?
?????????*len:要轉(zhuǎn)換的字節(jié)數(shù) (有幾個(gè)字節(jié))
?????????*
?????????*??
?????????*??String s ---->char[] buffer?
?????????*buffer = s.toCharArray();
?????????*
?????????*???char[] buffer----->String s??
?????????*??s = new String(buffer);??
?????????*??
?????????*??s= new String(buffer,int from,int len);?
?????????*??from:buffer字符數(shù)組的起始索引
?????????*??len:要轉(zhuǎn)換的字符個(gè)數(shù) (與幾個(gè)字符)
**IO流文件流FileInputStream/FileOutstream**
???????聲明輸入輸入流輸出流對象
??????FileInputStream fis=null娩井;
??????FileOutputStream fos=null暇屋;
??????建立輸入流,輸出流與源文件的聯(lián)系
??????fis=new FileInputStream(" ");
??????fos=new FileOutputStream(" ");
???????聲明byte[]字節(jié)數(shù)組洞辣,用于存儲讀取的內(nèi)容
???????byte[] buffer=new byte[1024];
???????int len=0咐刨;
???????while((len=fis.read(buffer))!=-1){
???????String data=new String(buffer,0,len);
???????syso(data);
???????len=fis.read(buffer,0,buffer.length);
????????fos.write(buffer,0,len);
????????fos.flush();
???????}
拷貝
???????????//聲明輸入流對象,輸出流對象
????????FileReader fr = null;
????????FileWriter fw = null;
????????try {
????????????//建立輸入流和源文件之間的聯(lián)系
????????????fr = new FileReader("E:/others/ceshi.txt");
????????????//建立輸出流和目標(biāo)文件之間的聯(lián)系
????????????fw = new FileWriter("D:/test/ceshi.txt");
????????????char[] buffer = new char[4];
????????????//len實(shí)際讀取的字符數(shù)
????????????int len=0;
????????????while((len=fr.read(buffer))!=-1){
?????????//????fw.write(buffer, 0, len);
????????????????//拷貝的時(shí)候扬霜,一定要帶上偏移量
????????????????String s = new String(buffer,0,len);
????????????????fw.write(s);
????????????????fw.flush();
????????????}
**緩沖流BufferInputStream/BufferOuputStream/BUfferReader/bufferWriter**
?????//聲明輸入流對象定鸟,輸出流對象
????????BufferedReader br = null;
????????BufferedWriter bw = null;
????????try {
????????????//建立輸入流和源文件之間的聯(lián)系
????????????br = new BufferedReader(new FileReader("E:/others/ceshi.txt"));
????????????//建立輸出流和目標(biāo)文件之間的聯(lián)系
????????????bw = new BufferedWriter(new FileWriter("D:/test/ceshi.txt"));
????????????//聲明String變量,用于存儲讀取的內(nèi)容?
????????????String data = null;
????????????while((data=br.readLine())!=null){
????????????????bw.write(data);
????????????????//刷新
????????????????bw.flush();
????????????????//寫一行著瓶,換一行
????????????????bw.newLine();
????????????}
????????}
復(fù)制圖片
????//聲明輸入流联予,輸出流對象
????????BufferedInputStream bis = null;
????????BufferedOutputStream bos = null;
????????try {
????????????//建立輸入流和源文件之間的聯(lián)系?
????????????bis = new BufferedInputStream(new FileInputStream(new File("E:/others/cat.png")));
????????????//建立輸出流和目標(biāo)文之間的聯(lián)系
????????????bos = new BufferedOutputStream(new FileOutputStream(new File("D:/test/cat.png")));
????????????//聲明byte[]數(shù)組
????????????byte[] buffer = new byte[1024];
????????????//聲明int變量
????????????int len=0;
????????????while((len=bis.read(buffer))!=-1){
????????????????String s = new String(buffer,0,len);
????????????????System.out.println("len="+len+",s="+s);
????????????????bos.write(buffer, 0, len);
????????????????bos.flush();
????????????}
**亂碼原因**
?*?1.兩邊的編碼方式不一致
?*?2.保存的不完整,數(shù)據(jù)有丟失
?*?InputStreamReader,提供構(gòu)造材原,可以傳入編碼方式
?*?InputStreamReader(InputStream in, String charsetName)
??????????創(chuàng)建使用指定字符集的 InputStreamReader沸久。
?*?ANSI ----->程序中g(shù)bk
?*?
?*?UTF-8----->程序中UTF-8
?*?
?*?亂碼因?yàn)椋篶eshi.txt ANSI??,本地程序中UTF-8,不一致導(dǎo)致的。
?*?
?*????解決辦法1:ceshi.txt 右擊 另存為 UTF-8
?*????
?*????解決辦法2:用InputStreamReader流
????//聲明輸入流對象
????????InputStreamReader isr = null;
????????try {
????????????//建立輸入流和源文件之間的聯(lián)系
????????????isr = new InputStreamReader(new FileInputStream("E:/others/ceshi.txt"),"gbk");
????????????//聲明char[]數(shù)組余蟹,用于存儲讀取的內(nèi)容
????????????char[] buffer = new char[4];
????????????//聲明int變量麦向,用來存儲實(shí)際讀取的字符數(shù)
????????????int len = 0;
????????????while(-1 !=(len=isr.read(buffer))){
????????????????String s = new String(buffer,0,len);
????????????????System.out.println(s);
????????????}
** FileInputStream與FileReader區(qū)別**:
FileInputStream是字節(jié)流,F(xiàn)ileReader是字符流客叉,用字節(jié)流讀取中文的時(shí)候诵竭,可能會出現(xiàn)亂碼话告,而用字符流則不會出現(xiàn)亂碼,而且用字符流讀取的速度比字節(jié)流要快卵慰;
**FileInputStream與BufferedInputStream區(qū)別**
FileInputStream是字節(jié)流沙郭,BufferedInputStream是字節(jié)緩沖流,使用BufferedInputStream讀資源比FileInputStream讀取資源的效率高(BufferedInputStream的read方法會讀取盡可能多的字節(jié)裳朋,執(zhí)行read時(shí)先從緩沖區(qū)讀取病线,當(dāng)緩沖區(qū)數(shù)據(jù)讀完時(shí)再把緩沖區(qū)填滿。)鲤嫡,因此送挑,當(dāng)每次讀取的數(shù)據(jù)量很小時(shí),F(xiàn)ileInputStream每次都是從硬盤讀入暖眼,而BufferedInputStream大部分是從緩沖區(qū)讀入惕耕。讀取內(nèi)存速度比讀取硬盤速度快得多,因此BufferedInputStream效率高诫肠,且FileInputStream對象的read方法會出現(xiàn)阻塞司澎;BufferedInputStream的默認(rèn)緩沖區(qū)大小是8192字節(jié)。當(dāng)每次讀取數(shù)據(jù)量接近或遠(yuǎn)超這個(gè)值時(shí)栋豫,兩者效率就沒有明顯差別了挤安。
**ObjectOutputStream/ObjectInputStream**
java.io.ObjectOutputStream代表對象輸出流,它的writeObject(Object obj)方法可對參數(shù)指定的obj對象進(jìn)行序列化丧鸯,把得到的字節(jié)序列寫到一個(gè)目標(biāo)輸出流中蛤铜。
java.io.ObjectInputStream代表對象輸入流,它的readObject()方法從一個(gè)源輸入流中讀取字節(jié)序列丛肢,再把它們反序列化為一個(gè)對象围肥,并將其返回。
**序列化**
只有實(shí)現(xiàn)了Serializable(si瑞爾奈zi包)和Externalizable接口的類的對象才能被序列化摔踱。
transient修飾屬性避免序列化
序列化是指將對象轉(zhuǎn)換成字節(jié)序列的過程稱為對象的序列化虐先,反序列化則是將字節(jié)序列恢復(fù)為對象的過程
對象的序列化通常有兩種用途
1、把對象的字節(jié)序列永久的保存到硬盤上派敷,通常存放到一個(gè)文件中
2蛹批、在網(wǎng)絡(luò)上傳送對象的序列化
*序列化步驟*
1) 創(chuàng)建一個(gè)對象輸出流,它可以包裝一個(gè)其他類型的目標(biāo)輸出流篮愉,如文件輸出流腐芍;
2) 通過對象輸出流的writeObject()方法寫對象。
????//聲明輸出流對象
????????ObjectOutputStream oos = null;
????????try {
????????????//建立輸出流和目標(biāo)文件之間的聯(lián)系??oos需要包裝其他的底層流
????????????oos = new ObjectOutputStream(new FileOutputStream(filePath));
????????????//調(diào)用write()方法寫出?
????????????List<Student> list=new ArrayList<Student>();
?????????????list.add(new Student("張偉",18));
?????????????list.add(new Student("張偉1",28));
?????????????list.add(new Student("張偉2",38));
????????????//刷新
?????????????oos.writeObject(list);?
????????????oos.flush();
????????}
*反序列化步驟*
1) 創(chuàng)建一個(gè)對象輸入流试躏,它可以包裝一個(gè)其他類型的源輸入流猪勇,如文件輸入流;
2) 通過對象輸入流的readObject()方法讀取對象颠蕴。
對象序列化和反序列范例:
????// 聲明輸入流對象
????????ObjectInputStream ois = null;
????????try {
????????????// 建立輸入流和源文件之間的聯(lián)系 泣刹,ois需要包裝其他的底層流
????????????ois = new ObjectInputStream(new FileInputStream(filepath));
????????????// 通過read()方法讀取
????????????List<Student> list = (List) ois.readObject();
????????????for (Student temp : list) {
????????????????System.out.println("取出的學(xué)生名:" + temp.getName() + ",年齡:" + temp.getAge() + ",性別:" + temp.getSex());
????????????}
????????}
*s?e?r?i?a?l?V?e?r?s?i?o?n?U?I?D?:?*
?字?面?意?思?上?是?序?列?化?的?版?本?號?助析,凡是實(shí)現(xiàn)Serializable接口的類都有一個(gè)表示序列化版本標(biāo)識符的靜態(tài)變量
????private static final long serialVersionUID
*顯式地定義serialVersionUID有兩種用途:*
1、 在某些場合椅您,希望類的不同版本對序列化兼容外冀,因此需要確保類的不同版本具有相同的serialVersionUID;
2掀泳、 在某些場合雪隧,不希望類的不同版本對序列化兼容,因此需要確保類的不同版本具有不同的serialVersionUID员舵。
**RandomAccessFile類**
RandomAccessFile類的主要功能是完成隨機(jī)讀取功能脑沿,可以讀取指定位置的內(nèi)容。
之前的File類只是針對文件本身進(jìn)行操作的马僻,而如果要想對文件內(nèi)容進(jìn)行操作庄拇,則可以使用RandomAccessFile類,此類屬于隨機(jī)讀取類巫玻,可以隨機(jī)讀取一個(gè)文件中指定位置的數(shù)據(jù)丛忆。
???????*?RandomAccessFile:既可以當(dāng)輸出流負(fù)責(zé)寫出祠汇,也可以當(dāng)輸入流負(fù)責(zé)讀取
?????*?體現(xiàn)它隨機(jī)訪問的特點(diǎn)??seek() skipBytes()
?????*?先將3個(gè)用戶信息仍秤,寫入到E:/others/user.txt中
?????*??然后讀取出來
?????*??
?????*??寫入的時(shí)候,構(gòu)造上 可很,mode模式選用:rw,文件不存在诗力,則創(chuàng)建
?????*??
?????*??讀取的時(shí)候??mode:r 只讀
?????*??
?????*??1.2個(gè)方法,一個(gè)方法負(fù)責(zé)寫入
?????*??一個(gè)方法負(fù)責(zé)讀取
?????*?@author Administrator
?????*
?????*/
????public class TestRandomAccess01 {
????????public static void main(String[] args) {
????????????String path = "E:/others/user.txt";
????????????save(path);
????//????????readFirst(path);
????????}
????/**
?????* 順序 我抠,1苇本,2,3?
?????* RandomAccessFile 當(dāng) 輸入流用
?????* @param filePath
?????*/
????public static void readFirst(String filePath){
????????//聲明輸入流對象
????????RandomAccessFile ra= null;
????????try {
????????????//建立輸入流和源文件之間的聯(lián)系
????????????ra = new RandomAccessFile(new File(filePath), "r");
????????????byte[] buffer = new byte[8];
????????????for(int i=0;i<buffer.length;i++){
????????????????buffer[i] = ra.readByte();
????????????}
????????????//讀取整數(shù)值
????????????int age = ra.readInt();
????????????System.out.println("第一個(gè)人信息:"+new String(buffer)+"---"+age);
????????????//讀取第2個(gè)人??
????????????for(int i=0;i<buffer.length;i++){
????????????????buffer[i] = ra.readByte();
????????????}
????????????//讀取整數(shù)值
????????????age = ra.readInt();
????????????System.out.println("第二個(gè)人信息:"+new String(buffer)+"---"+age);
????????????//讀取第3個(gè)人
????????????for(int i=0;i<buffer.length;i++){
????????????????buffer[i] = ra.readByte();
????????????}
????????????//讀取整數(shù)值
????????????age = ra.readInt();
????????????System.out.println("第三個(gè)人信息:"+new String(buffer)+"---"+age);
????????} catch (FileNotFoundException e) {
????????????e.printStackTrace();
????????} catch (IOException e) {
????????????e.printStackTrace();
????????} finally{
????????????if(ra!=null){
????????????????try {
????????????????????ra.close();
????????????????} catch (IOException e) {
????????????????????e.printStackTrace();
????????????????}
????????????}
????????}
????}
????/**
?????* 存儲
?????* RandomAccessFile 當(dāng)輸出流用
?????* @param filePath
?????*/
????public static void save(String filePath){
????????RandomAccessFile ra = null;
????????try {
????????????//建立輸出流和目標(biāo)文件之間的聯(lián)系菜拓,同時(shí)指定模式
????????????ra = new RandomAccessFile(new File(filePath), "rw");
????????????//調(diào)用write()方法寫出?
????????????ra.writeBytes("zhangsan");
????????????ra.writeInt(30);
????????????ra.writeBytes("lisi????");
????????????ra.writeInt(31);
????????????ra.writeBytes("wangwu??");
????????????ra.writeInt(32);
????????} catch (FileNotFoundException e) {
????????????e.printStackTrace();
????????} catch (IOException e) {
????????????e.printStackTrace();
????????} finally{
????????????if(ra!=null){
????????????????try {
????????????????????ra.close();
????????????????} catch (IOException e) {
????????????????????e.printStackTrace();
????????????????}
????????????}
????????}
????}
**線程**
進(jìn)程:運(yùn)行的程序瓣窄,動(dòng)態(tài)。是資源分配的基本單位纳鼎。 一個(gè)進(jìn)程可擁有多個(gè)并行的(concurrent)線程俺夕。
線程:進(jìn)程中一段代碼的執(zhí)行過程。是執(zhí)行和調(diào)度的基本單位贱鄙。是進(jìn)程中執(zhí)行運(yùn)算單位的最小單位劝贸,是進(jìn)程內(nèi)部的一個(gè)執(zhí)行單元。
**實(shí)現(xiàn)多線程兩種方式**
*繼承Thread類*
1.定義子類繼承Thread類
2.子類重寫Thread類run方法
3.創(chuàng)建Thread子類對象逗宁,即創(chuàng)建線程對象
4.調(diào)用線程對象的start()方法映九,啟動(dòng)線程
????public class Rabbit extends Thread {
????private int step = 1;
????// (1)線程類中定義一個(gè)標(biāo)志位
????private boolean isRunning = true;
????public Rabbit() {
????}
????public Rabbit(String name) {
????????super(name); // 調(diào)用父類Thread的帶參構(gòu)造
????}
????@Override
????public void run() {
????????// (2)線程體中使用該標(biāo)志位
????????while (isRunning) {
????????????System.out.println(Thread.currentThread().getName() + "跑了"
????????????????????+ (step++) + "步");
????????}
????}
????// 提供一個(gè)更改此標(biāo)志位的方法
????public void stopThread() {
????????isRunning=false;
????}
????}
????public static void main(String[] args) {
????????//新生狀態(tài)
????????Rabbit ra = new Rabbit();
????????ra.setName("兔子");
????????//就緒狀態(tài)
????????ra.start();
????????System.out.println("A判斷兔子線程的是否處于活動(dòng)狀態(tài):"+ra.isAlive());
????????//延遲2ms?
????????try {
????????????Thread.sleep(2);
????????} catch (InterruptedException e) {
????????????e.printStackTrace();
????????}
????????//終止線程?
????????//ra.stop();??//可以用,但是不建議用瞎颗,已過時(shí)的方法
????????//ra.destroy();//不可以用 件甥,不起作用
????????//(4)外部測試時(shí)候捌议,調(diào)用更改此標(biāo)志位的方法
????????ra.stopThread();
????????try {
????????????Thread.sleep(2);
????????} catch (InterruptedException e) {
????????????e.printStackTrace();
????????}
????????System.out.println("B判斷兔子線程的是否處于活動(dòng)狀態(tài):"+ra.isAlive());
????}
*實(shí)現(xiàn)Runnable接口*
1.定義子類實(shí)現(xiàn)Runnable接口
2.重寫Runnable接口run()方法
3.通過Thread含構(gòu)造器創(chuàng)建線程對象
4.將Runnable接口的子類對象作為實(shí)際參數(shù)傳遞給Thread類的構(gòu)造方法中
5.調(diào)用Thread類的start()方法
優(yōu)點(diǎn):1.避免單繼承
2.方便共享資源,同一份資源引有,多個(gè)代理訪問
**java中終止線程**
*1.使用標(biāo)志位*
*2.中斷策略*
使用標(biāo)志位這種方法有個(gè)很大的局限性禁灼,那就是通過循環(huán)來使每次的操作都需要檢查一下標(biāo)志位。
java還提供了中斷協(xié)作機(jī)制轿曙,能夠使一個(gè)線程要求另外一個(gè)線程停止當(dāng)前工作弄捕。其大致的思想為:調(diào)用線程Thread的interrupt([??nt??r?pt])方法,在線程內(nèi)部通過捕獲InterruptedException異常來決定線程是否繼續(xù)還是退出导帝。如下:
?????class InterruptRunnable implements Runnable{
????????private BlockingQueue queue = new ArrayBlockingQueue(10);
????????@Override
????????public void run() {
????????????int i= 0;
????????????for (;;) {
????????????????try {
????????????????????//線程的操作
????????????????????i++;
????????????????????queue.put(i);
????????????????} catch (InterruptedException e) {
????????????????????//捕獲到了異常 該怎么做
????????????????????System.out.println(queue);
????????????????????e.printStackTrace();
????????????????????return;
????????????????}
????????????}
??????????}
??????上述代碼通過BlockingQueue的put方法來拋出InterruptedException異常守谓。
??????當(dāng)內(nèi)部捕獲到該異常時(shí),從而決定是否繼續(xù)還是直接退出了
??????public void testInterruptRunnable() throws InterruptedException {
????????InterruptRunnable runnable = new InterruptRunnable();
????????Thread thread = new Thread(runnable);
????????thread.start();
????????System.err.println(thread.isAlive());
????????Thread.sleep(1000);
????????thread.interrupt();
????????Thread.sleep(1000);
????????System.err.println(thread.isAlive());
????????Thread.sleep(1000);
????????System.err.println(thread.isAlive());
????}
????該測試方法大致同使用標(biāo)志位的測試方法您单,同樣啟動(dòng)該線程后斋荞,1秒后調(diào)用線程的interrupt方法,從而觸發(fā)Runnable的內(nèi)部queue.put(i)操作拋出InterruptedException異常虐秦。
**進(jìn)程的幾種通信方式**
進(jìn)程間通信(IPC平酿,InterProcess Communication)是指在不同進(jìn)程之間傳播或交換信息。
IPC的方式通常有管道(包括無名管道和命名管道)悦陋、消息隊(duì)列蜈彼、信號量、共享存儲俺驶、Socket幸逆、Streams等。其中 Socket和Streams支持不同主機(jī)上的兩個(gè)進(jìn)程IPC暮现。
**多線程之線程間的通信方式**
*?wait/notify 等待
*?Volatile 內(nèi)存共享
**Yied放棄時(shí)間片(暫停線程)**
?*?yield: 暫停當(dāng)前正在執(zhí)行的線程對象还绘,并執(zhí)行其他線程
?*??yield:加在哪個(gè)線程體里,就暫停誰 栖袋,暫停不一定生效
????????class YieldDemo implements Runnable{
????????@Override
????????public void run() {
????????????for(int i=0;i<=1000;i++){
????????????????/*if(i%20==0){
????????????????????Thread.yield();??//暫停的線程A
????????????????}*/
????????????????System.out.println(Thread.currentThread().getName()+"----"+i);
????????????}
????????}
????????}
??????????public class TestYield {
??????????public static void main(String[] args) {
????????????//創(chuàng)建真實(shí)角色類的實(shí)例
????????????YieldDemo yd = new YieldDemo();
????????????//創(chuàng)建代理角色拍顷,代理持有對真實(shí)角色的引用
????????????Thread th = new Thread(yd,"線程A");
????????????//通過代理開啟
????????????th.start();
????????????//main()主線程中??
????????????for(int i=0;i<=1000;i++){
????????????????if(i%20==0){
????????????????????Thread.yield();??//暫停的main(),線程A獲得執(zhí)行的機(jī)會
????????????????}
????????????????System.out.println(Thread.currentThread().getName()+"----"+i);
????????????}
????????}
????????}
**Join合并線程**
?*?join:等待該線程終止。
?*?阻塞線程塘幅,合并線程
?*?join()阻塞自身昔案,讓其他線程獲得執(zhí)行的機(jī)會,等其他線程執(zhí)行完畢晌块,自身才接著執(zhí)行 爱沟。
?*?加在哪個(gè)線程體里,就阻塞誰
???????????class JoinDemo implements Runnable{
????????????@Override
????????????public void run() {
????????????????for(int i=0;i<=1000;i++){
????????????????????System.out.println(Thread.currentThread().getName()+"----"+i);
????????????????}
????????????}
?????????}
?????????public class TestJoin {
????????????public static void main(String[] args) {
????????????????//創(chuàng)建真實(shí)角色
????????????????JoinDemo jd = new JoinDemo();
????????????????//創(chuàng)建代理匆背,代理持有對真實(shí)角色的引用
????????????????Thread th = new Thread(jd,"線程a");
????????????????//通過代理啟動(dòng)
????????????????th.start();
????????????for(int i=0;i<=1000;i++){
????????????????if(i==50){
????????????????????try {
????????????????????????th.join(); //阻塞main線程
????????????????????} catch (InterruptedException e) {
????????????????????????e.printStackTrace();
????????????????????}?
????????????????}
????????????????System.out.println(Thread.currentThread().getName()+"----"+i);
????????????}
????????}
????????}
**Synchronized線程的同步與鎖**
*?Synchronized允許加在方法前呼伸,表示方法是線程安全的。
*?多個(gè)代理訪問同一份資源,出現(xiàn)資源搶奪的問題括享,同步 :并發(fā)搂根,多個(gè)線程訪問同一份資源,確保資源安?????????全----線程安全
*?方式一:同步代碼塊
synchronized(引用類型铃辖、this/類.class){??..... }
注意:使用實(shí)現(xiàn)Runnable接口方式創(chuàng)建多線程剩愧,同步代碼塊中的鎖可以用this,如何使繼承Thread類娇斩,慎this
*?方式二:同步方法
訪問修飾符??synchornized 返回值類型 方法名 (){...}
**單例模式**
單例模式的意思就是只有一個(gè)實(shí)例仁卷。單例模式確保某一個(gè)類只有一個(gè)實(shí)例,而且自行實(shí)例化并向整個(gè)系統(tǒng)提供這個(gè)實(shí)例犬第。這個(gè)類稱為單例類锦积。
關(guān)鍵點(diǎn):
1)一個(gè)類只有一個(gè)實(shí)例???????這是最基本的
2)它必須自行創(chuàng)建這個(gè)實(shí)例
3)它必須自行向整個(gè)系統(tǒng)提供這個(gè)實(shí)例
兩種實(shí)現(xiàn)方式:
*懶漢模式*
(類加載時(shí)不初始化)
?????public class LazySingleton {
????//懶漢式單例模式
????//比較懶,在類加載時(shí)歉嗓,不創(chuàng)建實(shí)例丰介,因此類加載速度快,但運(yùn)行時(shí)獲取對象的速度慢
????private static LazySingleton intance = null;//靜態(tài)私用成員鉴分,沒有初始化
????private LazySingleton()
????{
????????//私有構(gòu)造函數(shù)
????}
????public static synchronized LazySingleton getInstance()????//靜態(tài)哮幢,同步,公開訪問點(diǎn)
????{
????????if(intance == null)
????????{
????????????intance = new LazySingleton();
????????}
????????return intance;
????}
????}
*餓漢模式*
(在類加載時(shí)就完成了初始化志珍,所以類加載較慢橙垢,但獲取對象的速度快)
?????public class EagerSingleton {
????//餓漢單例模式
????//在類加載時(shí)就完成了初始化,所以類加載較慢碴裙,但獲取對象的速度快
????private static EagerSingleton instance = new EagerSingleton();//靜態(tài)私有成員钢悲,已初始化
????private EagerSingleton()?
????{
????????//私有構(gòu)造函數(shù)
????}
????public static EagerSingleton getInstance()????//靜態(tài)点额,不用同步(類加載時(shí)已初始化舔株,不會有多線程的問題)
????{
????????return instance;
????}
????}
**wait()和notify()**
?*?wait()方法:調(diào)用wait()方法,會掛起當(dāng)前線程还棱,并釋放共享資源的鎖.
*?notify()方法:調(diào)用了任意對象的notify()方法會在因調(diào)用該對象的wait()方法而阻塞的線程中隨機(jī)選擇一個(gè)解除阻塞载慈,但要等到獲得鎖后才可真正執(zhí)行。
*?notifyAll()方法:調(diào)用了notifyAll()方法會將因調(diào)用該對象的wait()方法而阻塞的所有線程一次性全部解除阻塞珍手。
*?wait(),notify(),和notifyall()這3個(gè)方法都是Object類中的final方法办铡,被所有的類繼承且不允許重寫。這3個(gè)方法只能在同步方法或同步代碼塊中使用琳要,否則會拋出異常寡具。
**wait()方法和sleep()方法??區(qū)別**
*?wait() :線程進(jìn)入等待狀態(tài),不占用任何資源稚补,不增加時(shí)間限制童叠,因?yàn)閣ait方法會釋放鎖,所以調(diào)用該方法時(shí)课幕,要確保調(diào)用wait()方法的時(shí)候擁有鎖厦坛,即五垮,wait()方法的調(diào)用必須放在synchronized方法或synchronized塊中。
*?sleep():線程睡眠杜秸,線程被調(diào)用時(shí)放仗,占著cpu不工作,消耗內(nèi)存資源撬碟,增加時(shí)間限制
诞挨,必須捕獲異常
**同步和異步的區(qū)別**
同步是指兩個(gè)線程的運(yùn)行是相關(guān)的,其中一個(gè)線程要阻塞等待另外一個(gè)線程的運(yùn)行呢蛤。異步的意思是兩個(gè)線程毫無相關(guān)亭姥,自己運(yùn)行自己的。
以通訊為例
??????????同步:發(fā)送一個(gè)請求,等待返回,然后再發(fā)送下一個(gè)請求?
異步:發(fā)送一個(gè)請求,不等待返回,隨時(shí)可以再發(fā)送下一個(gè)請求
??????????并發(fā):同時(shí)發(fā)送多個(gè)請求
**socket編程**
套接字使用Tcp提供了兩臺計(jì)算機(jī)之間的通信機(jī)制
區(qū)分不同應(yīng)用程序進(jìn)程之間的網(wǎng)絡(luò)通信和連接
ServerSocket用于服務(wù)器端顾稀,通過accept()監(jiān)聽請求达罗,然后返回Socket。
Socket用于客戶端
**TCP和UDP的區(qū)別**
Tcp提供面向連接的静秆,可靠的字節(jié)流傳輸粮揉,并且提供了擁塞控制和流量控制機(jī)制
UDP提供面向無連接的,不可靠的數(shù)據(jù)報(bào)的傳輸抚笔,不提供擁塞控制和流量控制機(jī)制
**Socket通信實(shí)現(xiàn)步驟:**
簡化出Socket通信的實(shí)現(xiàn)步驟:
1.創(chuàng)建ServerSocket和Socket扶认,建立連接
2.打開鏈接到Socket的輸入/輸出流
3.按照協(xié)議對Socket進(jìn)行讀/寫操作
4.關(guān)閉輸入輸出流、關(guān)閉Socket
*使用多線程實(shí)現(xiàn)多客戶端的通信:*
多線程基本步驟:
1.服務(wù)器端創(chuàng)建ServerSocket殊橙,循環(huán)調(diào)用accept()等待客戶端連接辐宾。
2.客戶端創(chuàng)建一個(gè)socket并請求和服務(wù)器端連接。
3.服務(wù)器端接收客戶端請求膨蛮,創(chuàng)建socket與該客戶建立專線連接叠纹。
4.建立連接的兩個(gè)socket在一個(gè)單獨(dú)的線程上對話。
5.服務(wù)器端繼續(xù)等待新的連接
**NIO主要原理及使用**
NIO采取通道(Channel)和緩沖區(qū)(Buffer)來傳輸和保存數(shù)據(jù)敞葛,它是非阻塞式的I/O誉察,即在等待連接、讀寫數(shù)據(jù)(這些都是在一線程以客戶端的程序中會阻塞線程的操作)的時(shí)候惹谐,程序也可以做其他事情持偏,以實(shí)現(xiàn)線程的異步操作。
考慮一個(gè)即時(shí)消息服務(wù)器氨肌,可能有上千個(gè)客戶端同時(shí)連接到服務(wù)器鸿秆,但是在任何時(shí)刻只有非常少量的消息需要讀取和分發(fā)(如果采用線程池或者一線程一客戶端方式,則會非常浪費(fèi)資源)怎囚,這就需要一種方法能阻塞等待卿叽,直到有一個(gè)信道可以進(jìn)行I/O操作。NIO的Selector選擇器就實(shí)現(xiàn)了這樣的功能,一個(gè)Selector實(shí)例可以同時(shí)檢查一組信道的I/O狀態(tài)附帽,它就類似一個(gè)觀察者埠戳,只要我們把需要探知的SocketChannel告訴Selector,我們接著做別的事情,當(dāng)有事件(比如蕉扮,連接打開整胃、數(shù)據(jù)到達(dá)等)發(fā)生時(shí),它會通知我們喳钟,傳回一組SelectionKey,我們讀取這些Key,就會獲得我們剛剛注冊過的SocketChannel,然后屁使,我們從這個(gè)Channel中讀取數(shù)據(jù),接著我們可以處理這些數(shù)據(jù)奔则。
Selector內(nèi)部原理實(shí)際是在做一個(gè)對所注冊的Channel的輪詢訪問蛮寂,不斷的輪詢(目前就這一個(gè)算法),一旦輪詢到一個(gè)Channel有所注冊的事情發(fā)生易茬,比如數(shù)據(jù)來了酬蹋,它就會讀取Channel中的數(shù)據(jù),并對其進(jìn)行處理抽莱。
要使用選擇器范抓,需要?jiǎng)?chuàng)建一個(gè)Selector實(shí)例,并將其注冊到想要監(jiān)控的信道上(通過Channel的方法實(shí)現(xiàn))食铐。最后調(diào)用選擇器的select()方法匕垫,該方法會阻塞等待,直到有一個(gè)或多個(gè)信道準(zhǔn)備好了I/O操作或等待超時(shí)虐呻,或另一個(gè)線程調(diào)用了該選擇器的wakeup()方法∠蟊茫現(xiàn)在,在一個(gè)單獨(dú)的線程中斟叼,通過調(diào)用select()方法偶惠,就能檢查多個(gè)信道是否準(zhǔn)備好進(jìn)行I/O操作,由于非阻塞I/O的異步特性犁柜,在檢查的同時(shí)洲鸠,我們也可以執(zhí)行其他任務(wù)。
基于NIO的TCP連接的建立步驟
服務(wù)端
????1馋缅、傳建一個(gè)Selector實(shí)例;
????2绢淀、將其注冊到各種信道萤悴,并指定每個(gè)信道上感興趣的I/O操作;
????3皆的、重復(fù)執(zhí)行:
????????1)調(diào)用一種select()方法覆履;
????????2)獲取選取的鍵列表;
????????3)對于已選鍵集中的每個(gè)鍵:
???????????a、獲取信道硝全,并從鍵中獲取附件(如果為信道及其相關(guān)的key添加了附件的話)栖雾;
???????????b、確定準(zhǔn)備就緒的操縱并執(zhí)行伟众,如果是accept操作析藕,將接收的信道設(shè)置為非阻塞模式,并注冊到選擇器凳厢;
???????????c账胧、如果需要怪与,修改鍵的興趣操作集梭域;
???????????d、從已選鍵集中移除鍵
客戶端
與基于多線程的TCP客戶端大致相同筏勒,只是這里是通過信道建立的連接遮精,但在等待連接建立及讀寫時(shí)居夹,我們可以異步地執(zhí)行其他任務(wù)。
**double轉(zhuǎn)byte類型**
????private static byte[] data;
????public static byte[] convert(double num) throws IOException {
????????data = null;
????????ByteArrayOutputStream bos = new ByteArrayOutputStream();
????????DataOutputStream dos = new DataOutputStream(bos);
????????dos.writeDouble(num);
????????dos.flush();
????????data = bos.toByteArray();
????????dos.close();
????????return data;
????}
**byte轉(zhuǎn)double類型**
????public static double convert(byte[] data) throws IOException {
????????DataInputStream dis = new DataInputStream(new ByteArrayInputStream(data));
????????double num = dis.readDouble();
????????dis.close();
????????return num;
????}
**UDP通信**
*發(fā)送引用數(shù)據(jù)類型*
*????客戶端:
1)????創(chuàng)建客戶端 DatagramSocket類 +指定端口
2)????準(zhǔn)備數(shù)據(jù)??字節(jié)數(shù)組
3)????打包 DatagramPacket +服務(wù)器地址及端口
4)????發(fā)送
5)????釋放資源
*????服務(wù)器:
1)????創(chuàng)建服務(wù)端DatagramSocket類+指定端口
2)????準(zhǔn)備接受容器??字節(jié)數(shù)組 封裝DatagramPacket(封裝成包)
3)????包 接收數(shù)據(jù)
4)????分析
5)????釋放資源
*發(fā)送基本數(shù)據(jù)類型*
*????客戶端:
1)????創(chuàng)建客戶端 DatagramSocket類 +指定端口
2)????準(zhǔn)備數(shù)據(jù) 基本數(shù)據(jù)類型轉(zhuǎn)換成字節(jié)數(shù)組(字節(jié)數(shù)組輸出流ByteArrayOutputStream toByteArray 數(shù)據(jù)字節(jié)輸出流DataOutputStream)
3)????打包 DatagramPacket +服務(wù)器地址及端口(發(fā)送的地點(diǎn)以及端口)
4)????發(fā)送
5)????釋放資源
*????服務(wù)器:
1)????創(chuàng)建服務(wù)端DatagramSocket類+指定端口
2)????準(zhǔn)備接受容器??字節(jié)數(shù)組 封裝DatagramPacket(封裝成包)
3)????包 接收數(shù)據(jù)
4)????分析數(shù)據(jù) 字節(jié)數(shù)組轉(zhuǎn)換成基本數(shù)據(jù)類型(字節(jié)數(shù)組輸入流ByteArrayOutputStream 數(shù)據(jù)字節(jié)輸入流DataInputStream)
5)????釋放資源