集合:工具类,可以存储任意数量具有共同属性的对象的容器
使用集合而不使用数组的场景
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;
}
}