文章目录
前言
·集合可以看作一个没有容量限制的数组。集合还可添加各样任意类型的元素。并且集合中的每个对象,既容易从中取出,也容易将其存放到集合中,还能按照一定顺序进行摆放。Java提供不同的集合类,这些集合类具有不同的存储对象的方法;同时都提供了相应的方法对集合进行遍历、添加、删除和查找指定的对象。集合是java的必学点。
一、Collection接口与List、Set集合是什么关系?
首先,集合类Collection接口,List集合、Set集合,都处于 java.util包中,在使用集合时一定要导入java.util包。
List集合、Set集合是Collection接口的具体实现(implements)类,这两个集合类实现Collection接口(是Set接口和List接口将图中的关系联系在一起),可以调用Collection接口中所有方法。
补充(数组与集合的区别):
(1)数组的长度是固定的,集合的长度是可变的。
(2)数组用来存放基本数据的数据,集合用来存放对象的引用;
二、Collection接口
Collection接口通常不会直接使用(因为有更加完备的子集合Set类、List类、Map类),但该接口提供了添加、删除、管理数据的方法,当然这些方法都可以被List,Set集合类使用。
方法 | 功能描述 |
add(Object o) | 将指定的对象添加到该集合中 |
remove(Object o) | 将指定的对象从该集合中移除 |
isEmpty() | 返回boolean值,用于判断当前集合是否为空 |
iterator() | 返回集合类的元素,进行迭代的迭代器,用于遍历集合中的对象 |
size() | 返回int值,获取该集合中元素的个数 |
实操:
import java.util.*;
public class Demo{
public static void main(String args[]){
//创建集合类对象
Collection<String> list = new ArrayList<>(); //设置泛型类型为String
list.add("a"); //向集合添加元素"a"
list.remove(0); //将在存储位置为0的元素从集合中移除
if(list.isEmpty()){ //判断该集合是否为空集合
Iterator it = list.iterator(); //创建该集合的迭代器对象
while(it.hasNext()){ //判断迭代器中的数据是否还有下一个值
System.out.println(it.next()); //遍历该集合的所有元素
}
}else{
Syetem.out.println(list.size()); //获取并输出该集合的长度
}
}
}
注:以上方法均可被 List集合、Set集合、Map集合调用。
1.List集合
List集合包括List接口以及List接口的所有实现类。List集合中的元素允许重复,可保存null值各元素的顺序就是对象插入的顺序。我们可以通过索引(元素在集合中的位置int值)来访问集合中的元素。
List接口继承了Collection接口,具有Collection接口的所有方法,同时自身还有额外的方法。
方法 | 功能描述 |
get(int index) | 获得指定索引位置的元素 |
set(int index,Object obj) | 将集合中指定索引位置的原对象修改为指定对象 |
List<String> list = new ArrayList<>();
list.add("a");
list.add("c");
System.out.println(list.get(1)); //获取集合对应指针位置的元素
list.set(1, "b"); //更改对应指针位置的元素内容(只能更改目前集合已有范围的元素),不然会报错
List接口的实现类: ArrayList 与 LinkedList
使用List集合时通常声明为List类型,可通过不同的实现类来实例化集合
ArrayList类:动态数组(最大容量动态变化),允许保存所有元素,包括 null值,可以保存相同元素。优势在于随机访问集合中的对象。
声明方式:
List<E> list = new ArrayList<>();
//声明ArrayList对象
实操:
public class Demo{
public static void main(String args[]){
List<String> list = new ArrayList<>();
list.add(null); //可以添加null值
list.add(null); //可以添加相同的值
list.add("666");
int i =(int)(Math.random()*list.size());
System.out.println("随机获取动态数组中的元素为"+i); //对集合进行快速的随机访问
}
}
--------------------------------------------------------------------------------------------------------------------------------
LinkedList类:链表,允许保存所有元素,包括 null值,可以保存相同元素。优势在于向集合中插入或删除对象时更加高效。
声明方式:
List<E> list = new LinkedArray<>();
//声明一个list链表对象
实操:
public class Demo{
public static void main(String args[]){
List<String> list = new Linkedlist<>();
list.add(null); //可以添加null值
list.add(null); //可以添加相同的值
list.add("666");
int i =(int)(Math.random()*list.size());
list.remove(i); //向集合中插入或删除对象效率更高一些
}
}
2.Set集合
Set集合只是简单地把对象添加到集合中,之后有比较器判断大小排序,没有比较器,则从小到大自然排序,Set集合不能包含重复的对象。Set集合由Set接口和其实现类(TreeSet类和HashSet)组成。
Set接口的实现类:TreeSet 和 HashSet
TreeSet类:不能保存null值。该类实现了Set接口,还实现了java.util.SortedSet接口。因此,可以通过比较器对用TreeSet类实现的Set对象进行排序,可以存储null值,同时自身会有额外的方法。
当创建一个TreeSet集合时,可以通过构造函数传入一个Comparator对象,该Comparator对象定义了元素的比较规则。在添加元素时,TreeSet会根据Comparator来确定元素的插入位置,保证集合中的元素始终按照指定的比较规则排序。
方法 | 功能描述 |
first() | 返回此Set中当前第一个(最小)元素 |
last() | 返回此Set中当前最后一个(最大)元素 |
comparator() | 返回对此Set中的元素进行排序的比较器,比较器排序位置。如果此Set为自然排序,返回值为null |
headSet(E toElement) | 返回一个新的Set集合,新集合是toElement(不包含自身)对象之前的所有对象(原集合的子集) |
subSet(E formElement,E toElement) | 返回一个新的Set集合,新集合是从fromElement(包含自身)到toElement(不包含自身)的所有对象(原集合的子集) |
tailSet(E fromElement) | 返回一个新的Set集合,新集合是包含对象fromElement(包含自身)之后的所有对象(原集合的子集) |
实操:
first()和last()
import java.util.TreeSet;
public class Main {
public static void main(String[] args) {
TreeSet<Integer> treeSet = new TreeSet<>();
treeSet.add(10);
treeSet.add(5);
treeSet.add(20);
// 获取TreeSet中的最第一个的元素
System.out.println("TreeSet中的第一个元素是: " + treeSet.first());
// 获取TreeSet中的最最后一个的元素
System.out.println("TreeSet中的最后一个元素是: " + treeSet.last());
}
}
未设置比较器,treeSet集合由小到大自然排序,第一个元素是5,最后一个元素是20
comparator()
import java.util.Comparator;
import java.util.TreeSet;
public class Main {
public static void main(String[] args) {
// 创建一个使用自定义比较器的TreeSet
TreeSet<String> treeSet = new TreeSet<>(Comparator.reverseOrder());
// 排序方式设置为降序排序
treeSet.add("apple");
treeSet.add("banana");
treeSet.add("orange");
// 获取TreeSet使用的比较器
Comparator<String> setComparator = treeSet.comparator();
if (setComparator == null) {
System.out.println("TreeSet使用自然排序");
} else {
System.out.println("TreeSet使用自定义比较器:" + setComparator);
}
}
}
TreeSet元素自定义排序方法:除了创建Comparator对象,在创建TreeSet对象时调用Comparator对象,实现对已有元素的自定义排序,还可以通过元素类实现Comparable接口,实现接口中的compareTo(Object o) 方法,比较此对象与指定对象的顺序,如果该对象小于、等于或大于指定对象,则分别返回负整数、0或正整数。
创建两个类,TreeSetDemo类和InnerPerson类,TreeDemo类向Set添加对象时,Set中所有的对象排序按照InnerPerson(实现了Comparable)类中compareTo(Object o)方法进行排序。
import java.util.*;
public class TreeSetDemo {
public static void main(String[] args) {
Set a = new TreeSet<>();
InnerPerson p1 = new InnerPerson(1, "阿琛", 32);
InnerPerson p2 = new InnerPerson(2, "阿明", 42);
InnerPerson p3 = new InnerPerson(3, "阿发", 33);
a.add(p1);
a.add(p2);
a.add(p3);
// TreeSet集合不能添加 null值
}
}
@SuppressWarnings("rawtypes")
class InnerPerson implements Comparable{
//定义人的属性
int id;
String name;
int age;
public InnerPerson(int id,String name,int age){
super();
this.id = id;
this.name = name;
this.age = age;
}
public String toString(){
return "Person [id="+id+", age="+age+", name="+name+"]";
}
public int compareTo(Object o){
InnerPerson p;
if(o instanceof InnerPerson){
p = (InnerPerson)o;
}else{
return -1;
}
int diff = this.id - p.id;
if(diff!=0){
diff = diff/Math.abs(diff);
}
return diff;
}
}
代码说明:此compareTo()方法将TreeSet中的元素排序顺序设置为了id排序,
当调用`compareTo()`方法时,传入元素(Object o)之间的比较结果会返回以下三种情况:
1. 负数:表示当前元素应该排在传入元素的前面。换句话说,当前元素在排序中应该位于传入元素之前。
2. 0:表示当前元素和传入元素是相等的,在排序中它们的顺序可以是任意的。
3. 正数:表示当前元素应该排在传入元素的后面。换句话说,当前元素在排序中应该位于传入元素之后。
这意味着,如果一个元素的`compareTo()`方法返回一个负数,那么它会被排序到前面;如果返回0,那么它可以和其他相等的元素的顺序任意;如果返回正数,那么它会被排序到后面。
subSet(E formElement,E toElement)
import java.util.TreeSet;
public class Tree {
public static void main(String[] args) {
TreeSet<Integer> treeSet = new TreeSet<>();
treeSet.add(10);
treeSet.add(20);
treeSet.add(30);
treeSet.add(40);
treeSet.add(50);
// 使用subSet方法获取子集视图
TreeSet<Integer> subSet = (TreeSet<Integer>) treeSet.subSet(20, 40);
// 遍历并输出子集视图中的元素
for (Integer element : subSet) {
System.out.println(element);
}
}
}
treeSet.sub(20,40); 获取一个新的子集合,对象个数从20(包含自身)到40(不包含自身)
HashSet类:
HashSet类,由哈希表支持,允许保存一个null值,它不能保证Set的迭代顺序,特别不能保证所有元素的排列顺序保持不变,使用HashSet类,需要覆写hashCode()和equals(Object o)方法,以确保对象的相等判断是正确的。
import java.util.*;
public class HashSetDemo {
public static void main(String[] args) {
Set set = new HashSet<>();
Person a = new Person(1,"小明");
Person b = new Person(2,"小强");
Person c = new Person(3,"小乐");
set.add(null);//HashSet集合可以添加null值
set.add(a);
set.add(b);
set.add(c);
Iterator iterator = set.iterator();
while (iterator.hasNext()) {
System.out.println(iterator.next());
}
}
}
/*HashSet存放数据的三种情况
1.向集合空哈希地址直接插入新对象
2.集合不会保存相同的对象(通过与equals方法对比原储存元素object哈希值是否相同)
3.同一个哈希值,可以存放多个不同的对象(例如在存入第二个相同哈希值对象前,更改第一个已存入该存储位置的对象的哈希值)
*/
class Person{
int id;
String name;
public Person (int id, String name){
super();
this.id=id;
this.name = name;
}
public String toString(){
return "Person [id="+id+", name="+name+"]";
}
public int hashCode(){ //返回值result为每个元素在equals方法中对比是否相同的关键值
final int prime = 31;
int result = 1;
result = prime*result+id;
return result;
}
public boolean equals(Object obj){ //对应哈希地址的储存元素(this)与obj新元素的对比HashCode返回数据是否为同一对象,返回true值不保存obj,返回false值在相同的哈希地址下保存这两个对象()
if(this == obj){
return true;
}else if(obj == null){
return false;
}
Person other = (Person)obj;
if(id!=other.id){
return false;
}
return true;
}
}
覆写hasCode()的原因:
- 相等的对象应该具有相等的哈希码。
- 尽可能地将不相等的对象映射到不同的哈希码,以提高哈希表的效率。
- 添加的对象,与该位置已有的对象(或者null值),通过equals()方法对比HashCode值,不同返回false,则保存在该集合的hashCode位置上。
总结
以上就是关于集合的部分内容,本文仅仅简单介绍了Collection接口与List、Set集合的使用,集合是我们学习java的必须掌握的内容。