java容器练习
Java容器相关练习,最后是知识总结
一基本方法练习,
通过练习ArrayList熟悉容器操作
1 package org; 2 3 import java.util.*; 4 //前言: 5 /* 6 * 7 * 关系树 8 * Iterable->map<K,value>/Collection<? extends E> 9 * Collection<? extends E> -> list/set 10 * List-> ArrayList 11 * set->hashset 12 * 13 * */ 14 //List容器练习 15 //1、初始化 1、<>告诉它是什么类型。 16 //2、添加 1、add()追加,add(index,value)某一位置插入2、addAll(Collection< extends E>) 17 //3、删除 1、remove(index),remove(Obj) ,removeAll(Collection< extends E>) ,clear() 18 //4、修改 1、set(index,value) 19 //5、遍历 1、for>for in(没啥) , iterator (hasnext()) .next() 20 //6、长度(元素个数),转换 1、换为数组, 建立数组(size()) toArray([]) 2、数组变为容器,new ArrayList(Array.asList([])); 21 //7、排序*** sort(CompareTo) Collections.shuffle(list); 22 //8、查找*** indexof(Obj) lastindexof(Obj) 23 //9、是否存在 contains(Obj) containsAll(Collection) 是否为空 isEmpty() 24 //10、截取 subList(from,to) [from,to) 25 //11、保留 retainAll retain() 保留里面的, 26 //12、迭代器 Iterator hasNext next() 27 //13、List.of 返回一个 ArrayList()容器实现类,这个ArrayList是不能增加,删除 类似Array.asList() 28 29 //总结: 30 /* 31 * 32 * 1、ArrayList是一个工具 33 * 1、泛型,存放Object类元素,基本数据类型就不要存放了 34 * 2、相比较于数据可以批量操作,长度是可变的,所以好的利用效率很高,尽量不要一个一个的操作。 35 * 3、可以通过迭代器遍历,也可随机存取 36 * 37 * 38 * 39 * */ 40 41 public class Test { 42 public static void testlist(){ 43 //几个容器的关系 --接口,接口,实现类 44 //Iterable<T> --- Collection<E> -- List<E> set<E> ArrayList<E> Has 45 // List 46 //我知道我的实现类实现了我的方法,利用重载机制就行了。所以可以通过实例化实现类,来对接口赋值, 47 //我的方法就是我的实现类的方法,还有我的实现类没有重载的,但是我实现的方法。 48 List<String> list = new ArrayList<String>(); 49 //list<E>,的E最好给一个类型,否则只能用公共的方法,公共的就是父类定义的。还要受到权限影响。 50 Set set = new HashSet(); 51 //E里面都是类,不是基本数据类型、 52 Map<Integer,String> map = new HashMap<Integer, String>(); 53 list.add("张三"); 54 list.add("李四"); 55 list.add("王五"); 56 list.add("赵六"); 57 list.add("张四"); 58 59 System.out.println(list.toString()); 60 set.add(list);//参数类型是list,个数还是一个 61 System.out.println(set); 62 System.out.println(list.get(0) instanceof String ? true : false); 63 System.out.println("添加一群元素到集合中,一定效率高于一个一个添加"); 64 list.addAll(List.of("java","html","c/c++","servlet","mysql")); 65 System.out.println("容器是否有某个元素"+list.contains("mysql")); 66 System.out.println("容器是否有某些元素,需要用到容器"+list.containsAll(List.of("java", "html"))); 67 68 69 //输出 70 for (String s : list) { 71 System.out.println(s+" "); 72 } 73 System.out.println(); 74 for(int i = 0;i<list.size();i++){ 75 System.out.print(list.get(i)+" "); 76 } 77 //从后往前遍历容器 78 for (int i= list.size()-1;i>=0;i--){ 79 System.out.print(list.get(i)+" "); 80 } 81 //查找某一个元素 82 System.out.print("java的下标是:"); 83 System.out.print(list.indexOf("java")); 84 System.out.print(" "); 85 System.out.print(list.lastIndexOf("java")); 86 //得到某个位置的元素 87 System.out.println("下标为1的元素是:"+list.get(1)); 88 //在某个位置插入元素 89 list.add(1,"mysql"); 90 //清空所有元素 91 list.clear(); 92 //判断容器是否为空 93 System.out.println(list.isEmpty()); 94 95 96 } 97 public static void testList2(){ 98 //容器和字符串之间的转换 99 //字符串数组 100 List<String> list = new ArrayList<String>(); 101 list.addAll(List.of("赵云","关羽","诸葛亮","曹操","周瑜")); 102 String[] strs = new String[list.size()]; 103 list.toArray(strs); 104 //通过Arrays工具输出字符串数组. 105 System.out.println(Arrays.toString(strs)); 106 107 //字符串数组变为ArrayList 108 //同样是利用Arrays 000000000 数组工具类 109 List<String> myList = Arrays.asList(strs);//数组变为ArrayList之后,容器就不能增加,删除。 110 System.out.println(myList); 111 //参数是一个方法(接口),作用是比较两个数的大小,如果前面的值大,返回值是正数, 112 //方法一改,如果前面大,返回值是负数,那么结果就是从小到大排序了。 里面是排序算法 113 //这里元素就是String类型,泛型的原因 114 //返回值是一个int类型 115 116 myList.sort((a,b)-> a.compareTo(b)); 117 System.out.println("正序排序后"+myList); 118 //添加一个负号 119 myList.sort((a,b)->-a.compareTo(b)); 120 System.out.println("倒序排序后"+myList); 121 //这是idea给我的方法 122 myList.sort(String::compareTo); 123 System.out.println("正序排序后"+myList); 124 //有点像Array里面的sort方法 125 126 //截取容器 127 //List<E> subList(int fromIndex, int toIndex); 128 129 // 下表范围 [2,3) 130 myList.subList(2,3); 131 // System.out.println(myList);//并没有改变原来的容器 132 System.out.println(myList.subList(2,3)); 133 //截取之后的元素 134 System.out.println(myList.subList(myList.indexOf("诸葛亮"), myList.size()-1)); 135 136 //截取元素并不能从一个位置截到最后一个位置, 137 // String.substring()//String里面有两个方法。 138 // System.out.println(myList.subList(myList.indexOf("诸葛亮"))); 139 140 //看看一群元素是否都有,不考虑位置 141 System.out.println(myList.containsAll(List.of("诸葛亮","赵云"))); 142 //不允许删除,添加 143 // myList.add("张三"); 144 myList.set(0,"王五"); 145 System.out.println(myList); 146 // myList.remove(0); 147 // System.out.println(myList.retainAll(List.of("关羽")));//保留 148 149 150 } 151 //再次验证一下integer数组 152 public static void testList4(){ 153 //将int[]转为integer[] 154 List<Integer> myList = new ArrayList(); 155 int[] arr = new int[]{1,2,3,4,5,6,7,8,34,2,1}; 156 Integers integers = new Integers(arr); 157 myList.addAll(Arrays.asList(integers.toIntegers())); 158 myList.sort((a,b)->a-b); 159 System.out.println(myList); 160 myList.sort((a,b)->b-a); 161 System.out.println(myList); 162 //add不同于赋值 163 myList.add(10); 164 myList.remove(0); 165 } 166 167 public static void testList5(){ 168 int[] arr = new int[]{1,2,3,4,5,6,7,8,34,2,1}; 169 Integers integers = new Integers(arr); 170 List<Integer> myList = Arrays.asList(integers.toIntegers()); 171 myList.sort((a,b)->a-b); 172 System.out.println(myList); 173 myList.sort((a,b)->b-a); 174 System.out.println(myList); 175 //add不同于赋值 176 try { 177 myList.add(10); 178 }catch (UnsupportedOperationException e){ 179 System.out.println("不可以添加"); 180 } 181 catch (Exception e){ 182 System.out.println("未知异常添加失败"); 183 } 184 185 try{ 186 myList.remove(0); 187 } 188 catch (Exception e){ 189 System.out.println("不能删除第1个元素"); 190 } 191 } 192 193 194 //迭代器练习 195 /* 196 * 197 * 泛型 198 * 1、类型必须是类 199 * 2、尽量告诉一下, 200 * 3、类型不匹配异常是常有的, java.lang.ClassCastException。 201 * 1、迭代器 202 * 2、add,添加 203 * 204 * 205 * */ 206 207 public static void testList3(){ 208 List myList = new ArrayList<>(); 209 try { 210 myList.addAll(List.of(1,3,4,"张四",6,1.12,"李四","赵四")); 211 } 212 catch (UnsupportedOperationException e){ 213 System.out.println("多种类型,类型不匹配"); 214 } 215 //迭代器只读吗?,可以修改,添加,删除 216 //Iterator 类型可以设置一下,防止意外. 217 Iterator<Object> it = myList.iterator(); 218 System.out.println("第4个元素的类型是Integer吗"+ (myList.get(3) instanceof Integer)); 219 int count = 0; 220 while(it.hasNext()){ 221 count++; 222 try { 223 //迭代器不能输出Integer,Double,因为我没有设,默认了 224 System.out.println(it.next().toString()); 225 } 226 catch (ClassCastException e){ 227 //利用try catch可以看看那个元素出问题。 228 System.out.printf("第%d个元素出现问题",count); 229 } 230 } 231 232 } 233 234 235 public static void main(String[] args){ 236 testList3(); 237 } 238 } 239 240 //对象排序 241 class User{} 242 243 //汉字排序 244 //对象排序, compareTo
二HashSet练习总结
1 package cn; 2 3 4 import java.util.*; 5 6 //集合是新的空间--存放的值是地址 7 //存储器保证值唯一 8 //链表,不能随机访问 9 10 public class Test { 11 { 12 coder = 19;//可以设置成一个常量值。 13 } 14 15 Void a = null;//Void类, 16 private final byte coder; 17 18 19 public Test() { 20 //可以在构造函数中初始化coder 21 // coder = 0; 22 } 23 //String//包装类 24 25 //set练习: 26 //1、增加,添加一群 add addAll 27 //2、删除,删除一群 28 //3、修改,不可直接修改,但是添加时可以覆盖。 29 //4、查找,只能遍历,不能随机查找 30 //5、排序,不存在 31 //6、是否包含 32 public static void test1() { 33 Set<String> set = new HashSet<String>(); 34 //测试一 添加 35 // 1、hashset里面是有顺序的,不管你按什么怎么添加,它始终在那个位置. 和添加顺序无关。 36 String[] strArr = new String[]{"诸葛亮", "汉武帝", "秦始皇", "汉高帝"}; 37 set.addAll(Arrays.asList(strArr)); 38 set.addAll(Set.of("张三", "李四", "王五", "赵六")); 39 for (String string : set) { 40 // System.out.print(string); 41 } 42 System.out.println(); 43 //使用迭代器,自动递增 44 Iterator<String> iterator = set.iterator(); 45 while (iterator.hasNext()) { 46 System.out.println(iterator.next()); 47 } 48 49 50 //2、每个值只存一次,String字符串,包装类是特殊的,他们并不是通过==比较值,而是通过equals比较 51 //存的是一个地址,(字符串,new区别很大) 52 // System.out.println(set.size()); 53 String a = new String("刘高源"); 54 String b = new String("刘高源"); 55 56 set.add(a); 57 set.add(b);//第二次就不存了,可以通过地址探究,遍历最后的值就是地址 58 System.out.println(set.size()); 59 a = b; 60 // b = "李四";//b又出现了,,可以看出字符串常量内存中只有一份。 61 b = new String("李四");//字符数组, 62 System.out.println("----------------------------------------"); 63 System.out.printf("a的值是%s%n", a); 64 iterator = set.iterator(); 65 //不能直接比较迭代器 66 while (iterator.hasNext()) { 67 String temp = iterator.next(); 68 System.out.println(temp); 69 if (a == temp) { 70 System.out.println("a的地址存入了"); 71 } 72 if (b == temp) { 73 System.out.println("b的地址存入了"); 74 } 75 // if(b==iterator.next()){ 76 // System.out.println("b的地址存入了"); 77 // }//越界了 78 } 79 80 //for in 效率很慢 81 for (String str : set) { 82 if (str == a) { 83 System.out.println("a的地址存入了"); 84 } 85 if (str == b) { 86 System.out.println("b的地址存入了"); 87 } 88 } 89 90 System.out.println("添加前set长度是:" + set.size()); 91 System.out.println("添加Integer后set长度是:" + set.size()); 92 System.out.println("添加User后set长度是:" + set.size()); 93 } 94 95 //Integer包装类 96 //自动装箱,自动拆箱 97 public static void testIntegerSet() { 98 Set<Integer> set = new HashSet<Integer>(); 99 set.addAll(Set.of(1, 2, 3, 4, 5, 6, 7, 9, 32, 12, 67, 34, 54, 23, 31)); 100 101 102 set.add(20); 103 System.out.println("添加前set长度是:" + set.size());//长度是16 104 set.add(20); 105 System.out.println("添加Integer后set长度是:" + set.size());//长度是16 106 107 //自动包装了,其实和add20一样 108 set.add(new Integer(20)); 109 System.out.println("添加Integer后set长度是:" + set.size());//长度是16 110 //自动装箱案例 111 Integer a = 1;//相当于重新new了一个 112 Integer b = a;//共用地址 113 b = 10;//重新new了,地址就变了 114 System.out.printf("a的值是%d", a);//1 115 116 //1、说明了set会包装类保证值不重复。不管地址是否一样,只要值一样认为是一个。 117 //2、自动装箱练习。 118 } 119 120 public static void testStringSet() { 121 Set<String> set = new HashSet(); 122 set.add("张三"); 123 System.out.printf("添加字符串前set容器长度是%d", set.size());//1 124 set.add("张三"); 125 126 set.add(new String("张三")); 127 System.out.printf("添加字符串后set容器长度是%d", set.size());//1 128 //字符串类似包装类,这里也是按照那个原则。 129 //字符串""也是可看成字符串,类似自动装箱。 130 } 131 132 133 public static void testUserSet() { 134 Set<User> set = new HashSet<User>(); 135 set.addAll(Set.of(new User(), new User(), new User(), new User(), new User())); 136 System.out.printf("添加前set长度是:%d\n", set.size());//5 137 User u = new User(); 138 set.add(u); 139 set.add(u); 140 System.out.printf("添加User后set长度是:%d%n", set.size());//6 141 142 //自定义类,普通的类并不会比较值,Comparable<User>接口,equals方法重写了也不行。 143 //set认为只要地址不同就是不同的,地址相同就是同一个, 144 } 145 146 147 //探究字符数组和通过字符数组new出来的字符串之间关系 148 //String是通过一个新的byte数组存储的,还有一些其它标志 149 /* 150 * 分配一个新的 String, 151 * 以便它表示当前包含在字符数组参数中的字符序列。 152 * 复制字符数组的内容; 153 * 对字符数组的后续修改不会影响新创建的字符串。 154 * */ 155 156 public static void testCharArr() { 157 158 char[] temp = new char[]{'刘', '高', '源'}; 159 String str1 = new String(temp); 160 String str2 = new String(temp); 161 temp[0] = '中'; 162 System.out.println(str1); 163 //字符串并不和字符数组共用地址(也就是不能赋值)。也是,他们毕竟不是同一个类型。 164 System.out.println(str1 == str2 ? true : false); 165 // System.out.println("" instanceof String);//""引起来的字符串常量也是字符串。 166 } 167 168 //hashset的删除,修改,查找 169 public static void test2() { 170 //1、删除remove,removeAll 171 HashSet<String> set = new HashSet(); 172 //删除值为张三的元素 173 System.out.println(set.remove("张三"));//false 174 set.add("张三"); 175 // set.add("李四"); 176 // set.add("王五"); 177 //批量删除所有值为张三,李四,王五的元素 178 //删除一个就返回true 179 System.out.println(set.removeAll(List.of("张三", "李四", "王五"))); 180 181 //清空所有元素 182 set.clear(); 183 //2修改,没有找到 --- 不能修改 184 // set. 185 186 //3查找,没有找到方法 187 188 // System.out.println(set.getClass()); 189 } 190 191 //迭代器 192 //迭代器的遍历---使用迭代器遍历HashSet容器,hasNext() next() 193 //迭代器的删除---使用迭代器删除HashSet容器元素 remove() 194 //没有迭代器的修改 195 196 public static void test3() { 197 HashSet<String> set = new HashSet(); 198 set.addAll(List.of("卫青","霍去病","汉武帝","张骞")); 199 Iterator<String> it = set.iterator(); 200 String temp ; 201 while(it.hasNext()){ 202 // //通过迭代器删除值为“汉武帝”的元素 203 //易错点:原因是:一次循环,应该是一次指针后移 204 //这样不仅判断的元素少了,输出的元素也少了 205 // if("汉武帝".equals(it.next())){ 206 // it.remove(); 207 // continue; 208 // } 209 // System.out.print(it.next()); 210 temp = it.next(); 211 if("汉武帝".equals(temp)){ 212 it.remove(); 213 continue; 214 } 215 System.out.println(temp); 216 } 217 //HashSet.toString(); 218 System.out.println(set); 219 } 220 221 //补充 List用迭代器删除元素 222 223 public static void testIterator(){ 224 ArrayList<String> list1 = new ArrayList(); 225 LinkedList<String> list2 = new LinkedList(); 226 list1.addAll(List.of("卫青","霍去病","汉武帝","张骞")); 227 list2.addAll(List.of("卫青","霍去病","汉武帝","张骞")); 228 Iterator<String> it = list1.iterator(); 229 String temp; 230 while(it.hasNext()){ 231 temp = it.next(); 232 if("汉武帝".equals(temp)){ 233 it.remove(); 234 continue; 235 } 236 System.out.println(temp); 237 } 238 System.out.println("-----------------------------"); 239 it = list2.iterator(); 240 while(it.hasNext()){ 241 temp = it.next(); 242 if("汉武帝".equals(temp)){ 243 it.remove(); 244 continue; 245 } 246 System.out.println(temp); 247 } 248 } 249 250 public static void test4(){ 251 252 List<String> list = List.of("卫青","霍去病","汉武帝","张骞"); 253 // list.remove(0); 254 // 不能删除;原因是相当于 List.of("卫青","霍去病","汉武帝","张骞").remove() 255 Iterator<String> it = list.iterator(); 256 // while(it.hasNext()){ 257 // it.next(); 258 // it.remove(); 259 // } 260 // //也不能用迭代器删除,迭代器根据对象来的 261 262 list = Arrays.asList(new String[]{"卫青","霍去病","汉武帝","张骞"}); 263 // list.remove(0); 264 // 相当于 Arrays.asList(new String[]{"卫青","霍去病","汉武帝","张骞"}.remove() 265 it = list.iterator(); 266 // while(it.hasNext()){ 267 // it.next(); 268 // it.remove(); 269 // } 270 //不能删除 271 272 //解决办法,拷贝值,类似字符串处理字符数组 273 274 list = null; 275 list.addAll(List.of("卫青","霍去病","汉武帝","张骞")); 276 list.remove(0); 277 list.addAll(Arrays.asList(new String[]{"卫青","霍去病","汉武帝","张骞"})); 278 it = list.iterator(); 279 while(it.hasNext()){ 280 it.next(); 281 it.remove(); 282 } 283 284 //总结: 285 //1、容器是一个独立的存储空间,起到存储元素的作用; 286 //2、容器操作可以是容器整体的操作,如addAll,removeAll;也可以是元素的操作,添加,查看(set不可以),删除,修改(set不可以), 287 //3、添加是拷贝值 288 //4、赋值是共用地址 289 //5、迭代器可以实现遍历修改,操作 290 291 } 292 293 //总结,只要容器是可变的的,那么就能删除,也就能用迭代器删除。 294 //即容器可以按照可变长,不可变长分类。 295 296 //HashSet其它操作 297 public static void test5(){ 298 HashSet<Integer> set = new HashSet<>(); 299 //包含元素AAA吗? 300 System.out.println(set.contains(1)); 301 302 //包含一批元素(容器AAA)吗? 303 System.out.println(set.containsAll(List.of("汉武帝", "卫青"))); 304 305 //容器是空的吗? 306 System.out.println(set.isEmpty()); 307 308 set.addAll(List.of(1,2,3,4,5)); 309 310 //克隆给数组的操作, 311 //问题是,是共用地址,还是在数组原有的里面修改。 312 Integer[] test = new Integer[set.size()];//分配合适空间 313 Integer[] copy = set.toArray(test); 314 System.out.println(Arrays.toString(test)); 315 test[2] = 6666; 316 System.out.println(Arrays.toString(test)); 317 System.out.println(set);//发现是克隆 318 System.out.println(copy==test);//true 返回数组就是实际参数 319 320 //那么如果空间不够,或者空间更多什么结果 321 322 // Integer[] test2 = null;//空指针异常 323 Integer[] test2 = new Integer[1]; 324 copy = set.toArray(test2); 325 System.out.println(Arrays.toString(test2));//null 326 System.out.println(copy==test2);//false 返回数组是new出来的数组 327 Integer[] test3 = new Integer[10]; 328 copy = set.toArray(test3); 329 System.out.println(Arrays.toString(test3));//[1, 2, 3, 4, 5, null, null, null, null, null] 330 System.out.println(copy==test3);//true 331 332 //如果空间不够,不会拷贝重新分配一个数组 333 //返回值T[] 是一个拷贝后的数组 334 335 // test3 = (Integer[])set.toArray();//这个方法返回值是Object[]数组, 336 //Object[]数组是对象,对象之间非继承,实现关系不能强制类型转换。 337 //Object[]并不是Integer[]的父类 338 Object[] obj = set.toArray(); 339 copy = new Integer[obj.length]; 340 for(int i=0;i<obj.length;i++){ 341 System.out.println(obj[i]); 342 copy[i] = (Integer) obj[i]; 343 } 344 345 System.out.println(Arrays.toString(copy)); 346 } 347 348 public static void main(String[] args) { 349 // test1();//普通添加 350 // testIntegerSet();//添加包装类 351 // testStringSet();//添加字符串 352 // testUserSet();//添加普通类 353 // testCharArr();//字符串和字符数组补充 354 // test2();//Hash其它操作,删除, 355 // test3();//通过迭代器删除 356 // testIterator();//练习其它容器的迭代器 357 // test4();//探究什么时候可以删除元素,可变长容器。 358 test5();//其它操作 359 // Map.Entry 360 } 361 } 362 363 364 class User implements Comparable<User> { 365 366 //没有用 367 @Override 368 public int compareTo(User o) { 369 return -1; 370 } 371 372 //没有用 373 @Override 374 public boolean equals(Object obj) { 375 return true; 376 } 377 }
1.3 HashMap存储探究和LinkedList 容器练习
1 package cn; 2 3 //练习Set --- HashSet -- 其实也就是HashMap 4 //练习list --- LinkedList 5 /* 6 * 7 * 深入理解 HashSet和LinkedList和ArrayList 8 * 结论:1.HashMap内部应该是散列存储。 9 * 2.LinkedList是双向循环链表 10 * 3.ArrayList是一个变长数组。 11 * 12 * */ 13 14 import java.util.*; 15 16 17 public class Test { 18 //hash,散列存储,查找,冲突处理 19 public static void test1(){ 20 // java.util包下 21 // Collection --- Set --- HashSet 22 Set<String> set = new HashSet<>(); 23 // set.addAll(List.of("A","B","C","D","E","F")); 24 // set.addAll(List.of("AA","BB","C","D","E","F")); 25 set.addAll(List.of("AAA","BBB","C","D","E","F")); 26 // set.addAll(List.of("AAAA","BBBB","C","D","E","F")); 27 // set.addAll(List.of("AAAAA","BBBBB","C","D","E","F")); 28 // set.addAll(List.of("AAAAAA","BBBBB","C","D","E","F")); 29 set.addAll(List.of("a","b","c","d","e","f")); 30 set.addAll(List.of("4","5","6","7","8","9")); 31 32 System.out.println(set); 33 34 List<String> arraylist = new ArrayList<String>(set); 35 arraylist.sort((a,b)->-a.compareTo(b)); 36 System.out.println(arraylist.toString()); 37 set.clear(); 38 set.addAll(arraylist); 39 System.out.println(set); 40 41 //排序机制 42 //简单的: 43 //1.如果addAll的顺序一定那么内部的顺序和原来可以不同,但是唯一。 44 //其它 45 //1.调整addAll的顺序可能set的顺序一样,也可能不一样 46 //结论 47 //1.取决于元素,也取决于元素添加顺序,取决于相同值元素个数(hash值相同时,往后走可能占下一个元素位置。) 48 // 1.有些元素一定在一些元素前面;元素个数比较少,位置足够时 49 // 2.有些元素先添加后添加相对位置不一样。 50 // 3.如果元素足够多,占相同位置,那么为了让所有元素都存下,所以会有一定算法。 51 //处理冲突的方法:用一个链表存放相同位置元素,链表超过一定长度变为红黑树。 52 //总结:1、有排序.但是这个排序规则我们不知道,也不需要知道2、存在冲突处理、使用的是红黑树,能处理大量数据。 53 //3、hashmap 查找,添加,删除效率很高。 54 } 55 56 //链表集合 java.util.LinkedList; 57 //remove()方法和List不匹配。 58 /* 59 *数据结构: 60 *利用LinkedList模拟栈和队列的数据结构 61 * 62 * */ 63 public static void test2(){ 64 //模拟栈的存储结构 --- 就不用递归了,可以无限查找。 65 LinkedList<String> list = new LinkedList<>(); 66 // List<String> list = new LinkedList<>();//不要写成这样,这是一个队列 67 //内部是一个双向循环链表. 68 //默认在尾添加,从头删除,类似一个栈。所以不能用它直接来模拟栈,但是可以模拟队列。 69 //使用addFirst() + remove()模拟栈, 70 list.addFirst("李四"); 71 list.addFirst("张三"); 72 list.addFirst("王五"); 73 list.addFirst("李四");//元素可以重复 74 if(list.getFirst()==list.getLast()){ 75 System.out.println("没有额外开辟内存,共用地址"); 76 //1.因为是共用地址,所以可能会有修改的问题。 77 // 遍历时理论上不会重复除了字符串特殊的 78 //2.效率很高 79 } 80 //出栈: 81 while(!list.isEmpty()){ 82 String temp = list.remove(); 83 System.out.println(temp.toString()); 84 } 85 //模拟队列 86 LinkedList<String> list1 = new LinkedList<>(); 87 list1.add("李四"); 88 list1.add("张三"); 89 list1.add("王五"); 90 list1.add("李四");//元素可以重复 91 92 while(!list1.isEmpty()){ 93 String temp = list1.remove();//参数是boolean类型 用于判断是否更改,废话, 94 System.out.println(temp.toString()); 95 } 96 97 //其它方法 Collection 98 //同样是在最后面添加 99 list1.addAll(List.of("A","B","C","D","E","F","G")); 100 //最后面添加一个元素 101 list1.addLast("A");//和add()一样 102 } 103 104 //迭代器遍历 105 /* 106 * 迭代器内部实现是一个带有头结点的单向链表 107 * 1、便利的始终是next,下一个元素。 具体方法,hasNext(),next(); 108 * hasNext(),看看下一个元素是否非空。 109 * next()返回下一个元素值,并且指针自动后移一位 110 * 2、删除当前元素,remove,可能对有些迭代器不适用。这里没有演示 111 * */ 112 public static void test3(){ 113 LinkedList<String> list1 = new LinkedList<>(List.of("张三","李四","王五","赵六","算法")); 114 115 Iterator<String> iterator = list1.iterator(); 116 System.out.println(iterator.getClass()); 117 while(iterator.hasNext()){ 118 String temp = iterator.next(); 119 System.out.println(temp); 120 } 121 122 } 123 124 //其他操作 125 //1、添加/插入,(1)最后添加:add(E);addLast(E);addAll(Collection<E>) (2)第一个位置插入:addFirst(E) (3)某一个位置插入元素add(index,E); addAll(index,collection<E>) 126 //2、删除,(1)删除第一个位置元素 remove(),removeFirst();(2)删除最后一个位置元素,removeLast(3)删除某一位置元素remove(index)(4)删除某个元素remove(Obj)(5)删除一群元素removeAll(Collection); 127 //3、修改,(1)修改set(index,E)(2)清空clear(); 128 //4、查找,(1)查找第一个元素,getFirst()(2)查找最后一个元素getLast()(3)查找某个位置元素get(index); 129 //5、将其它Collection容器变为LinkedList 构造方法,或者清空之后,addAll(); 130 //LinkedList的插入,删除速度快于ArrayList,但是查找,特别是修改速度很慢,所以必要时候可以将LinkedList转换为ArrayList; 131 132 public static void test4(){ 133 LinkedList<String> list = new LinkedList<>(); 134 list.clone(); 135 //同样是在最后面添加 index=0 136 list.addAll(List.of("A","B","C","D","E","F","G")); 137 //最后面添加一个元素 138 list.addLast("A");//和add()一样 139 //toString 140 System.out.println(list.toString()); 141 //长度,得到某个位置元素 142 //得到某个位置元素 143 System.out.println(list.get(list.size() - 1)); 144 //得到第一个位置元素 145 System.out.println(list.getFirst().toString()); 146 //得到最后一个元素 147 System.out.println(list.getLast().toString()); 148 //是否含有某个元素 --- 和地址无关 149 System.out.println(list.contains("A"));//true 150 System.out.println(list.contains(new String("A")));//true 151 //查找某个元素位置 152 System.out.println(list.indexOf("B")); 153 System.out.println(list.lastIndexOf("A")); 154 System.out.println(list.lastIndexOf("aaa")); 155 //删除某个元素 156 list.remove("AAA"); 157 list.remove(1); 158 159 160 } 161 162 public static void main(String[] args){ 163 test4(); 164 } 165 }
1.5 HashSet模拟
1 package com.testhashset; 2 3 //HashSet底层是一个HashMap 4 //也就是说HashSet添加删除,查看都是通过HashMap实现的,那么它是怎么实现的? 5 6 7 import java.util.ArrayList; 8 import java.util.HashMap; 9 import java.util.HashSet; 10 import java.util.List; 11 12 /* 13 * 14 * 启发: 15 * 1、容器套容器案例(一个容器的成员属性可以是容器) 16 * 用一个map作为实际存储容器。 17 * 需要理解map的用法 18 * 2、 19 * 20 * */ 21 22 public class Test { 23 24 //构造方法--实际是map的方法 25 //1.构造时,对应初始化存储容器 map 26 //2.有一个Object类私有最终常量,用于map添加元素 27 28 public static void test(){ 29 //无参初始化 30 HashSet<String> mySet = new HashSet<>(); 31 //设置初始容量大小 32 HashSet<String> mySet1 = new HashSet<>(10); 33 //拷贝一个实例化容器 34 HashSet<String> mySet2 = new HashSet<>(mySet1); 35 // 36 HashSet<String> mySet3 = new HashSet<>(10,10.1f); 37 38 Object temp = new Object(); 39 40 //无参初始化 41 HashMap<String,Object> myMap = new HashMap<>(); 42 HashMap<String,Object> myMap1 = new HashMap<>(10); 43 //HashSet里面的map只能一个一个添加 44 //HashSet参数是一个实例化map 45 HashMap<String,Object> myMap2 = new HashMap<>(myMap); 46 HashMap<String,Object> myMap3 = new HashMap<>(10,10.1f); 47 48 } 49 50 //Hashset add/addAll添加操作 51 //其实就是map的put操作 52 //Hashset add返回值类型是boolean,表示是否成功添加 53 //Hashmap put返回值类型是一个V,返回原来对象 54 //Hashset addAll 返回值是boolean ,表示是否至少添加一个元素 55 56 public static void test1(){ 57 HashSet<String> set1 = new HashSet<>(10); 58 Object obj = new Object(); 59 HashMap<String,Object> myMap = new HashMap(10); 60 61 System.out.println(set1.add("张三"));//true 62 System.out.println(myMap.put("张三", obj)==null);//false 63 System.out.println(set1.add("张三"));//false 64 System.out.println(myMap.put("张三", obj)==null);//false 65 66 System.out.println(set1.addAll(List.of("李四", "张三")));//true 67 boolean flag = false; 68 for (String s :List.of("李四","王五","赵六")){ 69 flag = flag||myMap.put(s, obj)==null; 70 } 71 System.out.println(flag);//true 72 } 73 74 //Hashset remove()removeAll()删除操作 clean()清空 75 //其实就是map的remove clean()清空操作 76 77 public static void test2(){ 78 HashSet<String> set = new HashSet<>(10); 79 Object obj = new Object(); 80 HashMap<String,Object> map = new HashMap(10); 81 set.add("张三"); 82 map.put("张三",obj); 83 84 System.out.println(set.remove("张三"));//true 85 //就是通过key删除 86 System.out.println(map.remove("张三")==null?false:true);//true 87 88 set.addAll(List.of("张三","李四")); 89 System.out.println(set.removeAll(List.of("张三", "李四", "王五")));//true 90 91 for (String s :List.of("张三","李四")){ 92 map.put(s,obj); 93 } 94 95 //不能直接删除一群,只能一个一个操作 96 97 boolean flag = false; 98 for (String s :List.of("张三", "李四", "王五")){ 99 flag = flag||map.remove(s)!=null;//true 100 } 101 System.out.println(flag);//true 102 103 set.clear(); 104 map.clear(); 105 } 106 107 //HashSet contains() containsAll()方法 108 //也是map的对key的操作 109 //同样不能一次判断群 110 111 public static void test3(){ 112 HashSet<String> set = new HashSet<>(10); 113 Object obj = new Object(); 114 HashMap<String,Object> map = new HashMap(10); 115 set.add("张三"); 116 set.addAll(List.of("李四","王五")); 117 map.put("张三",obj); 118 for (String s :List.of("李四","王五")){ 119 map.put(s,obj); 120 } 121 122 //判断是否包含某个元素 123 System.out.println(set.contains("张三"));//true 124 System.out.println(map.containsKey("张三"));//true 125 126 127 boolean flag = true; 128 //判断是否包含一群元素,必须都有 129 for (String s :List.of("张三", "李四", "王五")){ 130 flag = flag&&map.containsKey(s); 131 } 132 System.out.println(set.containsAll(List.of("张三", "李四", "王五")));//true 133 System.out.println(flag); 134 135 flag = true; 136 System.out.println(set.containsAll(List.of("张三", "李四", "王五", "赵六")));//false 137 for (String s :List.of("张三", "李四", "王五", "赵六")){ 138 flag = flag&&map.containsKey(s); 139 } 140 System.out.println(flag);//false 141 142 } 143 144 //HashSet不存在修改操作,HashMap也不存在修改 145 146 public static void main(String[] args) { 147 // test();//构造方法测试 148 // test1();//add/addAll方法模拟 149 // test2();//remove/removeAll方法模拟 150 test3(); 151 } 152 }
1.6HashMap效率测试
1 package com.testhashmap; 2 3 /* 4 * 5 * HashMap存储结构用在HashSet里面了。 6 * 7 * 1、概述: 8 * 1、数组的散列存储能够实现通过关键字找到值,但是随着元素个数增加,冲突概率增加,产生冲突需要解决,否则影响查找, 9 * 冲突解决可以采用拉链法,建立一个链表存储多余元素 10 * 2、但是链表查找效率低,于是有了红黑树。在链表个数超过一定数量的时候链表会变成一个红黑树,有了红黑树,我丝毫看不到链表的优势,除了实现简单。 11 * 2、怎么证明确实是 12 * 1、哈希函数 13 * 2、冲突处理 14 * 3、红黑树。 15 * 16 * 方法,通过比较LinkedList,ArrayList 增删改查的时间,估算用的是什么了。 17 * 18 * 19 * */ 20 21 import java.util.*; 22 23 public class TestHashMap { 24 public static void test1(){ 25 HashMap<User,Integer> map = new HashMap<>(); 26 ArrayList<User> list1 = new ArrayList<>(); 27 LinkedList<User> list2 = new LinkedList<>(); 28 29 //首先是10000个作为初始化的元素 30 for(int i =0;i<10000;i++){ 31 list1.add(new User()); 32 map.put(new User(),i);//无所谓,也可以单独拿出来写 33 } 34 //拷贝list1 35 list2.addAll(list1); 36 37 //插入的用时对比---就拿添加为例,因为map只有put 38 39 //100000次 40 long begin = System.currentTimeMillis(); 41 for(int i = 0;i<100000;i++){ 42 map.put(new User(),i); 43 } 44 long end = System.currentTimeMillis(); 45 System.out.println(end-begin); 46 begin = System.currentTimeMillis(); 47 for(int i = 0;i<100000;i++){ 48 list1.add(new User()); 49 } 50 end = System.currentTimeMillis(); 51 System.out.println(end-begin); 52 begin = System.currentTimeMillis(); 53 for(int i = 0;i<100000;i++){ 54 list2.addLast(new User()); 55 } 56 end = System.currentTimeMillis(); 57 System.out.println(end-begin); 58 59 //list并不一定每次都是在最后面添加 60 //这里添加10万个Hashmap用时52毫秒,速度已经很好了 61 //那么先试一下让list随机插入的后果。 就在10000的位置插入 62 63 for(int i = 0;i<100000;i++){ 64 list1.add(10000,new User()); 65 } 66 end = System.currentTimeMillis(); 67 System.out.println(end-begin); // 68 begin = System.currentTimeMillis(); 69 for(int i = 0;i<100000;i++){ 70 list2.add(10000,new User()); 71 } 72 end = System.currentTimeMillis(); 73 System.out.println(end-begin);// 74 begin = System.currentTimeMillis(); 75 for(int i = 0;i<100000;i++){ 76 map.put(new User(),i); 77 } 78 end = System.currentTimeMillis(); 79 System.out.println(end-begin);// 80 81 //总结如果是每次都是在最后面添加那么不用考虑了,数组Arraylist 82 //如果数据量很大,别用ArrayList和LinkedList,最少不要用LinkedList 83 //HashMap还是一如既往的稳定 31毫秒 84 } 85 86 public static void test2(){ 87 //补充元素150000 88 HashMap<Integer,Integer> map = new HashMap<>(); 89 ArrayList<Integer> list1 = new ArrayList<>(); 90 LinkedList<Integer> list2 = new LinkedList<>(); 91 for(int i =0;i<150000;i++){ 92 list1.add(i); 93 map.put(i,i); 94 } 95 list2.addAll(list1); 96 97 //删除 10000 - 100000的元素 98 long begin = System.currentTimeMillis(); 99 for(int i = 100000;i>=10000;i--){ 100 map.remove(i); 101 } 102 long end = System.currentTimeMillis(); 103 System.out.println(end-begin); 104 105 begin = System.currentTimeMillis(); 106 for(int i = 100000;i>=10000;i--){ 107 list1.remove(i); 108 } 109 end = System.currentTimeMillis(); 110 System.out.println(end-begin); 111 begin = System.currentTimeMillis(); 112 for(int i = 100000;i>=10000;i--){ 113 list2.remove(i); 114 } 115 end = System.currentTimeMillis(); 116 System.out.println(end-begin); 117 118 119 begin = System.currentTimeMillis(); 120 map.clear(); 121 end = System.currentTimeMillis(); 122 System.out.println(end-begin); 123 begin = System.currentTimeMillis(); 124 list1.clear(); 125 end = System.currentTimeMillis(); 126 System.out.println(end-begin); 127 begin = System.currentTimeMillis(); 128 list2.clear(); 129 end = System.currentTimeMillis(); 130 System.out.println(end-begin); 131 } 132 //一言难尽 133 134 //查找 -- 找某个位置的元素应该是ArrayList快 135 136 public static void test3(){ 137 HashMap<Integer,Integer> map = new HashMap<>(); 138 ArrayList<Integer> list1 = new ArrayList<>(); 139 LinkedList<Integer> list2 = new LinkedList<>(); 140 for(int i =0;i<150000;i++){ 141 list1.add(i); 142 map.put(i,i); 143 } 144 list2.addAll(list1); 145 146 //查找 10000 - 100000的元素 147 long begin = System.currentTimeMillis(); 148 for(int i = 100000;i>=10000;i--){ 149 map.containsKey(i); 150 } 151 long end = System.currentTimeMillis(); 152 System.out.println(end-begin); 153 154 begin = System.currentTimeMillis(); 155 for(int i = 100000;i>=10000;i--){ 156 list1.contains(i); 157 } 158 end = System.currentTimeMillis(); 159 System.out.println(end-begin); 160 begin = System.currentTimeMillis(); 161 for(int i = 100000;i>=10000;i--){ 162 list2.contains(i); 163 } 164 end = System.currentTimeMillis(); 165 System.out.println(end-begin); 166 } 167 //总结:Hash是真的牛,全能,显然就是用了Hash函数+红黑树(难点) 168 //删除和查找,LinkedList就离谱,越来越菜。 169 170 //神装大佬吊打2个小弟 171 172 //修改操作 173 public static void test4(){ 174 HashMap<Integer,String> map = new HashMap<>(); 175 ArrayList<Integer> list1 = new ArrayList<>(); 176 LinkedList<Integer> list2 = new LinkedList<>(); 177 for(int i =0;i<150000;i++){ 178 list1.add(i); 179 map.put(i,"1"); 180 } 181 list2.addAll(list1); 182 183 long begin = System.currentTimeMillis(); 184 Set<Integer> integers = map.keySet(); 185 // for(int i = 100000;i>=10000;i--){ 186 // 187 //// String temp = map.get(i); temp = " "+i;//因为String类型和包装类存在自动包装机制,所以难为它了 188 // 189 // } 190 //由于没有合适方法,内部还是通过迭代器一个一个找,所以这一轮认输算了。 191 //再试一下 192 //entries 是一个Set容器,但是元素也是一个容器, 193 // Set<Map.Entry<Integer, String>> entries = map.entrySet(); 194 // for(int i = 100000;i>=10000;i--){ 195 // 196 // } 197 //迭代器--这样就慢了 198 //突然发现迭代器也改不了, 199 200 201 long end = System.currentTimeMillis(); 202 System.out.println(end-begin); 203 204 begin = System.currentTimeMillis(); 205 for(int i = 100000;i>=10000;i--){ 206 list1.set(i,i+1); 207 } 208 end = System.currentTimeMillis(); 209 System.out.println(end-begin); 210 begin = System.currentTimeMillis(); 211 for(int i = 100000;i>=10000;i--){ 212 list2.set(i,i+1); 213 } 214 end = System.currentTimeMillis(); 215 System.out.println(end-begin); 216 } 217 public static void test5(){ 218 HashMap<Integer,User> map = new HashMap<>(); 219 ArrayList<Integer> list1 = new ArrayList<>(); 220 LinkedList<Integer> list2 = new LinkedList<>(); 221 for(int i =0;i<150000;i++){ 222 list1.add(i); 223 map.put(i,new User()); 224 } 225 list2.addAll(list1); 226 227 long begin = System.currentTimeMillis(); 228 Set<Integer> integers = map.keySet(); 229 for(int i = 100000;i>=10000;i--){ 230 map.get(i).value = i; 231 } 232 long end = System.currentTimeMillis(); 233 System.out.println(end-begin); 234 235 begin = System.currentTimeMillis(); 236 for(int i = 100000;i>=10000;i--){ 237 list1.set(i,i+1); 238 } 239 end = System.currentTimeMillis(); 240 System.out.println(end-begin); 241 begin = System.currentTimeMillis(); 242 for(int i = 100000;i>=10000;i--){ 243 list2.set(i,i+1); 244 } 245 end = System.currentTimeMillis(); 246 System.out.println(end-begin); 247 } 248 249 public static void main(String[] args) { 250 // test1();//添加和插入测试, 251 // test2();//删除测试 252 // test3();//查找测试 253 test5(); 254 } 255 } 256 257 //随意定义一个类,这个类存值。 258 259 class User{ 260 public int value; 261 // public String value; 262 }
2.1 TreeMap练习1
1 package com.day17; 2 3 import java.util.TreeMap; 4 5 public class TestTreeMap { 6 //key是有序的,当然也是唯一的。 7 public static void test1( ){ 8 //String类的比较器 9 TreeMap<String,String> map1 = new TreeMap<>(); 10 map1.put("1","1"); 11 map1.put("2","1"); 12 map1.put("3","1"); 13 map1.put("4","1"); 14 map1.put("5","1"); 15 map1.put("11","1"); 16 map1.put("111","1"); 17 map1.put("1111","1"); 18 map1.put("11111","1"); 19 //{1=1, 11=1, 111=1, 1111=1, 11111=1, 2=1, 3=1, 4=1, 5=1} 20 System.out.println(map1); 21 } 22 23 public static void testComparable(){ 24 TreeMap<Student,String> map1 = new TreeMap<>(); 25 Integer i = 1; 26 for(;i<=10;i++){ 27 try { 28 map1.put(new Student(i,i.toString()),i.toString()); 29 }catch (ClassCastException e){ 30 System.out.printf("添加第%d个元素异常%n",i); 31 } 32 } 33 System.out.println(map1); 34 } 35 public static void main(String[] args){ 36 // test1(); 37 testComparable(); 38 } 39 40 41 //原理就是一个比较器。不能排序的(Comp没有给我们默认实现)自己写排序, 42 //乱序--二分排序,(数组) 43 //怎么让自定义类型排序 44 //初始化时传递Comparator接口实现类-- 45 //--初始化可以初始化常量 46 //comparator.compare(k1, k2) 不能为映射中的任何键 k1 和 k2 抛出 ClassCastException(强制类型转换异常) 47 //初始化不初始化接口实现类 48 //插入map的所有键(KEY)必须实现可比较的接口Comparable<Student>。 49 // 此外,所有这些键必须相互可比:k1.compareTo(k2)不能为映射中的任何键k1和k2抛出ClassCastException。 50 51 } 52 53 54 class Student implements Comparable<Student>{ 55 private int id; 56 private String name; 57 Student(){ 58 59 } 60 Student(int id, String name){ 61 this.id = id; 62 this.name = name; 63 } 64 @Override 65 public int compareTo(Student o) { 66 if(o==null){ 67 return -1; 68 } 69 return this.id-o.id; 70 } 71 @Override 72 public String toString(){ 73 return "{"+this.id+","+this.name+",}"; 74 } 75 }
2.2TreeMap练习2Map集合遍历
1 package com.testtreemap; 2 3 import java.util.*; 4 import java.lang.String; 5 public class TestTreeMap { 6 //HashMap已经神装了,干嘛还要TreeMap 7 //TreeMap有什么特有的 8 //发现内部有一个比较器,优化了红黑树的比较,也就是说这次是真的可以随心所欲实现没有重复值了 9 //key一样时,后者value替代前者,但是key地址就不替代了。 10 11 //构造方法,比较器 12 //添加元素 13 public static void test1(){ 14 //说明: 15 //1、String类已经实现了Comparable<String>接口(自然比较器,可以比较的,不要把接口名字写错误,),所以它有接口方法compareTo(String); 16 //2、强制类型转换。我可以变成接口实现类啊,用接口实现类就是用我。我是多种实现的一个。 17 // TreeMap<String, Integer> map = new TreeMap<>((a,b)->a.compareTo(b)); 18 //因为方法中存在的强制类型转换,所以没有必要写 19 TreeMap<String,Integer> map = new TreeMap<>(); 20 map.put("张三",1); 21 map.put("李四",2); 22 map.put("王五",3); 23 map.put("张三",4); 24 //相同key时,后面的或默认把前面的value覆盖了 25 //这点不同于HashMap 26 System.out.println(map); 27 } 28 29 //添加一群元素 30 31 public static void test2(){ 32 TreeMap<String,Integer> map = new TreeMap<>(); 33 //果然,map也可以putall 34 map.putAll(Map.of("张三",1,"李四",2)); 35 36 } 37 38 39 //Treemap集合遍历 40 //也适用于HashMap 41 42 //Map.Entry内部类 43 /* 44 * 45 * 1、Map.Entry就是实例化Map的类的元素类型,所有Map.Entry的具体集合组成了Map集合。 46 * 猛一下子没有明白过来。 47 * 内部类就是专门定义的数据结构(类型+操作)。 48 * 2、迭代器泛型元素类型的就是集合元素类型。 49 * 迭代器就是容器本身产生的为了遍历元素用的,所以类型应该匹配。 50 *第一次遇到内部类。 51 * 易错点: 52 * 1.认为Map.Entry是一个类似Map一样的容器。 53 * 原因:没有正确理解泛型,理解容器。 54 * 并不是泛型类并不一定是容器,容器也不一定是泛型的。 55 *案例 56 * 迭代器(流技术)有点像数据库中的resultSet 57 * 58 * */ 59 60 public static void test3(){ 61 62 TreeMap<String,Integer> map = new TreeMap<>(); 63 map.putAll(Map.of("张三",1,"李四",2,"王五",3,"赵六",4)); 64 //通过迭代器遍历 65 Iterator<Map.Entry<String, Integer>> it = map.entrySet().iterator(); 66 while(it.hasNext()){ 67 Map.Entry<String, Integer> entry = it.next(); 68 System.out.println("key:"+entry.getKey()+",value:"+entry.getValue()); 69 } 70 //通过TreeMap的keySet()方法 71 //返回值是key的集合,类型是Set集合, 72 // Set是一个接口,实际对象是TreeMap返回的一个Set接口的实例化对象。 73 Set<String> keys = map.keySet(); 74 Iterator<String> it1 = keys.iterator(); 75 //遍历所有key对象。 76 while(it1.hasNext()){ 77 System.out.println("key="+it1.next()); 78 } 79 80 //通过TreeMap的Values() 81 //返回是一个values集合,类型是Collection 82 //Collection也是一个接口,实际对象是TreeMap返回的一个Collection 接口的实例化对象。 83 Collection<Integer> values = map.values(); 84 Iterator<Integer> it2 = values.iterator(); 85 //遍历所有values对象 86 //自动拆箱 87 while(it2.hasNext()){ 88 System.out.println("value="+it2.next()); 89 } 90 91 //也可用for:in语句,也可遍历容器 92 for (int i:values){ 93 System.out.println("value="+i); 94 } 95 96 for(String key:keys){ 97 System.out.println("key="+key); 98 } 99 } 100 101 public static void main(String[] args) { 102 // test1(); 103 // test2(); 104 test3(); 105 } 106 }
补充 1.TreeMap内部排序机制模拟
1 package cn; 2 3 import java.util.Comparator; 4 5 public class FX2 <E>{ 6 7 public E[] es; 8 // Comparable comparable=null;// 易错点,不能要这个,不能两个数比较 9 private final Comparator<E> comparator; 10 11 //方法中可以直接用?,更加灵活 12 FX2(){ 13 comparator = null; 14 } 15 16 FX2(Comparator<E> comparator){ 17 this.comparator = comparator; 18 } 19 20 21 //冒泡排序 22 //升序 23 void sort(){ 24 if(es==null||es.length==0){ 25 return; 26 } 27 if(comparator!=null){ 28 boolean flag=false; 29 for (int i=0,len=es.length;i<len;i++){ 30 flag=true; 31 for (int j =0;j<len-i-1;j++){ 32 if (comparator.compare(es[j],es[j+1])>0){ 33 flag = false; 34 E e = es[j]; 35 es[j] = es[j+1]; 36 es[j+1] = e; 37 } 38 if (flag){ 39 break; 40 } 41 } 42 } 43 } 44 else{ 45 System.out.println(es[0] instanceof Comparable); 46 //强制类型转换可能存在异常 -- 或者判断一下es是否是 47 try { 48 System.out.println((Comparable) es[0]); 49 } 50 catch(ClassCastException e){ 51 e.printStackTrace(); 52 System.out.println("强制类型转换异常,您传递的类没有实现Comparable接口,请实现接口,或者在传递比较器"); 53 return ; 54 } 55 56 boolean temp = false; 57 for (int i = 0,len = es.length;i<len;i++){ 58 temp = true; 59 for (int j = 0;j<len-1-i;j++){ 60 if(((Comparable)es[j]).compareTo(es[j+1])>0){ 61 temp = false; 62 E t = es[j]; 63 es[j] = es[j+1]; 64 es[j+1] = t; 65 } 66 } 67 if(temp){ 68 break; 69 } 70 } 71 } 72 } 73 74 }
补充:
1.Map实现类虽然不能修改,但是可以添加key相同的元素达到修改。
2.Map的元素类型是Map.Entry
3.HashMap操作是以key的HashCode,和equals方法为基础的
个人总结
1、TreeMap它的特点是什么,它是怎么实现的?
TreeMap;
特点:
1、继承抽象类AbstractMap,抽象类继承Map接口,是一个实例化对象。
2、有一个私有的,常量成员属性 Comparator类型的自然比较器comparator。
即:private final Comparator<? super K> comparator;
3、key顺序可控。
实现原理:
控制put
1、通过私有常量比较器接口通过比较每一个对象,如果对象和已有对象值相等那么就会覆盖前面的value保证key不会重复
多态--使用接口就是使用实现类
a、可以在初始的时候传递实例化对象,给接口赋值。这样用接口就使用实例化对象的方法。
b、key类可以实现Comparable<E>接口,这样添加元素的时候会自动使用key
a、b确实有,它内部通过if else实现了。
反之,如果不仅没有在初始时候初始化化是有最终比较器接口(手动赋值为null),而且Key也没有实现接口
那么比较器是自动调用的,put会抛出类转换异常ClassCastException
如果key实现了比较器,且初始化传递了参数,那么会先用初始化的比较器,内部的就不用了。
2、HashSet存储利用了HashMap,为什么要用到HashMap,它的特点是什么?应用场景
2.1
1、HashMap实现了Map接口,1、采用数值(散列存储)+链表/红黑树(冲突处理)快速实现存取,删除,查找。2、Key值不能重复(HashMap相同地址的元素后者Value覆盖前者,但是key地址不覆盖),所以Key元素还是保留前者。
2、HashMap实现原理不同于TreeMap,操作起来更加简单。
HashSet用HashMap数据结构后能干什么?
可以利用Hash存储结构存放元素,
可以利用HashMap的操作实现删除,添加, 查找。
2.2
HashMap实现原理
1、散列存储
关键字,存储地址,存储表(容器)
1、散列函数的定义域必须包含全部需要存储的关键字,值域范围依赖于散列表的大小或地址范围
2、散列函数计算出来的地址应该能等概率、均匀地分布在整个地址空间,减少冲突发生。
3、散列函数应尽量简单,能够在较短的时间内计算出任意关键字对应的散列地址
hash函数(其中一个)
1、直接定址法,没有冲突(线性函数)
2、除留余数法(关键),(存在冲突)
3、数字分析法,分部不均匀的
4、平方取中法
5、折叠法
2、冲突处理,
拉链法:链表+红黑树
3、存储顺序/hash函数
1、一定有序,有序是基础,但是我们不需要研究。
2、这个顺序并不是A一定在B前面,1一定在2前面,就是和平常排序不同。
2.3 HashSet特点
建立关键字和存储地址的映射关系
底层使用哈希表实现
元素不可重复
排列无序(准确说,应该是其不保证有序。迭代器在遍历HashSet时,大多情况下是无序的,但也可能由于巧合,使其输出恰好为有序,这也是允许的。所以你的程序不应该依赖这个巧合的有序情况,而应该按照无序这种普适的情况进行处理)
存取速度快
线程不安全
2.4HashSet应用场景
集合,元素不能重复,
String,包装类都会自动打包
3、LinkedList容器内部机制,它的特点是什么?
LinkedList是一个双向循环链表
插入删除快,可以模拟数据结构栈和队列,
4、ArrayList容器内部机制,它的特点是什么?
ArrayList是一个变长(动态)数组
随机存储,比较灵活,数值长度可变,但是删除,插入用时比较长。
5、HashMap存储原理,它的特点是什么?
存储原理见2.
特点
1、key上元素不能重复,否则保留前者key值,后者value值替代前者。
2、插入,删除,查找速度都很快
6、简述一下迭代器的特点和作用。
特点:
1、每个容器实现类都可返回一个迭代器,迭代器我们就不用new了。
2、利用了流技术,一般只能往后遍历。
3、迭代器也用到了泛型。元素类型就是容器元素类型。
作用
1、迭代器的作用是帮助容器快速遍历,查找,删除元素。
7、简述一下Map.Entry内部类的特点和作用。
7.1特点:
1、是Map接口的内部类。
2、利用泛型,但不是容器。
7.2
1、专门为所有Map对象定义的一个数据结构,方便内部成员使用。
2、一个元素不仅存储了key值,还同时存储了value值
可同时对key,value操作。
8、一个异常
ClassCastException//类型转换异常,
出现原因:
1、泛型中设置了,强制类型转换失败,
2、既没有实例化比较器,也没有实现Comparable接口
2022/9/23
集合遍历
第一种方式:迭代器
第二种方式:内置的方法,foreach方法
第三种:可以利用流
第四种:可以用for:in循环,
总结:
1.时刻记住遍历的底层元素是谁就行了,还有就是记住转换关系
底层元素就是泛型指定的元素
2.Map遍历的需要先变为Set<Map.Entry<Key,Value>>:然后按照遍历Set集合的方式遍历元素。不能直接遍历元素
3.Set,List遍历元素类型就是泛型的元素类型,可以直接遍历元素。
集合和mybatis
list集合作为方法返回值
List集合作为返回值可以接收多行查询的结果(List集合遍历,添加元素速度最快,并且是一个长度可变的数组)
map集合作为方法的返回值,
map元素是键值对,所以map可以看做抽象的实体类
集合和ajax请求
作为参数
Map可以作为参数,作用等同于实体类,非常灵活
作为返回值
map集合返回给前端,前端收到的是一个json对象。这和传统的字符串不一样,非常方便。 key和Value类型都是Object
list集合返回给前端,前端收到的是一个Object数组。
总结:map,list是一个非常好的数据结构,
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· winform 绘制太阳,地球,月球 运作规律
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 上周热点回顾(3.3-3.9)
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人