java集合结构----集合框架以及背后的数据结构
2.選擇排序和冒泡排序的原理和區(qū)別:
1.Collection常見的方法實(shí)例
1)咱們的JAVA集合框架是定義在java.util包底下的一組接口和實(shí)現(xiàn)類
2)實(shí)現(xiàn)Iterable接口的類可以通過for each來進(jìn)行遍歷我們的集合
3)實(shí)現(xiàn)list接口都屬于線性結(jié)構(gòu),比如說順序表,鏈表,隊(duì)列,戰(zhàn)
4)Queue:隊(duì)列,它本身也是一個(gè)線性結(jié)構(gòu),有一種隊(duì)列不是線性的,比如說優(yōu)先級(jí)隊(duì)列(沒實(shí)現(xiàn)Dqueue接口)
(隊(duì)尾進(jìn),隊(duì)頭出)
5)DeQueue:雙端隊(duì)列(兩端都可以進(jìn)出)
6)實(shí)現(xiàn)Set接口的類是不能重復(fù)的
7)sortSet實(shí)現(xiàn)了set接口,不僅僅可以放重復(fù)的元素,還可以在存放元素的時(shí)候進(jìn)行排序咱們的treeset就繼承了SortedSet這個(gè)類,但是HashSet就沒有實(shí)現(xiàn)SortedSet這個(gè)類
8)LinkedList本身可以做雙向鏈表,可以做普通的隊(duì)列,還可以做雙端隊(duì)列,他實(shí)現(xiàn)了Queue和list接口
9)PriorityQueue實(shí)現(xiàn)了Queue接口
10)實(shí)現(xiàn)Map接口的類是不可以通過foreach來進(jìn)行遍歷,TreeMap和TreeSet底層都是紅黑樹,TreeMap擁有排序的功能,HashMap沒有排序的功能
Collection的常用接口:
1)boolean add(E e)添加元素e放到集合里面
2)void clear()清除集合里面的所有元素,先通過循環(huán)的方式把每一個(gè)元素都置為空,再將我們的size變成0
3)boolean IsEmpty()判斷集合里面是否沒有任何元素
4)boolean remove(E e)如果元素e出現(xiàn)在集合里面,那么就刪除一個(gè)
5)int size()返回集合中的元素個(gè)數(shù)
沒有g(shù)et方法,沒有獲取元素的方法
,指定集合類中放哪些元素的時(shí)候,一定要指定類型,<>里面不要用簡單類型
Collection<Integer> collection=new ArrayList<>();//1添加某些元素collection.add(1);collection.add(2);collection.add(3);//2刪除某個(gè)元素collection.remove(1);//注意這里面的clear是針對集合類里面的元素全部進(jìn)行清空//3打印集合類里面的元素System.out.println(collection);//打印結(jié)果是2,3//4把集合類中的所有元素放到數(shù)組中Object[] arr1= collection.toArray();//5判斷是否為空System.out.println(collection.isEmpty());//6獲取到集合類里面的長度System.out.println(collection.size()); Map<String,String> map=new HashMap<>();map.put("及時(shí)雨","宋江");map.put("國民女神","高圓圓");Set<Map.Entry<String,String>> set=map.entrySet();//1)當(dāng)我們調(diào)用這個(gè)方法之后,會(huì)把哈希表中的每一對key和value包裝成一個(gè)整體,相當(dāng)于把兩個(gè)元素放到一個(gè)大盒子里面,變成一個(gè)元素//2)然后內(nèi)存就會(huì)把每一個(gè)大盒子放到Set里面,這個(gè)大盒子就是Map.Entry(String,String)類型for(Map.Entry<String,String> sb:set){System.out.println(sb.getKey());System.out.println(sb.getValue());}Map的常用方法:
1)V? get(object k)根據(jù)K查找對應(yīng)的value
2)V? getOrDefault(Object K,V defaultValue)根據(jù)K查找對應(yīng)的V,查不到就用我們制定的默認(rèn)值來進(jìn)行代替
3) V put(K k,V v)存放鍵值對
4)boolean containsKey(Object K),boolean containsValue(Object V)判斷是否存在Key和Value
2.簡單類型和包裝類(針對的是基本數(shù)據(jù)類型)
1)將簡單的數(shù)據(jù)也是可以面向?qū)ο蟮?#xff0c;讓整數(shù)與字符串之間的轉(zhuǎn)換更加方便,只需要調(diào)用一個(gè)方法即可,就不需要自己寫一個(gè)方法來進(jìn)行實(shí)現(xiàn),幫我們對數(shù)據(jù)進(jìn)行處理,String不是一個(gè)包裝類
byte Byte short Short int Integer long Long float Float double Double char Character boolean Boolean我們在對數(shù)據(jù)類型進(jìn)行轉(zhuǎn)換的時(shí)候
//1將字符串轉(zhuǎn)化成整數(shù)String str="123";int a=Integer.valueOf(str);int b=Integer.parseInt(str);//2將整數(shù)轉(zhuǎn)化成字符串String str1=Integer.toString(a);int與Integer的區(qū)別
1)類型不同:Integer是對象類型,int是基本數(shù)據(jù)類型,Integer是int的包裝類
2)Integer的默認(rèn)值是null,int的默認(rèn)值是0,當(dāng)new Integer()的時(shí)候?qū)嶋H上是生成一個(gè)指針指向?qū)ο?#xff0c;但是int直接儲(chǔ)存數(shù)值;
3)Integer變量需要實(shí)例化之后才能使用,int則不需要。
4)Integer變量和int變量進(jìn)行比較時(shí),java會(huì)自動(dòng)將Integer對象拆包裝為int,然后進(jìn)行比較,實(shí)際上就變?yōu)閮蓚€(gè)int變量比較。
5)Integer實(shí)際是對象的引用,指向此new的Integer對象;int是直接存儲(chǔ)數(shù)據(jù)值
6)包裝類型可以用于泛型,但是簡單類型是不可以的
2)裝箱和拆箱
裝箱/裝包:將一個(gè)簡單的數(shù)據(jù)類型轉(zhuǎn)化成包裝類型Integer.valueOf();
拆箱/拆包:將一個(gè)包裝類型轉(zhuǎn)化成簡單的數(shù)據(jù)類型intValue();
//1.自動(dòng)裝箱裝包,隱式Integer a=10;//看似是將一個(gè)簡單類型轉(zhuǎn)化成包裝類型,本質(zhì)上就是調(diào)用了Integer.valueOf方法//2.自動(dòng)進(jìn)行拆箱,拆包,隱式int b=a;//在這里面默認(rèn)調(diào)用了Integer的intValue方法,自動(dòng)進(jìn)行拆包 //1.下面都是裝包,是顯式的進(jìn)行裝包Integer t1=Integer.valueOf(123);Integer t2=new Integer(123);Integer t1=(Integer)123;//2.下面是拆包,是顯式的進(jìn)行拆包int a=t1.intValue();double b=t1.doubleValue();float c=t1.floatValue();int f=(int)t1; 下面是隱式的進(jìn)行裝包和拆包1)Integer a=123;//123本來是一個(gè)簡單數(shù)據(jù)類型,但是最終變成了包裝類,這個(gè)過程就是裝箱 //上面的過程中底層默認(rèn)調(diào)用了Integer.valueOf()方法2)int b=a;//a本來是一個(gè)包裝類,就將一個(gè)包裝類型轉(zhuǎn)化成簡單的數(shù)據(jù)類型,拆箱 //他的底層默認(rèn)調(diào)用了intValue()方法 _________________________________________________________________________________________Integer a=10;System.out.println(a.value); 這會(huì)訪問失敗,因?yàn)関alue字段是默認(rèn)是Integer包裝類中的用private修飾的字段 所以說簡單數(shù)據(jù)類型在包裝類中就是一個(gè)Value屬性 下面是顯示進(jìn)行裝包和拆包//顯示進(jìn)行裝包Integer integer=new Integer(123);Integer s1=Integer.valueOf(123);//顯示進(jìn)行拆包int a=s1.intValue();double b=s1.doubleValue(); Integer a=123;Integer b=123;System.out.println(a==b);//trueInteger c=129;Integer d=129;System.out.println(c==d);//false上面都涉及了自動(dòng)裝包 public static Integer valueOf(int i) {? ? ? if(i>IntegerCache.low&&i<=IntegerCache.high)(low=-128,high=127){ return Integer.Cache[i+(-IntegerCache.low)](注意,這里面的Cache是一個(gè)數(shù)組)}return new Integer(i);//new 對象 }1)當(dāng)我們傳入的數(shù)據(jù)是在-128-127之間,會(huì)返回一個(gè)catche數(shù)組的值
當(dāng)我們傳入127的時(shí)候,返回的是Cache[255],此時(shí)128是最大的數(shù)據(jù),此時(shí)得到的數(shù)組下標(biāo)就是255;當(dāng)我們傳入-128的時(shí)候,返回的是Cache[0]
注意這個(gè)數(shù)組里面的范圍下標(biāo)是0-255;
Cache[0]=-128; Cache[1]=-127;.........Cache[255]=127
總結(jié):當(dāng)我們傳入的數(shù)據(jù)在-128-127內(nèi),會(huì)先進(jìn)行計(jì)算下標(biāo),再會(huì)返回?cái)?shù)組里面所存放的值;返回的是數(shù)值;
掏出了這個(gè)數(shù)據(jù)范圍之后,就會(huì)在堆上new 一個(gè)新的對象,返回的是一個(gè)對象,此時(shí)我們要進(jìn)行比較的是引用;
Integer的比較方式:
1)==只能用于非Integer的值,在-127~128直接按照值的方式來進(jìn)行比較,超過這個(gè)范圍就不適用了,在valueOf方法里面,Integer的取值在-128~127之間,他會(huì)進(jìn)行復(fù)用原來有的對象,否則就會(huì)直接在堆上面new Integer()對象出來
2)使用equals方法,在Integer中重寫了equals方法:通過拆箱來進(jìn)行比較
public boolean equals(Object obj) {if (obj instanceof Integer) {return value == ((Integer)obj).intValue();}return false;}3)Integer實(shí)現(xiàn)了Compareable接口,并且重寫了里面的compareTo方法,取出Integer對象的value屬性來進(jìn)行比較:前一個(gè)數(shù)-后一個(gè)數(shù)
public int compareTo(Integer anotherInteger) {return compare(this.value, anotherInteger.value); } public static int compare(int x, int y) {return (x < y) ? -1 : ((x == y) ? 0 : 1); }4)直接進(jìn)行運(yùn)算:我們可以直接將兩個(gè)值進(jìn)行相減,來進(jìn)行判斷,如果說相減的值是0,那么說明他們相等
5)我們可以進(jìn)行調(diào)用里面的intValue方法來進(jìn)行比較:
Integer a=new Integer(100);Integer b=new Integer(100);System.out.println(a.intValue()==b.intValue());6)通過異或的方式來進(jìn)行比較:不同為1,相同為0
3.泛型
問題:下面是一個(gè)簡單的順序表,我們在這里面實(shí)現(xiàn)的一個(gè)順序表,是存放的數(shù)據(jù)類型只有int類型,這就會(huì)很不通用,如果我們想什么樣的類型的數(shù)據(jù)都想要放進(jìn)去,就要把這個(gè)數(shù)組的類型設(shè)置成Object類型
能不能啥樣的類型都可以存放呢?
class MyArraylist{private int[] arr1;private int usedsize;public MyArraylist(){this.arr1=new int[10];}public void add(int pos,int val){this.arr1[pos]=val;}public int get(int pos){return this.arr1[pos];}}改成下面的代碼之后,還是發(fā)現(xiàn)有問題:
1)這個(gè)代碼太通用了,什么樣類型的數(shù)據(jù)都可以進(jìn)行存放不能指定元素,下面的代碼里面的元素既可以存放int,又可以存放String,完全就是一個(gè)大雜燴,能不能只讓他存放整型或者是
字符串類型呢?
2)取出我們的Object順序表中的元素,因?yàn)樵蹅兎祷氐氖荗bject類型,還需要進(jìn)行強(qiáng)制類型轉(zhuǎn)換,這是很麻煩的;
我們現(xiàn)在想要做到下面幾件事:
1)能不能指定我這個(gè)順序表的類型,只能存放一種數(shù)據(jù)類型?
2)指定類型之后,是不是就只能存放指定類型的數(shù)據(jù)呢?
3)取出數(shù)據(jù)之后,可不可以不進(jìn)行數(shù)據(jù)類型轉(zhuǎn)換?
static class MyArraylist{private Object[] arr1;private int usedsize;public MyArraylist(){this.arr1=new Object[10];}public void add(Object val){this.arr1[usedsize]=val;usedsize++;}public Object get(int pos){return this.arr1[pos];}}public static void main(String[] args) {MyArraylist list=new MyArraylist();list.add(1);list.add("hello");String ret=(String)list.get(1);}在指定類的后面寫上<T>,它是代表當(dāng)前的類是一個(gè)泛型類,此時(shí)的這個(gè)T就只是一個(gè)占位符而已,把類型參數(shù)化了,直接就是一個(gè)T類型的數(shù)組了,不能泛型化數(shù)組
private T[]=new T[10];--------private T[]=(T[])new Object[];創(chuàng)建數(shù)組最好用反射
泛型的意義:
1)存放數(shù)據(jù)的時(shí)候,在編譯的時(shí)候會(huì)自動(dòng)地對要放進(jìn)去的類型進(jìn)行檢查,當(dāng)取數(shù)據(jù)的時(shí)候,編譯器會(huì)自動(dòng)地對取出來的數(shù)據(jù)進(jìn)行強(qiáng)制類型轉(zhuǎn)換
2)泛型中<>里面的內(nèi)容是不進(jìn)行參與類型的組成的
3)泛型類型的參數(shù),只能是包裝類,而不能是簡單類型
咱們內(nèi)部的ArrayList使用泛型的時(shí)候也是new Object數(shù)組,但是他的get方法,把他的單個(gè)元素強(qiáng)轉(zhuǎn)成(E)(array[index]),不是整體數(shù)組強(qiáng)轉(zhuǎn),而是單個(gè)類型強(qiáng)轉(zhuǎn)成E類型
泛型是怎么進(jìn)行編譯的?范型只有上界,沒有下界
toarray()將一個(gè)list數(shù)組轉(zhuǎn)化成數(shù)組
javap -c? 類名
反省是編譯時(shí)期的一種機(jī)制
泛型這個(gè)概念只在編譯時(shí)期起作用,在運(yùn)行時(shí)期是沒有泛型這個(gè)概念的;在編譯時(shí)會(huì)被擦除為Object類型,編譯器生成的字節(jié)碼文件并不包含泛型的類型信息
一:public class MyArray<E extends Number>{ } 這表示E可以是Number或者是Number的子類 1)MyArray<Integer> l1;//這是正常的,因?yàn)镮nteger是Number的子類 2)MyArray<String> l2;//這是錯(cuò)誤的,因?yàn)镾tring并不是Integer的子類 二:沒有指定邊界,默認(rèn)就是Object,比如說class MyArray<T>{}下面我們來寫一個(gè)方法,來求數(shù)組中元素的最大值
class ALG<T>{public T GetMax(T[] array){T max=array[0];for(int i=1;i<array.length;i++){//這是引用類型的比較,max是T類型,array[i]也是引用類型,引用類型是不可以通過>=<來進(jìn)行比較的if(array[i]>max){max=array[i];}}return max;}}既然是引用類型,我們就要重寫Compareable接口,重寫compareTo方法來比較兩個(gè)引用類型,但是我們發(fā)現(xiàn)上述這個(gè)代碼,compareTo方法點(diǎn)不出來,因?yàn)槌绦虿恢滥氵@個(gè)類是否繼承了Compareable接口?重寫了CompareTo方法
class ALG<T extends Comparable<T>> 這種寫法就表示此時(shí)這個(gè)T一定要實(shí)現(xiàn)Compareable接口,這是泛型的上界 package Demo; class ALG<T extends Comparable<T>>{public T GetMax(T[] array){T max=array[0];for(int i=1;i<array.length;i++){//這是引用類型的比較,max是T類型,array[i]也是引用類型,引用類型是不可以通過>=<來進(jìn)行比較的if(array[i].compareTo(max)>0){max=array[i];}}return max;} } public class TestData {public static void main(String[] args) {ALG<String> avg=new ALG<>();String[] strings={"abcd","abc","ab","a"};int[] array={1,3,2,45,67,87};String str= avg.GetMax(strings);System.out.println(str);} }1)這時(shí)候會(huì)出現(xiàn)一個(gè)問題,咱們每一次調(diào)用findmax都要newALG()這樣的對象嗎,才可以通過這個(gè)對象的實(shí)例來進(jìn)行調(diào)用findmax這樣的方法,就顯得太麻煩了
2)這個(gè)時(shí)候我們加上static關(guān)鍵字,不就可以保證通過類名來進(jìn)行調(diào)用了嗎?如果加上了static關(guān)鍵字之后,這個(gè)靜態(tài)方法是不依賴于對象的,咱們的這個(gè)T參數(shù)是在new ALG中的尖括號(hào)進(jìn)行傳參的
class ALG<T extends Comparable<T>>{public static<T extends Comparable<T>> T GetMax(T[] array){T max=array[0];for(int i=1;i<array.length;i++){//這是引用類型的比較,max是T類型,array[i]也是引用類型,引用類型是不可以通過>=<來進(jìn)行比較的if(array[i].compareTo(max)>0){max=array[i];}}return max;}} 這個(gè)時(shí)候就不需要進(jìn)行new對象了,這就是咱們的一個(gè)靜態(tài)的泛型方法 package Demo; class ALG{public static<T extends Comparable<T>> T GetMax(T[] array){T max=array[0];for(int i=1;i<array.length;i++){//這是引用類型的比較,max是T類型,array[i]也是引用類型,引用類型是不可以通過>=<來進(jìn)行比較的if(array[i].compareTo(max)>0){max=array[i];}}return max;}} public class TestData {public static void main(String[] args) {Integer[] array={12,34,34,45,67};int max=ALG.<Integer>GetMax(array);}}理論上來說ArrayList<Integer> 不是ArrayList<Number>的父親類型
ArrayList<Number>也不是ArrayList<Integer>的子類
通配符:
通配符是無法解決泛型無法諧變的問題的,諧變指的是Student如果是Person的子類,那么List<Student>也應(yīng)該是List<Person>的子類,但是泛型是不支持這樣的父子類關(guān)系的
1)泛型T是確定的類型,一旦你要是傳了,我就定下來了,但是通配符可以說是更為靈活或者不穩(wěn)定,更多地用于擴(kuò)充參數(shù)的范圍
2)或者我們可以這么理解:泛型T就像是一個(gè)變量,等待著你可以傳輸一個(gè)具體的類型,而通配符是一種規(guī)定,規(guī)定你可以傳哪些參數(shù)
class AVL{public static<T> void print1(ArrayList<T> list){for(T x:list){//編譯器一定知道當(dāng)前傳遞過來的是一個(gè)T類型的數(shù)據(jù)System.out.println(x);}}public static void print2(ArrayList<?> list){for(Object x:list)//編譯器不知道?是啥類型,具體的類型我不知道{System.out.println(x);}} }通配符的上界:
<? extends 上界> <? extends Number>//可傳入的參數(shù)類型是Number或者是Number的子類 舉例: public static void printAll(ArrayList<? extends Number > list>{} //上面表示可以傳入的類型是Number的子類的任意類型的ArrayList 下面都是正確的: printAll(new ArrayList<Integer>()); printAll(new ArrayList<Double>()); printAll(new ArrayList<Number>()); 下面搜是錯(cuò)誤的 printAll(new ArrayList<String>()); printAll(new ArrayList<Object>());假設(shè)現(xiàn)在有下面的關(guān)系:
Animal
Cat extends Animal
Dog extends Animal
根據(jù)上面的關(guān)系,寫一個(gè)代碼,打印一個(gè)存儲(chǔ)了Animal或者Animal子類的list
代碼1:
public static void print(ArrayList<Animal> list>{}這樣是不可以進(jìn)行解決問題的,因?yàn)閜rint的參數(shù)是List<Animal>,我們就不可以進(jìn)行接收List<Cat> list
代碼2:
public static<T extends Animal> void print3(List<T> list){for(T animal:list){System.out.println(animal);}}這時(shí)候T類型是Animal的子類或者是自己,該方法也是可以實(shí)現(xiàn)的,這里面的類型是一個(gè)確定的類型,編譯器知道是什么類型
代碼三:通配符來進(jìn)行實(shí)現(xiàn):
public static void print(List<? extends Animal> list> {for(Animal x:list){System.out.println(x);//編譯器此時(shí)不知道這是調(diào)用誰的ToString方法 發(fā)生了向上轉(zhuǎn)型,不知道這個(gè)類型具體是啥類型,反正指定了上界,編譯器就認(rèn)為你傳遞過來的類一定是Animal或者是Animal的子類,如果沒有這個(gè)通配符上界Animal這里面就應(yīng)該寫成Object了} }1)總結(jié):ArrayList<? extends Number>是ArrayList<Integer>或者ArrayList<Double>的父類類型
2)ArrayList<?>是ArrayList<? extends Number>的父親類型
通配符的上介是不適合用于寫入對象的:
ArrayList<Integer> list1=new ArrayList<>();list1.add(1);list1.add(2);ArrayList<Double> list2=new ArrayList<>();List<?extends Number> list=list1;//list.add(1,9);//這里面是不適合進(jìn)行寫入數(shù)據(jù)的,適合于讀數(shù)據(jù),如果你進(jìn)行存放的話,即可以進(jìn)行存放整數(shù),也可以存放浮點(diǎn)數(shù)這是不可以的,因?yàn)樽钭罱K引用的只有一種類型//list.add(2,10.9);Number number= list.get(1);//正確//Integer s1=list.get(0);這樣的寫法是錯(cuò)誤的,因?yàn)椴恢览锩婢唧w存放的是哪一種類型,萬一存放的是Double類型呢我們的通配符的上介適合讀取數(shù)據(jù),不適合寫入數(shù)據(jù),上面的list可以進(jìn)行引用的對象有很多,編譯器是無法確定你的具體的類型的,所以說編譯器為了安全起見,此時(shí)只允許你進(jìn)行讀取
通配符的下界:
<? super 下界> <? super Integer>這是代表可以進(jìn)行傳入的實(shí)參的類型是Integer或者是Integer的父類類型假設(shè)有下面代碼:
public static void printAll(ArrayList<? super Integer> list){ } //下面表示傳入的實(shí)參都是Integer的父類的任意類型的ArrayList 下面的調(diào)用都是正確的: printAll(new ArrayList<Integer>()); printAll(new ArrayList<Number>()); printAll(new ArrayList<Object>()); 下面的調(diào)用是編譯錯(cuò)誤的: printAll(new ArrayList<String>); printAll(new ArrayList<Double>);咱們的ArrayList<? super Integer> 是ArrayList<Integer>的父類類型
ArrayList<?>是ArrayList<? super Integer>的父類類型
ArrayList<? super Person> list=new ArrayList<>(); //ArrayList<? super Person> list2=new ArrayList<Student>();這里面會(huì)出現(xiàn)報(bào)錯(cuò),因?yàn)閘ist2只能引用Person或者Person父類類型的list list.add(new Person());//添加元素的時(shí)候,只要添加的元素是Person或者是Person的子類就可以了 list.add(new Student()); Person person=list.get(0)//父類引用引用子類對象,應(yīng)該是對的呀???? Student s=list.get(0)//錯(cuò)誤,因?yàn)镻erson的子類有很多,不一定就是Student Object s=list.get(1);//正確我們在進(jìn)行添加元素的時(shí)候,我們知道list引用的對象肯定是Person或者是Person的父類的集合,此時(shí)我們可以確定此時(shí)能夠儲(chǔ)存的最小粒度比Person小就可以,你放的時(shí)候,放的都是Person或者Person的子類,但是你讀取的時(shí)候,你能確定你讀取的時(shí)候讀取的是那一個(gè)子類嗎?
關(guān)于異常的復(fù)習(xí):
1、運(yùn)行時(shí)異常
(1)運(yùn)行時(shí)異常都是RuntimeException類及其子類異常,如NullPointerException、IndexOutOfBoundsException等,這些異常是不檢查異常,程序中可以選擇捕獲處理,也可以不處理。這些異常一般是由程序邏輯錯(cuò)誤引起的,程序應(yīng)該從邏輯角度盡可能避免這類異常的發(fā)生。
當(dāng)出現(xiàn)RuntimeException的時(shí)候,我們可以不處理。當(dāng)出現(xiàn)這樣的異常時(shí),總是由虛擬機(jī)接管。比如:我們從來沒有人去處理過NullPointerException異常,它就是運(yùn)行時(shí)異常,并且這種異常還是最常見的異常之一。
出現(xiàn)運(yùn)行時(shí)異常后,如果沒有捕獲處理這個(gè)異常(即沒有catch),系統(tǒng)會(huì)把異常一直往上層拋,一直到最上層,如果是多線程就由Thread.run()拋出,如果是單線程就被main()拋出。拋出之后,如果是線程,這個(gè)線程也就退出了。如果是主程序拋出的異常,那么這整個(gè)程序也就退出了。運(yùn)行時(shí)異常是Exception的子類,也有一般異常的特點(diǎn),是可以被catch塊處理的。只不過往往我們不對他處理罷了。也就是說,你如果不對運(yùn)行時(shí)異常進(jìn)行處理,那么出現(xiàn)運(yùn)行時(shí)異常之后,要么是線程中止,要么是主程序終止。
如果不想終止,則必須捕獲所有的運(yùn)行時(shí)異常,決不讓這個(gè)處理線程退出。隊(duì)列里面出現(xiàn)異常數(shù)據(jù)了,正常的處理應(yīng)該是把異常數(shù)據(jù)舍棄,然后記錄日志。不應(yīng)該由于異常數(shù)據(jù)而影響下面對正常數(shù)據(jù)的處理。
2、非運(yùn)行時(shí)異常
(2)非運(yùn)行時(shí)異常是RuntimeException以外的異常,類型上都屬于Exception類及其子類。如IOException、SQLException等以及用戶自定義的Exception異常。對于這種異常,JAVA編譯器強(qiáng)制要求我們必需對出現(xiàn)的這些異常進(jìn)行catch并處理,否則程序就不能編譯通過。所以,面對這種異常不管我們是否愿意,只能自己去寫一大堆catch塊去處理可能的異常,也可以用throws聲明異常
RuntimeException體系包括錯(cuò)誤的類型轉(zhuǎn)換,數(shù)組越界訪問以及嘗試訪問空指針,必須被try catch語句塊捕獲,這是錯(cuò)誤的,可以直接由JVM處理
1)Object類型是所有class類型的父親,是根,數(shù)組當(dāng)然也是一種class類型,因此Object[]和Test[]類型都是Object類型的子類型,對于Test[]類型和Object[]類型,二者同為數(shù)組類型,他們之間沒有什么父子關(guān)系,而是平級(jí)的關(guān)系,所以數(shù)組之間是不可以進(jìn)行強(qiáng)制類型轉(zhuǎn)換的,String與String[]的父類都是Object類型
2)如果強(qiáng)制進(jìn)行數(shù)組類型轉(zhuǎn)換就會(huì)拋出ClassCastException異常
String[] s=new String[10];Object e=new String[10];Object t=new String("abc"); import java.io.FileNotFoundException; import java.io.IOException; public class HelloWorld {public static void TestDemo(){System.out.println("執(zhí)行這個(gè)方法");}public static void main(String[] args) {((HelloWorld)null).TestDemo();}public static void run(){try{//這里面做了一些事情} catch(FileNotFoundException e){System.out.println("發(fā)生文件找不到異常");}catch (IOException ex){System.out.println("發(fā)生了IOException");}catch (java.lang.Exception e){System.out.println("發(fā)生了異常");}}//這里面無論語句發(fā)生了什么異常,最終只能有一個(gè)catch語句快執(zhí)行,他們是構(gòu)成父子類關(guān)系的,只能拋出一個(gè)異常,只能捕獲一個(gè)異常 }重寫equals方法的時(shí)候?yàn)槭裁匆欢ㄒ貙慼ashcode?
1)equals方法和hashcode方法是Object中的兩個(gè)基礎(chǔ)方法,他們共同來協(xié)作判斷兩個(gè)對象是否相等,這樣做的好處就是,效率更高,如果不重寫,就會(huì)出現(xiàn)BUG
2)因?yàn)橥ㄟ^hashcode的值,我們就可以直接定位到一個(gè)數(shù)據(jù)的存儲(chǔ)位置,而不需要一個(gè)一個(gè)的循環(huán)查找
3)hashcode也叫作散列碼,他是由對象推導(dǎo)出的一個(gè)整數(shù)值,并且這個(gè)值包括任意整數(shù),包括正數(shù)和負(fù)數(shù),況且散列碼是沒有規(guī)律的,如果說x,y是兩個(gè)不同的對象,那么x.hashcode()和y.hashcode()基本上不會(huì)相同(也有可能是相同的),Object中的hashcode是只是根據(jù)地址只生成的,對比兩個(gè)對象的引用地址
String str=new String("abc");String str2=str;//重寫了hashcode方法String str3=str2;System.out.println(str.hashCode());System.out.println(str2.hashCode());System.out.println(str3.hashCode()); 他們的地址值都是相同的 package Demo; class Task{public String name;public int age;public Task(String name,int age){this.age=age;this.name=name;} } public class DemoKail{public static void main(String[] args) {Task task1=new Task("李佳偉",19);Task task2=task1;System.out.println(task1.hashCode());System.out.println(task2.hashCode());Task task3=new Task("李佳偉",19);System.out.println(task3.hashCode());} } 打印結(jié)果:644117698 644117698 1872034366但是重寫hashcode之后,這三個(gè)值就相同了
總結(jié):
1)當(dāng)我們使用HashMap,HashSet集合的時(shí)候,會(huì)進(jìn)行計(jì)算對象在散列表中的位置
2)如果我們只重寫hashcode方法,不重寫equals方法,兩個(gè)相同的對象就會(huì)存儲(chǔ)到相同的位置,但是此時(shí)equals方法沒有重寫,兩個(gè)對象就被判定成不相等
3)如果我們只重寫equals方法,而沒有重寫hashcode方法,像hashMap等集合類的判斷邏輯是先進(jìn)行判斷hash之是否相等,在進(jìn)行判斷對象值是否相等,如果沒有重寫hashcode,兩個(gè)相等的對象可能就被放在散列表不同的位置,根本就沒有equals判斷的機(jī)會(huì)
4)如果是我們自己自定義的類,也不用這些集合類,就不會(huì)調(diào)用hashcode方法,只需要重寫equals方法即可,此時(shí)也沒有必要重寫equals方法了
如果在HashSet中存儲(chǔ)重寫的自定義對象的時(shí)候,就會(huì)無法實(shí)現(xiàn)去重:
package Demo;import java.util.HashSet; import java.util.Iterator; import java.util.Objects;class Task{public String name;public int age;public Task(String name,int age){this.age=age;this.name=name;}@Overridepublic boolean equals(Object o) {if (this == o) return true;if (o == null || getClass() != o.getClass()) return false;Task task = (Task) o;return age == task.age && Objects.equals(name, task.name);}// @Override // public int hashCode() { // return Objects.hash(name, age); // }@Overridepublic String toString() {return "Task{" +"name='" + name + '\'' +", age=" + age +'}';} } public class DemoKail{public static void main(String[] args) {Task task1=new Task("李佳偉",18);Task task2=new Task("李佳偉",18);Task task3=new Task("李佳偉",18);HashSet<Task> set=new HashSet<>();set.add(task1);set.add(task2);set.add(task3);Iterator<Task> iterable=set.iterator();while(iterable.hasNext()){Task task=iterable.next();System.out.println(task);}} }總結(jié)
以上是生活随笔為你收集整理的java集合结构----集合框架以及背后的数据结构的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 国内人才申领《上海市居住证》审核试行办法
- 下一篇: 《上海市居住证》积分申请基本流程