/** * */ package com.qfedu.Day18.HomeWork; public abstract class Animal { private int tui; public int getTui() { return tui; } public void setTui(int tui) { this.tui = tui; } public Animal(int tui) { super(); this.tui = tui; } public Animal() { super(); // TODO Auto-generated constructor stub } } /** * */ package com.qfedu.Day18.HomeWork; public class Cat extends Animal { /** * @param tui */ public Cat(int tui) { super(tui); // TODO Auto-generated constructor stub } /** * */ public Cat() { // TODO Auto-generated constructor stub } } /** * */ package com.qfedu.Day18.HomeWork; public class Fish extends Animal{ //子類是無法繼承父類的構造方法的 //子類必須提供自己的構造方法 public Fish() { //調用父類的無參構造方法 super(); } public Fish(int tui) { super(tui); // 調用類父類的有參構造方法 } } /** * */ package com.qfedu.Day18.HomeWork; public class QQ extends Animal { /** * @param tui */ public QQ(int tui) { super(tui); // TODO Auto-generated constructor stub } /** * */ public QQ() { // TODO Auto-generated constructor stub } } /** * */ package com.qfedu.Day18.HomeWork; /** * Description: 創建自定義異常<br/> * Copyright (c) , 2018, JK <br/> * This program is protected by copyright laws. <br/> * Program Name:TUIException.java <br/> * * @author 千鋒智哥 * @version : 1.0 * 繼承Exception --> 編譯時異常 --> 在書寫代碼調用方法或其他的屬性時就會出現異常信息,必須處理 * try...catch...finally throws * 繼承RuntimeException -->運行時異常 在程序運行以后,才會出現的異常 出現異常之后,可以捕捉也繼續拋出 */ public class TUIException extends Exception{ /** * 區分JdK版本號使用 --> 對象流 */ private static final long serialVersionUID = -2974291582387079751L; public TUIException() { super(); // TODO Auto-generated constructor stub } public TUIException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) { super(message, cause, enableSuppression, writableStackTrace); // TODO Auto-generated constructor stub } public TUIException(String message, Throwable cause) { super(message, cause); // TODO Auto-generated constructor stub } public TUIException(String message) { super(message); // TODO Auto-generated constructor stub } public TUIException(Throwable cause) { super(cause); // TODO Auto-generated constructor stub } } /** * */ package com.qfedu.Day18.HomeWork; public class AnimalFactory { private AnimalFactory() {} public static Animal getAnimal(int tui,String AnimalName) { switch (AnimalName) { case "貓": return new Cat(tui); case "魚": return new Fish(tui); case "企鵝": return new QQ(tui); default: throw new RuntimeException("沒有這種動物"); } } } /** * */ package com.qfedu.Day18.HomeWork; import java.util.HashSet; import java.util.Scanner; import java.util.Set; public class AnimalManagerSystem { public static void main(String[] args) { Scanner input = new Scanner(System.in); Set set = new HashSet(); while(true) { System.out.println("請輸入您要添加的動物:"); String name = input.next(); System.out.println("請輸入退的個數:"); int tui = input.nextInt(); //通過工廠就能的到對象 try { Animal animal = AnimalFactory.getAnimal(tui, name); addAnimal(animal); set.add(animal); System.out.println("謝謝添加"); break; }catch(TUIException | RuntimeException e) { System.out.println(e.getMessage()); } } } /** * 就是一個檢查動物退是否正確的一個方法 * @param a 父類Animal * @throws TUIException 個數不對 */ public static void addAnimal(Animal a)throws TUIException { if(a instanceof Cat) { Cat c = (Cat)a; if(c.getTui() != 4) { throw new TUIException("這個退不對"); } }else if(a instanceof Fish) { Fish f = (Fish)a; if(f.getTui() != 0) { throw new TUIException("這個魚是不可能有退的,若有拿來看!!!!"); } }else { QQ qq = (QQ)a; if(qq.getTui() != 2) { throw new TUIException("這個退不對"); } } System.out.println("添加成功"); } }
回顧:
學習了Set集合
Set集合的特點就是:無序(無序不等於隨機),排重
ps:打印是打印 存儲是存儲
打印只是展示存儲的數值數據
存儲是底層存放的方式
實現類:
HashSet:使用Hash表的形式來存數據, 無序 ,排重
當前類的子類:
LinkedHashSet:鏈表和Hash表的雙重實現,即可以排重也可以記錄存儲信息本身沒有特殊方法,使用可以參考Set集合中的方法
TreeSet:二叉樹形式存儲-->使用紅黑二叉樹
排重 排序(默認是升序) 使用TreeSet需要注意:存儲的數據必須具備可比性(相同數據類型才行)
自定義類進行排序如何使用:
實現兩個接口
Comparator 自定義比較器
Comparable 系統比較器
兩者接口返回的 使用 正數,負數,零來判斷這些升序,降序,不變
兩個接口實現的方法時不同的
TreeSet排序建議使用哪個Comparable接口 對應TreeSet默認無參構造方法
Comparator可以使用在一些自己定義排序的方式
例如: Collections.sort Arrays.sort 也能對應TreeSet的有參構造方法
/** * */ package com.qfedu.Day18.HomeWork; public class Worker implements Comparable{ private int age; private int workAge; private int money; public Worker(int age, int workAge, int money) { super(); this.age = age; this.workAge = workAge; this.money = money; } public Worker() { super(); // TODO Auto-generated constructor stub } public int getAge() { return age; } public void setAge(int age) { this.age = age; } public int getWorkAge() { return workAge; } public void setWorkAge(int workAge) { this.workAge = workAge; } public int getMoney() { return money; } public void setMoney(int money) { this.money = money; } /* (non-Javadoc) * @see java.lang.Comparable#compareTo(java.lang.Object) */ @Override public int compareTo(Object o) { //沒有泛型之前 Worker other = (Worker)o; int Sage = this.age - other.age; int SworkAge = other.workAge - this.workAge; int Smoney = other.money - this.money; int sum = Sage == 0 ? SworkAge == 0 ? Smoney : SworkAge : Sage; //return sum; return this.age - other.age == 0 ?other.workAge - this.workAge == 0 ? other.money - this.money : other.workAge-this.workAge : this.age-other.age; } /* (non-Javadoc) * @see java.lang.Object#toString() */ @Override public String toString() { return "年齡:"+age+","+"工齡:"+workAge+","+"薪水:"+money; } } /** * */ package com.qfedu.Day18.HomeWork; import java.util.TreeSet; public class Test { public static void main(String[] args) { TreeSet set = new TreeSet(); set.add(new Worker(18, 2, 3000)); set.add(new Worker(18, 5, 3100)); set.add(new Worker(18, 2, 3700)); set.add(new Worker(19, 2, 3200)); set.add(new Worker(30, 10,1500)); System.out.println(set); } }
泛型(genericity):
為什么要使用泛型?
/** * */ package com.qfedu.Day18.Genericity.Tong; import java.util.ArrayList; import java.util.List; public class Demo { public static void main(String[] args) { List<Integer> list = new ArrayList<>(); list.add(123); //list.add("123"); //手動擦除 -->嚴禁使用 List list1 = list; list1.add("1111"); System.out.println(list); } } /** * */ package com.qfedu.Day18.Genericity.Tong; import java.util.ArrayList; import java.util.List; public class Test { public static void main(String[] args) { //千萬不能這樣使用 ? 是通配符 錯誤 // List<?> list = new ArrayList<>(); // list.add("1"); //蓋住變量名 去除等號右邊 ,剩下的就是數據類型 List<Integer> list1 = new ArrayList<>(); doWork(list1); List<String> list2 =new ArrayList<>(); doWork(list2); } //若集合使用了泛型,此時在方法中作為參數是,也要指定泛型是什么 // public static void doWork(List<Integer> array) { // // } //1.通配符的第一個作用就是作為方法的參數的數據類型而存在 //此時,此方法可以接受任何泛型的集合,傳入到方法中 public static void doWork(List<?> list) { //list.add(1); System.out.println(list); } }
案例1:
集合可以存儲任何數據類型,必然集合中需要使用Object類型接受
1.若需要使用計算或是當前對象的特有屬性和方法強制類型轉換(向下轉型)
2.向集合中存儲元素,無法限制存儲元素的數據類型
我們可以使用泛型來約束集合中存儲的數據類型,並且使用了泛型后就不需要強制類型轉換了(向下轉型)
但是這樣一來會出現一個問題,不能再存儲任何數據類型,只能存儲限制的數據類型對應的值
案例2:
設計一個點(Ponit),來封裝坐標,要求坐標的數據類型可以支持String,int,double,float,
class Point{
private String x;
private String y;
}
class Point{
private int x;
private int y;
}
....
原則DRY 不要重復自己
可以通過創建對象時在決定Point的數據是什么,這樣一來是不是就可以不用創建多個Point而只要建立一個類即可
class Point{
privare T x;
private T y;
}
new Point();
就可以使用泛型
什么是泛型:
1.泛型的含義就是代表任何數據類型,但是本身沒有任何含義,就是一個站位符
2.在不能明確數據類型式,我們即可以使用這種占位符的形式來替代數據類型
特點:
通過<數據類型>接收一種引用數據類型,在編譯程序時該類型會對[集合、類、接口、方法]中傳入的數據進行類型匹配
如果不是當前類型,編譯就不會通過,從運行時的問題提升到了編譯時
泛型是用在編譯時期的,編譯完成之后產生.class文件后泛型就不會存在了-->泛型擦除
泛型在定義階段沒有任何意義,只是占位符問題
實際使用中參數的傳遞或類型的定義,此時當前泛型才會有真正的意義
泛型的分類
泛型應用在類上
泛型中定義的字本身沒任何意義,就是占位
看Class包
/**
*
*/
package com.qfedu.Day18.Genericity.Class;
/**
* Point類可以接受String,double,float,int,long 作為參數的數據類型
*/
public class Point<T> {//泛型類 -->類中定義的泛型可以在類體中使用 -->通用性
//在沒有給ArrayList指定泛型時,可以接受任何數據類型
//此時定義在ArrayList上的<E> 相當於什么 --> Object
//可以作為屬性的數據類型而存在 ,當前數據類型是不能確定了 只是使用了一個字母T作為占位使用
private T x;
private T y;
public Point() {
}
public Point(T x, T y) {//類中方法可以作為數據類型
this.x = x;
this.y = y;
}
public T getX() {
return x;
}
public void setX(T x) {
this.x = x;
}
public T getY() {
return y;
}
public void setY(T y) {
this.y = y;
}
public void show(T z) {
System.out.println(z);
}
}
/**
*
*/
package com.qfedu.Day18.Genericity.Class;
public class Test {
//如何使用泛型類
public static void main(String[] args) {
//不推薦
// Point p1 = new Point();
// //默認是泛型類,在創建對象時不指定泛型類型也可以使用但是,不指定就是Object
// p1.show(10);
//如何創建對象
Point<String> p1 = new Point<>();
p1.setX("1");
//T 相當於 Object
Point<Integer> p2 = new Point<>();
p2.setX(1);
Point<Boolean> p3 = new Point<>();
p3.setX(true);
}
}
/** * */ package com.qfedu.Day18.Genericity.Method; public class MethodClass<T> { //當前方法使用泛型類型就和類是一致的了 public void show(T t) { } //類所定義的泛型不能再靜態方法中使用,提供自己的泛型方法 // public static void display(T t) { // System.out.println(t); // } //泛型方法的定義 //什么時候能確定這個泛型的數據類型-->調用方法時傳遞參數,就會決定方法的泛型的數據數據類型 public<E> void dispaly(E e) { System.out.println(e); } public static<K> void showInfos(K k) { } }
泛型應用在方法上
1.泛型類中的泛型只能適用於非靜態方法,如果需要給靜態方法添加泛型,此時就需要定義泛型方法了
2.方法想使用自己的泛型類型,並不想使用其他方式提供的泛型,此時就需要使用泛型方法了
看Method包
泛型應用在接口上
看Inteface包
/** * */ package com.qfedu.Day18.Genericity.Inteface; //和類是類似的使用方式 public interface InterFaceDemo<T> { //1.8之前 String NAME = "1"; //public static final //抽象方法 全局靜態常量 void show(T t); // public abstract //1.8之后 //定義實現方法 //default 修飾 static 修飾 --> 都是公有public //default可以重寫 static 不行 //default可以通過接口對象調用 static接口名調用 } /** * */ package com.qfedu.Day18.Genericity.Inteface; //1.確定泛型接口中泛型的數據類型,使用類實現接口並制定泛型類型 public class Person implements InterFaceDemo<String>{ /* (non-Javadoc) * @see com.qfedu.Day18.Genericity.Inteface.InterFaceDemo#show(java.lang.Object) */ @Override public void show(String t) { // TODO Auto-generated method stub } } /** * */ package com.qfedu.Day18.Genericity.Inteface; //2.泛型類實現泛型接口,此時可以通過泛型類型中的泛型來占位泛型接口中的泛型 // 創建當前泛型類對象的時,此時就可以制定泛型的數據類型 public class Student<M> implements InterFaceDemo<M>{ /* (non-Javadoc) * @see com.qfedu.Day18.Genericity.Inteface.InterFaceDemo#show(java.lang.Object) */ @Override public void show(M t) { // TODO Auto-generated method stub } } /** * */ package com.qfedu.Day18.Genericity.Inteface; public class Test { public static void main(String[] args) { //3.以匿名內部類的形式來完成泛型接口的創建,同時指定泛型類型 new InterFaceDemo<String>() { @Override public void show(String t) { // TODO Auto-generated method stub } }; } }
泛型通配符 ?
通配符不能單獨使用,僅限於在使用參數定義數據類型時使用
? 在不知道是什么數據類型時,也可以使用? 來代替
泛型的限定:
<? extends 類>
此時只能傳入當前類的子類或當前類
<? super 類>
此時只能傳入當前類或父類類型
ps:
泛型擦除:
1.泛型在編譯過后會被自動消除
2.當把帶有泛型的集合賦值給不帶有泛型的集合時,此時泛型被擦除(手動擦除)
Map集合:(非常重要)
Map集合是一種映射集合,map集合集合中存在着一種對應關系 key- value 鍵值對 -->(JSON數據格式)
要求:
1.key的值必須是唯一的,不能重復
2.value的可以重復必備唯一
key必須唯一,但是Value可以不唯一 一個key只能對應一個value 同一個value可以對應多個key
key這邊想成是一個Set集合
value這邊想成是一個List集合
HashMap集合常用方法
API
看HashMap包
/** * */ package com.qfedu.Day18.HashMap; public class Card { //cardNo:銀行卡號,startDate:開戶日期, money private String cardNo; private String startDate; private String money; public Card() { super(); // TODO Auto-generated constructor stub } public Card(String cardNo, String startDate, String money) { super(); this.cardNo = cardNo; this.startDate = startDate; this.money = money; } public String getCardNo() { return cardNo; } public void setCardNo(String cardNo) { this.cardNo = cardNo; } public String getStartDate() { return startDate; } public void setStartDate(String startDate) { this.startDate = startDate; } public String getMoney() { return money; } public void setMoney(String money) { this.money = money; } /* (non-Javadoc) * @see java.lang.Object#toString() */ @Override public String toString() { return "卡號:"+cardNo+"開戶日期:"+startDate+"金額:"+money; } } /** * */ package com.qfedu.Day18.HashMap; import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Scanner; import java.util.Set; public class HashMapDemo { public static void main(String[] args) { //1.創建Map集合對象 Map<String,String> map = new HashMap<>(); //2.向map集合對象中存儲map集合中的元素 Map<String,String> map1 = new HashMap<>(map); //常用方法: //1.向集合中添加元素 /* * 這個方法是有返回值的,返回的是 value的數據類型 */ map.put("key1", "value1"); map.put("key2", "value2"); map.put("key3", "value3"); map.put("key4", "value4"); map.put("key5", "value5"); map.put("key6", "value6"); System.out.println(map); //2.向集合中添加集合(添加集合中的元素) map1.putAll(map); System.out.println(map1); //3.清空集合,集合還在 map1.clear(); System.out.println(map1); //4.判斷集合中是否存在指定的key值 //true證明存在 false 不存在 boolean res = map.containsKey("key7"); System.out.println(res); //5.判斷集合中是否存在指定的value值 //true證明存在 false 不存在 boolean result = map.containsValue("value7"); System.out.println(result); //6通過key獲取value值 ,若key不存在返回null String value = map.get("key4"); System.out.println(value); //7.判斷集合是否是空,說明集合存在,沒有元素 System.out.println(map1.isEmpty()); //8.key相當於存儲到了set集合中 排重 保持唯一 //獲取所有的key值並存儲到set集合中 Set<String> set = map.keySet(); //此時所有的key是不是都在set集合集合中了 //是不是通過操作set集合就能獲取或改變map集合對應的鍵值對 for(String keys : set) { if(keys.equals("key6")) { //不僅是向集合中添加元素,修改對應的鍵值對 map.put(keys, "vlaue10"); } } System.out.println(map); //9.獲取Map集合中所有Value的值,存儲到Collection集合中 Collection<String> c = map.values(); for(String value1 : c) { System.out.println(value1); } //10.獲取所有鍵值對的總和(個數) System.out.println(map.size()); //11.通過key刪除對應的鍵值對 ,返回值是對應的value //刪除成功會獲取對應的value 失敗則返回null String value2 = map.remove("key9"); System.out.println(value2); //12. /* * Set<Map.Entry<K,V>> entrySet() 返回此映射所包含的映射關系的 Set 視圖。 通過此方法可以的到一個set集合 需要給set集合添加泛型 這個方法的類型是一個Map.Entry Map.Entry自己也有泛型 這個泛型類型需要和map集合中存儲的 key和value的數據類型一致 * */ Set<Map.Entry<String,String>> mapSet = map.entrySet(); System.out.println(mapSet); for(Map.Entry<String, String> entry :mapSet) { //取出key 和 value System.out.println(entry.getKey()+" ---> "+ entry.getValue()); } //若存在兩個相同的key值最后一次添加的鍵值對會替代第一次添加鍵值對 map1.put("key1", "value1"); map1.put("key1", "value2"); System.out.println(map1); map1.put("key1", "value1"); map1.put("key2", "value1"); System.out.println(map1); /* * 需求: 一個人對應多張銀行卡 Card: cardNo:銀行卡號,startDate:開戶日期, money:余額 請設計一個程序,輸入一個人的名稱,得到這個人的所有銀行卡信息。 鍵值對 一個對多 value是什么? 分析如下: 1.通過第一句話已知得到一個信息就是需要一個描述Card的方式 在java中描述只能有類來完成所以 應該創建一個Card類 2.Card的后面提供了一些信息 包括卡號 開戶日期 余額 這些明顯的屬於是對類的信息描述,那信息描述應該是類的屬性 3.第二句話中隱藏着一些信息,首先既然是輸入一個人名 那么必然要用到Scanner 人名是String類型所以是字符串 再者人名是屬於對人的一種描述屬性 所以應該推斷而出 可以創建一個人類 屬性是人名 綜上所述這個參數即可以用String也可以使用自己創建的類來完成 4.第二句話還有一個信息就是一個人有多張卡的問題 這里應該很明確卡不能是單純的一張?那么如何來表示多張卡呢?--> 集合 選用那個集合呢? 一個人可以在同一個銀行辦多張卡 所以在不考慮其他特殊情況下應該使用 List 5.最后將這些信息匯總,即可以通過人名獲取對應的卡,那么就需要一個穩定的獲取模式 鍵值對 key-value形式 即 key 是人名 value 是list集合 集合中存在多張卡 */ System.out.println("請輸入一個人名:"); Scanner input = new Scanner(System.in); String name = input.next(); List<Card> list = new ArrayList<>(); list.add(new Card("88888888", "1900-01-01", "1")); list.add(new Card("77777777", "1292-02-02", "10000")); list.add(new Card("66666666", "2018-08-22", "1000000000000000000000000")); //非常常見的集合中存儲了另外一個集合 Map<String,List<Card>> hmap = new HashMap<>(); hmap.put("王健林", list); System.out.println("稍等正在查詢......."); if(hmap.containsKey(name)) { // List<Card> listmap = hmap.get(name); // for(Card c1 : listmap) { // System.out.println(c1); // } System.out.println(hmap.get(name)); }else { System.out.println("不好意思沒有這個人"); } } }
LinkedHashMap是HashMap的子類沒有特殊方法使用方式參考HashMap即可
TreeMap二叉數 --> 自帶排序 這個排序時key排序 ,需要進行排序的數據存儲到Key
key是什么集合 Set --> TreeSet
Hashtable和HashMap都是Map的實現類
Hashtable是線程安全的,效率低 - properties 資源文件 --> 加載
HashMap是線程不安全,效率高
總結:
Collection:
List:有序存儲,允許存重復值並且有下標 提供了迭代器,for循環等方式遍歷集合
主要應用 ArrayList
Set:無序存儲,不允許重復,沒有下標,提供了迭代器和for循環等遍歷方式遍歷集合
主要應用 HashSet
TreeSet --> 自帶排序功能的集合
必須實現Comparable接口
若自定義類需要進行排序,建議實現Comparable接口
實現Comparator接口也可以
Map:無序 是一種映射關系,鍵值對 key-value ,key必須唯一,value可以不唯一
並沒有提供Iterator,但是提供了另外一種方式 Map.Entry --> entrySet
主要應用 HashMap
Collections工具類:
為集合提供方法可以方便操作
/** * */ package com.qfedu.Day18.Collections; import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; import java.util.List; import java.util.Vector; public class CollectionsDemo { public static void main(String[] args) { List<Integer> list = new ArrayList<>(); //向集中一次性添加多個元素 /* * 第一個參數需要是一個Collection這邊的集合 * 第二個參數是一個可變參數(可以什么都沒有,也可以有一堆) */ Collections.addAll(list, 1,2,3,4,5,56,6,4,3,5,2); System.out.println(list); //不是只有TreeSet才可以進行排序操作 //List這邊的集合以可以 //Collections.sort(list);//升序 //System.out.println(list); //重載方法 // Collections.sort(list, new Comparator<Integer>() { // // @Override // public int compare(Integer o1, Integer o2) { // // return o2-o1; // } // });//降序 //降序快捷方式,這個方式不適合自定義類的排序 Collections.sort(list, Collections.reverseOrder()); System.out.println(list); //static void shuffle(List<?> list) // 使用默認隨機源對指定列表進行置換 //3個51 - 17 1次一個呢只能有1張 Collections.shuffle(list); System.out.println(list); //集合中查找某個元素--> 二分查找 /* * 第一個參數是要查找的集合 * 第二個參數要查找的值 *找到就是下標 找不到-1的值 *一定要先排序 */ Collections.binarySearch(list, 1); // static void reverse(List<?> list) // 反轉指定列表中元素的順序。 //若需要線程安全時,只需要通過Collections中的方法即可 完成轉換 /* * static <T> Collection<T> synchronizedCollection(Collection<T> c) 返回指定 collection 支持的同步(線程安全的)collection。 static <T> List<T> synchronizedList(List<T> list) 返回指定列表支持的同步(線程安全的)列表。 static <K,V> Map<K,V> synchronizedMap(Map<K,V> m) 返回由指定映射支持的同步(線程安全的)映射。 static <T> Set<T> synchronizedSet(Set<T> s) 返回指定 set 支持的同步(線程安全的)set。 * * */ List<Integer> safeList = Collections.synchronizedList(list); System.out.println("當前線程安全的集合是:"+(safeList instanceof Vector)); } }