Java集合

it2026-01-07  5

集合:工具类,可以存储任意数量具有共同属性的对象的容器

使用集合而不使用数组的场景 1、无法预测存储数据的数量 2、同时存储一对一关系数据 3、需要进行数据的增删(动态增长) 4、数据重复问题

集合框架的体系结构

1、集合分为Collection和Map两类,Collection存储类的对象,Map存储键值对信息 2、Collection接口下有三个子接口,List与Queue中存储有序且允许重复的对象,Set中存储无序且不允许重复的对象,List的实现类包括ArrayList,ArrayList可看作长度动态变化的数组

List(列表)

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(列表名)输出所有内容

在ArrayList中添加字符串对象

ArrayList arrayList=new ArrayList(); //List l=new ArrayList();接口引用指向实现类 arrayList.add("Java"); arrayList.add("C++"); arrayList.add("C"); String[] s=new String[3]; s[0]="Java"; s[1]="C++"; //输出列表中元素的个数 System.out.println(arrayList.size()); //遍历输出所有内容 System.out.println(arrayList); //遍历输出所有内容 for(int i=0;i<arrayList.size();i++) System.out.println(arrayList.get(i)); //移除列表中的C++ // arrayList.remove("C++"); arrayList.remove(1); System.out.println(arrayList); System.out.println(s); for(String i:s) System.out.println(i);

在ArrayList中添加自定义类的对象(增删改查)(add remove size get set)

添加公告,显示公告,在指定位置添加公告删除公告,修改公告 添加公告: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; } }

Set:元素不可重复的集合,称为集

1、HashSet中元素无序且不可重复 2、实现类HashSet只允许包含一个null元素(因为不允许重复) 3、HashSet具有良好的存取和查找性能 4、HashSet底层是HashMap 5、HashSet的构造方法:HashSet() HashSet(已存在的集合数据) HashSet(初始容量)

Set方法:add、addAll、clear、contains、equals、hashcode、iterator、size、remove、toArray

在Set中添加字符串对象

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()+" "); }

在HashSet中加入自定义类的对象

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方法)

hashCode()方法

需了解数据结构哈希表(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); }

引入泛型:在类或接口添加<元素类型>,泛型规定了插入集合的元素必须是某一类型,与c = (Cat) (i.next());//next()得到object类的对象,需要强制转换 相比 c=i.next();无需添加显示强制类型转换,可直接被隐式类型转换

Set<Cat> set=new HashSet<Cat>; HashSet<Cat> set=new HashSet<Cat>; Iterator<Cat> it=set.iterator();

set中删除元素for-each避免异常的方法

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); }

进行上面的操作会报错: **

set的size是动态变化的,当移除一个元素后,长度变化了,不会按照原来的规则进行遍历(set是无序的),因此报错,完成所需操作时就应该退出遍历,(注意for-each循环,可能for-size的遍历可以时刻更新size的变化,iterator hasNext的遍历也可以时刻更新size的变化)修改如下:

**

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())

Map:重要的三个方法,获取键值对对象所在集合entrySet()、获取键所在集合keySet()、获取值所在集合values(),添加键值对put(k,v),获取键对应的值get();注意泛型,HashMap创建是用的是<String,String>,获取键值对对象所在集合时用的是<Map.Entry<String,String>>(所以对hashmap的操作与对hashset的操作相比多了一步entrySet),获取键和值所在集合时用的是;entrySet()k-v组合到一起就是一个entry的对象,把hashmap里的键值对全部放到一个entry的集合中,就可以遍历集合

(1)Entry是Map中的一个接口,k-v以键值对的形式存储到接口对象中 (2)HashSet是在HashMap基础上实现的 (3)HashMap中只能有一个null键 (4)Entry对象就是k-v键值对所对应的实例(k-v是一种形式,实际上是Entry实例),Entry对象无序排列

Map中的方法

获取Entry键值对的所有内容,返回一个Set,限定了返回元素是Map.Entry<K,V>

获取key对应的value值

与entrySet对应,取出所有K值,返回一个Set

与HashSet中添加新元素的add方法不同,HashMap中添加新元素使用put方法

根据key值移除map中的元素

返回一个集合的对象,集合中元素是value值 key和value也是对象

HashMap的方法

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;} }

与前面的简单添加元素不一样,使用了键盘输入,因此就需要对输入参数的合法性进行判断,引入重复数据判断(containsKey())和异常处理(try-catch)

商品信息管理 商品信息添加

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; } }
最新回复(0)