集合,什么是集合?
集合就是一个容器,容器无非就是用来装各种东西的!
注意:所有的集合的父类都是Collection(接口)
Collection:是集合的顶层接口,它的子体系有重复,有唯一的,有有序的,也有无序的。
- Collection
-
|--List
-
有序,可重复
-
|--Set
-
无序,唯一
- HashSet:不保证Set的迭代顺序,特别是它不保证该顺序恒久不变。
- 注意:虽然Set集合的元素是无序,但是作为集合来说,它肯定有它自己的存储顺序,
- 而你的顺序恰好和它存储顺序一致的是,这代表不了有序,你可以多存储一丢丢数据来试试。
- */
下面是Collection接口的功能:
-
1.添加功能:
-
boolean add(E e) 确保此集合包含指定的元素(可选操作)。 返回是boolean 即表示是否添加成功! boolean addAll(Collection<? extends E> c) 将指定集合中的所有元素添加到此集合(可选操作)。
2.删除功能:
void clear()
从此集合中删除所有元素(可选操作)。
boolean remove(Object o)
从该集合中删除指定元素的单个实例(如果存在)(可选操作)。
boolean removeAll(Collection<?> c)
删除指定集合中包含的所有此集合的元素(可选操作)。3.判断功能:
boolean contains(Object o)
如果此集合包含指定的元素,则返回 true 。
boolean containsAll(Collection<?> c)
如果此集合包含指定 集合中的所有元素,则返回true。
boolean isEmpty()
判断集合是否为空;4.获取功能(重点):
Iterator iterator()
返回此集合中的元素的迭代器。
boolean hasNext()
如果迭代具有更多元素,则返回 true 。 (意思就是是否还有下一个元素,如果有就是true)
E next()
返 一个元素。
举个小例子:
while(iterator.hasNext()){//如果有更多的元素就执行循环体
String next = iterator.next();
System.out.println(next);
}
//将while变成for
System.out.println("--------------");
for (Iterator it = c2.iterator();it.hasNext()? {
System.out.println(it.next());
}5.长度功能:
int size():元素的个数。 -
6.交集功能:
-
boolean retainAll(Collection<?> c) * 交集:相同的元素 * 假设有两个集合 A,B * A对B做交集,最终结果保存在A中,B不变 * 返回值是表示的是A是否发生过变化 *
7.把集合转换为数组
Object[] toArray()
返回一个包含此集合中所有元素的数组。
例子:
Object[] array = c3.toArray();
for (int i = 0; i < array.length; i++) {
System.out.println(array[i]);
}
//数组变集合
Collection asList = Arrays.asList(array);
题目(练习题):
用集合存储5个学生对象,并把学生对象进行遍历 ,用迭代器
解答:
很明显我们需要先写出一个实体类(学生类)
定义一个集合
讲学生类存储进集合中
利用迭代器进行遍历,输出!
ArrayList是Collection的实现类,我们就用它作为new的对象。
class Student{
private String name;
private int age;
public Student(){}
public Student(String name,int age){
this.name = name;
this.age =age;
}
public void setAge(int age) {
this.age = age;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public String getName() {
return name;
}
@Override
public String toString() {
// TODO Auto-generated method stub
return “name:”+name+",age:"+age;
}
}
public class IreratorTest {
public static void main(String[] args) {
// TODO Auto-generated method stub
Collection<Student> c = new ArrayList<>();
c.add(new Student("关羽",24));
c.add(new Student("张飞", 36));
c.add(new Student("赵云", 18));
c.add(new Student("黄忠", 60));
c.add(new Student("关羽",24));
Iterator<Student> iterator = c.iterator();
while(iterator.hasNext()){
System.out.println(iterator.next());
}
}
}
ArrayList也是List的子接口,所以ArrayList拥有Collection的方法
List(列表[集合])是也Collection子接口
List的特点:
有序(存进去的顺序等于取出的顺序) 可重复
例子:
public static void main(String[] args) {
List<String> list = new ArrayList<String>();
list.add("Java14");
list.add("马可波罗");
list.add("Java14");
list.add("NykoY");
//因为上面说过,List也是子接口,所以一样拥有父接口的方法
Iterator<String> iterator = list.iterator();
while(iterator.hasNext()){
String next = iterator.next();
System.out.println(next);
}
}
当然作为子类,拥有自己特有的功能是理所当然的(要不然还要这个子类干什么,直接使用父接口的方法就好了)
- List集合的特有功能:
- 1.添加功能
-
void add(int index, E element):在指定位置添加元素(插入,指定索引值插入)
- 2.获取功能
-
E get(int index):获取指定位置的元素
- 3.列表迭代
-
listIterator():List集合特有的迭代器
- 4.删除功能
-
E remove(int index):通过索引值去删除,返回被删除的元素
-
注意注意 : 返回的是被删除的元素
- 5.修改功能
-
E set(int index, E element):根据索引修改元素,返回的被修改的元素
- 6 . List集合的特有的遍历功能:
-
size()和get()方法结合去使用
- for(int i = 0;i<list.size();i++){
String string = list.get(i);
System.out.println(string);
}
以及增强for循环:
for(String str: list){ //String代表的是传入的是String类 str对象名:需要遍历的集合名
System.out.println(str);
}
例子:
public static void main(String[] args) {
// TODO Auto-generated method stub
List<String> list = new ArrayList<>();
list.add("老子");
list.add("庄子");
list.add("孙子");
list.add(1, "孔子"); //在该索引值位置插入一个元素
System.out.println(list);
String string = list.get(0); //获取该索引值的元素的内容
System.out.println(string);
System.out.println("---------");
ListIterator<String> listIterator = list.listIterator(); //迭代器
while(listIterator.hasNext()){
String next = listIterator.next();
System.out.println(next);
}
System.out.println("---------");
String remove = list.remove(1); //通过索引值去删除,返回被删除的元素 注意注意 : 返回的是被删除的元素
System.out.println(remove);
System.out.println("----------------");
String set = list.set(0, "鬼谷子");//根据索引修改元素,返回的被修改的元素
System.out.println(set);
}
上面我们讲了ArrayList是List的子接口,那么除此之外还有哪些呢?
- List的实现类:ArrayList、LinkedList 、Vector
- List的子类:
(1)子类的特点:
ArrayList:
底层数据结构是数组,查询快,增删慢。
线程不安全,效率高。
LinkedList:
底层数据结构是链表,查询慢,增删快。
线程不安全,效率高。
Vector:
底层数据结构是数组,查询快,增删慢。
线程安全,效率低。
要线程安全吗?
要:Vector(即使要线程安全,也不用这个了,后面有替代的)
不要:ArrayList或者LinkedList
查询多:ArrayList
增删多:LinkedList
练习:
将自定义对象作为元素存到ArrayList集合中,并去除重复元素。
比如:存人对象。同姓名同年龄,视为同一个人。为重复元素。
解答:既然是存人,当然是先创建一个人类
人类里面拥有年龄和姓名的属性
创建集合
如果是看对象是否包含在集合中,必须要重写对象中equals方法
遍历输出
例子:
class Person{
private String name;
private int age;
public Person() {
// TODO Auto-generated constructor stub
}
public Person(String name,int age){
this.age = age;
this.name = name;
}
public void setAge(int age) {
this.age = age;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public String getName() {
return name;
}
@Override
public String toString() {
// TODO Auto-generated method stub
return "姓名:"+name+",age:"+age;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + age;
result = prime * result + ((name == null) ? 0 : name.hashCode());
return result;
}
@Override
public boolean equals(Object obj) { //重写equals方法
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Person other = (Person) obj;
if (age != other.age)
return false;
if (name == null) {
if (other.name != null)
return false;
} else if (!name.equals(other.name))
return false;
return true;
}
}
public class ArrayListTest1 {
public static void main(String[] args) {
// TODO Auto-generated method stub
ArrayList<Person> list1 = new ArrayList<>();
list1.add(new Person("张三", 16));
list1.add(new Person("李四", 26));
list1.add(new Person("张三", 16));
list1.add(new Person("王五", 36));
System.out.println(list1);
/*
* 1.在创建一个集合list2,用来保存最后的数据(不重复)
* 2.遍历list1,看list2是否包含list1遍历出来的数据,如果不包含则添加到list2,如果包含就不添加
* */
ArrayList<Person> list2 = new ArrayList<>();
for (Person person : list1) { //遍历对象
if(!list2.contains(person)){//如果是看对象是否包含在集合中,必须要重写对象中equals方法
list2.add(person);
}
}
System.out.println(list2);
}
}
LinkedList的特有功能:
-
1.添加功能:
-
void addFirst(E e) 在该列表开头插入指定的元素。 void addLast(E e) 将指定的元素追加到此列表的末尾。 2.获取功能: E getFirst() 返回此列表中的第一个元素。 E getLast() 返回此列表中的最后一个元素。 3.删除功能: E removeFirst() 从此列表中删除并返回第一个元素
-
E removeLast() 从此列表中删除并返回最后一个元素。
- */
Vector的特有功能:
*
- 1.添加功能:
-
void addElement(E obj) --->add()
- 2.获取功能:
-
E elementAt(int index) --->get()
-
Enumeration<E> elements() ---->Iterator iterator()
-
boolean hasMoreElements() ---->hasNext()
-
E nextElement() ---->next()
- */
嵌套集合:
小例子:
一个班有一群学生,如果我们用集合来表示班级应该怎么写呢?ArrayList
-
但是呢,我们现在不仅仅只有一个班,而我却有一个学校。
-
ArrayList<ArrayList<Studnent>>
以上就是List集合的简述,接下来是Set
HashSet:不保证Set的迭代顺序,特别是它不保证该顺序恒久不变。
- 注意:虽然Set集合的元素是无序,但是作为集合来说,它肯定有它自己的存储顺序,
- 而你的顺序恰好和它存储顺序一致的是,这代表不了有序,你可以多存储一丢丢数据来试试。
跟上面 List一样,HashSet一样是Set的子接口
所以他也拥有Set的方法,而Set是Collection的子接口。
例子:
public static void main(String[] args) {
// TODO Auto-generated method stub
Set set = new HashSet<>();
set.add(“华盛顿”);
set.add(“林肯”);
set.add(“罗斯福”);
set.add(“肯尼迪”);
set.add(“小布什”);
set.add(“奥巴马”);
set.add(“特朗普”);
System.out.println(set);
Iterator<String> iterator = set.iterator();
while(iterator.hasNext()){
System.out.println(iterator.next());
}
System.out.println("-----------");
for (String string : set) {
System.out.println(string);
}
}
- HashSet:存储字符串并遍历
- HashSet为什么不能重复呢?
-
因为add()底层依赖了两个方法 一个 hashCode()和equals()
- 步骤:
-
首先比较哈希值
-
如果哈希值相同,继续走,走equals();
-
如果哈希值不同,添加到集合中
public static void main(String[] args) {
// TODO Auto-generated method stub
HashSet set = new HashSet<>();
set.add(“hello”);
set.add(“world”);
set.add(“java”);
System.out.println(set.add(“world”));//如果该字符串已经存在了,那么将不在添加
System.out.println(set);
}
LinkedHashSet:底层数据结构是由哈希表和链表组成( LinkedHashSet为HashSet的子接口)
- 哈希表 保证元素的唯一性
- 链表 保证元素的有序(存储和取出是一致的)
- 例子:
- public static void main(String[] args) {
// TODO Auto-generated method stub
LinkedHashSet hs = new LinkedHashSet();
hs.add(“华盛顿”);
hs.add(“林肯”);
hs.add(“罗斯福”);
hs.add(“肯尼迪”);
hs.add(“小布什”);
hs.add(“奥巴马”);
hs.add(“特朗普”);
hs.add(“肯尼迪”);
hs.add(“小布什”);
System.out.println(hs);
} - 小总结:HashSet存储的是无序的,唯一的元素。
- LinkedHashSet存储的是有序的,唯一的元素。这里所指的有序是存 取的顺序
除此之外,Set还有一个已实现的子接口,TreeSet
TreeSet集合的特点:排序和唯一 //注意,这里说的是排序
- TreeSet:能够对元素按照某种规则来进行排序
- 排序方式两种:
-
1.自然排序
-
2.比较器排序
先说第一种,自然排序,例子:
public static void main(String[] args) {
// TODO Auto-generated method stub
TreeSet<Integer> ts = new TreeSet<>();
ts.add(20);
ts.add(18);
ts.add(2;3);
ts.add(22);
ts.add(17);
ts.add(19);
ts.add(18);
ts.add(24);
ts.add(20);
System.out.println(ts);
}
输出结果为:
思考,为什么是排序是从小到大,而不是从大到小?
答案是因为Integer实现了Comparable中的ComparTo方法
所以我们得知
自然排序:
-
让元素所属的类实现自然排序接口Comparable
这样只有,才能知道怎么去实现自然排序!
那么接着说说比较排序:
比较排序:
-
让集合的构造方法接受一个比较器接口的实现类或者匿名内部类的形式 Comparator
- 这样才能够做出比较,然后排序!
- 例子:
- 键盘录入5个学生信息(姓名,语文成绩,数学成绩,英语成绩),按照总分从高到低输出
解答:
1.定义学生类
-
2.创建一个TreeSet集合
-
3.总分从高到低怎么做,如果总分相同又该怎么比较
-
4.键盘录入5个学生信息 (循环录入)
-
5.遍历TreeSet集合
public class Student1 {
private String name;
private int chinese;
private int math;
private int english;
public Student1() {
super();
}
public Student1(String name, int chinese, int math, int english) {
super();
this.name = name;
this.chinese = chinese;
this.math = math;
this.english = english;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getChinese() {
return chinese;
}
public void setChinese(int chinese) {
this.chinese = chinese;
}
public int getMath() {
return math;
}
public void setMath(int math) {
this.math = math;
}
public int getEnglish() {
return english;
}
public void setEnglish(int english) {
this.english = english;
}
@Override
public String toString() {
return "Student1 [name=" + name + ", chinese=" + chinese + ", math=" + math + ", english=" + english + "]";
}
//计算总成绩的方法
public int getSum(){
return chinese+math+english;
}
}
public class TreeSetTest1 {
public static void main(String[] args) {
// TODO Auto-generated method stub
TreeSet<Student1> ts = new TreeSet<>(new Comparator<Student1>() { //匿名内部类实现该接口的compare方法
@Override
public int compare(Student1 o1, Student1 o2) {
// TODO Auto-generated method stub
//总分从高到低
int num = o2.getSum()-o1.getSum();
int num2 = num==0?o1.getChinese()-o2.getChinese():num;
int num3 = num2==0?o1.getMath()-o2.getMath():num2;
int num4 = num3==0?o1.getEnglish()-o2.getEnglish():num3;
int num5 = num4==0?o1.getName().compareTo(o2.getName()):num4;
return num5;
}
});
for (int i = 0; i <5; i++) {
Scanner sc = new Scanner(System.in);
System.out.println("请输入学生名字:");
String name = sc.nextLine();
System.out.println("请输入语文成绩:");
int chinese = Integer.parseInt(sc.nextLine());
System.out.println("请输入数学成绩:");
int math = Integer.parseInt(sc.nextLine());
System.out.println("请输入英语成绩:");
int english = Integer.parseInt(sc.nextLine());
Student1 stu1 = new Student1(name, chinese, math, english);
ts.add(stu1);
}
System.out.println("学生信息录入完毕");
for (Student1 student1 : ts) {
System.out.println(student1);
}
}
}
总结:
集合的顶级接口父类Collection
Collection的遍历使用迭代器来遍历,List可以结合get和size方法
Collection的子接口List以及Set
List的子接口又有ArrayList以及LinkedList和Vector,他们的特点分别是
ArrayList:
底层数据结构是数组,查询快,增删慢。
线程不安全,效率高。
LinkedList:
底层数据结构是链表,查询慢,增删快。
线程不安全,效率高。
Vector:
底层数据结构是数组,查询快,增删慢。
线程安全,效率低。
要线程安全吗?
要:Vector(即使要线程安全,也不用这个了,后面有替代的)
不要:ArrayList或者LinkedList
查询多:ArrayList
增删多:LinkedList
List存储的元素是有序的,重复的。
用List(多数是用ArrayList)来实现剔除重复对象,先遍历对象,然后使用contains方法判断是否存在了
boolean contains(Object o)
如果此集合包含指定的元素,则返回 true 。
注意,ArrayList的底层是数组,需要实现equals的方法重写才能实现查看该对象是否已经在集合中
Set存储的元素是无序的,唯一的。
Set的两个子接口,HashSet和TreeSet,HashSet存储的是无序的,唯一的元素。
TreeSet集合的特点:排序和唯一
排序方式两种: 1.自然排序,2.比较器排序
HashSet还有一个子接口那就是LinkedHashSet
LinkedHashSet存储的是有序的,唯一的元素。这里所指的有序是存 取的顺序
如果使用TreeSet进行存储,那么需要实现接口。
自然排序:
-
让元素所属的类实现自然排序接口Comparable
这样只有,才能知道怎么去实现自然排序!
那么接着说说比较排序:
比较排序:
-
让集合的构造方法接受一个比较器接口的实现类或者匿名内部类的形式 Comparator
- 这样才能够做出比较,然后排序!
如果想要存储重复的(或者唯一的也可以),有序的就使用List
如果想要存储唯一的,(有序的也可以)或者无序就使用Set