东软--->Set、Map
package Demo1.JavaSe.NeusoftEdu.zuoye; import java.time.LocalDate; import java.util.*; /** * @program: FirstDemo * @description: 东软第七天:异常 * @author: GuoTong * @create: 2020-08-19 10:38 **/ public class day7 { /** * 继承Exception 就是自定义的编译时异常 * 继承RuntimeException 就是自定义的运行时异常 * * @param args */ public static void main(String[] args) { // new day7().test(); /*Exception in thread "main" java.lang.StackOverflowError at Demo1.JavaSe.NeusoftEdu.zuoye.day7.test(day7.java:30) at Demo1.JavaSe.NeusoftEdu.zuoye.day7.test(day7.java:30) at Demo1.JavaSe.NeusoftEdu.zuoye.day7.test(day7.java:30)*/ try { //人造栈溢出: new day7().test(); } catch (Exception e) { e.printStackTrace(); } catch (Throwable e) { System.out.println("栈溢出"); } finally { System.out.println("ok"); } System.out.println("NiHao"); } public void test() { try { int x = 1 / 0; } catch (ArithmeticException e) { throw new RuntimeException("运行时异常"); } test(); } } class EcmDef { public static void main(String[] args) { Scanner scanner = new Scanner(System.in); boolean flag = true; while (flag) { try { System.out.println("输入除数:"); int i = Integer.parseInt(scanner.next()); System.out.println("输入被除数:"); int j = Integer.parseInt(scanner.next()); int result = ecm(i, j); System.out.println(result); } catch (ArithmeticException e) { System.out.println("除0异常"); } catch (NumberFormatException e) { System.out.println("异常:您输入的不是一个数?"); } catch (EcDef e) { System.out.println(e.getMessage()); } catch (ArrayIndexOutOfBoundsException e) { System.out.println("缺少命令行参数"); } finally { System.out.println("输入exit退出|任意键继续"); if (scanner.next().equals("exit")) scanner.close(); flag = false; } } } public static int ecm(int i, int j) throws EcDef { if (i < 0 || j < 0) { throw new EcDef("自定义异常:分子或分母为负数了!"); } return i / j; } } class EcDef extends RuntimeException { public EcDef(String message) { super(message); } } class ConletionIsMy { public static void main(String[] args) { Collection collection = new ArrayList(); collection.add("1"); collection.add("2"); collection.add(LocalDate.now());//java 8 时间新特性 //集合转数组--for循环遍历 Object[] array = collection.toArray();//集合转化为数组 for (int i = 0; i < array.length; i++) { System.out.println(array[i]); } System.out.println("===="); //迭代器 //集合的元素进行(CRUD)后,必须要重新获取迭代器,否则会出现异常。 // IllegalAccessException() Iterator iterator = collection.iterator(); collection.add(new Date()); iterator = collection.iterator(); //看看迭代器指针是否还有下一个值 while (iterator.hasNext()) { Object next = iterator.next();//返回当前元素 System.out.println(next); } System.out.println("===="); //foreach 便利 collection.forEach(System.out::println); System.out.println("===="); //或者增强for循环 for (Object o : collection) { System.out.println(o); } //清空集合 collection.clear(); //集合大小 int size = collection.size(); //集合是否为空 boolean empty = collection.isEmpty(); //集合是否包含某个元素,contains方法:实际上是通过该类中定义的equals方法判断两个对象是否相等。 boolean contains = collection.contains("3"); //删除某个元素 collection.remove("2"); } } class ListIsMy { public static void main(String[] args) { /*int x =10; int y = x+(x>>1);//1.5倍扩容 System.out.println(y);*/ List list = new ArrayList();//初始化list list.add(LocalDate.now()); list.add("郭童"); list.add("王尼玛"); //list可以通过索引取值:list.get(i) for (int i = 0; i < list.size(); i++) { System.out.println(list.get(i)); if (i == 2) { list.remove(i); } } System.out.println("list集合for循环遍历:删除remove:" + 2 + ":" + list.size()); for (Object o : list) { list.remove(o);//增强for:底层是迭代器:会报错 遍历不能删除操作:快照和·实体不一致 //但是iterator为什么可以,他删除的时候回吧快照和实体同步。就一致了。 } } } class HashSetIsMy { private String name; private int age; public HashSetIsMy(String name, int age) { this.name = name; this.age = age; } public HashSetIsMy() { } @Override public boolean equals(Object o) { System.out.println("equals...."); if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; HashSetIsMy that = (HashSetIsMy) o; return age == that.age && Objects.equals(name, that.name); } @Override public int hashCode() { System.out.println("hashCode!!!"); return Objects.hash(name, age); } @Override public String toString() { return "HashSetIsMy{" + "name='" + name + '\'' + ", age=" + age + '}'; } public static void main(String[] args) { HashSet hashSet = new HashSet(); HashSetIsMy hashSetIsMy = new HashSetIsMy("tom",23); HashSetIsMy tom = new HashSetIsMy("tom", 23); /*System.out.println(hashSetIsMy.hashCode()); System.out.println(tom.hashCode()); System.out.println(hashSetIsMy.hashCode()==tom.hashCode()); System.out.println("equals:"+tom.equals(hashSetIsMy));*/ hashSet.add(hashSetIsMy); hashSet.add(40); hashSet.add(12); hashSet.add(tom); hashSet.add(-90); hashSet.forEach(System.out::println); } }
hashCode!!! 第一次调用,是得到对象的hash值,通过该hash值,计算出元素的存储位置
hashCode!!! 第二次调用,是比较添加元素是否和里面的元素的hashcode值是否相等
equals.... 如果hashcode值相等,那就比较equals方法,也相等的话就不加入hashset集合。
HashSetIsMy{name='tom', age=23}
40
-90
12
重写hashCode()方法的基本原则
-
在程序运行时,同一个对象多次调用 hashCode() 方法应该返回相同的值。
-
当两个对象的 equals() 方法比较返回 true 时,这两个对象的 hashCode() 方法的返回值也应相等。
-
对象中用作 equals() 方法比较的 Field,都应该用来计算 hashCode 值。
重写equals()方法的基本原则
-
当一个类有自己特有的“逻辑相等”概念,当改写equals()的时候,总是 要改写hashCode(),根据一个类的equals方法(改写后),两个截然不 同的实例有可能在逻辑上是相等的,但是,根据Object.hashCode()方法,它们仅仅是两个对象。
-
因此,违反了“相等的对象必须具有相等的散列码”。
-
结论:复写equals方法的时候一般都需要同时复写hashCode方法。通常参与计算hashCode的对象的属性也应该参与到equals()中进行计算
LinkedHashSet实现类
-
LinkedHashSet 是 HashSet 的子类
-
LinkedHashSet 根据元素的 hashCode 值来决定元素的存储位置,但它同时使用双向链表维护元素的次序,这使得元素看起来是以插入顺序保存的。
-
LinkedHashSet插入性能略低于 HashSet,但在迭代访问 Set 里的全部元素时有很好的性能。
-
LinkedHashSet 不允许集合元素重复。
TreeSet实现类
-
TreeSet是SortedSet接口的实现类,TreeSet可以确保集合元素处于排序状态。正因为这个特点,所以查询速度比List快
-
TreeSet底层使用红黑树结构存储数据
-
TreeSet 两种排序方法
-
自然排序
-
TreeSet 会调用集合元素的 compareTo(Object obj) 方法来比较元素之间的大小关系,然后将集合元素按升序(默认情况)排列
-
如果试图把一个对象添加到 TreeSet 时,则该对象的类必须实现 Comparable 接口。
-
实现 Comparable 的类必须实现 compareTo(Object obj) 方法,两个对象即通过compareTo(Object obj) 方法的返回值来比较大小。
-
Comparable 的典型实现:
-
BigDecimal、Integer 以及所有的数值型对应的包装类:按它们对应的数值大小 进行比较
-
Character:按字符的 unicode值来进行比较
-
Boolean:true 对应的包装类实例大于 false 对应的包装类实例
-
String:按字符串中字符的 unicode 值进行比较
-
-
-
向 TreeSet 中添加元素时,只有第一个元素无须比较compareTo()方法,后面添加的所有元素都会调用compareTo()方法进行比较。
-
因为只有相同类的两个实例比较大小才有意义,所以向TreeSet中添加的应该是同 一个类的对象。
-
对于 TreeSet 集合而言,它判断两个对象是否相等的唯一标准是:两个对象通 过 compareTo(Object obj) 方法比较返回值。
-
当需要把一个对象放入 TreeSet 中,重写该对象对应的 equals() 方法时,应保 证该方法与 compareTo(Object obj) 方法有一致的结果:如果两个对象通过equals() 方法比较返回 true,则通过 compareTo(Object obj) 方法比较应返回 0。否则,让人难以理解。
-
-
定制排序
-
TreeSet的自然排序要求元素所属的类实现Comparable接口,如果元素所属的类没 有实现Comparable接口,或不希望按照升序(默认情况)的方式排列元素或希望按照 其它属性大小进行排序,则考虑使用定制排序。定制排序,通过Comparator接口来实现。需要重写compare(T o1,T o2)方法。
-
利用int compare(T o1,T o2)方法,比较o1和o2的大小:如果方法返回正整数,则表示o1大于o2;如果返回0,表示相等;返回负整数,表示o1小于o2。
-
要实现定制排序,需要将实现Comparator接口的实例作为实参传递给TreeSet的构造器。
-
此时,仍然只能向TreeSet中添加类型相同的对象。否则发生ClassCastException异常。
-
使用定制排序判断两个元素相等的标准是:通过Comparator比较两个元素返回了0。
class TreeSetTest { public static void main(String[] args) { TreeSet set = new TreeSet(); /* set.add(12); set.add(3); set.add(19); set.add(-19); set.add(25); //tree set 回添加进去后就自动排序的。底层红黑树||一种平衡二叉树*/ set.add(new TestTreeSetEntity("tom", 12)); set.add(new TestTreeSetEntity("gt", 22)); set.add(new TestTreeSetEntity("gte", 12)); set.add(new TestTreeSetEntity("tom", 11)); set.add(new TestTreeSetEntity("tosm", 22)); //如果添加对象进去: /* Exception in thread "main" java.lang.ClassCastException: Demo1.JavaSe.NeusoftEdu.zuoye.HashSetIsMy cannot be cast to java.lang.Comparable 所以需要实现Comparable接口的才能加进去 */ set.forEach(System.out::println); } } @Data @AllArgsConstructor @NoArgsConstructor class TestTreeSetEntity implements Comparable { private String name; private int age; //如果是整数,调用者大,如果是0则相等,如果是负数,被调用者大 /* 自然排序 implements Comparable 自定义排序: implements Comparator TreeSet 会调用集合元素的 compareTo(Object obj) * 方法来比较元素之间的大小关系,然后将集合元素按升序(默认情况)排列 */ @Override public int compareTo(Object o) { int compareAge = age - ((TestTreeSetEntity) o).age; if (compareAge != 0) return compareAge; return name.compareTo(((TestTreeSetEntity) o).name); } }
Map接口
Map概述
-
Map与Collection并列存在。用于保存具有映射关系的数据:key-value
-
Map 中的 key 和 value 都可以是任何引用类型的数据
-
Map 中的 key 用Set来存放,不允许重复,即同一个 Map 对象所对应的类,须重写hashCode()和equals()方法
-
常用String类作为Map的“键”
-
key 和 value 之间存在单向一对一关系,即通过指定的 key 总能找到唯一的、确定的 value
-
Map接口的常用实现类:HashMap、TreeMap、LinkedHashMap和Properties。其中,HashMap是 Map 接口使用频率最高的实现类
常用方法
-
添加、删除、修改操作:
-
Object put(Object key,Object value):将指定key-value添加到(或修改)当前map对象中
-
void putAll(Map m):将m中的所有key-value对存放到当前map中
-
Object remove(Object key):移除指定key的key-value对,并返回value
-
void clear():清空当前map中的所有数据
-
-
元素查询的操作:
-
Object get(Object key):获取指定key对应的value
-
boolean containsKey(Object key):是否包含指定的key
-
boolean containsValue(Object value):是否包含指定的value
-
int size():返回map中key-value对的个数
-
boolean isEmpty():判断当前map是否为空
-
boolean equals(Object obj):判断当前map和参数对象obj是否相等
-
-
元视图操作的方法:
-
Set keySet():返回所有key构成的Set集合
-
Collection values():返回所有value构成的Collection集合
-
Set entrySet():返回所有key-value对构成的Set集合
-
HashMap实现类
-
HashMap是 Map 接口使用频率最高的实现类。
-
允许使用null键和null值,与HashSet一样,不保证映射的顺序。
-
所有的key构成的集合是Set:无序的、不可重复的。所以,key所在的类要重写: equals()和hashCode()
-
所有的value构成的集合是Collection:无序的、可以重复的。所以,value所在的类要重写:equals()
-
一个key-value构成一个entry(node)
-
所有的entry构成的集合是Set:无序的、不可重复的
-
HashMap 判断两个 key 相等的标准是:两个 key 通过 equals() 方法返回 true,hashCode 值也相等。
-
HashMap 判断两个 value相等的标准是:两个 value 通过 equals() 方法返回 true。
TreeMap实现类
-
TreeMap存储 Key-Value 对时,需要根据 key-value 对进行排序。
-
TreeMap 可以保证所有的 Key-Value 对处于有序状态。
-
TreeMap底层使用红黑树结构存储数据
-
TreeMap 的 Key 的排序:
-
自然排序:TreeMap 的所有的 Key 必须实现 Comparable 接口,而且所有 的 Key 应该是同一个类的对象,否则将会抛出 ClasssCastException
-
定制排序:创建 TreeMap 时,传入一个 Comparator 对象,该对象负责对 TreeMap 中的所有 key 进行排序。此时不需要 Map 的 Key 实现 Comparable 接口
-
-
TreeMap判断两个key相等的标准:两个key通过compareTo()方法或者compare()方法返回0。
class TsetHashMap { public static void main(String[] args) { HashMap hashMap = new HashMap(); hashMap.put("1001", "李四"); hashMap.put("1002", "张三"); hashMap.put("1003", "王五"); //遍历map,不可以用迭代器或者for系列。。没有索引,无序 //方式一:获取所有的key,组成set集合,遍历set集合,通过key获取value Set set = hashMap.keySet();//获取所有的key for (Object key : set) { Object value = hashMap.get(key); System.out.println("key:" + key + "\t" + "value" + value); } //方式二:获取 所有的 键值对(entry)形式:{key=value} 组成的 set集合 Set entrySet = hashMap.entrySet(); // entry hashmap$node类型:标识hashmap中的内部类node类型《Map.Entry》 entrySet.forEach(System.out::println); // //方式二:第二个方式 for (Object obj : entrySet) { Map.Entry entry = (Map.Entry) obj; Object key = entry.getKey(); Object value = entry.getValue(); System.out.println("key:" + key + "\t" + "value" + value); } //获取所有的value的集合 Collection values = hashMap.values();//无序可重复 //collection使用迭代器遍历 Iterator iterator = values.iterator(); while (iterator.hasNext()) { Object next = iterator.next(); System.out.println(next); } } } class TestList { public static void main(String[] args) { List list = new ArrayList(); Comparator comparator = new Comparator<Object>() { @Override public int compare(Object o1, Object o2) { return (int) (((StudentB) o1).getScore() - ((StudentB) o2).getScore()); } }; TreeSet<StudentB> treeSet = new TreeSet<StudentB>(comparator); Random random = new Random(); for (int i = 1; i <= 10; i++) { // int anInt; anInt = random.nextInt(100); list.add(anInt); treeSet.add(new StudentB("李四" + i, anInt, 100 + i)); } Collections.sort(list); list.forEach(System.out::println); int i=treeSet.size(); for (StudentB studentB : treeSet) { if (i<=3) System.out.println("第"+i+"名"+"分数:"+studentB); i--; } } } @Data @AllArgsConstructor @NoArgsConstructor class StudentB implements Comparable { private String name; private double score; private int id; /* public static <T extends Number> T add(T num1,T num2){ return num1+num2; }*/ @Override public int compareTo(Object o) { return (int) (score - ((StudentB) o).score); } }
自定义泛型结构
泛型的声明
-
interface List<T> 和 class GenTest<K,V> 其中,T,K,V不代表值,而是表示类型。这里使用任意字母都可以。 常用T表示,是Type的缩写。
泛型的实例化
-
一定要在类名后面指定类型参数的值(类型)。如:
List strList = new ArrayList();
Iterator iterator = customers.iterator();
-
T只能是类,不能用基本数据类型填充。但可以使用包装类填充
-
把一个集合中的内容限制为一个特定的数据类型,这就是generics背后的核心思想
个性签名:独学而无友,则孤陋而寡闻。做一个灵魂有趣的人!
如果觉得这篇文章对你有小小的帮助的话,记得在右下角点个“推荐”哦,博主在此感谢!
Java入门到入坟
万水千山总是情,打赏一分行不行,所以如果你心情还比较高兴,也是可以扫码打赏博主,哈哈哈(っ•̀ω•́)っ✎⁾⁾!
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· AI与.NET技术实操系列:基于图像分类模型对图像进行分类
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 25岁的心里话
· 闲置电脑爆改个人服务器(超详细) #公网映射 #Vmware虚拟网络编辑器
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· 零经验选手,Compose 一天开发一款小游戏!
· 通过 API 将Deepseek响应流式内容输出到前端