集合一:Collection接口下的所有集合
集合和数组的区别:
- 数组特点:大小固定,只能存储相同数据类型的数据
- 集合特点:大小可动态扩展,可以存储各种类型的数据,但只能是引用数据类型
Iterator接口被Collection接口继承, Collection的集合分别被List和set接口继承。
List接口和Set接口的区别:
-
有序性: List保证按照插入顺序排序 ,Set 存储和取出的顺序不一致
-
唯一性:List可重复,Set元素唯一
-
获取元素:List可根据索引获取,Set无法根据索引获取
其实,有序或无序是指是否按照其添加的顺序来存储对象。List 是按照元素的添加顺序来存储的。而 Set 的实现类都有一套自己的排序算法,每添加一个元素,都会按照其内部算法将元素添加到合适的位置,所以不能保证内部存储是按元素添加的顺序而存储的。
List接口(有序且参数可重复)
List接口主要被:ArrayList、LinkedList、Vector类实现
(1)ArrayList:底层数据结构是数组,查询快,增删慢,线程不安全,效率高,可以存储重复元素
(2)LinkedList: 底层数据结构是链表,查询慢,增删快,线程不安全,效率高,可以存储重复元素
(3)Vector:底层数据结构是数组,查询快,增删慢,线程安全,效率低,可以存储重复元素
List集合常用的方法:
1、add(Object element): 向列表的尾部添加指定的元素。
2、size(): 返回列表中的元素个数。
3、get(int index): 返回列表中指定位置的元素,index从0开始。
4、add(int index, Object element): 在列表的指定位置插入指定元素。
5、set(int i, Object element): 将索引i位置元素替换为元素element并返回被替换的元素。
6、clear(): 从列表中移除所有元素。
7、isEmpty(): 判断列表是否为空,不包含元素则返回 true,否则返回false。
8、contains(Object o): 如果列表包含指定的元素,则返回 true。
9、remove(int index): 移除列表中指定位置的元素,并返回被删元素。
10、remove(Object o): 移除集合中第一次出现的指定元素,移除成功返回true,否则返回false。
11、iterator(): 返回按适当顺序在列表的元素上进行迭代的迭代器。
12、toArray(); 将集合转换成数组
13、subList(int, int) 获取集合中某个范围的元素 //subList(0, 2)前2个元素
14、lastIndexOf(object obj)获取集合中某个元素最后一次出现的索引
Set接口(无序且参数不可重复)
Set接口主要被HashSet、LinkedHashSet、TreeSet实现。
(1)HashSet:底层是哈希表实现的,存储顺序无序。可过滤重复的数据(需要在引用类型中重写hashCode和equals方法)。
(2)LinkedHashSet:底层哈希表加双向链表实现的,存储顺序有序。可过滤重复的数据(需要在引用类型中重写hashCode和equals方法)。
(3)TreeSet(自定义类型排序):数据结构采用二叉树来实现,元素唯一且已经排好序。自定义排序:具体实现看下面实现。
Person类:
public class Person {
private String name;
private int age;
private String version;
public Person(String name, int age,String version) {
this.name = name;
this.age = age;
this.version=version;
}
//去参数重复时要重写hashCode和equals
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof Person)) return false;
Person person = (Person) o;
return getAge() == person.getAge() &&
Objects.equals(getName(), person.getName());
}
@Override
public int hashCode() {
return Objects.hash(getName(), getAge(),getVersion());
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", age=" + age +
", version='" + version + '\'' +
'}';
}
}
(1)HashSet底层数据结构采用哈希表实现,元素无序且唯一,线程不安全,效率高,可以存储null元素,元素的唯一性是靠所存储元素类型是否重写hashCode()和equals()方法来保证的,如果没有重写这两个方法,则无法保证元素的唯一性。
//HashSet重写 hashCode和equals去重,他的存储是无序的
HashSet<Object> i = new HashSet<>();
i.add(new Person("小明",11,"0.0.1"));
i.add(new Person("小明",12,"0.0.1"));
i.add(new Person("小凯",11,"0.0.1"));
i.add(new Person("小明",11,"0.0.1"));
i.add(new Person("小明",11,"0.0.4"));
for (Object o:i){
System.out.println(o);
}
//输出:
// Person{name='小明', age=12, version='0.0.1'}
// Person{name='小明', age=11, version='0.0.4'}
// Person{name='小明', age=11, version='0.0.1'}
// Person{name='小凯', age=11, version='0.0.1'}
(2)LinkedHashSet底层数据结构采用链表和哈希表共同实现,链表保证了元素的顺序与存储顺序一致,哈希表保证了元素的唯一性。线程不安全,效率高。(比HashSet多了个保证存储顺序)
//LinkedHashSet重写hashCode去重复,并且存储顺序是有序的
LinkedHashSet<Object> linkedHashSet = new LinkedHashSet<>();
linkedHashSet.add(new Person("小明",11,"0.0.1"));
linkedHashSet.add(new Person("小凯",11,"0.0.1"));
linkedHashSet.add(new Person("小明",12,"0.0.1"));
linkedHashSet.add(new Person("小明",11,"0.0.4"));
linkedHashSet.add(new Person("小明",11,"0.0.1"));
linkedHashSet.add("dsaf4");
for (Object o:linkedHashSet){
System.out.println(o);
}
//输出:
// Person{name='小明', age=11, version='0.0.1'}
//Person{name='小凯', age=11, version='0.0.1'}
//Person{name='小明', age=12, version='0.0.1'}
//Person{name='小明', age=11, version='0.0.4'}
//dsaf4
(3)TreeSet底层数据结构采用二叉树来实现,元素唯一且已经排好序;唯一性同样需要重写hashCode和equals()方法,二叉树结构保证了元素的有序性。根据构造方法不同,分为自然排序(无参构造)和比较器排序(有参构造);
-
自然排序要求元素必须实现Compareable接口,并重写里面的compareTo()方法,元素通过比较返回的int值来判断排序序列, 返回0说明两个对象相同,不需要存储;
-
比较器排需要在TreeSet初始化是时候传入一个实现Comparator接口的比较器对象,或者采用匿名内部类的方式new一个Comparator对象,重写里面的compare()方法;
1.自然排序
public class Person {
//需要在引用类型的数据中实现Compareable接口的compareTo(),实现排序
private String name;
private int age;
private String version;
public Person(String name, int age,String version) {
this.name = name;
this.age = age;
this.version=version;
}
//实现参数去重复
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof Person)) return false;
Person person = (Person) o;
return getAge() == person.getAge() &&
Objects.equals(getName(), person.getName());
}
@Override
public int hashCode() {
return Objects.hash(getName(), getAge(),getVersion());
}
//自然排序(根据年龄重小到大排序)
@Override
public int compareTo(Person o) {
//注意:Age重复情况下会数据会被过滤掉,参数比较是age
return this.age-o.getAge();
}
}
自然排序实现:
Set<Person> treeSet = new TreeSet<>();
treeSet.add( new Person("张三", 12,"1.2.9.10"));
treeSet.add(new Person("小孩", 14,"9.0"));
treeSet.add(new Person("李四",18,"2.7.9.20"));
treeSet.add(new Person("王五", 11,"9.0"));
treeSet.add(new Person("小五", 11,"10.0"));
for (Person p:treeSet){
System.out.println(p);
}
//输出:因为age值排序中去重了,所以Person类小五被认为是重复的,不存入了集合
//Person{name='王五', age=11, version='9.0'}
//Person{name='张三', age=12, version='1.2.9.10'}
//Person{name='小孩', age=14, version='9.0'}
//Person{name='李四', age=18, version='2.7.9.20'}
2.比较器排序
方法一:使用匿名内部类
Set<Person> treeSet = new TreeSet<>(new Comparator<Person>() {
@Override
public int compare(Person o1, Person o2) {
Person s1= (Person) o1;
Person s2= (Person) o2;
//现根据Version比较,version相等时在根据age比较
int num2 = s1.getVersion().compareTo(s2.getVersion()) ;
// 次要条件 内容比较
int num3 = num2 == 0 ? s1.getAge() - s2.getAge() : num2;
return num3;
}
});
treeSet.add( new Person("张三", 12,"1.2.9.10"));
treeSet.add(new Person("小孩", 14,"9.0"));
treeSet.add(new Person("李四",18,"2.7.9.20"));
treeSet.add(new Person("王五", 11,"9.0"));
for (Person p:treeSet){
System.out.println(p);
}
//输出:
// Person{name='张三', age=12, version='1.2.9.10'}
// Person{name='李四', age=18, version='2.7.9.20'}
// Person{name='王五', age=11, version='9.0'}
// Person{name='小孩', age=14, version='9.0'}
方法二:使用TreeSet的有参构造方法实现,传入实现Comparator接口compare方法的类
MycompareTo 实现 Comparator
public class MycompareTo implements Comparator {
@Override
public int compare(Object o1, Object o2) {
Person s1= (Person) o1;
Person s2= (Person) o2;
if(s1.getVersion().compareTo(s2.getVersion()) >0){
return 1;
}else if (s1.getVersion().compareTo(s2.getVersion()) ==0){
return s1.getAge() - s2.getAge();
}else {
return -1;
}
}
}
实现treeSet集合自定义排序:
Set<Person> treeSet = new TreeSet<>(new MycompareTo());
treeSet.add( new Person("张三", 12,"1.2.9.10"));
treeSet.add(new Person("小孩", 14,"9.0"));
treeSet.add(new Person("李四",18,"2.7.9.20"));
treeSet.add(new Person("王五", 11,"9.0"));
for (Person p:treeSet){
System.out.println(p);
}