Java 进阶之类集(三)

    上一篇介绍了 List 接口,旧的子类 Vector,ArrayList 与 Vector 的区别。

    接下来介绍一下 LinkedList 类、Queue 接口、Set接口。

一、LinkedList 子类与 Queue 接口
1. LinkedList 子类

    LinkedList 表示的是一个链表的操作类,此类的定义如下:

public class LinkedList<E>extends AbstractSequentialList<E>implements List<E>, Deque<E>, Cloneable, Serializable

    LinkedList 是一个继承于 AbstractSequentialList 的双向链表,实现 List 接口、Deque 接口。它也可以被当作堆栈、队列或双端队列进行操作。实现了 Cloneable 接口,即覆盖了函数 clone(),能够克隆。实现了 java.io.Serializable 接口,这意味着 LinkedList 支持序列化操作,能通过序列化去传输

    ArrayList 底层是由数组支持,而 LinkedList 是由双向链表实现的,其中的每个对象包含数据的同时还包含指向链表中前一个与后一个元素的引用。

2. Queue 接口

    Queue 用于模拟队列数据结构,采用“先进先出”的方式。Queue 接口继承了 Collection 的接口,而 Queue 接口下面的实现类是 PriorityQueue,继承的接口是 Deque,Deque 接口的实现类是 ArrayDeque,同时 Deque 还被 LinkedList 类实现。

    Queue 接口是 Collection 的子接口,此接口的定义如下:

public interface Queue<E> extends Collection<E>

Queue 接口定义的部分方法:

No方法类型描述
1public  E  element ()普通找到链表的表头
2public  boolean  offer (E  o)普通将指定的元素增加到链表的结尾
3public  E  peek ()普通找到但并不删除链表的头
4public  E  pool ()普通找到并删除此链表的头
5public  E  remove ()普通检索并移除表头

LinkedList 中操作链表的部分方法:

No方法类型描述
1public  void  addFirst (E  o)普通在链表开头增加元素
2public  void  addLast (E  o)普通在链表结尾增加元素
3public  boolean  offer (E  o)普通将制定元素增加到链表的结尾
4public  E  removeFirst ()普通删除链表的第一个元素
5public  E  removeLast ()普通删除链表的最后一个元素

    LinkedList 本身大量扩充了 Queue 接口和 List 接口的操作,所以在使用时最好直接使用 LinkedList 类完成操作

    示例代码1:为链表的开头和结尾增加数据

import java.util.LinkedList;
public class LinkedListDemo01 {
	public static void main(String[] args) {
		LinkedList<String> link = new LinkedList<String>();
		link.add("A");
		link.add("B");
		link.add("C");
		System.out.println("初始化:" + link);
		link.addFirst("E");	//在开头增加数据
		link.addLast("F");	//在结尾增加数据
		System.out.println("增加头和尾之后的链表:" + link);
	}
}

    示例代码2:通过多个方式找到链表表头

import java.util.LinkedList;
public class LinkedListDemo02 {
	public static void main(String[] args) {
		LinkedList<String> link = new LinkedList<String>();
		link.add("A");	//增加元素
		link.add("B");	//增加元素
		link.add("C");	//增加元素
		System.out.println("1-1、element()方法找到表头:" + link.element());
		System.out.println("1-2、找完之后的链表内容:" + link);
		System.out.println("2-1、peek()方法找到表头:" + link.peek());
		System.out.println("2-2、找完之后的链表内容:" + link);
		System.out.println("3-1、poll()方法找到表头:" + link.poll());
		System.out.println("3-2、找完之后的链表内容:" + link);
	

    既然 LinkedList 实现了 Queue 接口,那么就可以按照队列的方式实现 FIFO(先进先出)的操作

    示例代码3:实现 FIFO 操作

import java.util.LinkedList;
public class LinkedListDemo03 {
	public static void main(String[] args) {
		LinkedList<String> link = new LinkedList<String>();
		link.add("A");//增加元素
		link.add("B");//增加元素
		link.add("C");//增加元素
		int length = link.size();//获取长度
		for (int i = 0; i < length; i++) {
			System.out.print(link.poll() + "、");
		}
	}
}
二、Set 接口
1. 接口定义

    Set 接口也是 Collection 的子接口,但是与 Collection 或 List 接口不同的是,Set 接口不能增加重复的元素

    Set 接口的定义如下:

public interface Set<E> extends Collection<E>

    ◇ Set 接口的主要方法与 Collection 是一致的

    ◇ Set 接口的实例无法像 List 接口那样进行双向输出:Collection 不能进行双向输出,因为没有提供 get() 方法,Set 接口与 Collection 接口的定义一致,所以其本身也不能双向输出。

    ◇ Set 接口的常用子类有:

        1)散列存放:HashSet,使用散列的方式存放内容,本身没有顺序,会根据算出的 Hash 值进行排序,而 List 接口插入内容的顺序就是其保存的顺序;

        2)有序存放:TreeSet,使用有序的方式存放内容,所有的内容都可以自动进行排序。

    示例代码1:HashSet

import java.util.HashSet;
import java.util.Set;
public class HashSetDemo01 {
	public static void main(String[] args) {
		Set<String> set = new HashSet<String>();
		set.add("A");//有序增加内容
		set.add("B");
		set.add("C");//重复增加内容
		set.add("C");
		set.add("C");
		set.add("D");
		set.add("E");
		System.out.println(set);
	}
}

    代码运行结果:

