当前位置: 移动技术网 > IT编程>开发语言>Java > Java语言基础之List集合以及Set集合的使用

Java语言基础之List集合以及Set集合的使用

2020年07月03日  | 移动技术网IT编程  | 我要评论

集合类概述

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("张三");
      list.add("李四");
      list.add("王五");
      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中元素的个数 

代码演示

import java.util.*;

public class CollectionDemo{
	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");
		 //打印原集合
		 sop(al);
		 //删除元素
		 al.remove("lisi");
		 //打印删除元素后的集合
		 sop(al);
		 //清空集合
		 al.clear();
		 //获取集合长度
		 sop("size = "+al.size());
		 //判断元素是否存在集合中
		 sop("wangwu是否存在?"+al.contains("wangwu"));
		 //判断集合是否为空
		 sop("集合是否为空?"+al.isEmpty());
	}
	public static void sop(Object obj){
		System.out.println(obj);
	}
}

迭代器Iterator

迭代器其实就是集合取出元素的方式。
迭代器中的方法摘要:

boolean hasNext():如果集合中还有元素可以迭代,那么返回true
next():返回迭代的下一个元素
void remove():从迭代器指向的Collection中移除迭代器返回的最后一个元素

因此可以把取出方式定义在集合内部,这样取出方式就可以直接访问集合中的元素。那么取出方式就被定义成了内部类。

而每一个容器的数据结构都不同,所以取出的动作细节也不同,但是都有共性内容判断和取出。那么可以将这些共性进行抽取。

那么这些共性都符合一个规则,该规则是Iterator。如何获取集合的取出对象呢?
通过一个对外的方法iterator()。

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):修改指定索引处的元素

代码演示

 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方法获取。
说白了就是ListInterator迭代器可以对集合中的元素进行增删查改。

import java.util.*;

public class ListDemo {
   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.add("java09"); //在元素java02后面添加java09
            li.set("java06"); //将元素java02修改成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("java01"); //add(Object obj);
        a.add("java02");
        a.add("java01");
        a.add("java03");
        a.add("java03"); 
        System.out.println("删除重复元素前:"+a);
        a = singleElement(a);
        System.out.println("删除重复元素后:"+a);
    }
    public static ArrayList<String> singleElement(ArrayList<String> a1) {
       //创建一个新的容器 将不重复元素存入
       ArrayList<String> newal = new ArrayList<String>();
       Iterator<String> it = a1.iterator();
       while(it.hasNext()) {
           Object obj = it.next();
           if(!newal.contains(obj))
               newal.add((String)obj);
       }
       return newa1;
   }
}

LinkedList集合

(1)Linkedist的特有方法:
①增加:

addFirst()在链表的开头插入指定的元素。
addLast()在链表末尾插入指定的元素。

②删除:

removeFirst()删除链表的第一个元素
removeLast()删除链表的最后一个元素(获取元素也删除元素)

③查询:

getFirst()获取链表的第一个元素
getLast()获取链表的最后一个元素(获取元素但不删除元素)

代码演示

 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");
      sop("Stack:"+s.Mysize());
      while(!(s.MyisEmpty()))
          sop(s.Myget());    
      Queue q = new Queue(); //队列
      q.Myadd("java01");
      q.Myadd("java02");
      q.Myadd("java03");
      q.Myadd("java04");
      sop("Queue:"+q.Mysize());
      while(!(q.MyisEmpty()))
          sop(q.Myget());
   }
   public static void sop(Object obj) {
      System.out.println(obj);
   }
}
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特有的取出方式,枚举和迭代都是取出元素的方式,都一样。
因为枚举的名称和方法的名称都过长,所以被迭代器取代了,枚举也就郁郁而终了。

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"));
      System.out.println(hs.add("lisi"));
      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集合的底层数据结构是二叉树。可以对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的注意事项

TreeSet要求往里面存的元素具备比较性,否则会报错。
TreeSet排序的第一种方式:让元素自身具备比较性。排序时,当主要条件相同时,要判断次要条件,如果次要条件也相同,那么就不能存入,因为Set是不允许有重复元素的。
TreeSet排序的第二种方式:定义对象类,实现Compareble接口,复写compareTo方法,此方式是元素的自然顺序。基本数据类型或字符串对象也都实现了Comparable接口,故同种类型基本数据间具备比较性,即自然顺序。

练习:往TreeSet集合中存储自定义对象学生,按照学生的年龄进行排序。
使用第一种排序方式:

import java.util.*;

public class TreeSetTest{
   public static void main(String[] args) {
       TreeSet<Student> ts = new TreeSet<Student>();
       ts.add(new Student("zhangsan02",22));
       ts.add(new Student("zhangsan07",20));
       ts.add(new Student("zhangsan08",19));
       ts.add(new Student("zhangsan08",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 { //强制让学生具备比较性
    private String name;
    private int age;
    Student(String name,int age){
        this.name = name;
        this.age = age;
    }
   public int compareTo(Object obj){
       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("zhangsan02",22));
       ts.add(new Student("zhangsan07",20));
       ts.add(new Student("zhangsan08",19));
       ts.add(new Student("zhangsan08",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/107081945

如对本文有疑问, 点击进行留言回复!!

相关文章:

验证码:
移动技术网