Java基礎課的中下基礎課04

?目錄

二十三、集合相關

23.1 集合

(1)集合的分支

23.2 List有序可重復集合

(1)ArrayList類

(2)泛型

(3)ArrayList常用方法

(4)Vector類

(5)Stack類(棧)

(6)Queue/ kju? /類

(7)LinkedList類

23.3 Set無序無重復集合

(1)HashSet類

(2)Set集合常用方法

(3)HashSet無重復的原則

(4)TreeSet類

(5)TreeSet無重復規則是如何實現的?

(6)Set集合總結

23.4 Map集合

(1)Map介紹

(2)HashMap

(3)如何選用集合和數組?

(4)登錄小流程來體驗如何選用集合

(5)TreeMap

(6)設計學生做選擇題(考試機)

二十四、錯誤與異常

24.1 異常

(1)異常的分支體系:

①、運行時異常(非檢查異常)

②、編譯時異常(檢查異常)

(2)添加處理異常的手段:

①、try{ }catch(){ }[finally{ }]

②、throws拋出

(3)自定義異常


二十三、集合相關

23.1 集合

1、變量----容器:存儲一個元素

2、數組----容器:一組具有某種特性的數據存在在一起,存儲一組元素(數據類型一致),長度固定

3、我們自己封裝了一個Box(ArrayBox、LinkedBox)----容器:存儲一組元素,長度可變

4、集合--容器:集合是指具有某種特定性質的具體或抽象的對象匯總而成的集體與數組類似,集合的長度存儲之后還能改變,集合用來存儲一組元素,可以理解為集合是我們封裝的Box,只不過比我們寫的更加優秀,更多的方法

5、集合的分支:Collection、Map、List、Set都是接口,需要通過子類來完成操作(所有的集合都在Java.util)

(1)集合的分支

1、Collection:存儲的都是value(value有可能是基本類型或引用類型)

2、Map:存儲的是以Key-value(鍵值對)的形式存在的,(Key無序無重復,Value無序可重復)

3、List:有序可重復

4、Set:無序無重復

(1)序:順序,添加進去的元素 和 取得元素的順序一致(指的不是集合自己的順序)

(2)重復:兩個對象元素一致

23.2 List有序可重復集合

1、List集合的子類:(1)ArrayList(2)LinkedList(3)Vector

2、ArrayList 和 Vector區別:

(1)相同:底層都是數組

(2)不同:類似StringBuffer 和 String Builder的不同,但是相反(早--線程同步安全效率低;晚---線程非同步不安全效率高)

ArrayList是早版本、Vector是晚版本(早--線程非同步不安全效率高;晚---線程同步安全效率低)

(3)特點:Vector底層也是利用(動態)數組的形式存儲;Vector是線程同步的(synchronized),安全性高,效率低

(1)ArrayList類

1、ArrayList------底層就是數組

(1)所屬包java.util

(2)有序:順序,添加進去的元素 和 取得元素的順序一致(指的不是集合自己的順序)

(3)重復:兩個對象元素一致

(4)ArrayList特點適合遍歷查詢,不適合插入刪除,按照1.5倍擴容

(6)創建對象:無參構造方法 和 帶默認空間的構造方法 和 帶collection參數的構造方法ArrayList(cllection c){}(意思是它可以將collection家族的任何一個構建成一個ArrayList)

(6)常用方法---小容器

add();get();remove();size()個數;能添取刪,由于ArrayList底層是一個Object[],所以什么類型都可以存進去,取出來的時候是多態的效果,需要自己造型才可以,顯得用來了非常麻煩,所以在JDK1.5版本以后提出了一個概念泛型

ArrayList objects = new ArrayList();
objects.add("abc");
String value = (String) objects.get(0);//很麻煩,需要自己在進行造型才能賦值使用
value.trim();

(2)泛型

1、泛型:用來規定數據類型的,定義的時候用一個符合代替某種類型,在使用的時候用具體的數據類型,將定義的那個符合替換掉

如:ArrayList< T >------------->ArrayList< String >

2、泛型可以使用在哪里?

(1)類定義的時候描述某種數據類型,所以集合的使用就是這樣

//ArrayList是個集合,這個集合里面只能存String
ArrayList<String> list = new ArrayList<String>();

(2)泛型接口:與泛型類的使用基本一致,子類實現接口時必須添加泛型

public interface Person<X> {public X value;
}
public class Son<X> implements Person<X>{}

3、泛型方法:方法調用時傳參數在方法描述的時候加泛型,注意方法的泛型與類無關,帶有泛型的方法可以不放在帶有泛型的類中

4、高級泛型:用于規范邊界的 extends、super

(3)ArrayList常用方法

 ? ? ? 
