java概述:
一:java體系
1、javaSE(Java Platform, Standard Edition),標准版,各應用平台的基礎,桌面開發和低端商務應用的解決方案。
--Java SE是基於JDK和JRE的,包括用於開發Java Web服務的類庫,同時,Java SE為Java EE和Java ME提供了基礎。 2、javaEE(Java Platform,Enterprise Edition),企業版,以企業為環境而開發應用程序的解決方案。
--Java EE 是在 Java SE 的基礎上構建的,能夠幫助我們開發和部署可移植、健壯、可伸縮且安全的服務器端 Java應用程序。 3、javaME(Java Platform,Micro Edition),微型版,致力於消費產品和嵌入式設備的最佳方案。
--
是為機頂盒、移動電話和PDA之類嵌入式消費電子設備提供的Java語言平台,包括虛擬機和一系列標准化的Java API。
二:Java的特性
1、一種面向對象的編程語言。 2、一種與平台無關的語言(根據JVM實現的)。 3、一種健壯性語言。 4、具有較高的安全性。
三:JDK、JRE與JVM
1、JVM:虛擬機,java虛擬機實際上只是一層接口,一層Java程序和操作系統通訊的接口。.java源文件經編譯生成.class字節碼文件,
再由
java虛擬機加載並運行.class文件,若將.class文件看成一個軟件,那么java虛擬機就是
運行
這個軟件的操作系統。
2、
JRE:java運行環境,包括:JVM+系統類庫,它是運行Java程序的最小單位。
3、JDK:java開發工具包,包括:JRE+編譯運行指令,它是開發Java程序的最小單位。
注:安裝了JDK后,JRE已經存在無需額外安裝。
四:Java程序開發與運行機制
1、編寫源程序,java源代碼文件。
2、編譯源程序,編譯器編譯編譯成.java字節碼文件。
3、運行時,Java虛擬機(JVM)將.Java源文件編譯成可運行的.class文件。
4、Java環境變量的配置:
1)下載安裝JDK,進入電腦的高級系統設置,找到環境變量;
2)新建JAVA_HOME :%安裝路徑%\Java\jdk(安裝JDK路徑);
3)path 后追加兩個變量,即 : %JAVA_HOME%\bin 與%JAVA_HOME%\jre\bin;
4) 新建CLASSPATH系統變量,CLASSPATH= .;%JAVA_HOME%\lib;%JAVA_HOME%\lib\tools.jar (注意:一定要寫 ".;",標點全部為英文狀態下)。
五:Java中的一些規則
1、應用
1) 一個源文件中只
能有一個public修飾的類,其他類個數不限。
2)
一個
源文件有n個類時,編譯結果的class文件就有n個。
3) 源文件的名字必須和public修飾的類名相同
。
4)
Java語言中單詞拼寫大小寫嚴格區分。
5) main方法為入口方法。
6) 每一句以分號(;)結束。
2、注釋
1) 單行注釋//
2) 多行注釋/* */
3) java文檔注釋/** */
3、標識符
1) 命名規則:
由字母、下划線、數字和美元符號組成;
不能以數字開頭;
區分大小寫;
不能是關鍵字和保留字(goto、const);
長度一般不超過15個字符。
2)
駝峰式命名:
包名:全部小寫。
類名:每個單詞首字母都大寫。--大駝峰
方法名、參數名、變量名:第一單詞首字母小寫,后面其他單詞首字母大寫。--小駝峰
六:Java語言基礎
1、關鍵字:Java中賦予了特殊含義的單詞
訪問控制 :public、private、protected
類,方法和變量修飾符 : abstract class extends final implements interface native new
static strictfp synchronized transient volatile
程序控制 : break continue return do while if else for instanceof switch case default
異常處理 : try cathc throw throws
包相關 : import package
基本類型 : boolean byte char double float int long short null true false
變量引用 : super this void
保留字 : goto const
2、數據類型
1) 基本數據類型:byte、short、int、long、float、double、char、boolean
數據類型 |
boolean |
byte |
char |
short |
int |
long |
float |
double |
void |
二進制位數 |
1 |
8 |
16 |
16 |
32 |
64 |
32 |
64 |
-- |
封裝類 |
Boolean |
Byte |
Character |
Short |
Integer |
Long |
Float |
Double |
Void |
2) 引用數據類型: 字符串 String、數組 []、類 class、接口 interface、枚舉 enum。
3) a.數據類型划分:
基本類型變量:數據的值
引用類型變量:數據的地址
b.聲明的位置划分: 局部變量 全局變量
區別:
1、默認值:局部變量沒有默認值,使用前必須初始化。
全局變量有默認值,默認為0,不必須初始化。
2、聲明位置:局部變量在方法內。 全局變量在方法外類內。
3、作用位置:局部變量只能在自己聲明的方法里。全局變量在整個類中。
3、自動類型轉換與強制類型轉換
自動類型轉換:從低級別到高級別,系統自動轉的;
強制類型轉換:把一個高級別的數賦給一個比該數的級別低的變量;
4、常量與變量
常量:在程序中,不會變化的數據。
變量:其實就是內存中的一個存儲空間,用於存儲常量數據。
作用:方便於運算。因為有些數據不確定。所以確定該數據的名詞和存儲空間。
特點:變量空間可以重復使用。
變量的作用域:作用域從變量定義的位置開始,到該變量所在的那對大括號結束;
生命周期:變量從定義的位置開始就在內存中活了;變量到達它所在的作用域的時候就在內存中消失了;
5、運算符
1) 算術運算符:+ 、 - 、 * 、 / 、 % 、 ++ 、 --
2) 賦值運算符:= 、 += 、 -= 、 *= 、 /= 、 %=
3) 關系運算符:> 、 < 、 >= 、 <= 、 == 、 !=
4) 邏輯運算符:
! (一般用於boolean類型前,表示非);
& (只要有一個false 最終結果就是false);
| (但凡有一個true 最終結果就是true);
^ (如果兩邊一樣,最終結果為false;如果兩邊不同,最終結果為true);
&& (若第一個表達式結果為false,發生短路,第二個表達式不執行,最終結果為false);
|| (若第一個表達式結果為true,發生短路,第二個表達式不執行,最終結果是true)
5) 位運算符:用於操作二進制位的運算符。
~ 、 >> 、 << 、 >>>(無符號右移) 6) 字符串連接運算符:+ 7) 三目運算符:X ? Y : Z
X為boolean類型表達式,若x的結果為true,返回表達式Y的值,否則返回表達式Z的值。
七:Java中的流程控制
1、三種結構: 順序、分支、循環
1) if語句
a.if(
){}
b.
if(){}else{}
c.
if(){}else if(){}
d.if(){if(){}else()}
e.if()執行語句 esle 執行語句 (
注意:執行語句只有一條語句的時候.可以將if esle 的大括號省略)
注意:()中為boolean類型表達式,
{}中為執行語句塊
equals : 比較字符串用,比較的是內容。
== : 比較數值,比較的是引用的地址。
基本數據類型:變量名、變量值在棧中。
引用數據類型:變量名在棧中,變量值在常量池中。
object中的equals比較的是地址,底層封裝的是==
== 比較基本數據類型時,比較的是內容
比較引用數據類型時,比較的是地址
String中也有equals,String中的equals被重寫過了,比較的是內容。
2)switch多分支語句
import java.util.Scanner;
public class MySwitch {
public static void main(String[] args) {
Scanner scan = new Scanner(System.in);
System.out.print("請輸入今天星期幾:");
int week = scan.nextInt();
switch (week) {
case 1:
System.out.println("星期一");
break;
case 2:
System.out.println("星期二");
break;
case 3:
System.out.println("星期三");
break;
case 4:
System.out.println("星期四");
break;
case 5:
System.out.println("星期五");
break;
case 6:
System.out.println("星期六");
break;
case 7:
System.out.println("星期天");
break;
default:
System.out.println("今天要不要上班呢?");
break;
}
}
}
注意:
1、表達式必須是int、byte、char、short、enmu、String類型
2、case后必須是常量或者finall變量,不能是范圍
3、所有的case語句的值不能相同,否則編譯會報錯
4、default可要可不要
5、break用來執行完一個分支后使程序跳出switch語句塊,否則會一直會執行下去。
if與switch比較:
a.if可以判斷范圍,也可以判斷一個值switch只能判斷指定的值。
b.若只判斷指定的值,則使用switch語句,效率快 if判斷范圍,對數據判斷靈活,自身的格式也比較靈活。
3)for循環
for ([循環變量初始值設定]; [循環條件判斷]; [改變循環變量的值]){
循環體;
}
注意:
1、表達式2一般不可以省略,否則死循環
2、表達式3可以省略,但是在循環體中必須有語句修改變量,以使表達式2在某一時刻為false結束循環。
3、若同時省略表達式1,表表達式3,則相當於while(表達式2)語句
4、三個表達式均省略 即for(;;)語句,此時相當於while(true)語句
5、表達式1、表達式3可以是逗號表達式,以使循環變量值在修改時可以對其它變量賦值
6、一般情況下,表達式3,應向循環的結束變
1 public class Sfor { 2 3 public static void main(String[] args) { 4 for (int i = 1; i <= 9; i++) { 5 for (int j = 1; j <= i; j++) { 6 System.out.print(i+"*"+j+"="+j*i+" "); 7 } 8 System.out.print("\n"); 9 } 10 } 11 12 } 13 輸出結果是: 14 1*1=1 15 2*1=2 2*2=4 16 3*1=3 3*2=6 3*3=9 17 4*1=4 4*2=8 4*3=12 4*4=16 18 5*1=5 5*2=10 5*3=15 5*4=20 5*5=25 19 6*1=6 6*2=12 6*3=18 6*4=24 6*5=30 6*6=36 20 7*1=7 7*2=14 7*3=21 7*4=28 7*5=35 7*6=42 7*7=49 21 8*1=8 8*2=16 8*3=24 8*4=32 8*5=40 8*6=48 8*7=56 8*8=64 22 9*1=9 9*2=18 9*3=27 9*4=36 9*5=45 9*6=54 9*7=63 9*8=72 9*9=81
4)while循環
while(條件表達式語句){
循環體語句;
}
do{
循環體;
}while( 循環條件判斷);
注意:
1、當第一次執行時,若表達式=false時,則while語句不執行,而do/while語句執行一次后面的語句
2、一定要切記在switch循環中,如果沒有break跳出語句,每一個case都要執行一遍,在計算最終結果。
public class SWhile { public static void main(String[] args) { int x = 1; // 定義初值 int sum = 0; // 定義求和變量,用於存儲相加后的結果 while(x <= 10) { sum += x; // 循環相加,也即 sum = sum + x; x++; } System.out.println(sum); } } public class CDoWhile { public static void main(String[] args) { int a = 10; int b = 10; // while循環語句 while(a == 8) { System.out.println("a == " + a); a--; } // do···while循環語句 do { System.out.println("b == " + b); b--; } while(b == 8); } }
2、break、return和continue
break:跳出某個循環
continue:跳出本次循環,進入下一輪
return:以return;終止方法的執行
注意:if外有循環可以用break、continue,單純if不可以用。
3、遞歸
a.有返回值
b.有參數
c.能夠有跳出循環的控制語句
d.自己調用自己
//用遞歸方法求累加
public class Recursion {
public static void main(String[] args){
Scanner scan = new Scanner(System.in);
System.out.print("請輸入要求的值:");
int N =scan.nextInt();
for(int n = 1; n <= N; n++) {
if(n % 20 == 0){
int sum = recursion(n);
System.out.println("1 到 " + n + " 的累加值是: " + sum);
}
}
}
public static int recursion(int n) {
if (n < 1) return 0;
return recursion(n - 1) + n;
}
}
八:重寫(Overriding)與重載(Overloading)
方法重載:指同一個類中的多個方法具有相同的名字,但這些方法具有不同的參數列表,即參數的數量或參數類型不能完全相同
方法重寫:存在子父類之間的,子類定義的方法與父類中的方法具有相同的方法名字,相同的參數表和相同的返回類型
注:
(1)子類中不能重寫父類中的final方法
(2)子類中必須重寫父類中的abstract方法
(3)子類函數的訪問修飾權限不能小於父類的;
(4)子類的異常類型要小於父類;
重寫方法的規則:
1、參數列表必須完全與被重寫的方法相同,否則不能稱其為重寫而是重載。
2、返回的類型必須一直與被重寫的方法的返回類型相同,否則不能稱其為重寫而是重載。
3、訪問修飾符的限制一定要大於被重寫方法的訪問修飾符(public>protected>default>private)
4、重寫方法一定不能拋出新的檢查異常或者比被重寫方法申明更加寬泛的檢查型異常。例如:父類的一個方法申明了一個檢查異常IOException,
在重寫這個方法是就不能拋出Exception,只能拋出IOException的子類異常,可以拋出非檢查異常。
而重載的規則:
1、必須具有不同的參數列表;
2、可以有不責罵的返回類型,只要參數列表不同就可以了;
3、可以有不同的訪問修飾符;
4、可以拋出不同的異常;
重寫與重載的區別在於:
重寫多態性起作用,對調用被重載過的方法可以大大減少代碼的輸入量,同一個方法名只要往里面傳遞不同的參數就可以擁有不同的功能或返回值。
用好重寫和重載可以設計一個結構清晰而簡潔的類,可以說重寫和重載在編寫代碼過程中的作用非同一般.
1、重寫是在繼承關系中;重載是在同一個類中。
2、重寫是方法名、參數列表和父類相同;重載,方法名相同,參數列表不相同(個數、類型、順序)。
3、重寫返回值類型和父類相同;重載和返回值無關。
4、重寫訪問權限修飾符不能比父類更加嚴格;重載沒有要求。
九:面向對象和面向過程
1、面向對象:是以具體的事物為單位,考慮的是它的特征(屬性)和行為(方法)。
2、面向過程:是以具體的流程為單位,考慮功能的實現。
十:類和對象
1、對象:看得見摸得着的具體事物。
類:抽象化的概念
2、類和對象的關系:
類是對象的模板/抽象化的概念,對象是類的實例。
3、創建類和對象
類:
特征:全局變量/屬性/成員變量
動作:方法
對象:
類名 對象名=new 類名()
注意:一個類可以創建多個對象,,每個對象之間沒有關系。
十一:內存圖
1、棧:先進后出,存放基本數據類型變量名和變量值,引用數據類型的變量名,方法執行的時候進入棧中
2、堆:先進先出,new出來的對象的實例,包括類的屬性個方法。
十二:構造方法
1、構造方法是new關鍵字調用的,用來幫助構建對象
2、顯示構造對象
3、隱示構造對象(沒有顯示的情況下存在)
4、構造對象可以重載,參數類型不一致。
十三:關鍵字
1、static調用格式:
1)同一個類中:
靜態的: 方法名 屬性名
類名.方法名 類名.屬性名
對象名.方法名 對象名.屬性名
非靜態的: 對象名.屬性名 對象名.方法名
2)不同類中:
靜態的: 對象名.方法名 對象名.屬性名
類名.方法名 類名.屬性名
非靜態的: 對象名.屬性名 類名.方法名
注意:
1、static可以修飾屬性、方法、代碼塊,不可以修飾類和構造方法。
2、靜態方法隨着類的加載而加載。
3、在靜態方法區內的東西只有一份,所有的對象共享這一份空間,只要有一個對象對屬性進行修改,所有的對象調用都是修改后的數據。
4、代碼塊的執行順序:靜態代碼塊(只被調用一次)>構造代碼塊{}>構造方法>普通方法(需調用)
2、this關鍵字
1)可以調用屬性和方法。 this.屬性名(全局變量) this.方法名();
2)在構造方法中:
a.this();括號內的參數個數、順序、類型根據調用的方法來決定。
b.必須放在第一行,只能調用一次。
c.調用構造方法時只能在構造方法中調用,調用屬性和方法時可以在構造方法中可以在普通方法中。
d.當全局變量和局部變量有重名字的時候,用this來區分。
3、super關鍵字
1)super指代父類對象。
2)super可以調用屬性、方法、構造方法。
3)super調用父類的構造方法。
4)super調用構造方法時候必須放在第一行。
4、final最終的
1)可以修飾全局變量,聲明的時候必須賦值,只能賦值一次。
2)可以修飾局部變量,聲明時候可以不賦值,但也只能賦值一次。
3)可以修飾方法,可以正常使用,不能被重寫。
4)可以修飾類,可以正常使用,不能被繼承。
5)用final修飾的屬性通常叫常量。
6)static final 全局變量。每個字母都要大寫。
5、this和super的區別
1)this指的是本類創建的對象。 super指代的是父類的對象
2)this可以調用屬性、方法、構造方法。 super也可以調用屬性、方法、構造方法。
3)this調用屬性和方法的時候,調用自己本類的屬性和方法。 如果本類沒有,那就用super去父類中找
4)this調用構造方法調用,調用本類的其他構造方法。 super調用父類的構造方法。
5)this和super在調用構造方法的時候必須放在第一行。
6)this和super不能同時存在
6、最小作用域最強原則: 局域變量在此方法中,比全局變量在此方法中的作用強。
十四:面向對象的三大特征
1、封裝
作用:提高代碼的安全性 1)將屬性私有化,並提供對外界的接口(get/set方法)。 2)用private修飾的屬性和方法,只能在本類中使用。
2、繼承
作用:提高代碼的復用性,減少重復代碼 1)子類可以繼承父類非私有的屬性和方法,不能繼承構造方法和私有的屬性和方法。 2)可以綜合子類的共同特征來去提煉父親的類。 3)子類在繼承父類的各種屬性和方法時,也可以有自己的屬性和方法。 4)一個子類只能有一個父類,java只能單繼承,不能多繼承,因為多個類中的方法名相同,方法體不同,不知使用哪個。 5)一個類繼承最頂端叫做基類或者超類,所有的超類叫做object 。 6)在繼承關系中,如果父類沒有無參數的構造方法,如何解決? a.子類中添加一個和父類構造方法參數列表相同的構造方法,通過super參數傳遞給父類的構造方法 b.如果父類允許修改的時候,可以在父類中創建一個無參的構造方法 7)在繼承關系中,代碼塊的執行順序:父靜>子靜>父構造代碼塊>父構造方法>子構造代碼塊>子構造方法
3、多態
1)分類 編譯時多態:在編譯過程中察覺的多態,重載,向上轉型。 運行時多態:在運行過程中察覺的多態,向下轉型。 2)向上轉型、向下轉型是在繼承關系中,向下轉型必須在向上轉型的基之上。 3)在繼承關系中,父類的對象可以指向子類的實例,父類引用實體方法的時候,是調用子類重寫以后的方法。 4)向上轉型 父類的引用指向子類的實體 父類類名 對象名=new 子類類(); 優點:減少重復代碼,提高代碼的復用性 缺點:父類的引用無法調用子類特有的屬性和方法 解決方案:向下轉型 5)向下轉型: 子類對象的父類引用賦給子類 子類類名 對象名=(子類類名)父類對象; 6) instanceof 判斷左邊的對象是否屬於右邊的類 對象名 instanceof 類名(子類類名) 7)匿名對象 new 類名() 只有堆空間,沒有棧空間,只能屬於一次,為了節省代碼。
十五:
抽象abstract與接口interface
abstract:
作用:節省代碼,提高代碼的復用性
1)抽象類格式:訪問權限修飾符 abstract class 類名{ 2)抽象方法格式:訪問權限修飾符 abstract 返回值類型 方法名(形式參數列表); 注意: 1、如果一個類里有抽象方法,那么這個類必須聲明成抽象類。 2、一個類里面可以沒有抽象方法,可以有非抽象方法, 3、類繼承抽象類: 把子類也用abstract修飾,變成抽象類。 子類重寫父類的抽象的方法 4、抽象類不能創建對象。 5、抽象類可以有構造方法,在創建子類的時候,super隱式調用父類的構造方法,將父類的屬性和方法放到子類的對象空間里。 6、在繼承你關系中,子類能夠繼承抽象類的各種屬性和方法,除了私有的和構造方法。 7、只有公開的才可以和abstract連用,static final private 都不可以。 static屬於類方法,不允許覆蓋,abstract必須被覆蓋。final不能被重寫。
interface:
作用:規范了代碼,提高代碼的拓展性
1、格式:訪問權限修飾符 interface 接口名稱{}
2、實現類的格式:訪問權限修飾符 class 實現類名 implements 接口名{必須重寫接口中的所有的抽象方法}
3、接口中只有全局常量和抽象方法。
4、書寫的時候可以省略部分修飾符,系統會默認給添上。
5、接口在實現的同時去繼承,extends在implement前面。
6、接口可以多實現,實現的也必須是接口,方法名可以重復,實現類實現一個就行了,因為沒有方法體,不會發生沖突。
抽象和接口的區別:
1、關鍵字:抽象類 abstract 接口interface
2、抽象類繼承 extends 接口實現 implements
3、子類繼承抽象類和 實現類實現接口的格式不同
4、接口中只有全局變量和抽象方法 抽象類中有各種屬性和方法
5、抽象類只能單繼承 接口可以多實現
6、抽象類的子類只能繼承一個父類 實現類可以實現多個接口,並且還可以繼承父類
7、抽象類的作用:提高代碼的復用性 接口的作用:1、規范代碼2、提高代碼的拓展新
十六:訪問權限修飾符
本類中 本包中 其他包子類 其他包非子類
public √ √ √ √
protected √ √ √ ×
default √ √ × ×
private √ × × ×
十七:內部類
分類:成員內部類、靜態內部類、局部內部類、匿名內部類
1、成員內部類: 1、可以用四種訪問權限修飾符修飾 2、可以有自己的屬性和方法,除了靜態的。 3、可以使用外部類的所有屬性和方法,包括私有的。 4、創建對象 1、通過創建外部類對象的方式創建對象 外部類 外部類對象=new 外部類(); 內部類 對象名=外部類對象.new 內部類(); 2、內部類 對象名=new 外部類.new 內部類(); 2、靜態內部類 1、格式:static class 類名{} 2、可以聲明靜態的屬性和方法 3、可以使用外部的靜態的屬性和方法 4、創建對象 內類名 對象名=new 內類名();(可以直接創建) 外部類名.內部類 對象名=new 外部類.內部類(); 包名.外部類名.內部類 對象名=new 包名.外部類.內部類(); 5、外部類與內部類同名時,默認是使用內部類對象調用外部類屬性 this代表內部類對象 6、要想使用外部類屬性,需要使用外部類對象調用 3、局部內部類 1、在方法中聲明 2、只能用default修飾 3、可以聲明屬性和方法,但不能是靜態的 4、創建對象,必須在聲明內部類的方法內創建 5、調用方法的時候,局部內部類才會被執行 4、匿名內部類 1、匿名內部類只是用一次 2、格式: 父類或接口名 對象名=new 父類或接口名(參數列表){ 重寫抽象方法 } 調用抽象方法:對象名.方法名
十八:常用設計模式
1、單例模式 分類:懶漢式、餓漢式
1、構造方法私有化
2、在本類中創建本類對象
3、保證對象的唯一性final
4、給外界提供得到對象的方法 static
5、在多線程中,餓漢式安全,懶漢式不安全
2、簡單工廠模式 批量創建對象
1 創建工廠類 : 創建對象的方法
2 果汁類 是所有種類果汁的父類
3 在工廠類的方法中返回果汁類
4 根據測試類中傳遞的字符串判斷到底返回哪種果汁
5 測試類通過工廠類返回果汁對象
3、建造者模式
內部類使用場景 目的:靜態內部類創建外部類對象
1、 創建外部類,在其中創建一個靜態內部類
2、靜態內部類中寫屬性,構造方法和set get方法
3、靜態內部類中寫一個方法,必須返回外部類對象
4、 給外部類創建對象,傳遞參數。
4、裝飾者模式
1、在處理流中使用
2、子類重寫父類的方法,提高父類方法的功能及效率
3、為了盡可能減少重復代碼,在重寫的方法中用父類的對象調用父類原來的方法
4、得到父類對象可以通過將父類對象作為子類屬性,通過子類構造方法傳遞父類對象
十九:數組及常用算法
1、聲明: int a[]; int []b;
2、初始化:
動態初始化:
1、a=new int[2]; int[0]=1;... 動態初始化:
2、b=new b[]{3,4}; 靜態初始化:int [] c={5,6};
3、數組常用的方法:
排序:Array.sort();
查找:Array.binarySearch();
打印:Array.toString();
復制:Array.copyof();
4、常用操作
1、冒泡排序 for(int i=0;i<a.length-1;i++){//控制外循環的次數 for(int j=0;j<a.length-1-i;j++){//控制內循環次數,比外循環少一次,與下一個比較 if(a[j]>a[j+1]){ int temp=a[j]; a[j]=a[j+1]; a[j+1]=temp; } } } 2、選擇排序 for (int i = 0; i < a.length-1; i++) { int k=i; for (int j = i; j < a.length-1; j++) { if (a[k]>a[j+1]) { k=j+1; } } if(i!=k){ int temp=a[i]; a[i]=a[k]; a[k]=temp; } } 3、順序查找 public static int find(int []b,int a){ for (int i = 0; i < b.length; i++) { if (a==b[i]) { return i; } } return -1; } 4、二分查找 public static int find(int b[],int a){ int max=b.length-1; int min=0; for (int i = 0; i < b.length; i++) { int midle=(max+min)/2; if(a==b[midle]){ return midle; }else if(a>b[midle]){ min=midle+1; }else if(a<b[midle]){ max=midle-1; } } return -1; }
二十:時間相關的類
1、Date類 .getTime();計算毫秒
2、SimpleDateFormat類 格式化時間 .format();返回的是String字符串
3、Calendar接口
日歷字段之間的轉換提供了一些方法
.get(Calendar.YEAR);
.get(Calendar.MONTH);// 默認是當前月份減一 從0開始的
.get(Calendar.DAY_OF_MONTH);
.get(Calendar.DAY_OF_WEEK);
Calendar calendar = Calendar.getInstance();
Date date = calendar.getTime();
4、Runtime運行時時間 .freeMemory(); 當前的系統剩余空間
5、System.exit(0);退出程序,參數是0是正常退出
System.gc();調用垃圾回收器,不一定能夠起來,只是起到一個促進的作用
二十一:Java異常處理機制
異常:
1、在運行時期出現的不正常的事件,從繼承的角度看,throwable是錯誤和異常的超類
2、錯誤Error:程序員無法處理的嚴重性問題,資源耗盡,jvm系統內部的錯誤
異常Exception:程序員可以處理的一般性問題,偶然的外界因素,編程的邏輯性錯誤
3、處理的必要性角度:
受檢異常:編譯時期就能發現的異常,必須要去處理的異常,繼承自Exception
非受檢異常:運行時期發現的異常,不是必須要去處理的,繼承自RuntimeException
4、異常的處理機制: 當運行代碼的時候首先先碰到異常,首先產生異常對象,拋出給jvm,jvm會攜帶異常對象,
去找代碼能夠處理或者捕獲異常代碼,如果找到了,則交給這個代碼去處理,沒有找打,則程序停止運行。
5、異常處理的兩種方式
1、捕獲異常
try{可能會產生異常的代碼}catch(異常類 異常對象){處理異常的代碼}
try{}catch(){}catch(){}... catch中子類異常放在父類異常的上面
try{]catch(){}finally{} finally中的代碼一定會被執行到
try{}finally{}
1> 如果不去捕獲異常,發生異常,異常后面的代碼都不會被執行到
2> 如果捕獲異常 try/catch后面的代碼會被執行到
3> 捕獲異常,try塊中異常后面的代碼不會被執行到
2、拋出異常
產生異常的位置不去處理異常,由調用此方法的調用者去處理異
throws 方法的聲明后面 后面跟的是異常的類名 可以跟多個類名之間用逗號隔開 可以拋出受檢異常和非受檢異常
throw 方法的內部 異常的對象名 一個對象 拋出非受檢異常
6、自定義異常
自定義
受檢異常繼承Exception
非受檢異常 RuntimeException
final finally finalize區別
final 最終的,可修飾類,方法,屬性
類:不能被繼承
方法:不能被重寫,可以被繼承
屬性:全局變量:聲明是必須初始化。局部變量:聲明的時候可以不初始化。但都只能賦值一次
finally 跟try/catch后面,無論是否發生異常都會被執行。關閉數據庫,關閉數據流。
finalize 由系統調用,垃圾回收器回收之前做一些清理的工作。
二十二:
數組:長度固定,數據類型相同
集合:長度不固定,數據類型可以不同,只能存對象
collection
List Set
Vector
ArrayList HashSet
LinkedList TreeSet
Map
HashMap
TreeMap
List:元素是有序的,元素可以重復。因為該集合體系有索引。
|--ArrayList:底層的數據結構使用的是數組結構。特點:查詢速度很快。但是增刪稍慢。線程不同步。
|--LinkedList:底層使用的是鏈表數據結構。特點:增刪速度很快,查詢稍慢。
|--Vector:底層是數組數據結構。線程同步。被ArrayList替代了。
Set:元素是無序(存入和取出的順序不一定一致),元素不可以重復。
|--HashSet:底層數據結構是哈希表。線程不同步。 保證元素唯一性的原理:判斷元素的hashCode值是否相同。如果相同,還會繼續判斷元素的equals方法,是否為true。
|--TreeSet:可以對Set集合中的元素進行排序。默認按照字母的自然排序。底層數據結構是二叉樹。保證元素唯一性的依據:compareTo方法return 0。
Set集合的功能和Collection是一致的
1、HashSet: 哈希表 1、可以通過元素的兩個方法,hashCode和equals來完成保證元素唯一性。如果元素的HashCode值相同,才會判斷equals是否為true。
如果元素的hashCode值不同,不會調用equals。
2、hashcode是內存地址通過一定運算的到的int類型的數值。返回值是int類型的數據,各個屬性的hash值。 相加
3、hashcode值相同,也不一定是同一個對象
4、調用hashcode方法可以幫助去過濾調用完全不可能相同的 對象,提高執行效率
5、equals最終確定兩個對象是否相同的
Map :
1)該集合存儲鍵值對,一對一對往里存
2)要保證鍵的唯一性 |--Hashtable:底層是哈希表數據結構,不可以存入null鍵null值。該集合是線程同步的。JDK1.0,效率低。 |--HashMap:底層是哈希表數據結構。允許使用null鍵null值,該集合是不同步的。JDK1.2,效率高。 |--TreeMap:底層是二叉樹數據結構。線程不同步。可以用於給Map集合中的鍵進行排序。 初始容量16,加載因子0.75 Map和Set很像。其實Set底層就是使用了Map集合。
二十三:Java多線程
1)線程和進程
1、線程
注意:多線程。從宏觀角度:同時執行了多個線程。
從微觀角度:同一時間只能執行一個線程
多個線程是競爭關系,搶占cpu資源,否則只能等待。
2、進程和線程的區別
進程是應用程序,線程是一條執行路徑
進程有獨立的內存空間,崩潰不會影響其他程序,
線程沒有獨立的空間,多個線程在同一個進程的空間,可能會影響其他線程
一個進程中,至少有一個線程
3、主線程與子線程
主線程:main方法產生的線程,也叫作UI線程。
子線程:除了主線程以外的,也叫工作線程。
守護線程(即daemon thread),是個服務線程,准確地來說就是服務其他的線程。
4、創建線程的方式
a.創建一個類繼承Thread,重寫run方法,創建線程對象,啟動線程,Thread.currentThread().getName(),哪個線程調用,名字就是哪個現成的名字.
b
.
共享資源類實現Runable接口,
重寫run方法,創建共享資源對象
,
創建線程對象,將共享資源對象添加到線程中
,啟動線程
c.實現callable接口,Callable接口代表一段可以調用並返回結果的代碼;Future接口表示異步任務,是還沒有完成的任務給出的未來結果。
所以說Callable用於產生結果,Future用於獲取結果。
d.線程池ThreadPoolExcutor
new ThreadPoolExecutor(int corePoolSize, int maximumPoolSize,long keepAliveTime, TimeUnit unit,BlockingQueue workQueue,RejectedExecutionHandler handler)
(1)corePoolSize: 線程池維護線程的最少數量 (core : 核心)
(2)maximumPoolSize: 線程池維護線程的最大數量
(3)keepAliveTime: 線程池維護線程所允許的空閑時間
(4)unit: 線程池維護線程所允許的空閑時間的單位
(5)workQueue: 線程池所使用的緩沖隊列
(6)handler: 線程池對拒絕任務的處理策略
思考:說一下 runnable 和 callable 有什么區別?
Runnable接口中的run()方法的返回值是void,它做的事情只是純粹地去執行run()方法中的代碼而已;
Callable接口中的call()方法是有返回值的,是一個泛型,和Future、FutureTask配合可以用來獲取異步執行的結果。
5、run和start的區別
每個線程都是通過某個特定Thread對象所對應的方法run()來完成其操作的,方法run()稱為線程體。通過調用Thread類的start()方法來啟動一個線程。
start()方法來啟動一個線程,真正實現了多線程運行。這時無需等待run方法體代碼執行完畢,可以直接繼續執行下面的代碼; 這時此線程是處於就緒狀態, 並沒有運行。
然后通過此Thread類調用方法run()來完成其運行狀態, 這里方法run()稱為線程體,它包含了要執行的這個線程的內容, Run方法運行結束, 此線程終止。然后CPU再調度其它線程。
run()方法是在本線程里的,只是線程里的一個函數,而不是多線程的。 如果直接調用run(),其實就相當於是調用了一個普通函數而已,直接待用run()方法必須等待run()方法執行完畢
才能執行下面的代碼,所以執行路徑還是只有一條,根本就沒有線程的特征,所以在多線程執行時要使用start()方法而不是run()方法。
run沒有開辟新的棧空間,沒有新線程,都是主線程在執行
start開辟了新的棧空間,在新的棧空間啟動run()方法
6、線程的調度
setPriority();分配優先級,默認5,最低1,最高10
.join();插隊,阻塞指定的線程等到另一個線程完成以后再繼續執行
.sleep();需要設置睡眠時間
.yield();禮讓,當執行到這個方法時,會讓出cpu時間,立馬變成可執行狀態
sleep和pield的區別:
sleep 線程進入被阻塞的狀態
yeild 線程轉入暫停執行的狀態
7、打斷線程的終止方式
1、用標記,當終止線程時,會執行完run方法
2、stop()方法,不建議使用,會執行不到特定的代碼
3、interrupt(),只能中斷正在休眠的線程,通過拋異常的方法中斷線程的終止。
InputStream inputStream=System.in;
int m=inputStream.read();
myThread2.interrupt();//通過外界輸入打斷
8、線程的五種狀態
新建(new) 就緒(runnable) 執行(running) 死亡(dead) 阻塞(blocked)
1、新建狀態(New):新創建了一個線程對象。
2、就緒狀態(Runnable):線程對象創建后,其他線程調用了該對象的start()方法。該狀態的線程位於“可運行線程池”中,
變得可運行,只等待獲取CPU的使用權。即在就緒狀態的進程除CPU之外,其它的運行所需資源都已全部獲得。
3、運行狀態(Running):就緒狀態的線程獲取了CPU,執行程序代碼。
4、阻塞狀態(Blocked):阻塞狀態是線程因為某種原因放棄CPU使用權,暫時停止運行。直到線程進入就緒狀態,才有機會轉到運行狀態。
阻塞的情況分三種:
(1)、等待阻塞:運行的線程執行wait()方法,該線程會釋放占用的所有資源,JVM會把該線程放入“等待池”中。
進入這個狀態后,是不能自動喚醒的,必須依靠其他線程調用notify()或notifyAll()方法才能被喚醒,
(2)、同步阻塞:運行的線程在獲取對象的同步鎖時,若該同步鎖被別的線程占用,則JVM會把該線程放入“鎖池”中。
(3)、其他阻塞:運行的線程執行sleep()或join()方法,或者發出了I/O請求時,JVM會把該線程置為阻塞狀態。
當sleep()狀態超時、join()等待線程終止或者超時、或者I/O處理完畢時,線程重新轉入就緒狀態。
5、死亡狀態(Dead):線程執行完了或者因異常退出了run()方法,該線程結束生命周期。
思考:(1)sleep() 和 wait() 有什么區別?
sleep():方法是線程類(Thread)的靜態方法,讓調用線程進入睡眠狀態,讓出執行機會給其他線程,等到休眠時間結束后,線程進入就緒狀態和其他線程一起競爭cpu的執行時間。
因為sleep() 是static靜態的方法,他不能改變對象的機鎖,當一個synchronized塊中調用了sleep() 方法,線程雖然進入休眠,但是對象的機鎖沒有被釋放,其他線程依然無法訪問這個
對象。
wait():wait()是Object類的方法,當一個線程執行到wait方法時,它就進入到一個和該對象相關的等待池,同時釋放對象的機鎖,使得其他線程能夠訪問,
可以通過notify,notifyAll方法來喚醒等待的線程
(2)notify()和 notifyAll()有什么區別?
如果線程調用了對象的 wait()方法,那么線程便會處於該對象的等待池中,等待池中的線程不會去競爭該對象的鎖。
當有線程調用了對象的 notifyAll()方法(喚醒所有 wait 線程)或 notify()方法(只隨機喚醒一個 wait 線程),被喚醒的的線程便會進入該對象的鎖池中,鎖池中的線程會
去競爭該對象鎖。也就是說,調用了notify后只要一個線程會由等待池進入鎖池,而notifyAll會將該對象等待池內的所有線程移動到鎖池中,等待鎖競爭。
優先級高的線程競爭到對象鎖的概率大,假若某線程沒有競爭到該對象鎖,它還會留在鎖池中,唯有線程再次調用 wait()方法,它才會重新回到等待池中。而競爭到對象鎖的線程
則繼續往下執行,直到執行完了 synchronized 代碼塊,它會釋放掉該對象鎖,這時鎖池中的線程會繼續競爭該對象鎖。
2)同步
發生在兩個以兩個以上的線程中
解決代碼的重復問題 優點:提高了線程中數據的安全性 缺點:降低了執行效率
1、同步代碼塊 synchronized(鎖){同步代碼塊} 注意:鎖分任意鎖和互斥鎖,鎖是對象,瑣是唯一的。
2、同步方法 public synchroinzed 返回值類型 方法名(){同步代碼}
3、在共享資源中:
線程操作相同,鎖是this
synchronized (this) {// 同步代碼塊,包含同步代碼塊。任意鎖,互斥鎖。
if (ticket > 0) {
System.out.println(Thread.currentThread().getName() + "---" + ticket--);
} else {
break;
}
}
線程操作不相同,鎖是共享資源對象
synchronized (card) {
card.setMoney(card.getMoney() + 1000);
System.out.println("Boy+1000---" + card.getMoney());
}
4、在同步方法中:
共享資源,線程操作相同,資源類中的鎖是this
共享資源,線程操作不相同,資源類中的鎖也是this
public synchronized void input(){
money+=100;
System.out.println("input+100----"+money);
}
(1)什么是死鎖?
死鎖是指兩個或兩個以上的進程在執行過程中,由於競爭資源或者由於彼此通信而造成的一種阻塞的現象,若無外力作用,它們都將無法推進下去。此時稱系統處於死鎖狀態或系統
產生了死鎖,這些永遠在互相等待的進程稱為死鎖進程。是操作系統層面的一個錯誤,是進程死鎖的簡稱,最早在 1965 年由 Dijkstra 在研究銀行家算法時提出的,它是計算機操作系統
乃至整個並發程序設計領域最難處理的問題之一。
(2)怎么防止死鎖?
死鎖的四個必要條件:
1、互斥條件:進程對所分配到的資源不允許其他進程進行訪問,若其他進程訪問該資源,只能等待,直至占有該資源的進程使用完成后釋放該資源
2、請求和保持條件:進程獲得一定的資源之后,又對其他資源發出請求,但是該資源可能被其他進程占有,此事請求阻塞,但又對自己獲得的資源保持不放
3、不可剝奪條件:是指進程已獲得的資源,在未完成使用之前,不可被剝奪,只能在使用完后自己釋放
4、環路等待條件:是指進程發生死鎖后,若干進程之間形成一種頭尾相接的循環等待資源關系
這四個條件是死鎖的必要條件,只要系統發生死鎖,這些條件必然成立,而只要上述條件之 一不滿足,就不會發生死鎖。理解了死鎖的原因,尤其是產生死鎖的四個必要條件,
就可以最大可能地避免、預防和 解除死鎖。所以,在系統設計、進程調度等方面注意如何不讓這四個必要條件成立,如何確 定資源的合理分配算法,避免進程永久占據系統資源。
此外,也要防止進程在處於等待狀態的情況下占用資源。因此,對資源的分配要給予合理的規划。
(3)說一下 synchronized 底層實現原理?
synchronized可以保證方法或者代碼塊在運行時,同一時刻只有一個方法可以進入到臨界區,同時它還可以保證共享變量的內存可見性。Java中每一個對象都可以作為鎖,
這是synchronized實現同步的基礎:
普通同步方法,鎖是當前實例對象
靜態同步方法,鎖是當前類的class對象
同步方法塊,鎖是括號里面的對象
(4)synchronized 和 Lock 有什么區別?
首先synchronized是java內置關鍵字,在jvm層面,Lock是個java類;
synchronized無法判斷是否獲取鎖的狀態,Lock可以判斷是否獲取到鎖;
synchronized會自動釋放鎖(a 線程執行完同步代碼會釋放鎖 ;b 線程執行過程中發生異常會釋放鎖),Lock需在finally中手工釋放鎖(unlock()方法釋放鎖),否則容易造成線程死鎖;
用synchronized關鍵字的兩個線程1和線程2,如果當前線程1獲得鎖,線程2線程等待。如果線程1阻塞,線程2則會一直等待下去,而Lock鎖就不一定會等待下去,如果嘗試獲取不到鎖,
線程可以不用一直等待就結束了;
synchronized的鎖可重入、不可中斷、非公平,而Lock鎖可重入、可判斷、可公平(兩者皆可);
Lock鎖適合大量同步的代碼的同步問題,synchronized鎖適合代碼少量的同步問題。