[D, E, A, B, C]

    示例代码2:TreeSet

import java.util.TreeSet;
import java.util.Set;
public class TreeSetDemo01 {
	public static void main(String[] args) {
		Set<String> set = new TreeSet<String>();
		set.add("C");//无序增加内容,重复内容
		set.add("E");
		set.add("C");
		set.add("D");
		set.add("A");
		set.add("C");
		set.add("B");
		System.out.println(set);
	}
}

    代码运行结果(TreeSet 类是可以排序的):

[A, B, C, D, E]
2. 排序及重复元素说明

    Comparable 主要是进行排序的操作接口,一个对象数组要想排序,则依靠 Comparable 接口完成,对于 TreeSet 也一样,如果要想使用 TreeSet 接口进行对象的排序操作,则对象所在的类也必须实现 Comparable 接口,覆写 compareTo() 方法制定排序规则

    【如果没有实现 Comparable 接口,则会出现以下错误↓】

Exception in thread "main" java.lang.ClassCastException: setdemo02.Person cannot be cast to java.lang.Comparable

    去掉重复元素的操作是依靠 Comparable 接口完成的,但是为了保证正确,所有的属性都应该进行比较,不能只是比较部分属性。真正的取消掉重复的元素,还需要 Object 类中的两个方法帮助:

    1)hashCode():表示唯一的编码,一般通过计算表示;

    2)equals():进行对象的比较操作。

    示例代码3:实现 Comparable 接口去掉重复的元素(还不是真正意义上的去除重复)

import java.util.Set;
import java.util.TreeSet;
public class TreeSetDemo {
	public static void main(String[] args) {
		Set<Person> ts = new TreeSet<Person>();
		ts.add(new Person("张三", 30));
		ts.add(new Person("李四", 31));
		ts.add(new Person("王五", 32));
		ts.add(new Person("王五", 32));//有两个相同的元素
		ts.add(new Person("赵六", 33));
		ts.add(new Person("孙七", 34));
		ts.add(new Person("张三", 32));
		System.out.println(ts);
	}
}
/**
 * 实现 Comparable 接口的类才可以进行排序操作
 * */
class Person implements Comparable<Person>{
	private String name;
	private int age;
	
	public Person(String name, int age){
		this.age = age;
		this.name = name;
	}
	
	public String toString(){
		return "姓名:" + this.name + ",年龄:" + this.age ;
	}
	
	public int compareTo(Person per){
		if(this.age > per.age){
			return 1;
		}else if(this.age < per.age){
			return -1;
		}else{
//			return 0;//应该比较类中的所有属性,不能只比较其中一个属性
			return this.name.compareTo(per.name);//调用 String 中的compareTo()方法
		}
	}
}

    代码运行结果:

[姓名:张三,年龄:30, 姓名:李四,年龄:31, 姓名:张三,年龄:32, 姓名:王五,年龄:32, 姓名:赵六,年龄:33, 姓名:孙七,年龄:34]

    示例代码4:真正去掉重复元素

import java.util.Set;
import java.util.HashSet;
public class RepeatDemo {
	public static void main(String[] args) {
		Set<Person03> ts = new HashSet<Person03>();
		ts.add(new Person03("张三", 30));
		ts.add(new Person03("李四", 31));
		ts.add(new Person03("王五", 32));
		ts.add(new Person03("王五", 32));//有两个相同的元素
		ts.add(new Person03("赵六", 33));
		ts.add(new Person03("孙七", 34));
		System.out.println(ts);
	}
}
class Person03{
	private String name;
	private int age;
	
	public Person03(String name, int age){
		this.age = age;
		this.name = name;
	}
	public boolean equals(Object obj){//覆写 equals,完成对象的比较,比较的是对象的内容
		if(this == obj){
			return true;
		}
		if(!(obj instanceof Person03)){
			return false;
		}
		Person03 p = (Person03)obj;//向下转型
		if((this.name.equals(p.name)) && (this.age == p.age)){
			return true;
		}else{
			return false;
		}
	}
	public int hashCode(){
		return this.name.hashCode() * this.age;//自己定义一个公式,返回 hashCode:
	}
	
	public String toString(){
		return "姓名:" + this.name + ",年龄:" + this.age ;
	}
}

    代码运行结果:

[姓名:李四,年龄:31, 姓名:张三,年龄:30, 姓名:孙七,年龄:34, 姓名:王五,年龄:32, 姓名:赵六,年龄:33]

    如果要想使用 Set,就必须注意以上的问题

三、总结

1、实际上此集合中增加元素的操作都是一样的,因为都是 Collection 的子类

2、各个类有各个类自己的单独的实现,只需要单独使用即可;

3、一个好的类,就应该覆写 Object 类中的 equals()hashCode()toString() 三个方法,实际上 String 中已经全部覆写完成了。

4、Set 接口依靠 hashCode() 和 equals() 完成重复元素的判断,这一点在 Map 接口中也有体现。

5、TreeSet 依靠 Comparable 接口完成排序的操作

参考文章:

https://blog.csdn.net/shengmingqijiquan/article/details/52640584

https://blog.csdn.net/u010871004/article/details/52604171

(以上只是一些大概的内容介绍,在后面的文章中将会逐个介绍其他的子接口。)

希望此篇文章对大家在学习上有所帮助,若有不对之处也请指出!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值