/*ArrayList objects = new ArrayList();objects.add("abc");String value = (String) objects.get(0);value.trim();*/
?//ArrayList(有序可重復)是個集合,這個集合里面只能存StringArrayList<String> list = new ArrayList<String>();list.add("a");list.add("b");list.add("c");list.add("d");System.out.println(list.get(0));//aSystem.out.println(list.get(3));//d
// ? ?  System.out.println(list.get(4));//沒有索引4,所以異常IndexOutOfBoundsExceptionSystem.out.println(list.size());//4  有效元素個數
?for (int i = 0; i < list.size(); i++) {String value = ?list.get(i);System.out.print(value + "\t");//a b c d}
System.out.println("==================================================================================================");
?System.out.println(list);//list底層重寫了toString方法,原本Object是返回包名.類名@ hashCode
System.out.println("==================================================================================================");
?/*集合元素全部刪除,通過for循環是否能把所以元素刪除?不能i=0時,size=4,list=abcd刪除后為:bcdi=1時,size=3,list=bcd刪除后為:bdi=2時,size=2remove(int index);刪除索引為index的位置元素,所以刪不干凈remove(i);  和 ? remove(0) ? 都刪不干凈因為你的size一直在變化,所以刪不干凈for (int i = 0; i < list.size(); i++) {list.remove(i);}*///這樣可以刪除干凈,給一個固定值int size = list.size();for (int i = 0; i < size; i++) {list.remove(i);}System.out.println(list);

(1)boolean = add(E e); 將指定的元素追加到此列表的末尾

(2)void = add(int index, E e); 在此列表中的指定位置插入指定的元素。

(3)boolean = addAll(Collection c); 按指定集合的Iterator返回的順序將指定集合中的所有元素追加到此列表的末尾。

(4)boolean = addAll(int index , Collection c); 將指定集合中的所有元素插入到此列表中,從指定的位置開始。

//泛型不能使用基本類型————如果想要使用基本類型,需要使用其對應的包裝類
ArrayList<Integer> list1 = new ArrayList<Integer>();
list1.add(10);
list1.add(20);
list1.add(30);
list1.add(40);
ArrayList<Integer> list2 = new ArrayList<Integer>();
list2.add(300);
list2.add(100);
//我想要將list2集合中的所有元素添加到list1中
list1.addAll(list2);
System.out.println(list1);//[10,20,30,40,300,100]
/*list1.addAll(Collection<? extends E> list2)將list2集合中的全部元素存入list1集合中,這個?問號,問的就是你傳進來的是不是我的子類如:如果list1存在泛型Integer,list2存在泛型String,那么就不對,類型至少是一致的
*/
//將list2里面的內容插入到索引為2號的list1中
list1.addAll(2,list2);//[10,20,300,100,30,40]

(5)void = clear();將集合內的全部元素清除

(6)boolean = contains(Object);找尋某一個給定的元素是否在集合中擁有

boolean b = list1.contains(100);//list1中是否存在100元素
System.out.println(b);//true

(7)void = ensureCapacity(int minCapacity);如果需要,增加此 ArrayList實例的容量,以確保它可以至少保存最小容量參數指定的元素數。

(8)E = get(int index); 返回此列表中指定位置的元素(返回值是一個咱們自己規定的類型)

(9)int = indexOf(); 返回此列表中指定元素的第一次出現的索引,如果此列表不包含元素,則返回-1。

(10)int = lastIndexOf(); 返回此列表中指定元素的最后一次出現的索引,如果此列表不包含元素,則返回-1。

(11)boolean = isEmpty();判斷集合是否為空,如果size的個數為0就是空

(12)Iterator = iterator();返回值是它自己,迭代器,JDK1.5版本之后,以正確的順序返回該列表中的元素的迭代器。

(13)boolean = remove(int index);刪除指定索引位置的元素

(14)boolean = remove(Object obj);刪除指定元素,就是我不知道這個元素在哪,不知道索引;

//這兩個出現重載,那么remove(1)是刪除的位置?還是1這個元素?
list.remove(1);//刪除的是位置
list.remove(new Integer(1));//刪除的是1這元素

(15)boolean = removeAll(Collection c);差集 從此列表中刪除指定集合中包含的所有元素。(Collection 集合的意思)

(16)boolean = retainAll(Collection c);交集 僅保留此列表中包含在指定集合中的元素。

(17)E = set(int index , E value); 用指定的元素替換此列表中指定位置的元素。

ArrayList<Integer> list3 = new ArrayList<>();ArrayList<Integer> list4 = new ArrayList<>();list3.add(10); ? ? ? ? ?list4.add(10);list3.add(20); ? ? ? ? ?list4.add(200);list3.add(30);
?//list3 = [10,20,30] ? ? ?  list4 = [10,200] ?  最終:list3 = [10,20,30,10,200]list3.addAll(list4);//并集,將list2中的元素合并給list1//list3 = [10,20,30,10,200] list4 = [10,200] ?  最終:list3 = [20,30]list3.removeAll(list4);//差集,在list1中將list2與list1相同的元素及其list2中的所有元素都刪除//list3 = [20,30] ? ? ? list4 = [10,200] ?  最終:list3 = [200]list3.retainAll(list4); //返回list3和list4中相同的元素
?
System.out.println("==================================================================================================");
?ArrayList<Integer> list5 = new ArrayList<>();ArrayList<Integer> list6 = new ArrayList<>();list5.add(10); ? ? ? ? ?list6.add(10);list5.add(20); ? ? ? ? ?list6.add(200);list5.add(30);//set修改,它也是會保留原本的元素int value = list5.set(1,10);System.out.println(list5);//list5 = [10,10,30]System.out.println(value);//20

(18)List = subList(int begin , int end);返回此列表中指定的 begin (包括)和 end之間的獨占視圖。

ArrayList<Integer> list5 = new ArrayList<>();
list5.add(10);
list5.add(20);
list5.add(30);
list5.add(40);List<Integer> newList = list5.subList(1,3);System.out.println(newList);//[20,30]

(19)Object[] = toArray();集合變成數組 以正確的順序(從第一個到最后一個元素)返回一個包含此列表中所有元素的數組。

(20)T[] = toArray( T [] );看起來是個參數,實則是為了讓它裝滿的。以正確的順序返回一個包含此列表中所有元素的數組(從第一個到最后一個元素); 返回的數組的運行時類型是指定數組的運行時類型。

ArrayList<Integer> list6 = new ArrayList<>();
list6.add(10);
list6.add(20);
list6.add(30);
list6.add(40);
//實現準備好一個空的數組,這個數組其實是用來接收返回值的(接收list6這個集合中的每一個元素)
Integer[] x = new Integer[list6.size()];//這個數組里面沒有元素,目的是為了拿這個數組裝東西
//我想要同學手里的椅子,我很懶,不想動手,這時我就提前準備好一個空教室,讓同學們把椅子裝到這個空教室中
//所以做返回結果不一定用返回值,可以用引用類型參數,我給你一個空教室,你把這個教師塞滿
//把list6中的元素挨個裝進這個空數組x中
list6.toArray(x);
System.out.println(x.length);//4

(21)void = trimTosize();變成有效元素個數那么長; 修改這個 ArrayList實例的容量是列表的當前大小。

(4)Vector類

1、Vector

(1)java.util包

(2)是ArrayList集合的早期版本1.0版本(StringBuffer早期1.0版本、StringBuilder是后期JDK1.5版本)

(3)特點:Vector底層也是利用(動態)數組的形式存儲;Vector是線程同步的(synchronized),安全性高,效率低

(4)擴容方式與ArrayList不同,Vector是擴容2倍,可以通過構造方式創建對象時修改這一機制

(5)有三個構造參數,無參 ,有參,帶collection(集合)參數的構造方法

//無參,默認容量20,空間不夠自動增加20個
Vector<String> vector = new Vector<String>();
for (int i = 0; i < 20; i++) {vector.add("a");//有效元素個數,底層真實數組容量System.out.println(vector.size() + "----------" + vector.capacity());
}
//有參,自己定義創建100個空間
Vector<String> vector2 = new Vector<String>(100);
//默認剛開始就創建4個空間,如果不夠用每次就擴大4個空間,4個4個的增加空間
Vector<String> vector3 = new Vector<String>(4,4);

(5)Stack類(棧)

1、Stack類:先進后出

(1)java.util包

(2)繼承Vector類,是Vector的子類

(3)構造方法只有一個無參數的

(4)除了繼承Vector類的方法為還有幾個特殊方法

2、stack中的常用方法

(1)E = push(E e);將某一個元素壓入棧頂,壓棧

(2)E = pop();將某一個元素從棧頂取出并刪除,出棧

(3)E = peek();查看棧頂的一個元素,不刪除只是看

(4)boolean = empty();判斷棧內元素是否為空

(5)int = search();查找給定的元素在棧中的位置

Stack<String> stack = new Stack<>();
stack.push("a");//將a壓入      a
stack.push("b");//將b壓入      b————a
stack.push("c");//將c壓入      c————b————a
//此時c是棧頂
System.out.println(stack);//[a,b,c] 最右邊為棧頂
System.out.println(stack.pop());//c 將棧頂元素取出刪除
System.out.println(stack);//[a,b]   最右邊為棧頂
System.out.println(stack.peek());//b將棧頂元素取出不刪除
System.out.println(stack);//[a,b]
System.out.println(stack.search("b"));//2,返回元素的第幾個位置(不是所索引)

(6)Queue/ kju? /類

1、Queue

(1)java.util包

(2)通過無參數構造方式創建對象

2、一般方法

(1)boolean = add(E e); 將指定的元素插入到此隊列中,如果可以立即執行此操作,而不會違反容量限制, true在成功后返回 IllegalStateException如果當前沒有可用空間,則拋出IllegalStateException。

(2)E = element()————get();檢索,但不刪除,這個隊列的頭。取得是棧底的第一個元素,也就是你壓入得第一個元素,不刪除

(3)E = remove(); 檢索并刪除此隊列的頭。

(4)bollean = offer(E e);如果在不違反容量限制的情況下立即執行,則將指定的元素插入到此隊列中。 相當于add,但是這個方法不會拋異常,出現錯誤就變為空

(5)E = peek();檢索但不刪除此隊列的頭,如果此隊列為空,則返回 null 。相當于element方法

(6)E = poll;檢索并刪除此隊列的頭,如果此隊列為空,則返回 null 。相當于remove()

(7)LinkedList類

1、LinkedList:他是List的子類,也是Queue的子類

(1)java.util包,自己封裝過(LinkedBox,內部類Node<T>對象(節點 prev item next))

(2)底層使用雙向鏈表的數據結構形式來存儲,適合于插入或刪除,不適合遍歷查詢

(3)構建對象:無參數構造對象,帶參數構造方法LinkedList(Collection <? extends E> c)

(4)常用方法

增刪改查:add();remove();ser();get();size();------- offer();poll();peek();

(5)手冊中提供的其他常用方法:

addAll(); addFirst();( 相當于add(0 , value) ); addLast(); clear();contains(); element();getFirst();

getLast();indexOf();lastIndexOf();等.....

23.3 Set無序無重復集合

(1)HashSet類

(1)java.util包

(2)HashSet的底層是HashMap(數組+鏈表的形式,也可以叫散列表或臨接連表)

(3)無序:我們使用集合存放元素的順序,集合內取出來的順序不一致,集合本身是有自己的算法排布順序,hash算法,只不過這個順序咱們自己找不到規律

HashSet<String> set = new HashSet<>();set.add("a");set.add("b");set.add("A");set.add("C");set.add("c");set.add("B");set.add("d");
System.out.println(set);//[a,a,b,B,C,c,d]每一次順序都不一樣,無序,Hashset有自己排序算法

(4)利用無參數構造方法和有參數構造方法創建對象

(2)Set集合常用方法

boolean = add( value ) ;addAll( collection c );retainAll( );removeAll( );boolean = remove( Object );注意:HashSet是沒有修改方法;

沒有循環遍歷的方法,但是可以使用增強for進行集合遍歷(在JDK1.5版本以后的),在1.5之前是用iterator()進行的

(1)iterator();獲取一個迭代器,增強for循環的底層就是迭代器

工人做事沒有順序,貼完商標就往傳送帶上送,傳送帶就是個HashSet集合;

(2)hasNext();判斷有沒有元素

(3)next();取元素

HashSet<String> set = new HashSet<>();set.add("a");set.add("b");set.add("A");set.add("C");set.add("c");set.add("B");set.add("d");//獲取一個迭代器對象,通過set集合獲取Iterator<String> it = set.iterator();//iterator接口 多態的效果//判斷下一個位置是否有元素if (it.hasNext()) {String value = it.next();System.out.println(value);//a}//將所有元素取出來,用while如果有就取,因為for循環你都不知次數while (it.hasNext()) {String value = it.next();System.out.println(value);//a A b B C c d}

(3)HashSet無重復的原則

public class Person {private String name;
?public Person(String name) {this.name = name;}
}
public class TestHashSet {public static void main(String[] args) {//什么是無重復?名字一樣就叫重復嘛?不是的!每次new一個地址都不一樣HashSet<Person> people = new HashSet<>();people.add(new Person("曹宇希"));people.add(new Person("曹宇希"));people.add(new Person("曹宇希"));people.add(new Person("曹宇希"));System.out.println(people.size());//4//到底什么是無重復?String就是1個,可以看出String比較的是名字,Person比較的是地址HashSet<String> str = new HashSet<>();str.add(new String("曹宇希"));str.add(new String("曹宇希"));str.add(new String("曹宇希"));str.add(new String("曹宇希"));System.out.println(str.size());//1}
}

(6)首先通過String類型和Person類型存儲,可以猜測出?有可能它底層無重復原則是通過利用equals方法進行比較的;如果我們想讓Person對象的name一致,認為是同一個對象,那么我們可以重寫equals方法

//在Person中重寫equals方法,然后在執行TestHashSet中的代碼,發現還是沒有出現無重復的效果,繼續猜測?
//重寫equals方法,為了將Person放入set集合中,去掉重復
public boolean equals(Object obj) {if (this == obj) {//如果傳進來的對象和當前對象地址一樣,就說明重復了return true;}if (obj instanceof Person) {//如果不滿足就看看傳進來的obj屬不屬于Person這個類型//如果屬于(屬于的化可能是子類)就將obj這個傳進來的轉為Person類型Person anotherPerson = (Person)obj;//this 是一個對象,anotherPerson也是有一個對象,比較對象中的name屬性if (this.name.equals(anotherPerson.name)) {//不是遞歸,這個equals是String的方法,不是重寫的equals方法return true;}}return false;
}

(7)但是發現我們重寫equals方法還是沒有產生無重復的效果,證明可能原則不知equals一個方法這么簡單!!!

(8)我們想想以前的知識點,往往重寫equals方法就會伴隨這重寫hasheCode方法,所以我們再次猜測?

還有另一個規則同時起著作用:hashCode方法,所以我們還需要重寫hashCode()

//在Person中重寫hashCode方法,然后在執行TestHashSet中的代碼,就成功了無重復效果
//重寫hashCode方法
public int hashCode() {//兩個Person對象的name屬性一致,我需要讓hashCode返回值一樣return this.name.hashCode();//這個hashCode是name的
}
package testhashset;public class Person {private String name;private int testNum;//記錄人是誰,來分辨剩下的一個,是第一次存儲的還是最后一次存儲的?public Person(String name, int testNum) {this.name = name;this.testNum = testNum;}public int getTestNum() {return this.testNum;}//重寫equals方法,為了將Person放入set集合中,去掉重復public boolean equals(Object obj) {if (this == obj) {//如果傳進來的對象和當前對象地址一樣,就說明重復了return true;}if (obj instanceof Person) {//如果不滿足就看看傳進來的obj屬不屬于Person//先把obj還原回Person類型,因為你傳進來的obj有可能不是Person,是Person的子類也可能,需要造型Person anotherPerson = (Person)obj;//this 是一個對象,anotherPerson也是有一個對象,比較對象中的name屬性if (this.name.equals(anotherPerson.name)) {//不是遞歸,這個equals是String的方法,不是重寫的equals方法return true;}}return false;}//重寫hashCode方法public int hashCode() {//兩個Person對象的name屬性一致,我需要讓hashCode返回值一樣return this.name.hashCode();//這個hashCode是name的,是String類型的}}
public class TestHashSet {public static void main(String[] args) {HashSet<Person> people = new HashSet<>();people.add(new Person("曹宇希",1));people.add(new Person("曹宇希",2));people.add(new Person("曹宇希",3));people.add(new Person("曹宇希",4));System.out.println(people.size());//1}
}

(9)五個Person對象只剩下一個,那么問題來了,這剩下的一個,是第一次存儲的那個,還是最后一次存儲的那個?

(10)Set集合是發現重復的元素,就拒絕存入,所以存儲的是第一個元素

public class TestHashSet {public static void main(String[] args) {HashSet<Person> people = new HashSet<>();people.add(new Person("曹宇希",1));people.add(new Person("曹宇希",2));people.add(new Person("曹宇希",3));people.add(new Person("曹宇希",4));System.out.println(people.size());//1//利用getTestNum查看一下是第幾個元素System.out.println(people.iterator().next().getTestNum());//1}
}

(11)發現這種方式太麻煩了,還需要用迭代器訪問;能不能直接輸出一個Person呢?為了輸出打印方便重寫toString(可以不重寫toString,這里重寫就是為了方便打印)

package testhashset;import java.util.HashSet;
import java.util.Iterator;public class TestHashSet {public static void main(String[] args) {HashSet<String> set = new HashSet<>();set.add("a");set.add("b");set.add("A");set.add("C");set.add("c");set.add("B");set.add("d");HashSet<Person> people = new HashSet<>();people.add(new Person("曹宇希",1));people.add(new Person("曹宇希",2));people.add(new Person("曹宇希",3));people.add(new Person("曹宇希",4));System.out.println("people的集合:" + people.size());//1//發現這種方式太麻煩了,還需要用迭代器訪問System.out.println(people.iterator().next().getTestNum());//1//能不能直接輸出一個Person呢?為了輸出打印方便重寫toString,如果不重寫就會輸出的是Person地址System.out.println(people);//[{曹宇希,1}]}
}
package testhashset;public class Person {private String name;private int testNum;//記錄人是誰,來分別剩下的一個,是第一次存儲的還是最后一次存儲的?public Person(String name, int testNum) {this.name = name;this.testNum = testNum;}public int getTestNum() {return this.testNum;}//重寫equals方法,為了將Person放入set集合中,去掉重復public boolean equals(Object obj) {if (this == obj) {//如果傳進來的對象和當前對象地址一樣,就說明重復了return true;}if (obj instanceof Person) {//如果不滿足就看看傳進來的obj屬不屬于Person//先把obj還原回Person類型,因為你傳進來的obj有可能不是Person,是Person的子類也可能,需要造型Person anotherPerson = (Person)obj;//this 是一個對象,anotherPerson也是有一個對象,比較對象中的name屬性if (this.name.equals(anotherPerson.name)) {//不是遞歸,這個equals是String的方法,不是重寫的equals方法return true;}}return false;}//重寫hashCode方法public int hashCode() {//兩個Person對象的name屬性一致,我需要讓hashCode返回值一樣return this.name.hashCode();//這個hashCode是name的}//重寫toString方法,讓對象打印輸出的時候,不需要在.get方法了,而是直接輸出對象的屬性// ,而不是hashCode碼了public String toString() {/* 這種方法不是很好return "{" + this.name + ", " + this.testNum + "}";*/StringBuilder builder = new StringBuilder("{");builder.append(this.name);builder.append(", ");builder.append(this.testNum);builder.append("}");/*return builder.toString(); 下面的也可以*/return new String(builder);}
}

(4)TreeSet類

1、TreeSet

(1)無序無重復,java.util

(2)TreeSet的底層是TreeMap(二叉樹的形狀,也是利用Node(left item right) item是數據、left左節點、right右節點)

(3)創建對象------無參數構造方法,帶Collection(集合)構造方法

(4)基本常用方法:add(); iterator(); 沒有修改....等

(5)TreeSet無重復規則是如何實現的?

1、treeSet集合本身有順序,它的無序指的是,我們自己存的順序和它取的順序不一樣,但是它本身是可以按照unicode字典的順序排布

public class TestTreeSet {public static void main(String[] args) {TreeSet<String> strings = new TreeSet<>();strings.add("a");strings.add("c");strings.add("A");strings.add("D");strings.add("d");strings.add("b");strings.add("A");strings.add("B");strings.add("C");strings.add("D");System.out.println(strings.size());//6  set家族若有相同的對象,拒絕存入System.out.println(strings);//[A,B,C,D,a,b,c,d]  集合本身有自己的排布順序}
}

2、那我們猜測?有可能它底層的順序是按照compareTo的形式排序的(按照字母的自然順序排序Unicode)

3、那我們來看一下是否出現無重復,TreeSet這么寫不但不能輸出還會拋異常,ClassCastException----->造型異常,實際它底層是TreeMap,是它給造的型

package testhashset;
?
import java.util.TreeSet;
public class TestTreeSet {public static void main(String[] args) {TreeSet<String> strings = new TreeSet<String>();strings.add(new String("曹宇希"));strings.add(new String("曹宇希"));strings.add(new String("曹宇希"));strings.add(new String("曹宇希"));System.out.println(strings.size());//1  set家族若有相同的對象,拒絕存入
?TreeSet<Person> people = new TreeSet<Person>();people.add(new Person("曹宇希",1));people.add(new Person("曹宇希",2));people.add(new Person("曹宇希",3));people.add(new Person("曹宇希",4));//TreeSet這么寫不但不能輸出還會拋異常System.out.println(people.size());//1//ClassCastException----->造型異常,實際它底層是TreeMap,是它給造的型
?}
}

4、所以,如果想要把自己寫的類型 比如 Person對象存入TreeSet集合里,不能隨意的存儲

5、TreeSet不像HashSet,因為hashSet它的equals和hashCode方法默認繼承Object,誰都可以存

6、所以我們需要讓自己寫的類先實現Comparable接口,就是你這個對象先是可比較的才能放進TreeSet這個集合里,否則放不進去

7、如果想讓Person對象存入TreeSet集合內,必須實現Comparable接口,然后重寫這個compareTo方法

重寫后,然后咱們再去執行代碼就不會異常了,想要的無重復效果就出來了
package testhashset;
?
public class Person implements Comparable<Person>{private String name;private int testNum;//記錄人是誰,來分別剩下的一個,是第一次存儲的還是最后一次存儲的?public Person(String name, int testNum) {this.name = name;this.testNum = testNum;}public int getTestNum() {return this.testNum;}//如果想讓Person對象存入TreeSet集合內,必須實現接口,然后重寫這個compareTo方法@Overridepublic int compareTo(Person o) {//當前對象name和另一個對象name的compareTo結果,compareTo是String類型的,是name的compareToreturn this.name.compareTo(o.name);}
?
}
package testhashset;import java.util.TreeSet;public class TestTreeSet {public static void main(String[] args) {TreeSet<Person> people = new TreeSet<Person>();people.add(new Person("曹宇希",1));people.add(new Person("曹宇希",2));people.add(new Person("曹宇希",3));people.add(new Person("曹宇希",4));System.out.println(people.size());//1System.out.println(people);//[{曹宇希,1}]}
}

8、我們也可以規定一下排序的順序,可以才compareTo中進行修改,如:讓年齡大的排在后面,就要添加age屬性

package testhashset;import java.util.TreeSet;public class TestTreeSet {public static void main(String[] args) {TreeSet<Person> people = new TreeSet<Person>();people.add(new Person("曹宇希",1));people.add(new Person("曹宇希",2));people.add(new Person("曹宇希",3));people.add(new Person("曹宇希",4));System.out.println(people.size());//1System.out.println(people);//[{曹宇希,1}]}
}

這里重寫toString為了方便查看

package testhashset;public class Person implements Comparable<Person>{private String name;private int testNum;//記錄人是誰,來分別剩下的一個,是第一次存儲的還是最后一次存儲的?private int age;public Person(String name,int age, int testNum) {this.name = name;this.testNum = testNum;this.age = age;}//重寫toString方法,讓對象打印輸出的時候,不需要在.get方法了,而是直接輸出對象的屬性// ,而不是hashCode碼了public String toString() {/* 這種方法不是很好return "{" + this.name + ", " + this.testNum + "}";*/StringBuilder builder = new StringBuilder("{");builder.append(this.name);builder.append(", ");builder.append(this.testNum);builder.append("}");/*return builder.toString(); 下面的也可以*/return new String(builder);}public int compareTo(Person o) {//當前對象name和另一個對象name的compareTo結果,compareTo是String類型的,是name的compareToint value = this.name.compareTo(o.name);if (value != 0) {//如果他們兩個的名字不一樣,說明不是一個對象return value;//輸出名字}//這里自己規定了一個排序:正數排到后面去,正數說明年齡大,當前年齡大就拍到后面去return this.age - o.age;}
}
package testhashset;
?
import java.util.TreeSet;
?
public class TestTreeSet {public static void main(String[] args) {
?TreeSet<Person> people = new TreeSet<Person>();people.add(new Person("曹宇希",12,1));people.add(new Person("曹宇希",34,2));people.add(new Person("曹宇希",56,3));people.add(new Person("曹宇希",23,4));System.out.println(people.size());//4System.out.println(people);//[{曹宇希, 1}, {曹宇希, 4}, {曹宇希, 2}, {曹宇希, 3}]
?}
}

(6)Set集合總結

1、HashSet無序無重復集合

2、Set集合主要具體的實現類:HashSet、TreeSet

3、特點:無序無重復

4、無序:添加的順序和獲取的順序不一致(不是集合本身是否有效),Tree是自然有序(按照字典的索引號,字母的自然順序Unicode碼)

5、無重復:添加的元素不能一致(如果出現重復元素,只存儲第一個,后面的就不在存入了)

6、set集合家族的基本使用:增add(E e);刪remove(E e);沒有修改;查iterator迭代器:hasNext();next();獲取有序元素個數size();

1. HashSet無重復特性:

(1)HashSet 無重復原則有兩個方法同時起作用 equals()、hashCode();

(2)默認比較的是兩個對象的地址,若第二個對象地址與之前的一致,不再存入,如果想要改變比較的規則,可以重寫上述兩個方法

(3)HashSet(HashMap----->數據存儲結構 散列表(數組+雙向鏈表))

2. TreeSet無重復特性:

(1)TreeSet 無重復原則有一個方法起作用 compareTo

(2)上述這個方法不是每一個對象都有的,如想要將某一個對象存入TreeSet合集中,需要讓對象所屬的類實現接口Comparable,實現接口后將compareTo方法重寫,返回值int 負數靠前排布,正數排列靠后

(3)HashSet(TreeMap----->數據存儲結構 二叉樹)

HashSet無序無重復集合

(1)需要重寫equals、hashCode方法才可以實現無重復,

(2)HashSet的無序:我們存入的元素順序和我們取出來的不一致,它有自己的hash算法排序,但是咱們找不到規律;

(3)底層是個HashMap

TreeSet無序無重復集合

(1)需要重寫compareTo方法才能實現無重復,

(2)TreeSet無序:當我們存入元素時,它底層會給進行排序(就是compareTo按照字母unicode碼在底層給你排序好),當取出來時就按照它底層排序好的取;

(3)底層是個TreeMap

23.4 Map集合

(1)Map介紹

1、Map----映射----通過某一個key可以直接定位到一個value值,存儲方式以鍵值對存儲的(key-value),key無序無重復,value無序可重復

2、key無序:無序還是一樣,指的是存入順序與取得順序不一致

3、key無重復:指的是元素不能一致

4、Map的基本使用:HashMap、TreeMap、Properties(讀取文件中的信息)

(2)HashMap

1、java.util包

2、構造方法創建對象:無參數、參默認容量的、帶map參數的構造方法

3、特點:(數組 + 鏈表)底層散列表形式存儲,key無序無重復、value無序可重復(在找尋某一個唯一元素的時候建議使用map,更適合查找唯一元素)

4、基本方法:

(1)增put(key , value);存放一組映射關系(key-value)將指定的值與此映射中的指定鍵相關聯。

①key存儲的順序與取得順序不同,不同的key可以存儲相同的value

②key若有相同的,則將原有的value覆蓋,而不是拒絕存入(跟Set集合正好相反)

//創建一個HashMap對象
HashMap<Integer, String> map = new HashMap<Integer, String>();
//將一些key-value的映射關系存入集合
map.put(1,"a");//key不同 value同
map.put(4,"a");
map.put(2,"b");//key同 value不同
map.put(2,"bc");
System.out.println(map);// {1=a, 2=bc, 4=a}

(2)刪V = remove(object key);從該地圖中刪除指定鍵的映射(如果存在)。remove(object key,object value);

map.remove(1);//把key為1的刪除
System.out.println(map);//{2=bc, 4=a}

(3)改可以利用put進行覆蓋put( key , value1);put( key , value2);

也提供了修改的方法boolean = replace(key , new Value);只有當目標映射到某個值時,才能替換指定鍵的條目。

(4)查V = get(key);如果key不存在就返回null,存在就返回對應的value; 返回到指定鍵所映射的值,或 null如果此映射包含該鍵的映射。

(5)int = size();獲取有序元素

(6)void = clear()將Map集合中元素清空

(7)boolean = containsKey();是否包含建。boolean = containsValue();是否包含值

(8)V = getOrDefault( key , defaultValue);如果Key存在就返回對應的value,如果沒有就返回一個默認值(默認值可以自己定義)

map.getOrDefault(10,"1000");//如果沒有就返回自己定義的默認值1000

(9)boolean = isEmpty();判斷集合是否為空

(10)void = putAll(map);首先滿足你填進來的泛型得滿足我本身的泛型或者是子集才可以添加

(11)V = putIfAbsent(key ,value) ;如果key不存在才向集合內添加value,如果存在就不添加

map.putIfAbsent(2,"sss");//如果key=2的建沒有就添加這個字符串,如果有就不添加

5、遍歷map集合?需要有循序和次數才能遍歷,遍歷比較麻煩

(1)首先獲取到所有的key(利用keySet方法,然后返回一個Set父類集合)

(2)遍歷key(由于返回的是Set,所以要想遍歷Set就要通過迭代器)

(3)通過key獲取value(迭代器有hasNext和next方法)

 //創建一個HashMap對象HashMap<Integer, String> map = new HashMap<>();//將一些key-value的映射關系存入集合map.put(1,"a");//key不同 value同map.put(4,"a");map.put(2,"b");//key同 value不同map.put(3,"bc");map.put(5,"bc");//獲取map集合的全部key,返回值是Set集合是個父類Set<Integer> keys = map.keySet();//Set集合怎么遍歷?通過迭代器遍歷keysIterator<Integer> it = keys.iterator();while (it.hasNext()) {Integer key = it.next();String value = map.get(key);System.out.println(key + "--->" + value);//1--->a 2--->b 3--->bc 4--->a 5--->bc}

6、HashMap底層的數據結構存儲:

總:HashMap的存儲是以數組+ 鏈表的形式存儲,首先不同的對象可能產生相同code碼,但是不同code碼應該對應不同對象,然后這個Code碼經過Map自己的hash算法得到一個hash值,然后把key-value包裝成一個對象Entry存起來(這個Entry跟Node差不多)(這個Entry對象中存儲著key、value、next是下一個對象的地址),所以數組用于存儲hash值,當不同的對象產生相同的hash值時就在當前數組位置的后面串一個鏈,這個鏈就連接著對象,而這個對象的hash值和數組中的hash值一樣

7、兩種方式進行遍歷Map集合:

//獲取map集合的全部key,返回值是Set集合是個父類
Set<Integer> keys = map.keySet();
//Set集合怎么遍歷?通過迭代器遍歷keys
Iterator<Integer> it = keys.iterator();
while (it.hasNext()) {Integer key = it.next();String value = map.get(key);System.out.println(key + "--->" + value);
}
//獲取集合中全部的entry對象
Set<Map.Entry<Integer, String>> entries = map.entrySet();
//Set集合遍歷
Iterator<Map.Entry<Integer, String>> its = entries.iterator();
while (its.hasNext()) {Map.Entry<Integer, String> entry = its.next();//Entry中有:key value next(這個暫時不用,我不找下一個人,我想找的是Entry對象中的值)Integer key = entry.getKey();String value = entry.getValue();System.out.println(key + "--->" + value);
}

(3)如何選用集合和數組?

1、想要存儲一組元素

(1)數組,如果存儲的元素以后長度不變用數組;(比如星期,一周永遠是7天,長度固定不變)

(2)集合,如果長度以后不確定用集合

2、如果發現長度以后不確定--->集合

(1)List:list家族有序的,存儲有順序用這個

ArrayList(Vector) 更適合遍歷查詢

LinkedList 更適合插入刪除

Stack 先進后出

(2)Set:Set家族無重復,存儲元素希望自動去掉重復元素用這個

Hash 它的性能更高,但是排序亂

Tree 希望存進去的元素自動去重復,同時還能自動排序

(3)Map:map家族k-v,想要查找某一個元素的時候,通過唯一的k快速找尋v用這個

Hash 它的性能更高

Tree 希望存進去的元素key自動排序

(4)登錄小流程來體驗如何選用集合

1、數組:實現登錄認證

//方法:用來登錄認證--數組
private String[] userBox = new String[]{"yuxi","xixi","sad"};
private int[] passwordBox = new int[]{123,66,888};
?
//設計方法
public String loingForArray(String name, String password) {for (int i = 0; i < userBox.length; i++) {if (userBox[i].equals(name)) {if (passwordBox[i] == Integer.parseInt(password)){//你傳進來的password是Stringreturn "登錄成功";}break;}}return "用戶或密碼錯誤";
}

2、ArrayList:實現登錄認證

//方法:用來登錄認證--ArrayList
//new完之后也沒有我們想要的值
private ArrayList<String> userBox = new ArrayList<String>();
//可以用塊進行初始化,添加個人信息
{userBox.add("yuxi-123");userBox.add("xx-123");userBox.add("asd-123");
}
public String loginForList(String name, String password) {for (int i = 0; i < userBox.size(); i++) {//userBox.get(i)得到的是一個字符串String[] value = userBox.get(i).split("-");//返回值是數組了是一個人的信息 v[0]人名 v[1]密碼if (value[0].equals(name)) {if (value[i].equals(password)) {return "登錄成功";}break;}}return "用戶名或密碼錯誤";
}

3、Set:實現登錄認證

//方法:用來用戶認證--Set
private HashSet<String> userBox = new HashSet<String>();
{userBox.add("yuxi-123");userBox.add("xx-123");userBox.add("asd-123");
}
public String loginForSet(String name,String password) {//Set集合遍歷用迭代器IteratorIterator<String> it = userBox.iterator();while (it.hasNext()) {String[] value = it.next().split("-");//取出來的是一個人的信息,是個String串if (value[0].equals(name)) {if (value[1].equals(password)) {return "登錄成功";}break;}}return "用戶名或密碼錯誤";
}

4、Map:實現登錄認證

//方法:用來登錄認證--Map ?  name(唯一) pass
//key是唯一的可以通過人名直接就去找密碼
private HashMap<String,Integer> userBox = new HashMap<>();
{userBox.put("yuxi", 123);userBox.put("xx", 345);userBox.put("ss", 123);
}
public String loginForMap(String name, String password) {Integer realPassword = userBox.get(name);//如果key存在返回對應的value,不在就返回nullif (realPassword != null) { //證明人名存在//如果人名存在,那么我們就可以直接取找密碼了if (realPassword.equals(Integer.parseInt(password))) {return "登錄成功";}}return "用戶名或密碼錯誤";
}

優化后:

//簡化
public String loginForMap(String name, String password) {Integer realPassword = userBox.get(name);//如果key存在返回對應的value,不在就返回nullif (realPassword != null && realPassword.equals(Integer.parseInt(password))) { //證明人名存在return "登錄成功";}return "用戶名或密碼錯誤";
}

我們可以體會到每一個不同集合的特點

(5)TreeMap

1、java.util包

2、構建對象:無參數、帶map參數

3、自然有序,按照Unicode碼自然有序

4、底層數據結構的存儲

(6)設計學生做選擇題(考試機)

1、題目做成選擇題

(1)以下哪個選項不是Java基本類型?

A、short B、bollean C、String D、char

請您輸入認為正確的選項

2、學生考試之前需要先登錄認證

3、設計一個學生 考試機 老師關系

4、考試機存儲好多題目-----題庫10道

5、考試機隨機生成試卷的方法5道

6、學生利用生成的試卷開始-----------答案5個選項 A D B C A

7、老師負責批改卷子 最終成績

8、分析:

(1)考試的題目如何存儲?

自己去描述一個類---------一個題目類型,有兩個屬性----題干和真實的答案

(2)有幾個實體類(3個)類的關系?

1.考試機:

相當于一個題庫,存儲好多Question類型對象(包含關系,一個類當作另一個類的屬性存儲);

那么題庫能增加題進行擴容相當于是個集合,那么集合選用HashSet或ArrayList?假如你出了10個題又來了一個老師還要出10個題,以免防止題出現重復,所以要選用Set無重復集合;

考試機還有有一個功能就是隨機抽取題目的功能,定義一個方法-----隨機抽題目然后變為試卷,在給學生使用,所以返回值就是個試卷

2.學生:

學生要使用試卷才能做題(依賴關系,一個方法中出來另一個類),方法--參數試卷,返回一個學生最終的選項答案

3.老師:

方法---老師批卷子要拿學生的試卷答案和正確試卷答案進行比對,參數學生最終的選項答案 和 一個真實的試卷,返回學生成績

(3)具體添加每一個類中的成員描述(涉及到如何選擇容器來存儲的問題)

(4)具體的執行驗證

public class Question {private String title;//題目題干private String answer;//真實答案
?public Question(){}public Question(String title, String answer) {this.title = title;this.answer = answer;}//學生要看題干public String getTitle() {return title;}//老師要看答案public String getAnswer() {return answer;}//HashSet集合遵循原則;需要重寫equals和hashCode方法//將默認比較題目對象的地址規則,改成比較題干一致就是同一道題public boolean equals(Object obj) {//如果當前這個對象與傳進來的對象的地址一致,說明同一個對象,直接返回trueif (this == obj){return true;}//如果傳進來的對象屬于Question這個類型就比較if (obj instanceof Question) {Question anotherQuestion = (Question)obj;//傳進來的對象和Question是一個類型但是不是一個地址,需要造型//this.title 按照?截取 與 anotherQuestion.title?截取之前的部分比較if (this.title.equals(anotherQuestion.title)) {//比較全部題干return true;}}return false;//如果不屬于這個類型就false}public int hashCode() {return this.title.hashCode();}
}
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Random;
?
public class ExamMachine {//屬性---題庫,要存儲好多個Question類型的對象,每一個對象就是一道題目,把題放在集合中,這個題是個對象//Set集合,因為不重復,如果重復就覆蓋,如果題庫進行擴充,產生重復題目可以自動去掉//我們將題存在HashSet集合,那么它不會自動去掉重復元素,還要重寫equals和hashCode方法,才能遵循//所以我們要在Question中重寫規則,將默認比較題目對象的地址改為比較題干,題干一致就是同一道題private HashSet<Question> questionBank = new HashSet<Question>();
?//屬性---記錄學生賬號和密碼private HashMap<String, String> userBox = new HashMap<String,String>();//登錄就不用循環了//利用塊來初始化學生賬戶和密碼,學生登錄的時候都是學生自己的事{userBox.put("cao","123");userBox.put("hh","123");userBox.put("cxixi","123");}
?//利用塊來初始化hashSet集合內的題目對象{questionBank.add(new Question("如下哪個選項是Java基本數據類型?\n\tA.String\n\tB.Integer\n\tC.boolean\n\tD.Math","C"));questionBank.add(new Question("如下哪個選項不是Java基本數據類型?\n\tA.String\n\tB.int\n\tC.boolean\n\tD.double","A"));questionBank.add(new Question("如下哪個選項是Java引用數據類型?\n\tA.String\n\tB.int\n\tC.char\n\tD.char","A"));questionBank.add(new Question("如下哪個選項不是Java引用數據類型?\n\tA.String\n\tB.int\n\tC.char\n\tD.Double","C"));questionBank.add(new Question("如下哪個選項是java.util包中的類?\n\tA.String\n\tB.Integer\n\tC.Scanner\n\tD.Math","C"));questionBank.add(new Question("如下哪個選項不是java.util包中的類?\n\tA.Date\n\tB.Integer\n\tC.Calendar\n\tD.Random","C"));questionBank.add(new Question("如下選項不是java.util包中的類?\n\tA.Date\n\tB.Integer\n\tC.Calendar\n\tD.Random","C"));questionBank.add(new Question("如下選項不是java.util包中的類?\n\tA.Date\n\tB.Integer\n\tC.Calendar\n\tD.Random","C"));}
?//設計一個方法:隨機生成試卷,那么這個試卷有沒有參數?參數如果確定每張試卷的題是固定的就不用參數了(要是每張卷子的題不固定就需要參數)//返回值得是個卷子,試卷應該什么樣子啊?試卷應該和題庫一樣,就是比題庫的題少,所以試卷應該也是個集合,這個集合里面的泛型應該是Question//那這個試卷的集合用哪個好?大家知道這個試卷最后應該是給學生用,那么就要遍歷一個一個答題,那么遍歷好用的集合就是ArrayList,所以這個試卷//就是ArrayList<Question>public ArrayList<Question> getPaper() {System.out.println("考試機正在隨機的生成試卷,請耐心等待...");try{Thread.sleep(3000);//睡3秒等3秒} catch (Exception e) {e.printStackTrace();}//首先創建一個試卷用于存放隨機抽出來的題,然后每張試卷抽出來的題都不能完全一樣,在隨機抽取試卷的時候,試卷的題目應該是不重復的//試卷中的題可以用Set集合存,存完之后再把Set集合變為ArrayList集合HashSet<Question> paper = new HashSet<Question>();//這些題就能組合成一個試卷,然后在想辦法變成ArrayList
?//存完之后,這個試卷隨機抽,抽的題應該是在題庫中找,但是你想要去questionBank題庫中找題的話,通常是通過索引找,//,但是這個題庫是Set集合,是沒有索引的,所以要把題庫在這里轉化為ArrayListArrayList<Question> questionBank = new ArrayList<Question>(this.questionBank);//把當前題庫轉為有序的
?//一直隨機抽題,抽到這個題夠數為止while (paper.size() != 5) {//夠5題就不抽了//題庫有序了就可以抽題,產生個序號就行了,也就是索引號//隨機抽題,Random().nextInt()給出一個范圍,而這個范圍應該是題庫的長度int index = new Random().nextInt(this.questionBank.size());//[0~10)//抽到這個索引號之后,然后我們可以去當前函數的這個題庫中找題,就得到一個題目Question question = questionBank.get(index);//題目有了之后,放到這個當前的試卷中就可以了//將隨機抽的題放到試卷里paper.add(question);}//paper是HashSet類型的,如果要把這個試卷返回需要為ArrayList類型,那么我們就可以把Set集合構建成ArrayList集合return new ArrayList<Question>(paper);}
?//方法:用于學登錄認證,因為學生要在考試機上登錄成功才可以進行考試答題public String login(String username, String password) {//獲取Map集合中的密碼與輸入的密碼的進行比較String realPassword = this.userBox.get(username);//返回對應中的key的valueif (realPassword != null && realPassword.equals(password)) {return "登錄成功";}return "用戶名或密碼錯誤";}
?
}
import java.util.ArrayList;
import java.util.Scanner;public class TestMain {public static void main(String[] args){/*String question = "1、如下哪個選項不是Java基本數據類型?\n\tA.String\n\tB.int\n\tB.char";System.out.println(question);String answer = "A";*//*題干 答案 兩個字符串,需要存儲到一起,變成一個完整的題目,那怎么存儲呢?①String[2] {"title", "answer"}②String     "title-answer"③ArrayList<String[]>④HashMap<title, answer>;Map是通過key找value,找到這個value之后key就沒有了,get(key)得到value;如:get(1)得到A,key就沒有了,所以你得到一個答案但是你不知哪個題的上面的4種方法都不好,但能存儲Java是面向對象的編程思想------我能把每一道題當作每一個對象嘛?那么題干和答案就是屬性*//*Question question = new Question("1、如下哪個選項不是Java基本數據類型?\n\tA.String\n\tB.int\n\tC.char\n\tD.Double", "A");String value = question.getTitle();System.out.println(value);*///先創建考試機,用于獲取試卷ExamMachine machine = new ExamMachine();//調用構造器是,有一個塊默認執行,存入題//創建學對象用來考試Scanner scanner = new Scanner(System.in);System.out.println("歡迎進入考試系統\n請輸入人名");String username = scanner.nextLine();System.out.println("請輸入密碼");String password = scanner.nextLine();//然后創建學生對象Student student = new Student(username,password);//判斷輸入的是否正確String result = machine.login(student.getUsername(), student.getPassword());if (result.equals("登錄成功")) {System.out.println("登錄成功\n" + student.getUsername() + "同學開始考試啦!請認真作答");//獲得試卷后返回變為ArrayList集合//考試機隨機抽取一套試卷,這個試卷是個集合,集合中每一個元素都是一道題ArrayList<Question> paper = machine.getPaper();//學生考試,然后返回出學生的選項答案String[] answers = student.exam(paper);Teacher teacher = new Teacher();int score = teacher.checkPaper(paper, answers);System.out.println(student.getUsername() + "同學最終成績:" + score);} else {System.out.println(result + ";即將退出系統");}}
}
import java.util.ArrayList;
import java.util.Scanner;public class Student {private String username;private String password;public Student(String username, String password) {this.username = username;this.password = password;}public String getUsername() {return username;}public String getPassword() {return password;}//方法:學生需要考試,學生需要使用試卷,參數一套試卷,返回值學生做答得所有的選項//"A" "B" "C" "D"五個選項存哪,用數組好一點,因為你答完題最終得答案是不能改動//的,固定的String[]public String[] exam(ArrayList<Question> paper) {//先用數組存答案,有幾個題就給數組開辟多少空間的長度String[] answers = new String[paper.size()];//用于學生作答Scanner scanner = new Scanner(System.in);//學生答題一個一個答for (int i = 0; i < paper.size(); i++) {//我們要得到這個題庫中的題給學生作答Question question = paper.get(i);//但是Question中有題目和正確的答案,我們不能都拿因為正確答案不能給學生看,我們只獲取題干給學生看System.out.println( i+1 + "、" + question.getTitle());System.out.println("請輸入你認為正確的選項?");answers[i] = scanner.nextLine();//接收學生輸入的選項,存入數組中}return answers;}}
import java.util.ArrayList;public class Teacher {//負責批卷子,參數 學生作答所有選項,真實的試卷,跟學生隨機的那套一樣,因為要進行批改,返回值返回一個成績public int checkPaper(ArrayList<Question> paper, String[] answers) {System.out.println("老師正在批改卷子!");try {Thread.sleep(3000);} catch (InterruptedException e) {e.printStackTrace();}int score = 0;for (int i = 0; i < paper.size(); i++) {Question question = paper.get(i);//有可能學生輸入的選項答案有大寫還有小寫所以equalsIgnoreCase方法if (question.getAnswer().equalsIgnoreCase(answers[i])) {score = 100/paper.size();//答對一題就加一題的分  100/paper.size()如果以后擴題用這個好}}return score;}
}

二十四、錯誤與異常

24.1 異常

1、異常/錯誤:

(1)程序運行過程中,可能會發生一些不被期望的效果,肯定會阻止我們的程序按照指令去執行,這種不被預期出現的效果,肯定需要拋出來告訴我們。

(2)異常和錯誤是不能隨意被拋出的,需要定義或實現一些指定的規則才可以進行拋出。

(3)在Java中有一個定義好的規范Throwable類(可以拋出的),這個類實例化了一個序列化接口

2、Throwable有兩個子類:Error錯誤、Exception異常

3、Error錯誤:通常是一些物理性的,如:jvm虛擬機本身出現的問題,或者是咱們給出的程序或指令執行不了,或者是內存產生的一些問題,這些問題都是咱們程序指令處理不了的。StackOverflowError棧內存錯誤、OutOfMemoryError堆內存錯誤

4、Exception異常:我們主要關注異常,因為錯誤是我們自己不能解決的。異常通常是一種認為規定的不正常現象,通常是給定的程序指令產生了一些不符合規范的事情。

我們主要研究Exception異常,它下面還有很多子類

(1)異常的分支體系:

①、運行時異常(非檢查異常)

1、Error 和 RuntimeException都算作運行時異常

2、javac編譯的時候,不會提示和發現的(在程序編寫時不要求必須做處理),如果我們愿意可以添加處理手段,比如:try 和 throws

3、要求大家出現這樣異常的時候,知道怎么產生及如何修改

(1)InputMisMatchException 輸入不匹配 int value = scanner.nextInt();你輸入abc就會產生此異常

(2)NumberFormatException 數字格式化 int value = Integer.parseInt("abc");

(3)NegativeArraySizeException 數組長度負數 int[] array = new int[-2];

(4)ArrayIndexOutOfBoundsException 數組索引越界 int[] array = {1,2,3} ;array[10];

(5)NullPointerException 空指針異常 int[] [] array = new int[3] []; array0 = 10;相當于3個小數組,但是這個3個小數組沒有長度;

Person p = null;p.getName();都會產生空指針異常

(6)ArithmeticException 數字異常 ;如10/0 整數不允許除以0,Infinity小數除以0會產生無窮

(7)ClassCastException 造型異常; Person p = new Teacher(); Student s = (Student)p;就會產生

(8)StringIndexOutOfBoundsException 字符串越界 String str = "asd";char value = str.charAt(10); 打印value就會產生

(9)IndexOutOfBoundsException 集合越界 只有List家族 ArrayList<String> list = new ArrayList<String>() ;list.add("a"); list.get(20);

(10)IllegalArgumebtException 非法參數異常 ArrayList<String> list = new ArrayList<String>(-1) ;

②、編譯時異常(檢查異常)

1、除了Error和RuntimeException以外其他的異常

2、javac編譯的時候,強制要求我們必須為這樣的異常做處理(Try 或 throws),因為這樣的異常在程序運行過程中極有可能產生問題的,異常產生后后續的所有執行就停止了

(1)InterruptException;如:try{ Thread.sleep(5000); } catch(Exception e){ }

(2)添加處理異常的手段:

處理異常不是,異常消失了,處理異常指的是,處理掉異常之后,后續的代碼不會因為此異常而終止執行

兩種手段:

①、try{ }catch(){ }[finally{ }]

1、try不能單獨的出現,后面必須添加catch或finally,catch有一組()目的是為了捕獲某一種異常,catch可以有多個

 ? ? ? ?
try{System.out.println("try開始");String str = null;str.length();str.charAt(10);System.out.println("try完畢");} catch (NullPointerException e) {//這里只能捕獲空指針,其他異常不能捕獲System.out.println("捕獲到了空指針異常");} catch (StringIndexOutOfBoundsException e) {System.out.println("捕獲到了字符串越界");} finally {System.out.println("我是finally必須執行");}

捕獲的異常之間沒有任何的繼承關系,捕獲的異常需要從小到大進行捕獲

2、finally不是必須存在的,若存在finally結構,則必須執行

//就是用try去嘗試一下String str = null;這行代碼是否出現異常,如果沒異常就直接執行,有異常就捕獲了
try{System.out.println("try開始");String str = null;str.length();str.charAt(10);System.out.println("try完畢");
} catch (NullPointerException e) {//這里只能捕獲空指針,其他異常不能捕獲System.out.println("捕獲到了空指針異常");
} catch (Exception e) {System.out.println("捕獲到了其他的異常");
} finally {System.out.println("我是finally必須執行");
}
?

3、如果處理異常放在方法內部,可能還有一些問題:

(1)如果在方法內部含有返回值,不管返回值return關鍵字在哪里,finally一定會執行完畢,返回值的具體結果,看情況如果測試的代碼沒有問題就執行最后的retun,如果有問題就返回try中的

public class Test {public static void main(String[] args) {
?Test test = new Test();test.testException();}public String testException() {//無論return放在哪,都會執行finally,try catch finally是個整體,必須把這個整體執行完try{System.out.println("try開始");String str = null;System.out.println("try完畢");return "try中的返回值";}catch (Exception e) {//e.printStackTrace();//打印輸出異常的名字System.out.println("捕獲到了異常");} finally {System.out.println("我是finally必須執行");}return "最終的返回值";}
}
?
最后輸出:try開始 try完畢finally執行完try中的返回值

final 和 finally 和 finalize的區別:完全沒關系

1、final:

(1)特征修飾符,修飾變量、屬性、方法、類;

(2)修飾變量、基本類型的時候,值不能改變,修飾引用類型的時候,地址不能改變(如果變量沒有初值,給一次機會賦值);

(3)修飾屬性,特點與修飾變量類型(要求必須給屬性賦初始值,否則編譯報錯);

(4)修飾方法,不能被子類重寫

(5)修飾類,不能被其他的子類繼承

2、finnally:

(1)處理異常手段的一部分try{ }catch(){ }后面的一部分,這個部分可有可無,如果有只能含有一份,且必須執行

3、finalize:

(1)Object類中的一個protected方法,對象沒有任何引用指向的時候---會被GC回收,當對象回收的時候,默認調用finalize方法,若想看回收效果,需要重寫此方法

②、throws拋出

1、異常只能在方法上拋出,屬性是不能處理異常的,方法可以拋出不止一個異常,拋出的異常與多個catch類似,要么沒關系,要么先拋出小異常

(3)自定義異常

1、自己描述一個異常的類

2、讓我們自己的類繼承,如果繼承RuntimeException---》運行時異常(不需要必須添加處理手段)

如果繼承時Exception----》編譯時異常(必須添加處理手段)

3、需要創建一個當前自定義異常類的對象,通過throws關鍵字,主動產生異常

4、當我們設計描述的方法(事情),發現在之前沒有相關的異常能描述我的問題,這個時候才會利用自定義異常來描述

public class Test {public static void main(String[] args) {
?Test test1 = new Test();try {test1.testMyException();} catch (Exception e) {e.printStackTrace();}
?}//設計方法:測試自定義異常的使用public void testMyException() {System.out.println("測試自定義異常的方法執行了");if (3 > 2) { //若滿足某個條件throw new MyException("說明一下異常的具體問題");}}
}
package testthrowable;
?
public class MyException extends RuntimeException{public MyException(String msg) {super(msg);}
}

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/212718.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/212718.shtml
英文地址,請注明出處:http://en.pswp.cn/news/212718.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

gin博客項目開發日志1

gin項目博客系統偽第一代 項目概述 1.1 目標 實現一個功能完整、易用的博客系統&#xff0c;允許用戶發布、編輯和管理博客文章。 1.2 背景 看到網上有很多語言寫的博客系統&#xff0c;但go的卻很少&#xff0c;正好&#xff0c;現在我在學go&#xff0c;可以拿博客來練練…

組件之間傳值

目錄 1&#xff1a;組件中的關系 2&#xff1a;父向子傳值 3&#xff1a;子組件向父組件共享數據 4&#xff1a;兄弟組件數據共享 1&#xff1a;組件中的關系 在項目中使用到的組件關系最常用兩種是&#xff0c;父子關系&#xff0c;兄弟關系 例如A組件使用B組件或者C組件…

深入了解UDP協議:特點、應用場景及市面上常見軟件案例

目錄 引言 UDP的特點 UDP的應用場景 市面上使用UDP的軟件案例 結論 引言 在計算機網絡中&#xff0c;UDP&#xff08;User Datagram Protocol&#xff09;是一種面向無連接、無狀態的傳輸層協議。與TCP相比&#xff0c;UDP具有獨特的特點和適用場景。本文將深入探討UDP協…

解碼方法dp

1.狀態表示 2.狀態轉移方程 3.初始化 4.填表順序 從左往右 5.返回值 dp[n-1] 6.處理邊界問題以及初始化問題的技巧

Docker筆記:數據卷掛載的三種方式及物理機與容器內的環境變量的傳遞

容器數據掛載到物理機上的三種方式 1 &#xff09; 實名(指定路徑)掛載數據卷 docker run -v 物理機目錄:容器內目錄 鏡像id示例 docker run -it -d --name mynginx_p_v -p 82:80 -v /root/www:/usr/share/nginx/html nginx此時訪問 會報 403 forbidden因為 物理機上的 root/…

Electron[5] 渲染進程和主進程

1 進程 Electron里頭的進程分為渲染進程和主進程。簡單理解&#xff1a; main.js就是主進程每個頁面就是渲染進程一個Electron應用僅有一個主進程&#xff0c;可以有多個渲染進程 上面的這些概念很重要&#xff0c;不展開細講。 2 進程職責 主進程是用來實現應用的基礎功能…

【小沐學Python】Python實現TTS文本轉語音(speech、pyttsx3、百度AI)

文章目錄 1、簡介2、Windows語音2.1 簡介2.2 安裝2.3 代碼 3、pyttsx33.1 簡介3.2 安裝3.3 代碼 4、ggts4.1 簡介4.2 安裝4.3 代碼 5、SAPI6、SpeechLib7、百度AI8、百度飛槳結語 1、簡介 TTS(Text To Speech) 譯為從文本到語音&#xff0c;TTS是人工智能AI的一個模組&#xf…

K8S學習指南(6)-k8s核心概念label和label selector

文章目錄 前言Label是什么&#xff1f;示例 Label Selector是什么&#xff1f;示例 Label的使用場景Label Selector的類型Label和Label Selector的高級應用使用Label Selector選擇Service的后端Pod使用Label Selector進行滾動更新 總結 前言 Kubernetes是一個強大的容器編排平…

Python從入門到精通

一、Python基礎語法 1、字面量 掌握字面量的含義了解常見的字面量類型基于print語句完成各類字面量的輸出 什么是字面量&#xff1f; 字面量&#xff1a;在代碼中&#xff0c;被寫下來的的固定的值&#xff0c;稱之為字面量 常用的值類型 Python中常用的有6種值&#xff…

MyBatis 四大核心組件之 ResultSetHandler 源碼解析

&#x1f680; 作者主頁&#xff1a; 有來技術 &#x1f525; 開源項目&#xff1a; youlai-mall &#x1f343; vue3-element-admin &#x1f343; youlai-boot &#x1f33a; 倉庫主頁&#xff1a; Gitee &#x1f4ab; Github &#x1f4ab; GitCode &#x1f496; 歡迎點贊…

MyBatis動態SQL(Dynamic SQL)

Mybatis框架的動態SQL技術是一種根據特定條件動態拼裝SQL語句的功能&#xff0c;它存在的意義是為了解決拼接SQL語句字符串時的痛點問題。 實際開發中可以通過以下幾種標簽進行動態SQL拼接。 1 if標簽 根據test屬性所對應的表達式計算結果決定標簽中的內容是否拼接到sql中。 …

基于SpringBoot+JSP+Mysql寵物領養網站+協同過濾算法推薦寵物(Java畢業設計)

大家好&#xff0c;我是DeBug&#xff0c;很高興你能來閱讀&#xff01;作為一名熱愛編程的程序員&#xff0c;我希望通過這些教學筆記與大家分享我的編程經驗和知識。在這里&#xff0c;我將會結合實際項目經驗&#xff0c;分享編程技巧、最佳實踐以及解決問題的方法。無論你是…

《C++新經典設計模式》之第15章 適配器模式

《C新經典設計模式》之第15章 適配器模式 適配器模式.cpp 適配器模式.cpp #include <iostream> #include <vector> #include <string> #include <fstream> #include <memory> using namespace std;// 解決兩個類之間的兼容性問題 // 轉換接口調…

ffmpeg6.0之ffprobe.c源碼分析二-核心功能源碼分析

本篇我們繼續分析: 1、ffprobe -show_packets 參數的處理流程;2、ffprobe -show_frames 參數的處理流程;3、ffprobe -show_streams 參數的處理流程;4、ffprobe -show_format 參數的處理流程; 因為前面的文章已經回顧了這些命令的使用,以及作用。本文就不在贅述,以免篇幅…

《妙趣橫生的算法》(C語言實現)- 第5章 數學趣題(一)

《妙趣橫生的算法》&#xff08;C語言實現&#xff09;-第5章 數學趣題&#xff08;一&#xff09; 提示&#xff1a;這里可以添加系列文章的所有文章的目錄&#xff0c;目錄需要自己手動添加 例如&#xff1a;第一章 Python 機器學習入門之pandas的使用 提示&#xff1a;寫完文…

“新華三杯”第十屆成都信息工程大學ACM程序設計競賽(同步賽)L. 怎么走啊(最短路+二分 分段函數)

題目 登錄—專業IT筆試面試備考平臺_牛客網 思路來源 衡陽師范學院ac代碼、pj學弟 題解 大致可以證明&#xff0c;在w從1e5減小到1的過程中&#xff0c; 之前某條反向邊沒有用到&#xff0c;現在需要用到反向邊&#xff0c;也就是正向邊用到的變少了 這樣的變化有sqrt個&a…

分層網絡模型(OSI、TCP/IP)及對應的網絡協議

OSI七層網絡模型 OSI&#xff08;Open System Interconnect&#xff09;&#xff0c;即開放式系統互連參考模型&#xff0c; 一般都叫OSI參考模型&#xff0c;是ISO組織于1985年研究的網絡互連模型。OSI是分層的體系結構&#xff0c;每一層是一個模塊&#xff0c;用于完成某種功…

服務器GPU占用,kill -9 PID 用不了,解決辦法

PID&#xff08;progress ID 進程ID&#xff09; 上圖為占用情況&#xff0c;使用下面的指令都不管用 kill -9 PID kill -15 PID # 加入sudo 還是不行 # 等等網上的 chatgpt 提供的其他辦法&#xff0c;一圈試了下來還是不管用最后解決辦法 首先用下面的指令查看進程的樹結構…

【Hexo】自動在中英文之間添加空格

本文首發于 ??慕雪的寒舍 如題&#xff0c;中英文添加空格是比較規范的寫法&#xff0c; 但是我個人實在是懶&#xff0c;每次都要這么弄太累了。想找找hexo有沒有對應的插件&#xff0c;還是有的 npm install hexo-filter-auto-spacing --save安裝了之后&#xff0c;在hexo的…

〖大前端 - 基礎入門三大核心之JS篇?〗- 面向對象之對象的方法、遍歷、深淺克隆

說明&#xff1a;該文屬于 大前端全棧架構白寶書專欄&#xff0c;目前階段免費&#xff0c;如需要項目實戰或者是體系化資源&#xff0c;文末名片加V&#xff01;作者&#xff1a;哈哥撩編程&#xff0c;十余年工作經驗, 從事過全棧研發、產品經理等工作&#xff0c;目前在公司…