荐 Java语言基础之Collection接口、List集合、Set集合的基本使用
集合类概述
java.util包下提供了一些集合类,这些集合又被称为容器。提到容器不难想到数组,集合类与数组的不同之处就是,数组的长度是固定的,而集合的长度是可变的,集合不能直接存储基本数据类型,另外集合也不能直接存储java对象,集合当中存储的都是对象的内存地址(或者说集合中存储的是对象的引用)。常见的有List集合、Set集合、Map集合,其中List和Set继承了Collection接口,各接口还提供了不同的实现类。
为什么说集合在开发中使用较多?
集合是一个容器,是一个载体,可以一次容纳多个对象。在实际开发中,假设连接数据库,数据库当中有10条记录,那么假设把这10条记录查询出来,在java程序中会将10条数据封装成10个java对象,然后将10个java对象放到某一个集合当中,将集合传到前端,然后遍历集合,将一个数据一个数据展现出来。
集合框架结构
Collection接口
Collection接口是层次结构中的根接口。构成Collection的单元称为元素,Collection接口通常不能被直接使用,但该接口提供了添加元素、删除元素、管理数据的方法。由于List集合和Set集合都继承了Collection接口,因此这些方法对List集合和Set集合是通用的。
import java.util.*;
public class CollectionDemo {
public static void main(String[] args) {
//创建实例化集合类对象
Collection<String> list = new ArrayList<String>();
//添加数据
list.add("zhangsan");
list.add("lisi");
list.add("wangwu");
System.out.println(list);
}
}
Collection接口的常用方法摘要
①添加:
boolean add(E e):添加一个元素
boolean addAll(Collection c):添加一堆元素
②删除:
void clear():清空容器
boolean remove(Objec obj): 删除集合中的某个元素
③判断:
boolean contains(Object obj):判断是否包含此元素
boolean equals(Object object):比较与指定对象是否相等
boolean isEmpty():判断集合是否为空
④获取:
Iterator iterator():取出
int hashCode():返回此collection的哈希值
int size():返回此collection中元素的个数
代码演示
public class CollectionDemo2 {
public static void main(String[] args){
//创建一个集合容器,使用Collection的子类ArrayList
ArrayList<String> al = new ArrayList<String>();
//添加元素
al.add("zhangsan");
al.add("lisi");
al.add("wangwu");
al.add("zhaoliu");
//打印原集合
System.out.println(al);
//删除元素
al.remove("lisi");
//打印删除元素后的集合
System.out.println(al);
//清空集合
al.clear();
//获取集合长度
System.out.println("size = "+al.size());
//判断元素是否存在集合中
System.out.println("wangwu是否存在?"+al.contains("wangwu"));
//判断集合是否为空
System.out.println("集合是否为空?"+al.isEmpty());
}
}
迭代器Iterator
迭代器其实就是集合取出元素的方式。
迭代器中的方法摘要:
boolean hasNext():如果集合中还有元素可以迭代,那么返回true
Object next():返回迭代的下一个元素
void remove():从迭代器指向的Collection中移除迭代器返回的最后一个元素
因此可以把取出方式定义在集合内部,这样取出方式就可以直接访问集合中的元素。那么取出方式就被定义成了内部类。而每一个容器的数据结构都不同,所以取出的动作细节也不同,但是都有共性内容判断和取出。那么可以将这些共性进行抽取。这些共性都符合一个规则,该规则是Iterator。
如何获取集合的取出对象呢?
可以通过一个对外的方法iterator();
public class IteratorDemo {
public static void main(Stringp[] args) {
ArrayList<String> al = new ArrayList<String>();
al.add("zhangsan");
al.add("lisi");
al.add("wangwu");
al.add("zhaoliu");
//获取迭代器,用于取出集合中的元素
Iterator it = al.iterator();
while(it.hasNext()){
System.out.println(it.next());
}
}
}
List集合
List集合中的元素有序可重复。这里的有序是指存取的顺序有序。
List集合的特有方法
①增加:
add(int index, Object element):在指定索引处添加元素
②删除:
remove(int index):删除指定索引的元素
③查询:
get(int index):获取指定索引处的元素
subList(int from, int to):截取指定位置到指定位置的元素
listIterator():取出集合中的所有元素
④修改:
set(int index, Object element):修改指定索引处的元素
代码演示
public class ArrayListDemo {
public static void main(String[] args) {
ArrayList<String> al = new ArrayList<String>();
al.add("java01");
al.add("java02");
al.add("java03");
al.add("java04");
//在指定位置添加元素
al.add(1,"java05");
//删除指定位置的元素
al.remove(3);
//修改指定位置的元素
al.set(4, "java09");
//通过角标获取元素
System.out.println(("get(1)="+al.get(1)));
//获取所有元素
for(int x=0; x<al.size(); x++) {
System.out.println("al("+x+") = "+al.get(x));
}
}
}
List集合特有的迭代器
listInterator是Interator的子接口。在迭代时,不可以通过集合对象的方法操作集合中的元素,因为会发生异常。所以在迭代器时,只能通过迭代器的方法来操作元素,但是Interator方法有限,只能对元素判断、取出和删除的操作,如果想要其他操作如添加,修改等,就需要使用其子类ListInterator。该接口只能通过List集合的listInterator方法获取。
import java.util.*;
public class ListIteratorDemo {
public static void main(String[] args) {
ArrayList<String> al = new ArrayList<String>();
al.add("java01");
al.add("java02");
al.add("java03");
ListIterator<String> li = al.listIterator();
while(li.hasNext()) {
Object obj = li.next();
if(obj.equals("java02")) {
li.set("java06");
}
}
System.out.println(al);
}
}
注意:在迭代时,不能对集合中的元素同时进行添加、修改、删除操作,会发生异常。
ArrayList集合的注意事项
当往ArrayList里面存入元素要求不重复时,比如存入学生对象,当同名同岁时,视为同一个人,则不往里面存储。
所以在定义学生对象时,需重写Object类中的equals方法,因为Object类中的equals方法默认是比较两个对象的地址值是否相同,而我们的需求是同名同岁才是同一个对象,所以要重写equals方法里面的比较内容。
public boolean equals(Object obj) {
if(!(obj instanceof Student))
return false;
Student stu = (Student)obj;
return this.name.equals(stu.name) && this.age == stu.age;
}
则往ArrayList集合通过add存入学生对象时,集合底层自己会调用Student类的equals方法,判断重复学生则不存入。
注:对于List集合,无论是add、contains、还是remove方法,判断元素是否相同,都是通过重写equals方法来判断!
练习:去除ArrayList集合中的重复元素。
思路:定义一个方法,将原来的集合作为参数传入,在方法体中通过迭代器,判断新集合中是否包含该元素。如果不包含则添加,反之则相反,最后将新集合返回。
import java.util.*;
public class ArrayListTest {
public static void main(String[] args) {
ArrayList<String> a = new ArrayList<String>();
a.add("zhangsan"); //add(Object obj);
a.add("lisi");
a.add("wangwu");
a.add("zhangsan");
a.add("wangwu");
System.out.println("删除重复元素前:"+a);
a = singleElement(a);
System.out.println("删除重复元素后:"+a);
}
public static ArrayList<String> singleElement(ArrayList<String> al) {
//创建一个新的容器 将不重复元素存入
ArrayList<String> newal = new ArrayList<String>();
Iterator<String> it = al.iterator();
while(it.hasNext()) {
Object obj = it.next();
if(!newal.contains(obj))
newal.add((String)obj);
}
return newal;
}
}
LinkedList集合
(1)LinkLedist的特有方法:
①增加:
addFirst():在链表的开头插入指定的元素。
addLast():在链表末尾插入指定的元素。
②删除:
removeFirst():删除链表的第一个元素
removeLast():删除链表的最后一个元素(获取元素也删除元素)
③查询:
getFirst():获取链表的第一个元素
getLast():获取链表的最后一个元素(获取元素但不删除元素)
代码演示
public class LinkedListDemo {
public static void main(String[] args) {
LinkedList<String> link = new LinkedList<String>();
link.addFirst("java01");
link.addFirst("java02");
link.addFirst("java03");
link.addFirst("java04");
System.out.println(link.getFirst());
System.out.println(link.getLast());
//System.out.println(link.removeFirst());
//System.out.println(link.removeLast());
System.out.println(link.size()); //获取链表的长度
while(!(link.isEmpty())) {
System.out.println(link.removeLast());
}
}
}
练习:用LinkedList模拟堆栈和队列。
堆栈:先进后出,队列:先进先出
import java.util.*;
public class LinkedListTest{
public static void main(String[] args) {
Stack s = new Stack(); //堆栈
s.Myadd("java01");
s.Myadd("java02");
s.Myadd("java03");
s.Myadd("java04");
System.out.println("Stack:"+s.Mysize());
while(!(s.MyisEmpty())){
System.out.println(s.Myget());
}
Queue q = new Queue(); //队列
q.Myadd("java01");
q.Myadd("java02");
q.Myadd("java03");
q.Myadd("java04");
System.out.println("Queue:"+q.Mysize());
while(!(q.MyisEmpty())){}
System.out.println(q.Myget());
}
}
}
class Stack { //模拟堆栈
private LinkedList<String> li;
Stack() {
li = new LinkedList<String>();
}
public void Myadd(String str) {
li.addFirst(str);
}
public String Myget() {
return li.removeFirst();
}
public int Mysize() {
return li.size();
}
public boolean MyisEmpty() {
return li.isEmpty();
}
}
class Queue { //模拟队列
private LinkedList<String> link;
Queue() {
link = new LinkedList<String>();
}
public void Myadd(String str) {
link.addFirst(str);
}
public String Myget() {
return link.removeLast();
}
public int Mysize() {
return link.size();
}
public boolean MyisEmpty() {
return link.isEmpty();
}
}
Vector集合
枚举是Vector特有的取出方式,枚举和迭代都是取出元素的方式,都一样。
因为枚举的名称和方法的名称都过长,所以被迭代器取代了,枚举也就郁郁而终了。
public class VectorDemo {
public static void main(String[] args) {
Vector v = new Vextor();
v.add("zhangsan");
v.add("lisi");
v.add("wangwu");
Enumeration en = v.elements();
while(en.hasMoreElements()) {
System.out.println(en.nextElement());
}
}
}
总结:一般情况下,使用哪种List接口下的实现类呢?
- ArrayList:底层是数组结构,每个元素都有下标。特点:查询快,线程不安全。
- LinkedList:底层是链表结构,每个元素都有指向前一个元素的指针。特点:增删快
- Vector:底层是数组结构,和第一个ArrayList接口一样,不过在JDK1.2之后,才有了第一个的ArrayList接口,提高了效率。
Set集合
Set集合中的元素无序不可重复(无序是指存入和取出的顺序不一致)。Set集合的常用方法和Collection接口的方法一致。
Set接口常用的实现类有HashSet和TreeSet.
HashSet集合
HashSet集合底层数据结构是哈希表、存取速度快、元素唯一、线程不同步。
import java.util.*;
public class HashSetDemo {
public static void main(String[] args) {
HashSet<String> hs = new HashSet<String>();
System.out.println(hs.add("zhangsan")); //true
System.out.println(hs.add("zhangsan")); //false
hs.add("java02");
hs.add("java03");
hs.add("java04");
Iterator<String> it = hs.iterator();
while(it.hasNext()) {
System.out.println(it.next());
}
}
}
HashSet保证性元素唯一的原理
先判断元素的hashCode值是否相同,再判断两元素的equals方法是否为true,如果equals方法返回true,那么就不能往HashSet集合中存(往HashSet里面存的自定义元素重写hashCode和equals方法,以保证元素的唯一性)
HashSet的注意事项
通过new的方式往HashSet里面存的元素的hashCode值都不同,但通常我们定义对象,比如学生对象时,虽然是new的两个学生对象,但是当他们name和age一样时,我们认为是同一个对象,所以为了保证元素的唯一性,我们通常在往HashSet集合里面存储元素时,在定义对象的类中通常重写hashCode和equals方法。
public int hashCode() {
return name.hashCode()+age;
}
public boolean equals(Object obj) {
if(!(obj instanceof Student))
return false;
Student stu = (Student)obj;
return this.name.equals(stu.name) && this.age == stu.age;
}
HashSet集合是如何保证元素唯一性的呢?
- 如果两元素的hashCode值不同,则不会调用equals方法
- 如果两元素的hashCode值相同,则继续判断equals是否返回true;
hashCode和equals方法虽然定义在自定义对象类里面,但不是我们手动调用,而是往HashSet集合里面存储元素的时候,集合底层自己调用hashCode和equals,它会自己拿对象去判断,自己判断两元素是否是同一个元素。
练习:往HashSet集合中存入自定义元素人对象,姓名和年龄相同时视为同一个人,为重复元素,不能存入集合。
import java.util.*;
public class HashSetTest{
public static void main(String[] args) {
HashSet<Person> hs = new HashSet<Person>();
hs.add(new Person("zhangsan",19));
hs.add(new Person("lisi",20));
hs.add(new Person("wangwu",20));
hs.add(new Person("zhangsan",19)); //重复元素
Iterator<Person> it = hs.iterator();
while(it.hasNext()) {
Person s = (Person)it.next();
System.out.println(s.getName()+"..."+s.getAge());
}
}
}
class Person {
private String name;
private int age;
Person(String name,int age) {
this.name = name;
this.age = age;
}
public boolean equals(Object obj) { //重写equals方法
if(!(obj instanceof Person))
return false;
Person p = (Person) obj;
return this.name.equals(p.name) && this.age==p.age;
}
public int hashCode() { //重写hashCode方法
return name.hashCode()+age;
}
public String getName() {
return name;
}
public int getAge() {
return age;
}
}
TreeSet集合
TreeSet集合的底层数据结构是二叉树。TreeSet可以对Set集合中的元素进行排序(自然顺序)。元素有序、线程不同步。
import java.util.*;
public class TreeSetDemo {
public static void main(String[] args) {
TreeSet<String> ts = new TreeSet<String>();
ts.add("zhangsan");
ts.add("lisi");
ts.add("wangwu");
Iterator<String> it = ts.iterator();
while(it.hasNext()) {
System.out.println(it.next());
}
}
}
TreeSet集合保证元素唯一性原理
- ①TreeSet的第一种排序方式:让元素自身具备比较性,实现Compareble接口,重写compareTo方法,此方式是元素的自然顺序
-
②TreeSet的第二种排序方式:当元素自身不具备比较性,或者具备的比较性不是所需要的。这时需要让容器自身具备比较性,定义一个比较器,将比较器作为参数传递给TreeSet集合的构造方法。
定义比较器:定义一个类,实现Comparator接口,重写compare方法。
当两种排序都存在时,以比较器为主。
练习:往TreeSet集合中存储自定义对象学生,按照学生的年龄进行排序。
使用第一种排序方式:
import java.util.*;
public class TreeSetTest{
public static void main(String[] args) {
TreeSet<Student> ts = new TreeSet<Student>();
ts.add(new Student("zhangsan",22));
ts.add(new Student("lisi",20));
ts.add(new Student("wangwu",19));
ts.add(new Student("wangwu",19));
Iterator<Student> it = ts.iterator();
while(it.hasNext()) {
Student stu = (Student)it.next();
System.out.println(stu.getName()+"..."+stu.getAge());
}
}
}
class Student implements Comparable { //实现Comparable接口
private String name;
private int age;
Student(String name,int age) {
this.name = name;
this.age = age;
}
public int compareTo(Object obj) { //重写compareTo方法
if(!(obj instanceof Student)) {
throw new RuntimeException("不是学生对象");
}
Student s = (Student) obj;
System.out.println(this.name+"....compareTo...."+s.name);
if(this.age > s.age)
return 1;
if(this.age == age)
return this.name.compareTo(s.name);
return -1;
}
public String getName() {
return name;
}
public int getAge() {
return age;
}
}
使用第二种排序方式:
import java.util.*;
public class TreeSetTest2 {
public static void main(String[] args) {
//将比较器作为参数传递给TreeSet集合的构造方法
TreeSet<Student> ts = new TreeSet<Student>(new MyComparator());
ts.add(new Student("zhangsan",22));
ts.add(new Student("lisi",20));
ts.add(new Student("wangwu",19));
ts.add(new Student("wangwu",19));
Iterator< Student> it = ts.iterator(); //获取迭代器
while(it.hasNext()) {
Student s = (Student)it.next();
System.out.println(s.getName()+"..."+s.getAge());
}
}
}
class Student {
private String name;
private int age;
Student(String name,int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public int getAge() {
return age;
}
}
class MyComparator implements Comparator<Object> { //定义比较器
public int compare(Object o1,Object o2) { //重写compare方法
Student s1 = (Student)o1;
Student s2 = (Student)o2;
int num = s1.getName().compareTo(s2.getName());
if(num == 0) {
if(s1.getAge() > s2.getAge())
return 1;
if(s1.getAge() == s2.getAge())
return 0;
return -1;
}
return num;
}
}
TreeSet练习:按照字符串长度排序。字符串本身具备比较性,但它的比较方式不是所需要的。所以这里只能使用比较器
import java.util.*;
public class TreeSetTest {
public static void main(String[] args) {
TreeSet<String> ts = new TreeSet<String>(new StrLenComparator());
ts.add("a");
ts.add("aasfd");
ts.add("aasd");
ts.add("as");
ts.add("aasdasdsa");
Iterator<String> it = ts.iterator();
while(it.hasNext()) {
System.out.println(it.next());
}
}
}
class StrLenComparator implements Comparator<Object> { //定义比较器
public int compare(Object o1,Object o2) {
String s1 = (String)o1;
String s2 = (String)o2;
if(s1.length() > s2.length())
return 1;
if(s1.length() == s2.length())
return 0;
return -1;
}
}
本文地址:https://blog.csdn.net/weixin_45620489/article/details/107283391
上一篇: leetcode第二题