使用集合而不使用数组的场景 1、无法预测存储数据的数量 2、同时存储一对一关系数据 3、需要进行数据的增删(动态增长) 4、数据重复问题
1、集合分为Collection和Map两类,Collection存储类的对象,Map存储键值对信息 2、Collection接口下有三个子接口,List与Queue中存储有序且允许重复的对象,Set中存储无序且不允许重复的对象,List的实现类包括ArrayList,ArrayList可看作长度动态变化的数组
1、元素有序可重复的集合 2、可精确地控制某个位置的元素(删除、插入方便)。。应该是因为有序吧 3、两个实现类:ArrayList LinkedList 4、ArrayList底层是由数组实现,与数组类似,也是在内存中的一片连续空间存储,因此在ArrayList列表尾部插入或删除数据非常有效,在中间插入需要进行大量数组复制,因此不适合 5、ArrayList元素可为null值。。。应该是因为存储对象,对象默认值为null吧 6、ArrayList更适合查找和更新元素(类似数组)
Collection:****add() clear() contains() isEmpty() remove() toArray() size()(集合转换成数组) **List:**get(int index) **indexof()(两个不要搞混,类似的有String里的 charAt()和indexOf()) sort() ** ArrayList:构造函数: ArrayList(); ArrayList(已存在的集合数据); ArrayList(初始化容量); ArrayList重写了toString方法:System.out.println(列表名)输出所有内容
添加公告,显示公告,在指定位置添加公告删除公告,修改公告 添加公告:add方法,在末尾添加 显示公告:get方法的返回值是一个Object对象,需要对返回值进行强制转换,把父类Object的对象强制转换成子类的对象,再调用类内的get方法,遍历显示内容(之前想的改写toString方法有问题,因为返回的是Object对象,改写了类的toString方法也不会有效,不对,重写父类的方法是会被直接调用的,独有的方法则需要强制转换再调用)
在指定位置添加公告:add方法,在列表中间添加 删除公告:remove方法 修改公告:创建了新的对象去替换旧的对象需要调用ArrayList的set方法
public class ListDemo2 { public static void main(String[] args) { ArrayList arrayList=new ArrayList(); Brief notice1=new Brief("公告一",1); Brief notice2=new Brief("公告二",2); Brief notice3=new Brief("公告三",3); //添加公告,add在末尾添加 arrayList.add(notice1); arrayList.add(notice2); arrayList.add(notice3); // System.out.println(arrayList.get(0));//方法获取的是对象,因此需要重写toString方法 // System.out.println(arrayList); //显示公告 for(int i=0;i<arrayList.size();i++){ System.out.println(i+":"+((Brief)(arrayList.get(i))).getTime()); //+可进行字符串连接和加法运算,可同时进行 } //在指定位置添加公告删除公告,以及公告的修改 //在第一条公告后面添加一条新公告,add在中间指定位置插入 arrayList.add(1,new Brief("公告四",4)); //删除公告 //arrayList.remove(0); arrayList.remove(notice1); for(int i=0;i<arrayList.size();i++){ System.out.println(i+":"+((Brief)(arrayList.get(i))).getTime()); //+可进行字符串连接和加法运算,可同时进行 } //修改公告 //先修改对象中的内容,再修改ArrayList notice3.setContents("修改了"); //set把arraylist中对象的值重新设置一遍(如果创建了新的对象去替换旧的对象需要调用ArrayList的set方法 arrayList.set(2,notice3); for(int i=0;i<arrayList.size();i++){ System.out.println(i+":"+((Brief)(arrayList.get(i))).getContents()); //+可进行字符串连接和加法运算,可同时进行 } } } class Brief{ private String contents; private int time; public int getTime() { return time; } public void setTime(int time) { this.time = time; } public String getContents() { return contents; } public void setContents(String contents) { this.contents = contents; } public Brief(String contents,int time) { this.contents = contents; this.time=time; } @Override public String toString() { return this.contents+this.time; } }1、HashSet中元素无序且不可重复 2、实现类HashSet只允许包含一个null元素(因为不允许重复) 3、HashSet具有良好的存取和查找性能 4、HashSet底层是HashMap 5、HashSet的构造方法:HashSet() HashSet(已存在的集合数据) HashSet(初始容量)
1、向集合中添加元素
HashSet a=new HashSet(5); //向集合中添加元素 a.add("blue"); a.add("red"); a.add("black"); a.add("yellow"); a.add("white");2、显示集合中的元素(遍历),没有get方法,使用迭代器接口 (1)Iterator接口可以以统一的方式**对各种集合元素(ArrayList也可以用)**进行遍历 (2)Iterator接口中的hasNext()方法检测集合中是否还有下一个元素 (3)Iterator接口中的next()方法返回集合中的下一个元素 可能是新的接口使用方法吧,跟前面的不太一样,接口本质上还是一个类
Iterator it=a.iterator();集合调用iterator()方法把结果存放到Iterator的引用中(Set不能使用get方法取出元素,那么把集合中的数据放到迭代器中,使用迭代器的方法取出集合的元素) 遍历迭代器输出元素
while(it.hasNext()){ System.out.print(it.next()+" "); }3、在集合中插入新的单词,Set与ArrayList相比是无序的,因此只有一种在末尾添加元素的add方法,不能使用索引在中间指定位置添加 插入重复元素后遍历迭代器并输出,插入失败,但是不会报错,系统不会插入重复元素
a.add("black"); //插入重复元素后遍历迭代器并输出,插入失败,但是不会报错,系统不会插入重复元素 it=a.iterator(); while(it.hasNext()){ System.out.print(it.next()+" "); }1、添加和显示宠物猫信息 while(i.hasNext())返回集合元素对象的引用,输出时自动调用类的toString方法,输出的是地址信息 stringdemo.Cat@2f4d3709 stringdemo.Cat@b4c966a stringdemo.Cat@4e50df2e 因此需要重写toString方法
public class SetDemo2 { public static void main(String[] args) { Cat cat1=new Cat("猫1","品种1",2); Cat cat2=new Cat("猫2","品种2",4); Cat cat3=new Cat("猫3","品种3",6); HashSet set=new HashSet(); set.add(cat1); set.add(cat2); set.add(cat3); Iterator i= set.iterator(); while(i.hasNext()) //返回集合元素对象的引用,输出时自动调用类的toString方法,输出的是地址信息 //stringdemo.Cat@2f4d3709 stringdemo.Cat@b4c966a stringdemo.Cat@4e50df2e //重写toString方法 System.out.print(i.next()+" "); } } class Cat{ private String name; private String species; private int month; public String getSpecies() { return species; } public void setSpecies(String species) { this.species = species; } public String getName() { return name; } public void setName(String name) { this.name = name; } public int getMonth() { return month; } public void setMonth(int month) { this.month = month; } public Cat(String name, String species,int month) { this.month = month; this.name=name; this.species=species; } @Override public String toString() { return "Cat{" + "name='" + name + '\'' + ", species='" + species + '\'' + ", month=" + month + '}'; } }2、添加重复的宠物猫信息
Cat cat4=new Cat("猫3","品种3",6); set.add(cat4); //重新取一下集合中的元素放到迭代器中 //在类中重写Object中hashCode和equals方法 i=set.iterator();//重新取集合中的元素放到迭代器中 while(i.hasNext()) System.out.println(i.next()+" ");i=set.iterator();//重新取集合中的元素放到迭代器中 输出了重复元素,与元素是字符串时不同,字符串是系统给的类,判断数据是否重复的规则已经定义好了(String类重写了hashCode和equals方法,可以直接使用,而自己定义的类则需要修改判断是否重复的方法,所以需要在类中重写Object中hashCode和equals方法)
需了解数据结构哈希表(hashtable)(存储方式),可提高数据的查找速度 假设存储了100个数据,需要查找第100个数据,若使用ArrayList或数组在一片连续空间存储数据,则需要从第一个数据挨个循环比较数据遍历到第100个数据,当数据量大的情况下效率低下。使用哈希表存取,假设在内存中开辟三个区域存放正整数,如定义hashCode=n%3,hashCode规定这100个数据里什么数据放在哪个桶里,在查找时先判断要查找的数据会在哪个区域里(使用hashCode进行比较),找到所在区域再遍历元素(使用equals方法)
所以为了提高查询速度,需要重写hashCode和equals方法
1、hashCode相同不一定是同一个对象,需要进一步使用equals判断
public boolean equals(Object o) {//两个对象进行比较 //this当前对象和o传进来的对象相等,相等则返回true,不用再继续比较内容 if(this==o) return true; //反射,判断o是否是Cat类的对象,如果是则强制转换,返回两个对象属性比较之后的结果 if(o.getClass()==Cat.class) { Cat cat = (Cat) o;//强制转换 //cat的属性和当前对象的属性 return cat.getName().equals(name) && cat.getMonth()==month&&cat.getSpecies().equals(species); //判断两个Cat对象属性是否相等 } //以上都不满足,不相等 return false; }2、查找某只宠物猫的信息并输出 方式一:使用对象名查找
if (set.contains(cat1)) { System.out.println("找到cat1"); System.out.println(cat1); }方式二:通过名字进行查找,遍历集合
i = set.iterator();//进行一次操作就要重新取集合中的元素放到迭代器中,是next从头开始遍历 boolean flag = false; Cat c = null;//为了保存住遍历到的对象,定义在循环内部 while (i.hasNext()) { c = (Cat) (i.next());//next()得到object类的对象,需要强制转换 if (c.getName().equals("cat1")) { flag = true;//flag查询 break; } } if (flag) { System.out.println("找到cat1"); System.out.println(c); }4、删除某宠物猫信息并显示,引入泛型后可使用for增强循环进行遍历(或使用迭代器)(因为集合中的元素类型已经被指定)
for(Cat n:set) if(n.getName().equals("cat1"); set.remove(n); for(Cat n:set) System.out.println(n); 迭代器遍历后删除不会报错 while(!i.hasNext()) { if (i.next().getContents().equals("公告一")) l.remove(i); }进行上面的操作会报错: **
**
for(Cat n:set) if(n.getName().equals("cat1");{ set.remove(n); break;} 在ArrayList中进行删除操作时类似,for增强循环会报错,普通遍历不报错 for(Brief n:l) if(n.getContents().equals("公告一")) l.remove(n); for(int i=0;i<l.size();i++) if(l.get(i).getContents().equals("公告一")) l.remove(i);在ArrayList中进行删除操作时类似,for增强循环会报错,普通遍历不报错
5、删除多个宠物猫信息,removeAll()括号中的参数可以是一个集合(可以是集合的子集) (1)创建一个新的集合
Set set1=new HashSet();(2)将符合条件的元素添加到新的集合中
for(Cat n:set) if(n.getMonth<3) set1.add(n); set.removeAll(set1);6、删除所有宠物猫信息
set.removeAll(); if(set.isEmpty())(1)Entry是Map中的一个接口,k-v以键值对的形式存储到接口对象中 (2)HashSet是在HashMap基础上实现的 (3)HashMap中只能有一个null键 (4)Entry对象就是k-v键值对所对应的实例(k-v是一种形式,实际上是Entry实例),Entry对象无序排列
获取Entry键值对的所有内容,返回一个Set,限定了返回元素是Map.Entry<K,V>
获取key对应的value值
与entrySet对应,取出所有K值,返回一个Set
与HashSet中添加新元素的add方法不同,HashMap中添加新元素使用put方法
根据key值移除map中的元素
返回一个集合的对象,集合中元素是value值 key和value也是对象
HashMap中的构造方法与HashSet类似
**
完成一个类似字典的功能1、将单词以及单词的注释存储到HashMap中2、显示HashMap中的内容3、查找某个单词的注释并显示*/
public class MapDemo1 { public static void main(String[] args) { HashMap<String,String> hp=new HashMap<String,String>(); //从键盘输入单词和对应的注释 System.out.println("请输入三组单词对应的注释,并存放到HashMap中"); Scanner sc=new Scanner(System.in); //添加数据 int i=0; while(i<3){ System.out.println("请输入key值"); String key=sc.next(); System.out.println("请输入value值"); String value=sc.next(); hp.put(key,value); i++; } //打印输出value的值(直接使用迭代器) System.out.println("使用迭代器输出所有value"); Iterator<String> it=hp.values().iterator();//values返回集合后调用集合的iterator方法,存储到迭代器中 while(it.hasNext()) System.out.println(it.next()); //打印输出key和value的值(通过entrySet方法得到k-v) Set<Map.Entry<String,String>> set=hp.entrySet();//k-v组合到一起就是一个entry的对象,把hashmap里的键值对全部放到一个entry的集合中,就可以遍历集合 //把内容都取出来,Set后加泛型,Entry后也要加泛型,注意辨别 //使用增强型for循环遍历集合 for(Map.Entry<String,String> n:set){ System.out.println(n.getKey()); System.out.println(n.getValue()); } //通过单词找到注释并输出, 使用keySet方法直接获取key或 使用entrySet和getKey联合先获取entry对象再获取key //使用keySet方法 //取得keySet Set<String> set1=map.keySet(); //遍历keySet for(String i:set1) if(i.equals("单词一")){ System.out.println(map.get(i)); break;} }商品信息管理 商品信息添加
public class MapDemo3 { public static void main(String[] args) { //引入重复数据判断和异常处理 HashMap<String,Product> map=new HashMap<String, Product>(); Scanner sc=new Scanner(System.in); System.out.println("请输入三条商品信息:"); for(int i=0;i<3;){ System.out.println("请输入第"+(i+1)+"条商品信息:"); System.out.println("请输入商品编号:"); String id=sc.next(); //与hashset中元素不能重复类似,hashmap中键值不能重复, // 相同键值的元素只插入后面输入的一个 //解决重复输入的隐患 //判断输入的key值在当前的hashmap中是否存在 if(map.containsKey(id)){ System.out.println("该商品编号已存在,请重新输入"); //退出当前循环,执行下一趟循环,i++放在循环末尾, // continue后面i++没有执行,不会影响循环次数 continue;} System.out.println("请输入商品名称:"); String name=sc.next(); System.out.println("请输入商品价格:"); //防止输入的参数不合法,捕获异常 int price=0; try { //输入参数不合法时,nextInt报错,但输入的值已经存入for循环的下一个nextInt中,占据了下个元素的id值 //因此在捕获异常的代码块中多写一个sc.next(),把错误的输入参数放进来,就不会占据下一个元素的id price = sc.nextInt(); }catch (java.util.InputMismatchException e){ System.out.println("商品格式不正确"); sc.next(); continue; }; Product product1=new Product(id,name,price); map.put(id,product1); i++; } //遍历Map,输出商品信息 Iterator<Product> it=map.values().iterator(); while(it.hasNext()) System.out.println(it.next()); //与hashset中元素不能重复类似,hashmap中键值不能重复,相同键值的元素只插入后面输入的一个 //解决重复输入的隐患 } } class Product{ private String id; private String name; private int price; @Override public String toString() { return "Product{" + "id='" + id + '\'' + ", name='" + name + '\'' + ", price=" + price + '}'; } public int getPrice() { return price; } public void setPrice(int price) { this.price = price; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getId() { return id; } public void setId(String id) { this.id = id; } public Product(String id,String name,int price) { this.id=id; this.name=name; this.price = price; } }