JAVA基础--JAVA API集合框架(其他集合类,集合原理)15
Posted 最苦逼的程序猿
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了JAVA基础--JAVA API集合框架(其他集合类,集合原理)15相关的知识,希望对你有一定的参考价值。
一、ArrayList介绍
1.ArrayList介绍
ArrayList它是List接口的真正的实现类。也是我们开发中真正需要使用集合容器对象。
ArrayList类,它是List接口的实现。肯定拥有角标。并且可以存放重复元素,也能够使用List接口中的所有特有方法。ArrayList集合容器,它的底层使用的可变的数组作为存储元素的容器。
上述分析ArrayList底层的可变数组。这个可变数组也称为ArrayList集合的底层数据存储的结构(数据结构)。
ArrayList它的底层使用的可变数组:
它中增删效率相对较低。查询的效率较快。ArrayList它是JDK1.2出现的集合容器。它不保证数据的安全。
2. ArrayList的构造方法和方法介绍
ArrayList中的方法全部来自于Collection和List接口。
二、LinkedList 介绍
List 接口的链接列表实现。实现所有可选的列表操作,并且允许所有元素(包括 null)。
除了实现 List 接口外,LinkedList 类还为在列表的开头及结尾 get、remove 和 insert 元素提供了统一的命名方法。这些操作允许将链接列表用作堆栈、队列或双端队列。
LinkedList集合它是List接口的直接实现类。它实现了Collection和List接口中的所有方法。
LiknedList集合它的底层使用的链接列表:
LinkedList:集合底层使用的链表结构,由于链表有头和尾,因此在LinkedList集合中重新定义了新的方法,这些方法都是围绕链表的头和尾而设计的方法:
addFirst
addLast
removeFirst
removeLast
getFirst
getLast
链表结构可以完成数据结构中的部分结构的实现:
队列:先进先出,后进后出。最先 进入到结构中的数据,被最先取出。例如:排队买票,火车过山洞。
堆栈:先进后出,后进先出。例如:Java内存结构中的栈内存。手枪弹夹。
1 //模拟队列或者堆栈数据结构 2 class Queue{ 3 4 //定义一个LinkedList集合 5 private LinkedList list = new LinkedList(); 6 7 public void myAdd( Object obj ){ 8 list.addFirst(obj); 9 } 10 11 public Object myGet(){ 12 return list.removeLast(); 13 } 14 15 public boolean isEmpty(){ 16 return list.isEmpty(); 17 } 18 19 } 20 //测试类 21 public class LinkedListDemo2 { 22 public static void main(String[] args) { 23 24 Queue q = new Queue(); 25 26 q.myAdd("aaa"); 27 q.myAdd("bbb"); 28 q.myAdd("ccc"); 29 q.myAdd("ddd"); 30 31 while( !q.isEmpty() ){ 32 System.out.println(q.myGet()); 33 } 34 } 35 }
三、 List接口下的集合总结:
List:它下面的集合容器都有脚标,都可以使用角标或者ListIterator进行遍历。
ArrayList:它的底层是可变数组,增删慢,查询快。不安全。
LinkedList:它的底层是链表结构,有头和尾,可以模拟队列或者堆栈数据结构。增删快,查询慢。不安全
四、Vetor集合
1.Vector介绍
Vector集合是它JDK1.0时期就存在的一个集合容器对象。在JDK1.2的时候出现了集合体系,Vector变成List接口下的一个实现类。
Vector的底层使用的也是可变数组,和ArrayList底层一致。Vector它可以保证安全,因为它的什么效率都慢。
后期开发中看到Vector就可以直接把它看成ArrayList使用即可。
Vector中的方法名只要是和element相关的都是Vector的原生方法。其他的都是从Collection或者List接口中实现的。
1 /* 2 * 介绍古老的Vector集合 3 */ 4 public class VectorDemo { 5 public static void main(String[] args) { 6 7 //创建集合对象 8 Vector v = new Vector(); 9 10 v.addElement("aaa"); 11 v.addElement("aaa"); 12 v.addElement("abc"); 13 v.addElement("ccc"); 14 15 //遍历 16 for( Enumeration en = v.elements(); en.hasMoreElements() ; ){ 17 System.out.println(en.nextElement()); 18 } 19 20 for( Iterator it = v.iterator(); it.hasNext() ; ){ 21 System.out.println(it.next()); 22 } 23 } 24 }
Enumeration:它是Iterator的前身,也可以遍历集合容器。
但是由于它的功能和Iterator严重重复,并且Iterator中提供的方法名称比Enumeration中的方法名短。
开发中我们优先使用Iterator,而不使用Enumeration迭代集合。
五、SET集合
1. Set接口介绍
Set接口是Collection接口下的一个子接口。它和List接口相同,都是Collection的子接口。
区别:
List:有脚本、可以重复、拥有特有的ListIterator迭代器
Set:没有脚本、不能包含重复元素,没有特有的迭代器,只能使用Iterator进行遍历。
2.HashSet集合
Set接口没有自己的特有的方法,所有方法全部来自于Collection接口。
重点学习Set接口下的两个实现类:
HashSet:
TreeSet:
此类实现 Set 接口,由哈希表(实际上是一个 HashMap 实例)支持。它不保证 set 的迭代顺序;特别是它不保证该顺序恒久不变。此类允许使用 null 元素。
HashSet集合的底层使用的哈希表结构。
2.1 哈希表介绍
如果多个对象它们计算出的哈希值相同,这时在计算机中称为哈希冲突。如果哈希值相同了,这时必须调用对象的equals方法比较2个对象(多个对象)是否是同一个对象。
任何给哈希表中存储的对象都应该具备hashCode和equals方法。
1 /* 2 * 演示HashSet集合 3 */ 4 public class HashSetDemo { 5 public static void main(String[] args) { 6 7 //创建集合对象 8 HashSet set = new HashSet(); 9 10 //添加元素 11 set.add("bbb"); 12 set.add("cccc"); 13 set.add("cccc"); 14 set.add("abc"); 15 set.add("abc"); 16 //遍历HashSet集合 17 for( Iterator it = set.iterator() ; it.hasNext(); ){ 18 System.out.println(it.next()); 19 } 20 } 21 }
2.2 HashSet 保存自定义对象
1 /* 2 * 演示给HashSet中保存自定义类的对象 3 */ 4 public class HashSetDemo2 { 5 public static void main(String[] args) { 6 7 //创建集合对象 8 HashSet set = new HashSet(); 9 10 //创建自定义对象 11 //Person p = new Person("华安",23); 12 //set.add(p); 13 set.add(new Person("华安",23)); 14 set.add(new Person("华安",23)); 15 set.add(new Person("秋香",18)); 16 set.add(new Person("9527",23)); 17 set.add(new Person("小书童",33)); 18 19 //遍历 20 for( Iterator it = set.iterator() ; it.hasNext(); ){ 21 System.out.println( it.next() ); 22 } 23 } 24 }
分析:
我们自己定义了一个Person类,然后创建Person对象,将这些Person对象存储到HashSet集合中。
希望同姓名和年龄的Person对象,应该是同一个人,在集合中只能有一个。但是通过程序发现依然可以保存多个同姓名和年龄的Person对象。
HashSet集合底层使用的哈希表,给哈希表中存储对象的时候,需要调用当前对象自己的hashCode计算位置,equals判断对象是否相同。而我们的Person类继承了Object类,自然就会具备hashCode和equals方法。
但是Person类中并没有去复写hashCode和equals方法,说明在将Person对象给HashSet集合中保存的时候,调用的hashCode和equals方法依然使用的Object类中的方法。
Object类中的equals方法是在比较2个对象的地址值是否相同。
hashCode方法计算哈希值的是也是根据对象的地址值在进行计算。
如果创建了多个Person对象,它们的姓名和年龄相同,我们认为应该是同一个人,但是由于是new了多次,在堆中就会有多个Person对象,它们的地址值肯定是不相同的。
2.3 HashSet保证对象唯一的原因
HashSet保证对象的唯一依赖当前给HashSet集合中保存的对象的hashCode和equals方法。
使用hashCode计算位置,使用equals比较2个对象是否相同。
2.4 HashSet总结
要保证给HashSet集合中存储的自定义对象中的数据唯一,自定义对象所属的类需要复写Object类中的hashCode和equals方法 。
2.5 LinkedHashSet介绍
HashSet集合不保证存取的顺序,保证对象唯一。
LinkedHashSet它是HashSet集合的子类,它也属于Set接口下的集合容器,同样也能保证对象的唯一。
和HashSet的区别是:LinkedHashSet可以保证存放的元素的存取顺序一致。
LinkedHashSet它没有自己的特有方法,所有方法全部来自于父类。
1 /* 2 * 演示LinkedHashSet集合 3 */ 4 public class LinkedHashSetDemo { 5 public static void main(String[] args) { 6 7 //创建集合对象 8 LinkedHashSet set = new LinkedHashSet(); 9 10 set.add("ccc"); 11 set.add("aaa"); 12 set.add("abc"); 13 set.add("ccc"); 14 set.add("aaa"); 15 16 //遍历 17 for (Iterator it = set.iterator(); it.hasNext();) { 18 System.out.println(it.next()); 19 } 20 } 21 }
六、TreeSet介绍
1. TreeSet介绍
基于 TreeMap
的 NavigableSet
实现。使用元素的自然顺序对元素进行排序,或者根据创建 set 时提供的 Comparator
进行排序,具体取决于使用的构造方法。
TreeSet集合它是Set接口的间接实现类。TreeSet集合它也不能存放重复的元素。
TreeSet集合的底层使用的数据结构中的二叉树(红黑树)结构。这种数据结构可以对保存在其中的数据进行排序。
2. TreeSet演示
1 /* 2 * TreeSet集合的简单演示 3 */ 4 public class TreeSetDemo { 5 public static void main(String[] args) { 6 7 //创建集合对象 8 TreeSet set = new TreeSet(); 9 10 //添加元素 11 set.add("ddd"); 12 set.add("aaa"); 13 set.add("bbb"); 14 set.add("bbb"); 15 set.add("abc"); 16 set.add("ABC"); 17 set.add("ABC"); 18 set.add("aBC"); 19 set.add("eee"); 20 set.add("def"); 21 set.add("def"); 22 set.add("ddf"); 23 set.add("ddf"); 24 25 //遍历 26 for( Iterator it = set.iterator() ; it.hasNext(); ){ 27 System.out.println(it.next()); 28 } 29 } 30 }
3. 树结构介绍
介绍数据结构中的树结构:
树结构:
二叉树:每个节点最多只能有2个子节点。
非规则二叉树:有点节点可能会有2个子节点,有的只有一个。甚至没有。
普通的树结构:非规则树结构。
二叉树:
4.TreeSet保存自定义对象
如果将自定义对象存储到TreeSet集合(二叉树结构)中,这时底层会将传递的这个对象强制转成Comparable类型。
发生上述的原因是:
给TreeSet中保存的对象需要进行比较大小,然后确定它们在二叉树中存储位置,存储的对象就必须具备比较大小的功能。如果要使一个对象具备比较大小的功能,这个对象所属的类需要实现Java中提供的Comparable接口。实现其中的compareTo方法。
1 /* 2 * 演示给TreeSet集合中保存自定义对象 3 */ 4 public class TreeSetDemo2 { 5 6 public static void main(String[] args) { 7 8 //创建TreeSet集合对象 9 TreeSet set = new TreeSet(); 10 11 set.add(new Person("华安",23)); 12 set.add(new Person("华安",23)); 13 set.add(new Person("秋香",13)); 14 set.add(new Person("秋香",23)); 15 set.add(new Person("石榴",33)); 16 17 //遍历 18 for( Iterator it = set.iterator() ; it.hasNext() ; ){ 19 System.out.println(it.next()); 20 } 21 } 22 }
将对象保存到TreeSet集合中过程中:
在将对象保存到集合中的时候,需要将当前这个对象和集合中已经存在的对象进行大小比较,也就是去调用对象的compareTo方法。如果这个方法返回的结果是零,就说明当前正要往集合中存储的对象和已经在集合中的对象大小一样。这时这个对象就不会被保存到集合中。
5. Comparable介绍使用
1 /* 2 * 让我们自己的类实现Comparable接口,让其对象具备比较大小的功能 3 */ 4 5 public class Person implements Comparable{ 6 private String name; 7 private int age; 8 9 public Person(String name, int age) { 10 this.name = name; 11 this.age = age; 12 } 13 public String getName() { 14 return name; 15 } 16 public void setName(String name) { 17 this.name = name; 18 } 19 public int getAge() { 20 return age; 21 } 22 public void setAge(int age) { 23 this.age = age; 24 } 25 @Override 26 public String toString() { 27 return "Person [name=" + name + ", age=" + age + "]"; 28 } 29 /* 30 * 实现Comparable接口中的compareTo方法 31 * 需要在compareTo方法中根据对象的属性数据进行大小的比较 32 * 33 * compareTo方法的调用时间: 34 * 当正要给TreeSet中保存对象的时候,由TreeSet集合的底层,会将 35 * 当前这个对象强转成Comparable类型,然后再用强转后的这个对象 36 * 调用compareTo方法,将已经在集合中的对象传递Object o ,然后 37 * 在compareTo方法中比较当前正要存放的对象和已经在集合中的对象的大小。 38 */ 39 public int compareTo(Object o) { 40 41 //判断传递进来的o是否是Person类型 42 if( !(o instanceof Person) ){ 43 //判断成立,说明当前传递进来的o不是Person类型 44 throw new ClassCastException("传递的对象不是Person类型"); 45 } 46 Person p = (Person) o; 47 /* 48 //比较 49 if( this.age == p.age ){ 50 //年龄相同,判断姓名 51 if( this.name.equals(p.name) ){ 52 //判断成立说明 年龄和姓名都相同认为是同一个人 53 return 0; 54 }else{ 55 return this.name.compareTo(p.name); 56 } 57 }else{ 58 return this.age - p.age; 59 } 60 */ 61 int temp = this.age - p.age; 62 return temp == 0 ? this.name.compareTo(p.name) : temp; 63 } 64 }
七、比较器介绍
1. 比较器介绍
需求:将字符串数据保到TreeSet集合中,要求按照字符串的长度进行排序。
“AAAAA” “aaa”
分析:
本身TreeSet集合可以对存放在其中的任何对象进行排序,依赖的是对象自己的compareTo方法。String类本身已经具备compareTo方法,但是这个方法是按照字符串中每个字符的编码值大小进行比较。而需求要求按照字符串的长度进行比较。String类中的compareTo方法不能满足需求。
针对上述的问题,本身应该可以定义一个新的类,继承String类,复写compareTo方法,然后使用子类自己的比较方式。但是由于String类被final修饰,不能再有子类。
Java给出另外一种处理方案:如果对象自身具备了比较功能,或者对象自身根本就没有比较功能,这时依然需要对这些对象进行排序,我们可以自己创建一个专门负责比较对象大小的新的比较器对象。
2. 比较器演示
1 /* 2 * 演示使用比较器对TreeSet集合中的元素(对象)进行比较大小排序 3 */ 4 public class TreeSetDemo3 { 5 public static void main(String[] args) { 6 //没有传递比较器,会按照元素自身的compareTo进行大小比较 7 //TreeSet set = new TreeSet( ); 8 //传递比较器 9 TreeSet set = new TreeSet( new MyComparator()); 10 11 set.add("AAAAA"); 12 set.add("aaa"); 13 set.add("aa"); 14 set.add("AAA"); 15 set.add("AAAAA"); 16 17 for (Iterator it = set.iterator(); it.hasNext();) { 18 System.out.println(it.next()); 19 } 20 } 21 } 22 23 //自定义比较器(自己定义比较规则) 24 public class MyComparator implements Comparator{ 25 26 //实现按照字符串长度比较大小 27 public int compare(Object o1, Object o2) { 28 29 //按照长度比较 30 if( !( o1 instanceof String && o2 instanceof String ) ){ 31 throw new ClassCastException("数据类型不统一,无法比较"); 32 } 33 34 String s1 = (String) o1; 35 String s2 = (String) o2; 36 37 int temp = s1.length() - s2.length(); 38 39 return temp == 0 ? s1.compareTo(s2) : temp ; 40 } 41 }
3. Comparator和Comparable总结
相同点:Comparator和Comparable:它们都可以提供比较大小的方法。
不同点:
Comparable:它是让某个类具备比较功能,当创建出这个类的对象,就可以直接使用这个对象中的compareTo方法进行比较大小。Comparable是让对象自己具备了比较功能
Comparator:它是提供比较两个对象大小,但是这个功能和对象自身并没有任何的关系。只要将需要比较的两个对象传递给compare方法即可。提供单独的比较器对象,可以比较任意的两个对象
Collection下的集合总结
以上是关于JAVA基础--JAVA API集合框架(其他集合类,集合原理)15的主要内容,如果未能解决你的问题,请参考以下文章
JAVA基础--JAVA API集合框架(ArrayListHashSetHashMap使用)