目录
(3.2)迭代器:Iterator iterator(),返回此集合中的元素的迭代器。
一.集合
1.集合的概念:
Java API中所提供的一系列类的实例,可以用来动态地存放多个对象。java集合框架提供了一套性能优良,使用方便的接口和类,位于java.util包中。
2.为啥使用集合:
当我们要存储多个数据,并且这个数据还会不断更新、改变的时候,数组的特性就难以支撑,所以需要使用集合。
3.集合和数组的异同:
数组的长度固定,集合不固定,可随意对其进行增删改查。
数组存储的数据单一,集合可存储多种类型的数据。
数组可存储引用类型和基本类型,集合只能存储引用类型,若要存储基本类型需得将其装箱为对应的包装类。
4.集合体系的框架结构:
二.Collection接口:
Collection是单例集合的顶层接口,它表示一组对象,这些对象也称为Collection的元素
JDK 不提供此接口的任何直接实现.它提供更具体的子接口(如Set和List)实现
因为接口无法实例化,所以我们需要使用实现类进行创建对象(多态),此处用ArrayList实现类。
例如:
1.常用方法:
(1).增加:
add(元素)添加指定的元素、addAll(集合)添加一个完整的集合进入当前集合
(2)删除:
remove(元素)删除指定的元素、removeAll(集合)删除添加的集合、clear()删除集合中的所有元素
(3)遍历:
(3.1)可以通过toArray将集合转换成数组进行遍历
(3.2)迭代器:Iterator<E> iterator(),返回此集合中的元素的迭代器。
(3.3)增强for循环(foreach):
for(集合/数组中元素的数据类型 变量名 : 集合/数组名) {
// 已经将当前遍历到的元素封装到变量中了,直接使用变量即可
}
(4)判断:
isEmpty()如果此集合不包含元素,则返回true。
contains(元素) 如果此集合包含指定元素,返回true
containsAll(集合)如果此集合包含指定集合的所有元素,则返回true。
(5)其他:
size()返回此集合的元素数
retainAll:
仅保留此集合中包含在指定集合中的元素。相当于求交集,返回结果为布尔型,如果为false,说明此集合是指定集合的一部分,此集合前后并未改变,为true说明此集合发生了改变,删除了指定集合中不包含的元素,仅保留了指定集合包含的部分。
三.List接口
由集合框架结构图可知,List接口继承Collection接口,所以Collection里包含的常用方法List也有,不同的是List有序,可以根据下标来增删改查、遍历(get(索引))。List有如下特点:
-
存取有序
-
可以重复
-
有索引
List特有的方法有如下:
方法名 | 描述 |
---|---|
void add(int index,E element) | 在此集合中的指定位置插入指定的元素 |
E remove(int index) | 删除指定索引处的元素,返回被删除的元素 |
E set(int index,E element) | 修改指定索引处的元素,返回被修改的元素 |
E get(int index) | 返回指定索引处的元素 |
ListIterator遍历(此接口继承Iterator)
-
允许程序员沿任一方向遍历列表的列表的迭代器,在迭代期间修改列表,并获取列表中迭代器的当前位置
-
-
hasPrevious()
返回
true
如果遍历反向列表,列表迭代器有多个元素。previous()
返回列表中的上一个元素,并向后移动光标位置。
previousIndex()
返回由后续调用
previous()
返回的元素的索引。 - 由上图可知,如果要进行逆序遍历,必须使得遍历起始位置位于集合最后一个元素的后面,不然在集合的第一个元素的前面,没有上一个元素,无法遍历。
-
1. ArrayList
ArrayList集合
-
可调整大小的数组的实现List接口。 实现所有可选列表操作,并允许所有元素,包括null 。
底层是数组结构实现,查询快、增删慢
可通过构造方法创建ArrayList对象。
由于ArrayList实现List接口,所以List有的方法ArrayList也具备,所以ArrayList的常用方法参考List就行。下面通过一个例子来使用一下ArrayList
import java.util.ArrayList;//导包系统能自动完成 import java.util.Iterator; import java.util.Scanner; //通过ArrayList建一个Person类(自建的Person类)的集合,并对集合进行去重和遍历的操作 public class ArrayListExer { public static void main(String[] args) { Scanner sc = new Scanner(System.in); ArrayList<Person> persons = new ArrayList<>();//通过构造函数来创建一个空的ArrayList集合 System.out.println("请输入您要录入的次数:"); int count = sc.nextInt(); int n = 0; while (true) {//通过无限循环录入信息 System.out.println("请输入姓名:"); String name = sc.next(); System.out.println("请输入年龄:"); int age = sc.nextInt(); Person per = new Person(name, age);//将录入的信息传入Person对象 persons.add(per);//将Person对象添加到persons集合里 n++;//通过n来控制循环次数 if (n >= count) { //若n=限定的录入次数count则打破循环 break; } } System.out.println(persons); //通过迭代器和增强for循环遍历集合 Iterator<Person> iter = persons.iterator();//通过Iterator遍历器对persons集合进行遍历 for(Object o:persons){//通过foreach增强for循环对persons进行遍历 if(iter.hasNext()){//判断当前位置是否有下一个元素 Person next = iter.next();//获取下一个元素 System.out.println(next);//打印获取的下一个元素 } } //删除集合中重复的元素 for(int i=0;i<persons.size()-1;i++){ for(int j=i+1;j<persons.size();j++){ Person person1 = persons.get(i);//获取persons的第i个元素 Person person2 = persons.get(j); if(person1.getName().equals(person2.getName())&&person1.getAge().equals(person2.getAge())){ persons.remove(j);//判断第i个元素是否和第j个元素相等(姓名、年龄),相等则删除第j个元素 //假设有三个连续相同的元素,删除第二个后,后续的元素会往前移,而i元素会继续和j+1元素相比, // 但此时j+1为原先的j+2,所以不会删除第三个重复的元素,所以删除一个元素后,我们要将j减1 j--; } } } System.out.println(persons); } }
2.LinkList
LinkedList集合
- 双链表实现了
List
和Deque
接口。 实现所有可选列表操作,并允许所有元素(包括null
)。所有的操作都能像双向列表一样预期。
底层是链表结构实现,查询慢、增删快,线程不安全,但效率高。
方法名 | 说明 |
---|---|
public void addFirst(E e) | 在该列表开头插入指定的元素 |
public void addLast(E e) | 将指定的元素追加到此列表的末尾 |
public E getFirst() | 返回此列表中的第一个元素 |
public E getLast() | 返回此列表中的最后一个元素 |
public E removeFirst() | 从此列表中删除并返回第一个元素 |
public E removeLast() | 从此列表中删除并返回最后一个元素 |
四.Set接口
-
不可以存储重复元素
-
没有索引(无序),不能使用普通for循环遍历
-
由于Set接口继承Collection,所以Collection有的方法set也具备,参考Set接口即可。
1.HashSet
-
此类实现Set接口,由哈希表(实际为HashMap实例)支持。 对集合的迭代次序不作任何保证(无序);允许null值。
-
不可以存储重复元素
-
没有索引,不能使用普通for循环遍历
散列表:查询、修改、添加、删除的效率都比较高(可以存储重复元素)。
散列表的逻辑:对元素进行取余(除数组长度,取余)操作,将余数作为元素的索引,存入相应的数组位置(如下图所示)。散列表相当于数组和链表的结合,所以存取、增删改查效率都比较高
HashSet底层是散列表,本质通过以下两个方法实现,但是不能存储重复元素。
int HashCode();确定散列表的下标
boolean equals(Object o);判断同一个下标对应的链表中的数据是否相等
HashSet的基本应用
由遍历结果可知,HashSet的存取不是一一对应的,所以存取无序 。
public class HashSetExer2 { public static void main(String[] args) { HashSet<Object> hsS = new HashSet<>(); Student st1 = new Student("李华",20); Student st2 = new Student("王芳",19); Student st3 = new Student("李华",21); Student st4 = new Student("李华",20); hsS.add(st1); hsS.add(st2); hsS.add(st3); hsS.add(st4); for(Object o:hsS){ System.out.println(o); } } } class Student { private String name; private Integer age; public Student() { } public Student(String name, Integer age) { this.name = name; this.age = age; } public String getName() { return name; } public void setName(String name) { this.name = name; } public Integer getAge() { return age; } public void setAge(Integer age) { this.age = age; } @Override public String toString() { return "Student{" + "name='" + name + '\'' + ", age=" + age + '}'; } @Override public boolean equals(Object o) {//重写equals对参数进行比较 if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; Student student = (Student) o; if (name != null ? !name.equals(student.name) : student.name != null) return false; return age != null ? age.equals(student.age) : student.age == null; } @Override public int hashCode() {//重写HashCode int result = name != null ? name.hashCode() : 0; result = 31 * result + (age != null ? age.hashCode() : 0); return result; } }//结果为:
Student{name='李华', age=21}
Student{name='李华', age=20}
Student{name='王芳', age=19}
重复的元素未被存储
HashSet集合存储自定义类型元素,要想实现元 素的唯一,要求必须重写hashCode方法和equals方法
2.TreeSet
-
不可以存储重复元素,无序
-
没有索引
-
不能存储null值
-
可以将元素按照规则进行排序
-
TreeSet():根据其元素的自然排序进行排序
-
TreeSet(Comparator comparator) :根据指定的比较器进行排序
-
两种比较方法的对比
-
自然排序: 自定义类实现Comparable接口,重写compareTo方法,根据返回值进行排序
-
比较器排序: 创建TreeSet对象的时候传递Comparator的实现类对象,重写compare方法,根据返回值进行排序
-
在使用的时候,默认使用自然排序,当自然排序不满足现在的需求时,必须使用比较器排序
//根据自然排序进行排序
public class TreeSetExer { public static void main(String[] args) { TreeSet<Student> treeSet = new TreeSet(); for (int i = 0; i < 10; i++) { Student student = new Student(); student.setName("wangfang"); student.setChinese(Math.random() * (93 - 91) + 91);//通过Math.random来生成随机成绩 student.setMath(Math.random() * (93 - 91) + 91); student.setEnglish(Math.random() * (93 - 91) + 91); student.setAge((int) (Math.random() * (20 - 18) + 18)); treeSet.add(student); } for(Student o:treeSet) { System.out.println(o+"-->"+o.getSum()); } } } //由于String类型的数据没有自然顺序,要运用自然排序Comparable,必须在定义的类中重写compareTo() class Student implements Comparable<Student> { private String name; private Integer age; private Double chinese; private Double math; private Double english; public Student() { } public Student(String name, Integer age, Double chinese, Double math, Double english) { this.name = name; this.age = age; this.chinese = chinese; this.math = math; this.english = english; } public String getName() { return name; } public void setName(String name) { this.name = name; } public Integer getAge() { return age; } public void setAge(Integer age) { this.age = age; } public Double getChinese() { return chinese; } public void setChinese(Double chinese) { this.chinese = chinese; } public Double getMath() { return math; } public void setMath(Double math) { this.math = math; } public Double getEnglish() { return english; } public void setEnglish(Double english) { this.english = english; } public Double getSum() { Double sum = chinese + math + english; return sum; } @Override public String toString() { return "Student{" + "name='" + name + '\'' + ", age=" + age + ", chinese=" + chinese + ", math=" + math + ", english=" + english + '}'; } @Override //+ 如果返回值为负数,表示当前存入的元素是较小值,存左边 //+ 如果返回值为0,表示当前存入的元素跟集合中元素重复了,不存 //+ 如果返回值为正数,表示当前存入的元素是较大值,存右边 public int compareTo(Student o) { int result = (int) (o.getSum() - this.getSum()); result = (result == 0) ? (int) (o.getChinese() - this.getChinese()) : result; result = (result == 0) ? (int) (o.getMath() - this.getMath()) : result; result = (result == 0) ? (int) (o.getEnglish() - this.getEnglish()) : result; result = (result == 0) ? (o.getName().compareTo(this.getName())) : result; return result; } }
五.Map接口
-
双列集合,一个键对应一个值
-
由于key的底层是红黑树
V put(K key,V value);//key(键)唯一,value(值)可以重复
viod putAll(Map<?extends K,? extends V> map);//加入一整个Map集合
V remove(key);//删除key,会返回V
void clear();//清空集合的所有元素
//Map遍历方法1
public class MapDemo01 {
public static void main(String[] args) {
//创建集合对象
Map<String, String> map = new HashMap<String, String>();//添加元素
map.put("001", "李华");
map.put("002", "王芳");
map.put("003", "赵素");//获取所有键的集合。用keySet()方法实现
Set<String> keySet = map.keySet();
//遍历键的集合,获取到每一个键。用增强for实现
for (String key : keySet) {
//根据键去找值。用get(Object key)方法实现
String value = map.get(key);
System.out.println(key + "," + value);
}
}
}
//Map遍历2
public class MapDemo02 {
public static void main(String[] args) {
//创建集合对象
Map<String, String> map = new HashMap<String, String>();//添加元素
map.put("001", "李华");
map.put("002", "王芳");
map.put("003", "赵素");//获取所有键值对对象的集合
Set<Map.Entry<String, String>> entrySet = map.entrySet();
//遍历键值对对象的集合,得到每一个键值对对象
for (Map.Entry<String, String> me : entrySet) {
//根据键值对对象获取键和值
String key = me.getKey();
String value = me.getValue();
System.out.println(key + "," + value);
}
}
}
1.HashMap
-
HashMap底层是哈希表结构的
-
依赖hashCode方法和equals方法保证键的唯一
-
如果键要存储的是自定义对象,需要重写hashCode和equals方法,下面通过一个例子来展示这条特性。
// 创建一个HashMap集合,键是学生对象(Student),值是居住地 (String)。存储多个元素,并遍历。
public class Student {
private String name;
private int age;public Student() {
}public Student(String name, int age) {
this.name = name;
this.age = age;
}public String getName() {
return name;
}public void setName(String name) {
this.name = name;
}public int getAge() {
return age;
}public void setAge(int age) {
this.age = age;
}@Override
public boolean equals(Object o) {//在类中重写equals方法,用于比较对象是否重复
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;Student student = (Student) o;
if (age != student.age) return false;
return name != null ? name.equals(student.name) : student.name == null;
}@Override
public int hashCode() { //重写hashCode
int result = name != null ? name.hashCode() : 0;
result = 31 * result + age;
return result;
}
}//测试类:
public class HashMapDemo {
public static void main(String[] args) {
//创建HashMap集合对象
HashMap<Student, String> hm = new HashMap<Student, String>();//创建学生对象
Student s1 = new Student("李华", 19);
Student s2 = new Student("赵四", 20);
Student s3 = new Student("李华", 19);
Student s4 = new Student("赵四", 18);//把学生添加到集合
hm.put(s1, "西安");
hm.put(s2, "武汉");
hm.put(s3, "郑州");
hm.put(s4, "北京");//遍历集合
Set<Student> keySet = hm.keySet();
for (Student key : keySet) {
String value = hm.get(key);
System.out.println(key.getName() + "," + key.getAge() + "," + value);
}
}
}
2.TreeMap
-
TreeMap底层是红黑树结构
-
依赖自然排序或者比较器排序,对键进行排序
-
如果键存储的是自定义对象,需要实现Comparable接口或者在创建TreeMap对象时候给出比较器排序规则(和之前的TreeSet类似,只不过对集合进行操作时多加一个键)