超詳細的java基礎知識學習(java SE、javaEE)筆記 核心重點!
識別符號
Java 的識別符號是由字母、數字、下劃線_、以及美元符$組成,但是首字母不可以是數字。Java 識別符號大小寫敏感,長度無限制,不能是 Java 中的關鍵字。命名規則:要見名知意!
u 變數要首字母小寫和駝峰原則;
u 常量的單詞字母要全部大寫,若有兩個以上的單片語成,就用下劃線"_"進行連線;
u 類名要首字母大寫和駝峰原則;
u 方法名要首字母小寫和駝峰原則,如showRun()
變數
通過變數來操縱儲存空間的資料,變數就指代這個儲存空間。空間的位置是確定的,但是裡面存放的值不確定。
區域性變數 |
存在於棧記憶體的方法中,生命週期伴隨所屬區域始終,使用前必須先宣告和初始化 |
成員變數 (例項變數) |
存在於堆記憶體的物件中,從屬物件,生命週期伴隨物件始終,自動初始化、有預設初始值 |
靜態變數 (類變數) |
存在於方法區,用static修飾,從屬類,生命週期伴隨類始終,自動初始化、有預設初始值 |
資料型別
1.分類
基本資料型別:邏輯型、文字型(char)、數值型
byte(1位元組)、short(2)、int(4)、long(8)、float(4)、double(8)
引用資料型別:類、介面、陣列
大小統一是4位元組,記錄的是其引用物件的地址!
注意:
u 實際上還有一種基本資料型別:void,其對應的包裝類是:java.lang.Void
u Java 中迚行方法呼叫傳遞引數時,基本資料型別傳遞的是該資料值本身,引用資料型別傳遞的是對物件的引用——地址,而不是物件本身;Java 中只有值傳遞!
u 轉義字元:\n換行 \r回車 \f換頁 \’引號 \\反斜槓號
2.基本資料型別物件包裝類
基本資料型別都有自己對應的包裝類:byte Byte;short Short;int Integer;long Long;boolean Boolean;float Float;double Double;char Character
基本資料型別儲存在棧記憶體中,而它們對應包裝類的例項物件儲存在棧記憶體中。
基本資料型別物件包裝類的最常見作用,就是基本資料型別和字串型別之間做轉換
(1)基本資料型別轉成字串:基本資料型別+""或基本資料型別.toString(基本資料型別值);
Integer.toString(34);//將34整數變成"34";
(2)字串轉成基本資料型別:xxx a = Xxx.parseXxx(String);
int a =Integer.parseInt("123");
double b = Double.parseDouble("12.23");
boolean b =Boolean.parseBoolean("true");
//或者可以寫成
Integer i = newInteger("123"); int num =i.intValue();
還可以進行進位制之間的互換:
(1)十進位制轉成其他進位制:toBinaryString();二 toOctalString();八 toHexString();十六
(2)其他進位制轉成十進位制:arseInt(string,radix);//其中,radix=2,8,16
JDK1.5以後,簡化了定義方式:Integer x = new Integer(4);可以直接寫成
Integer x = 4;//自動裝箱 x = x + 5;//自動拆箱,通過intValue方法。
注意:
u 使用時,如果寫成Integerx = null;上面的程式碼就會出現NullPointerException;
u 定義物件時,當數值在byte範圍內容,如果該數值已經存在,則不會在開闢新的空間;
u 對於數值型的取值範圍,它們都以常量的形式義在對應的包裝類中了。
System.out.println("基本型別:byte 二進位制位數:" + Byte.SIZE);
System.out.println("包裝類:java.lang.Byte");
System.out.println("最小值:Byte.MIN_VALUE="+ Byte.MIN_VALUE);
System.out.println("最大值:Byte.MAX_VALUE="+ Byte.MAX_VALUE);
// 以數值形式而不是字元形式將Character.MAX_VALUE輸出到控制檯
System.out.println("最小值:Character.MIN_VALUE="+(int) Character.MIN_VALUE);
System.out.println("最大值:Character.MAX_VALUE="+(int) Character.MAX_VALUE);
陣列
陣列是相同型別資料的集合。它的長度固定,一旦建立完成後長度是不可改變的。Java允許建立任何型別的陣列,而陣列的大小是int型變數,其值是非負數。
1.陣列的記憶體結構
2.賦值與複製
(1)賦值(必須是型別相同的):可以讓多個數組變數指向同一個陣列。
int[ ]arrs=arr;
(2)複製:通過clone()方法,其實新建了一個數組
int[ ] cloneArr=(int[ ])arr.clone( );
注意:當陣列型別是類(非基本資料型別)時,呼叫clone( )方法,複製的是陣列的內容即引用,並沒有複製引用指向的物件。
3.幾種常見操作
(1)排序
選擇排序法:從頭角標對應的元素開始,和每個元素進行一次比較。第一次內迴圈後,最值出現在頭角標位置
for (int x=0;x<arr.length-1 ; x++){
for(int y=x+1; y<arr.length; y++){
if(arr[x]>arr[y]){
swap(arr,x,y);}}}
氣泡排序:相鄰兩個元素以此比較,符合條件就調換順序。第一次內迴圈後,最值出現在未角標位置
for(int x=0;x<arr.length-1; x++){
for(int y=0; y<arr.length-x-1; y++){//-x:讓每一次比較的元素減少,-1:避免角標越界。
if(arr[y]<arr[y+1]){
swap(arr,y,y+1);}}}
(2)折半查詢
public static inthalfSearch (int[] arr,int key){
int min = 0,max =arr.length-1,mid;
while(min<=max){
mid = (max+min)/2;
if(key>arr[mid])
min = mid + 1;
else if(key<arr[mid])
max = mid - 1;
else
return mid;
}
return -1;}}// 如果要想實現在一個有序的數組裡面加入一個元素,要求加入後數組裡面的元素任然有有序的。此處應該改成return min
4.二維陣列
格式1:int[][] arr = new int[3][2]
l 定義了名稱為arr的二維陣列
l 二維陣列中有3個一維陣列,每一個一維陣列中有2個元素
l 一維陣列的名稱分別為arr[0],arr[1], arr[2]
l 給第一個一維陣列1腳標位賦值為78寫法是:arr[0][1] = 78;
格式2:int[][] arr = new int[3][];
l 二維陣列中有3個一維陣列,每個一維陣列都是預設初始化值null
l 可以對這個三個一維陣列分別進行初始化:
arr[0] = new int[3];
arr[1] = new int[1];
arr[2] = new int[2];
格式3:int[][] arr = {{3,8,2},{2,7},{9,0,1,6}};
l 二維陣列中的有三個一維陣列,每一個一維陣列中具體元素也都已初始化
第一個一維陣列arr[0] = {3,8,2};
第二個一維陣列arr[1] = {2,7};
第三個一維陣列arr[2] = {9,0,1,6};
l 第三個一維陣列的長度表示方式:arr[2].length;
多維陣列:由一級級的一維陣列組成,是陣列的陣列。除了最後一層陣列由陣列元素組成,其餘的陣列都是陣列變數的陣列。
記憶體結構
通過new建立的陣列和物件的例項都存放在堆記憶體中。
每一個實體都有記憶體地址值
n 實體中的變數都有預設初始化值
n 實體不在被使用,會在不確定的時間內被垃圾回收器回收
鍵盤輸入方法
1.接收一個字元:System.in.read();
char c=(char)System.in.read();
2.接收一個字串:BufferedRead類和InputStreamReader類
BufferedReaderbr=new BufferedReader(new InputStreamReader(System.in));
Stringc=br.readLine();
3.接受任意資料:Scanner類
Scanner s=new Scanner(System.in); System.out.println("請輸入你的姓名:"); String name=s.nextLine(); System.out.println("請輸入你的年齡:"); int age=s.nextInt(); System.out.println("請輸入你的工資:"); float salary=s.nextFloat(); |
Scanner s=new Scanner(System.in); System.out.println("請輸入你的年齡:"); int age=s.nextInt(); System.out.println("請輸入你的姓名:"); String name=s.next(); System.out.println("請輸入你的工資:"); float salary=s.nextFloat(); |
next()和nextLine()的區別:
在java中,next()方法是不接收空格的,在接收到有效資料前,所有的空格或者tab鍵等輸入被忽略,若有有效資料,則遇到這些鍵退出。nextLine()可以接收空格或者tab鍵,其輸入應該以enter鍵結束。
訪問控制符
使用訪問許可權符修飾方法/成員變數的可見性
訪問控制符 |
本類 |
同一個包中的類 |
子類 |
不同包中的類 |
public |
√ |
√ |
√ |
√ |
protected |
√ |
√ |
√ |
╳ |
預設 |
√ |
√ |
╳ |
╳ |
private |
√ |
╳ |
╳ |
╳ |
並不是絕對的,如果同時滿足兩個條件,要以前面的為主要標準。例如,對於A類中用protected修飾的方法test,異包中的B類繼承A類,此時可以看成B是A的子類。對於預設訪問許可權符修飾的類,如果子類和父類在同一個包中,那麼它對子類仍然可見。
跳轉語句
break |
結束其所在的迴圈而不進入下一輪迴圈;如果有迴圈巢狀則不會終止外部迴圈 |
continue |
結束當次迴圈,繼續進行下一輪迴圈 |
return |
返回資料,終止執行 |
面向物件
面向物件的特徵:封裝、繼承、多型
1.建構函式
給物件進行初始化時,物件一建立就會呼叫與之對應的建構函式。當分析事物時,該事物具備一些特性或者行為,就將這些內容定義在建構函式中。
u 名稱必須與類名一致,不能有返回值型別,沒有具體的返回值,通過new呼叫。
u 系統會預設給該類加入一個空引數的建構函式。
u 可以利用過載的形式定義多個建構函式以對不同物件進行鍼對性的初始化。
構造程式碼塊:給物件進行初始化,物件一建立就執行,而且優先於建構函式執行。定義的是不同物件共性的初始化內容,而建構函式是給對應的物件初始化。
把共性的初始化內容放在構造程式碼塊中! {共性的內容;}
2.this關鍵字
代表它所在函式所屬物件的引用。簡單的說,哪個物件在呼叫this所在的函式,this就代表哪個物件。
super與this的用法幾乎一致,this是本類物件的引用,super是父類物件的引用。
(1)this的用法:當定義類中功能(函式)時,該函式內部要用到呼叫該函式的物件時,這時用this來表示這個物件。但凡本類功能內部使用了本類物件,都用this表示。
class Person{
private String name;
private int age;
Person(int age){
this.age = age;}
//需求:給人定義一個用於比較年齡是否相同的功能。也就是是否是同齡人。
public boolean compare(Person p){
return this.age==p.age; }
}
(2)this語句:用於構造函數之間進行互相呼叫。
u this語句只能定義在建構函式的第一行!因為初始化要先執行。
u 建構函式第一行,預設有一條隱式語句this()
class Person{
private String name;
private int age;
{
System.out.println("coderun");//構造程式碼塊
}
Person(String name){
this();
this.name =name;}
Person(String name,int age){
this(name);
this.name = name;
this.age = age;}
}
3.static關鍵字
是一個修飾符,用於修飾成員(成員變數,成員函式),把物件的共享資料儲存在單獨的空間。當成員被靜態修飾後,就有兩種呼叫方式:被物件呼叫和直接被類名呼叫。
(1)特點:
u 隨著類的載入而載入,隨著類的消失而消失。說明它的生命週期最長。
u 優先於的物件存在。明確一點:靜態是先存在。物件是後存在的。
u 修飾後被所有物件所共享。
u 可以直接被類名所呼叫。
(2)注意:
u 主函式是靜態的。
u 靜態方法中不可以定義this,super關鍵字。因為靜態優先於物件存在。
u 靜態方法只能訪問靜態成員。非靜態方法既可以訪問靜態也可以訪問非靜態。
(3)什麼時候使用靜態:
什麼時候定義靜態變數(類變數)呢?
當物件中出現共享資料時,該資料被靜態所修飾存在於方法區,物件中的特有資料要定義成非靜態存在於堆記憶體中。
什麼時候定義靜態函式呢?
當功能內部沒有訪問到非靜態資料(物件的特有資料),該功能可以定義成靜態的。
繼承
1.繼承
Java只支援單繼承,不支援多繼承。但支援多層繼承,就是一個繼承體系。
子父類載入時,類成員的特點:
(1)成員變數
當子類中出現非私有的同名成員變數時,如果子類要訪問本類中的變數,用this;要訪問父類中的同名變數,用super。
(2)成員函式
當子類出現和父類一模一樣的函式時,如果子類物件呼叫該函式,會執行子類函式的內容,這叫覆蓋(或者重寫)
u 子類覆蓋父類,必須保證子類許可權大於等於父類許可權,否則編譯失敗。
u 靜態只能覆蓋靜態。
(3)建構函式
當子類物件進行初始化時,父類的建構函式也會執行,因為子類所有的建構函式第一行預設有一條隱式的語句 super(),它會訪問父類中空引數的建構函式。
u 當父類中沒有空引數的建構函式時,子類必須手動通過super語句形式來指定要訪問父類中的建構函式。
u 子類的建構函式第一行也可手動指定this語句來訪問本類中的建構函式,再通過本類指定的建構函式來訪問父類的建構函式
u 子類中至少會有一個建構函式會訪問父類中的建構函式。
u 子類建構函式呼叫父類建構函式用:super(引數) super(name);
u 子類成員函式呼叫父類成員函式用:super.父類方法 super.show();
2.abstract關鍵字
抽象。當多個類中出現相同功能定義不同功能主體時,可以進行向上抽取。這時,只抽取功能定義,而不抽取功能主體。
(1)抽象類:
u 抽象方法和抽象類都必須被abstract關鍵字修飾,抽象方法一定在抽象類中。
u 抽象類不可以用new建立物件。抽象類中的抽象方法要被使用,必須由子類複寫全部的抽象方法後才能建立子類物件進行呼叫。如果子類只覆蓋了部分抽象方法,那麼該子類還是一個抽象類。因為該子類繼承了抽象類的抽象方法。
u 抽象類只是比一般類多了抽象方法,它可定義非抽象方法,也可不定義抽象方法。
u 需要指出的是,抽象類也是有建構函式的。
(2)abstract關鍵字不能和哪些關鍵字共存?
final:被final修飾後,不能被子類繼承,無法重寫。
private: 私有後,不能被子類繼承,無法重寫。
static:如果static可以修飾抽象方法,那麼連物件都省了,直接類名呼叫就可以了。
3.final關鍵字
final作為一個修飾符,可以修飾變數,方法(函式),類
(1)修飾變數:是一個常量只能賦值一次,既可以修飾成員變數,也可以修飾區域性變數
(2)修飾方法:不可以被子類重寫但是可以過載
(3)修飾類:不能被繼承
4.介面
當抽象類中的方法都是抽象方法時,該類可以通過介面的形式來表示。它是對外暴露的規則,是對程式的擴充套件。用interface定義,用implement實現。
(1)介面定義時,格式特點:
u 介面中常見定義:常量,抽象方法。
u 介面中的成員都有固定修飾符。
常量:publicstatic final
抽象方法:publicabstract
記住:介面中的成員都是public的,以上固定的格式可以省略,java虛擬機器預設新增。
(2)介面是不可以建立物件的,因為有抽象方法,需要被子類實現。子類對介面中的抽象方法全都覆蓋後,子類才可以例項化。
(3)區分關係:
類與介面之間是實現關係,並且可以多實現
介面與介面之間是繼承關係,並且可以是多繼承
多型
1.定義
(1)體現:父類引用指向子類物件
Animal a =new Cat();//左邊是父類引用,右邊是子類物件
(2)必要條件:類之間繼承/實現的關係+重寫+父類/介面的引用指向子類物件
(3)多型提高了程式的擴充套件性,但是父類的引用只能訪問父類中的成員。可以通過強制轉換來訪問子類成員:
Animala=new Cat(); //向上轉型
Catc=(Cat)a;//向下轉型,強制轉換
可以看出,多型自始至終都是子類的物件在改變
2.多型中成員的特點:
(1)成員函式:成員函式在多型呼叫時,編譯看左邊,執行看右邊。
在編譯時期:看引用型變數所屬的類中是否有呼叫的方法。如果有,編譯通過,如果沒有編譯失敗。
在執行時期:看物件所屬的類中是否有呼叫的方法。
(2)成員變數和靜態成員函式:無論編譯還是執行,都看左邊(引用型變數所屬的類)。
3.instanceof運算子:返回值是boolean型別,判斷一個引用指向的物件所屬的類是不是某個類或者某個類的子類。左邊是一個物件,右邊是一個類
用法:物件的引用 instanceof 類名;
4.程式碼範例:主機介面
思想:先定義一個介面,讓需要用到的類實現去這個介面。然後再定義一個類去使用這個介面,此時方法的引數就是介面。那麼就可以定義介面的物件來使用重寫後的方法。
引申:可以將這兩個有相同方法的類A和B進行抽取,再把這個抽取出來的類C當做另一個類D中方法的引數,而這個方法就是完成之前那兩個方法。使用時,只需建立D類物件,就可以使用子類重寫的方法
interface PCI{ //C
public void open();
public void close();
}
class MainBoard{ //D
public void run(){
System.out.println("mainboard run ");}
public void usePCI(PCI p){//PCI p = new NetCard()//介面型引用指向自己的子類物件。
if(p!=null){
p.open();
p.close(); }
}
class NetCard implements PCI{ //A
public void open(){
System.out.println("netcard open");}
public void close(){
System.out.println("netcard close");
method();}
}
class SoundCard implementsPCI{ //B
public void open(){
System.out.println("SoundCard open");}
public void close(){
System.out.println("SoundCard close");}
}
class MainBoardDemo{
public static void main(String[] args) {
MainBoard mb = new MainBoard();
mb.run();
mb.usePCI(null);
mb.usePCI(newNetCard());
mb.usePCI(new SoundCard());}
}
Object類
Java中所有類的父類。該類定義的是所有物件都具備的功能,因此Object類中的方法可以被過載、重寫。
toString():返回該物件的字串表示
equals() :用於比較物件的引用指向的是否是同一個物件(比較的是地址)
物件比較的兩種方法:
hashcode( ) |
根據物件所在的記憶體返回一個能夠唯一代表這個物件的int值。兩物件相等,hashcode( )返回值相等;兩物件不相等,hashcode( )返回值不相等。 |
equals( ) |
比較的是地址,而不是兩個物件是否邏輯相等。 |
通常通過覆蓋hashcode( )和equals( )方法類達到比較自定義物件的目的。
public class Student(){
private String name;
private int age;
public student(name,age){
this.name=name;
this.age=age;
}
public bealoon equals(objectobj){
if(!(obj instanceof Student))
return false;
Student s=(Student)obj;
return (name.equals(s.name))&&(age==s.age);
}
public int hashCode(){
final int prime=31;
int result = 1;
result = result * prime + ((name==null)? 0 : name.hashCode());
result = result * prime +age
return result;
}
}
內部類
如果把內部類所在的類稱為外部類,那麼內部類同時具備類成員和類兩個屬性。可以分為成員內部類和區域性內部類。
l 內部類可以直接訪問外部類中的成員,包括private。因為內部類中有一個外部類的引用,格式:外部類名.this 如:外部類名.this.外部類變數/外部類方法
l 外部類要訪問內部類,必須建立內部類物件。內部類一般在外部類的內部使用,很少在外部類之外的一個類中使用這個內部類。
1.成員內部類:當內部類定義在外部類的成員位置上
² 一般內部類都預設是非靜態成員內部類
² 可以被任何成員修飾符修飾,如private、static、abstract、final。
若內部類被private修飾,就是將內部類在外部類中進行封裝,避免了外部其他類使用
若內部類被static修飾(靜態內部類),則該內部類就是一個類範疇的屬性而不是作為外部類的物件了。此時只能直接訪問外部類中的static成員,但可以通過new 外部類( ).成員的方式訪問外部非static成員
² 當內部類中定義了靜態成員,該內部類必須是static的;當外部類中的靜態方法訪問內部類時,內部類也必須是static的
² 在外部其他類中,訪問內部類,需要建立外部類裡面內部類的物件。成員內部類的全限定名是:外部類名.內部類名
直接訪問非static內部類的成員時,格式:
Outer out=new Outer();
Inner in =out.new Inner();
//可以簡寫成
Outer.Inner in = newOuter().new Inner();
in.function();//訪問非靜態方法
Outer.Inner.staticFunction();//訪問靜態方法
直接訪問static內部類的成員時,格式:
StaticInner in =new Outer.StaticInner();
in.function( );//訪問非靜態方法
StaticInner.staticFunction();//訪問靜態方法
2.區域性內部類:內部類定義在外部類方法的區域性位置上
² 可以直接在外部類方法中建立區域性內部類的物件,來呼叫區域性內部類的方法。
² 不能使用訪問許可權控制符和 static 修飾符;
² 可以直接訪問外部類中的成員,但不可以訪問外部類方法中區域性的變數(和區域性內部類等一個層次),除非這個變數被final修飾
class Outer{
int x = 3;
void method(final int a){
final int y = 4;//外部方法中區域性的變數,被final修飾
class Inner{
void function(){
System.out.println(y);}}
new Inner().function();
}
}
3.匿名內部類:沒有名字的內部類(無構造方法)。是內部類的簡寫格式,可以簡化程式碼
² 定義匿名內部類的前提:該內部類必須繼承一個抽象類或者實現介面。但是不能顯式地繼承或實現。所以匿名內部類其實就是一個匿名子類物件,而且是帶內容的物件。
² 匿名內部類能使用訪問許可權控制符和 static 修飾符
² 格式:new 父類或者介面(){定義子類的內容}
² 如果多次呼叫匿名內部類中的方法,可以通過多型建立匿名內部類的物件再呼叫。
abstract class AbsDemo{
abstract void show();
}
class Outer{
int x = 3;
new AbsDemo(){
int num = 9;
void show(){System.out.println("num==="+num);}
}.show;
//利用多型實現多次呼叫匿名內部類方法
AbsDemo c=new AbsDemo(){
int num = 9;
void show(){System.out.println("num==="+num);}
}
c.show;
}
異常
Throwable
|--Error:嚴重的問題,一般不編寫針對性的程式碼對其進行處理
|--Exceptoin:在執行時出現的一些異常,可以使用針對性的處理方式進行處理
|--RuntimeException
異常體系中的所有類以及建立的物件都具備可拋性。可以被throw和throws關鍵字所操作!
1.Throwable中方法(對捕獲到的異常物件進行的常見方法操作)
String getMessage() |
獲取異常資訊 |
String toString() |
獲取異常類名和異常資訊 |
void printStackTrace() |
獲取異常類名、異常資訊以及異常的位置 |
String printStackTrace(PrintStream s) |
將異常內容儲存在日誌檔案中 |
2.異常處理:try-catch-finally語句
try{需要被檢測的程式碼;}
catch(異常類 變數){處理異常的程式碼;}
finally{一定會執行的語句;(通常是關閉資原始碼,因為資源必須被釋放!)}
² 有三種方式:try-catch-finally; try-catch; try-finally
² finally程式碼塊只有一種情況不會被執行:在之前執行了System.exit(0) 系統退出
² 一個 try 塊後能跟多個 catch 塊。多個 catch 塊的語法像這樣:
3.throws和throw
throws:在方法宣告中丟擲異常,用在函式上,後面跟異常類名(可多個,用逗號隔開)
throw:在方法程式碼中丟擲異常,用在函式內,後面跟異常物件
注:在函式內部使用throw,要麼在內部try-catch處理(沒有catch就沒有被處理!);要麼在函式上宣告讓呼叫者處理。(RuntimeException除外)
4.自定義異常:必須是繼承Exception或者其子類!
一般通過建構函式定義異常資訊,通過throw將自定義異常丟擲。
class MyException extendsException{
MyException(String message){
super(message);}}
自定義負數異常
class FuShuException extendsException {
private int value;
FuShuException(String msg){
super(msg);}
}
class Demo{
int div(int a,int b)throwsFuShuException{
if(b<0)
//手動通過throw關鍵字丟擲一個自定義異常物件
throw new FuShuException("出現了除數是負數的情況-",b);
return a/b;}
}
class MyExceptionDemo{
public static void main(String[] args) {
Demo d = new Demo();
try{
int x = d.div(4,-9);
System.out.println("x="+x);
}catch (FuShuException e){
System.out.println(e.toString());}
System.out.println("over");}
}
5. 異常有兩種:
編譯時異常 |
編譯時,如果沒有處理(沒有throw也沒有try),編譯失敗。該異常被標識,代表這可以被處理 |
執行時異常 |
編譯時,不需要處理,編譯器不檢查。該異常的發生,建議不處理,讓程式停止。需要對程式碼進行修正 |
RuntimeException類:執行時異常。
l RuntimeException以及其子類如果在函式中被throw丟擲,可以不用在函式上宣告;
l RuntimeException以及其子類如果在函式上被throws宣告,可以不通過呼叫者進行處理。
l 該異常(RuntimeException類及其子類)發生,就是希望程式停止。因為在執行出現了無法繼續運算的情況時,只有當停止程式後,才可對程式碼進行修正。因此自定義異常時:如果該異常的發生,無法在繼續進行運算,就讓自定義異常繼承RuntimeException類。
6.異常在子父類覆蓋中的體現:
l 如果父類或者介面的方法中沒有異常丟擲,那麼子類在覆蓋方法時,也不可以丟擲異常。如果子類方法發生了特有的異常,就必須要進行try處理。絕對不能拋!
l 子類在覆蓋父類時,如果父類方法丟擲異常,那麼子類只能丟擲父類異常的子類或集合
7.總結:異常的處理原則
l 處理方式有兩種:try或者 throws。
l 宣告異常時,要宣告為具體的異常,以便具體的處理。呼叫到丟擲異常的功能時,宣告幾個,就處理幾個。
l 一個try可對應多個catch。但是最好不要定義多餘的catch塊,多個catch塊中的異常出現繼承關係,父類異常的catch塊放在最下面。
l catch內,需要定義針對性的處理方式。不要簡單地定義e.printStackTrace或者輸出語句
l 當捕獲到的異常,本功能處理不了時,可以繼續在catch中丟擲。
try{
throw new AException();
}catch (AException e){
throw e;}
如果異常不屬於該功能出現的異常,並且處理不了。可以將異常轉換後,再丟擲和該功能相關的異常。 下左
try{ throw new AException(); }catch (AException e){ throw new BException(); } |
try{ throw new AException(); }catch (AException e){ 先對AException處理; throw new BException();} |
如果異常不屬於該功能出現的異常,但是可以處理。可將異常產生的和本功能相關的問題提供出去讓呼叫者知道並處理;或將捕獲異常處理後,再轉換成新的異常丟擲。上右
//有一個圓形和長方形,都可以獲取面積。對於面積如果出現非法的數值,視為是獲取面積出現問題。問題可以通過異常來表示。
class NoValueExceptionextends RuntimeException{
NoValueException(String message){
super(message);}
}
interface Shape{
void getArea();
}
class Rec implements Shape{
private int len,wid;
Rec(int len ,int wid){
if(len<=0 || wid<=0)
throw new NoValueException("出現非法值");
this.len = len;
this.wid = wid;}
public void getArea(){
System.out.println(len*wid);}
}
class Circle implementsShape{
private int radius;
public static final double PI = 3.14;
Circle(int radius){
if(radius<=0)
throw new NoValueException("非法");
this.radius = radius;}
public void getArea(){
System.out.println(radius*radius*PI);}
}
class ExceptionTest{
public static void main(String[] args) {
Rec r = new Rec(3,4);
r.getArea();
Circle c = new Circle(-8);
c.getArea();
System.out.println("over");}
}
包(package)
用來對類檔案進行分類管理,給類提供多層名稱空間。包名必須是合法的識別符號名,寫在程式檔案的第一行。如果一個原始檔不是在default package中,那麼此原始檔的第一有效行必須是能正確表示原始檔所在包的package語句。
包的全限定名:從原始碼根目錄(src)開始,包名之間有點號隔開。
類的全限定名:類所在的包的全限定名.類名。
u 使用包中的類時都是要使用類的全限定名,包括建立類的物件等。但是使用類的引用則與全限定名沒有任何關係。Carcar=new Common.car();
u 包與包之間的訪問時:被訪問的包中類的許可權必須是public;類中的成員許可權必須是public或者protected。protected是為其他包中的子類提供的一種許可權
u 一個類使用同一個包中的其他類時,可以省略類的全限定名。
u 編譯:編譯包中的類時,需要進入原始碼的根目錄,然後根據類原始檔的路徑和原始檔名進行編譯,否則編譯失敗。
1.import語句:
u 兩種語法格式:
引入一個類:import 類全限定名;
引入一個包中的所有類:import 包全限定名.*; 不包含子包中的類!
u 一個程式檔案中只有一個package,但可以有多個import。
u 用來匯入包中的類,而不是匯入包中的包。
u Java編譯器預設引入java.lang中的所有類。
u 當類中的原始碼中使用了沒有全限定名的其他類,Java編譯器尋找這個類的順序規則:使用第1種格式引入的類;使用與這個類中同一個包中的類和使用第2種引入的類。
2.jar包
Java的壓縮包。方便專案的攜帶和使用,只要在classpath設定jar路徑即可
u 資料庫驅動,SSH框架等都是以jar包體現的。
u 通過jar.exe工具對jar的操作:
建立jar包 |
jar -cvf mypack.jar packa packb |
檢視jar包 |
jar -tvf mypack.jar [>定向檔案] |
解壓縮 |
jar -xvf mypack.jar |
自定義jar包的清單檔案 |
jar –cvfm mypack.jar mf.txt packa packb |
多執行緒
1.程序與執行緒
程序:是一個正在執行中的程式,負責整個程式的記憶體分配
執行緒:在一個程序中負責一條執行路徑。執行緒在控制著程序的執行。
多執行緒:一個程序中可以有多條執行路徑
JVM啟動時就啟動了多個執行緒,至少有兩個執行緒是可以確定的:
執行main函式的執行緒(主執行緒);負責垃圾回收的執行緒
Java給我們提供了物件執行緒這類事物的描述,Thread類。它有一些常用方法:
static Thread currentThead( ):
String getName( ):獲取名稱
static voidsleep(time)throws InterruptedException:
2.建立方法
(1)繼承Thread類:
定義類繼承Thread→覆蓋Thread類中的run( )方法→建立類的物件呼叫start( )方法
run( )方法:用於儲存執行緒要執行的程式碼;start( )方法:啟動執行緒和呼叫run方法
(2)實現Runnable介面:
定義類實現Runnable介面→覆蓋介面的run( )方法→建立Thread類的物件並將Runnable介面的子類物件作為引數傳給Thread的建構函式→呼叫Thread物件的start( )方法
3.執行緒的四種狀態:
4.同步(synchronized)
(1)導致執行緒出現安全問題的原因:多個執行緒訪問出現延遲;執行緒隨機性。
解決辦法是,在執行操作共享資料語句的過程中,只能讓一個執行緒都執行完後,其他執行緒才可以參與執行。java專業的解決方法就是:同步。
同步,解決了多執行緒的安全問題,但是耗費資源,降低程式的執行效率
(2)同步的前提:需要兩個或者兩個以上的執行緒+多個執行緒使用的是同一個鎖。
(3)同步的兩種表現形式:
同步程式碼塊:synchronized(物件){需要被同步的程式碼};
同步函式:在函式上加上synchronized修飾符
同步可以解決安全問題的根本原因就在那個物件上。該物件就如同鎖,只有持有鎖的執行緒才可以在同步中執行。
Ø 區別:同步程式碼塊使用的鎖是任意物件(可以建立obj物件);同步函式使用的鎖是this。
Ø 注意:對於static同步函式,使用的鎖不是this。是類名.class,即該類的位元組碼檔案物件
(4)死鎖:同步中巢狀同步。
4.執行緒間通訊:多個執行緒操作同一個資源,但是操作的動作不同。
字串
String類
String類是對字串的事物的描述,而字串是一個特殊的物件,注意,字串一旦被初始化就不可以被改變!因此,複製字串等修改操作都是重新建立一個新的字串!
String s1 = “abc”; //s1是一個常量,“abc”是一個物件
String s2 = newString(“abc”);
char chars[]={'a','b','c'};
String s3=new String(chars);
s1和s2有什麼區別? s1在記憶體中只有一個物件,s2在記憶體中有兩個物件。
String s1 = “abc”這個語句會先檢查字串常量池是否存放這個”abc”這個字串物件,如果沒有存在,那麼就會在字串常量池中建立這個字串物件,如果存在直接返回該字串的記憶體地址值。就一個物件
String s2= new String(“abc”) 這個語句首先會先檢查字串常量池中存不存在jack這個字串物件,如果不存在就會建立,如果存在就返回記憶體地址值。建立了出來之後,new String這個語句就會在堆記憶體中開闢一個字串物件。總共兩個物件。
常用方法:
說明 |
方法 |
|
獲取 |
獲取字串長度 |
int length( ) |
返回指定位置的字元 |
char charAt(int index) |
|
返回的str在字串中第一次出現的位置 |
int indexOf(String str) |
|
指定位置開始返回str在字串中出現的位置 |
int indexOf(String str, int fromIndex) |
|
判斷 |
字串中是否包含某一個子串 |
boolean contains(str) |
字串中是否有內容 |
boolean isEmpty( ) |
|
字串是否是以指定內容開頭 |
boolean startsWith(str) |
|
字串是否是以指定內容結尾 |
boolean endsWith(star) |
|
² 字串內容是否相同 |
boolean equals(str) |
|
字串內容是否相同,忽略大小寫 |
boolean equalsIgnoreCase( ) |
|
轉換 |
將字元陣列轉成字串 |
String(char[]) |
將字元陣列中的一部分轉成字串 |
String(char[],offset,count) |
|
u 將字串轉成字元陣列 |
char[] toCharArray() |
|
將位元組陣列轉成字串 |
String(byte[]) |
|
將位元組陣列中的一部分轉成字串 |
String(byte[],offset,count) |
|
u 將字串轉成位元組陣列 |
byte[] getBytes( ) |
|
將基本資料型別轉成字串 |
static String valueOf(int/double/...) |
|
將字串轉成大寫或小寫 |
String toUpperCase( )/toLowerCase( ) |
|
替換 |
將原來的字串替換成的指定的字串 |
String replace(oldchar,newchar) |
切割 |
根據給定正則表示式的匹配拆分此字串 |
String[] split(string regex) |
子串 |
返回一個新的字串(原字串的子串) |
String substring(begin) |
返回一個新的字串(原字串的子串) |
String substring(begin,end) |
|
除空 |
將字串兩端的多個空格去除 |
String trim( ) |
比較 |
² 對兩個字串進行自然順序的比較 |
int compareTo(string) |
StringBuffer類
是一個字串緩衝區,一個容器。字串的組成原理就是通過該類實現的。它的特點是:
² 長度是可變;
² 可以位元組操作多個數據型別;
² 最終會通過toString方法變成字串。
常用方法:
新增:StringBuffer append():將指定資料作為引數新增到已有資料結尾處。
StringBufferinsert(index,資料):可以將資料插入到指定index位置。
刪除:StringBuffer delete(start,end):刪除緩衝區中的資料,包含start,不包含end。
StringBufferdeleteCharAt(index):刪除指定位置的字元。
修改:StringBufferreplace(start,end,string); voidsetCharAt(int index, char ch) ;
獲取:char charAt(int index);int indexOf(String str); Stringsubstring(int start, int end);
反轉:StringBuffer reverse();
將緩衝區中指定資料儲存到指定字元陣列中:
voidgetChars(int srcBegin, int srcEnd, char[] dst, int dstBegin)
StringBuffer sb= newStringBuffer(“abcdef”);
char [] chs=new char[4];
sb.getChars(1,4,chs,1);//在緩衝區中,從1開始到4結束取字元,放在chs陣列中,從1開始
for(intx=0;x<chs.length;x++){
System.out.println(“char[“+x+“]=“+char[x]+“;“);
}
結果:
char[0]= ;
char[1]=b;
char[2]=c;
char[3]=d;
//清空緩衝區
sb.delete(0,sb.length());
StringBuilder類
與StringBuffer用法幾乎一致,區別:StringBuffer執行緒同步,StringBuilder執行緒不同步
Ø 三者比較
String:在字串不經常變化時使用,如:常量的宣告、少量的變數運算
StringBuffer:在字串進行頻繁的運算(拼接、替換、刪除等),並且執行在多執行緒中
StringBuilder:在字串進行頻繁的運算(拼接、替換、刪除等)時使用
Ø 字串連線
+:String類使用的,返回新的字串
Concat():String使用的,返回新的字串
append():StringBuffer使用,返回的是原字串緩衝區,不是新是字串!
集合框架
集合:儲存物件的容器,儲存的是物件的引用
(1)與陣列的比較
陣列雖可以儲存物件,但長度是固定的,集合長度是可變的
陣列中還可以儲存基本資料型別,而集合只能儲存物件
集合和陣列儲存的都是對物件的引用,而不是物件本身
(2)特點:
只用於儲存物件;
一個集合可以同時儲存不同型別的物件;
長度是可變的。
(3)集合框架的常用介面及其子介面
Collection
|--List(列表):有索引,可存放重複元素,元素存取是有序的
|--ArrayList:底層資料結構是陣列結構,查詢速度快,增刪速度慢
|--LinkedList:底層資料結構是連結串列結構,查詢速度慢,增刪速度快
|--Vector:底層資料結構是陣列結構,執行緒安全,但速度慢,已被ArrayList替代
|--Set(集):無索引,不可以存放重複元素,元素存取是無序的
|--HashSet:底層資料結構是雜湊表,存取速度快
|--TreeSet:底層資料結構是二叉樹,可以對Set集合中的元素進行排序
|--LinkedHashSet:保留儲存順序, 並且可以過濾重複元素
Map:儲存的是鍵值對,需要保證鍵的唯一性
|--Hashtable:底層資料結構是雜湊表,執行緒安全,速度慢,不允許存放null鍵和null值
|--HashMap:底層資料結構是雜湊表,速度快,允許存放null鍵和null值。
|--LinkedHashMap
|--TreeMap:底層資料結構是二叉樹,對鍵進行排序,排序原理與TreeSet相同
1.Collection
1.1共性功能
新增:add(Object e); addAll(collection);
刪除:remove(Objecte); removeAll(collection); clear();移除所有元素
判斷:contains(Objecte);是否包含指定元素 isEmpty();
獲取:iterator(); size();返回此collection 中元素的個數
獲取交集:retainAll();
集合變陣列:toArray();
1.2迭代器
迭代是對集合中的元素的一種取出方式。對 Collection 進行迭代的類,稱其為迭代器。迭代器作為集合的物件,該物件比較特殊,不能通過new直接建立物件,該物件是以內部類的形式存在於每個集合類的內部。
Itreator介面是集合的迭代器介面類,定義了常見的迭代方法
boolean hasNext():判斷集合中是否有元素,如果有元素可以迭代,就返回true
E next():返回迭代的下一個元素
void remove():從迭代器指向的集合中移除迭代器返回的最後一個元素
遍歷迭代器有兩種用法 :
for(Iterator iter =al.iterator();iter.hasNext(); ){ Object obj =iter.next(); } |
Iterator iter =al.iterator(); while(iter.hasNext()){ Object obj =iter.next();} |
對於用法一,在for迴圈裡,使用完了ite物件後釋放了記憶體,更優化!
可使用迭代器清空集合
Collection coll = newArrayList();
coll.add("aaa");
coll.add("bbb");
coll.add("ccc");
System.out.println(coll);
Iterator it =coll.iterator();
while (it.hasNext()) {
it.next();
it.remove();
}
注意事項:
l 迭代器在Collcection介面中是通用的,它替代了Vector類中的Enumeration(列舉)。
l 迭代器的next方法是自動向下取元素,要避免出現NoSuchElementException。
l 迭代器的next方法返回值型別是Object,所以要記得強制型別轉換!
1.3 List
1.3.1 List介面的特有方法
凡是可以操作角標的方法都是該體系特有的方法。
增:add(index,element); addAll(index,Collection);
刪:remove(index);
改:set(index,element);
查:get(index); subList(from,to); listIterator(); intindexOf(obj):獲取指定元素的位置
注:List集合特有的迭代器ListIterator是Iterator的子介面。Iterator只能對元素進行判斷,取出,刪除的操作,如果想要其他的操作如新增,修改等,就需要使用其子介面:ListIterator。
1.3.2 ArrayList
陣列的記憶體空間地址是連續的。ArrayList底層維護了一個Object[]用於儲存物件,預設陣列的長度是10。可以通過 new ArrayList(20)顯式的指定用於儲存物件的陣列的長度。當預設的或者指定的容量不夠儲存物件的時候,容量自動增長為原來的容量的1.5倍。
由於ArrayList是陣列實現,陣列是可以直接按索引查詢,所以查詢時較快;在增和刪的時候會牽扯到陣列增容, 以及拷貝元素. 所以慢。
1.3.3 LinkedList
在記憶體中的地址不連續,需要讓上一個元素記住下一個元素。所以每個元素中儲存的有下一個元素的位置。雖然也有角標,但是查詢的時候,需要從頭往下找,顯然是沒有陣列查詢快的。但是,連結串列在插入新元素的時候,只需要讓前一個元素記住新元素,讓新元素記住下一個元素就可以了;刪除元素時讓前一個元素記住後一個元素, 後一個元素記住前一個元素。這樣的增刪效率較高。
特有方法介紹:
u 方法:addFirst(Ee); addLast(E e); removeFirst(); removeLast(); getFirst(); getLast();
u 資料結構:棧:先進後出 push() pop() 佇列:先進先出offer() poll()
u 回逆序的迭代器物件:descendingIterator(); 返
u 如果集合中沒有元素,獲取或者刪除元素式拋:NoSuchElementException
LinkedListlist = new LinkedList();
list.add("aa");
list.add("bb");
list.add("cc");
Iteratordit = list.descendingIterator();
while(dit.hasNext()) {
System.out.println(dit.next());}
}
用LinkedList模擬佇列(先進先出)和和堆疊(後進先出)的資料結構
//堆疊(後進先出) 資料結構
LinkedListlist = new LinkedList();
// 壓棧,先進後出
list.push("西遊記");
list.push("三國演義");
list.push("石頭記");
list.push("水滸傳");
System.out.println(list);
// 彈棧
Stringstr1 = (String) list.pop();
System.out.println(str1);
Stringstr2 = (String) list.pop();
System.out.println(str2);
Stringstr3 = (String) list.pop();
System.out.println(str3);
Stringstr4 = (String) list.pop();
System.out.println(str4);
System.out.println(list.size());//0
System.out.println(list);//[]
//佇列,先進先出
LinkedListlist = new LinkedList();
// 佇列,先進先出
list.offer("西遊記");
list.offer("三國演義");
list.offer("石頭記");
list.offer("水滸傳");
System.out.println(list);
// 出佇列
System.out.println(list.poll());
System.out.println(list.poll());
System.out.println(list.poll());
System.out.println(list.poll());
System.out.println(list.size());
System.out.println(list.peek());// 獲取佇列的頭元素,但是不刪除
System.out.println(list.peekFirst());// 獲取佇列的頭元素,但是不刪除
System.out.println(list.peekLast());// 獲取佇列的最後一個元素但是不刪除
1.4Set
1.4.1 HashSet
通過hashCode方法和equals方法來保證元素的唯一性!
如果元素的HashCode值相同,才會判斷equals是否為true;
如果元素的hashcode值不同,不會呼叫equals。
class Person{
private String name;
private int age;
Person(String name,int age){
this.name = name;
this.age = age;}
public int hashCode(){
System.out.println(this.name+"....hashCode");
return name.hashCode()+age*37;
}
public boolean equals(Object obj){
if(!(obj instanceof Person))
return false;
Person p = (Person)obj;
System.out.println(this.name+"...equals.."+p.name);
return this.name.equals(p.name) && this.age ==p.age;
}
}
class HashSetTest {
public static void main(String[] args) {
HashSet hs = new HashSet();
hs.add(new Person("a1",11));
hs.add(new Person("a2",12));
hs.add(new Person("a3",13));
hs.add(new Person("a1",13));
Iterator it = hs.iterator();
while(it.hasNext()){
Person p = (