ArrayList它是List接口的真正的实现类。也是咱们开发中真正须要使用集合容器对象。数组
ArrayList类,它是List接口的实现。确定拥有角标。而且能够存放重复元素,也可以使用List接口中的全部特有方法。ArrayList集合容器,它的底层使用的可变的数组做为存储元素的容器。安全
上述分析ArrayList底层的可变数组。这个可变数组也称为ArrayList集合的底层数据存储的结构(数据结构)。 数据结构
ArrayList它的底层使用的可变数组:ide
它中增删效率相对较低。查询的效率较快。ArrayList它是JDK1.2出现的集合容器。它不保证数据的安全。学习
ArrayList中的方法所有来自于Collection和List接口。测试
List 接口的连接列表实现。实现全部可选的列表操做,而且容许全部元素(包括 null)。this
除了实现 List 接口外,LinkedList 类还为在列表的开头及结尾 get、remove 和 insert 元素提供了统一的命名方法。这些操做容许将连接列表用做堆栈、队列或双端队列。编码
LinkedList集合它是List接口的直接实现类。它实现了Collection和List接口中的全部方法。 spa
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:它下面的集合容器都有脚标,均可以使用角标或者ListIterator进行遍历。
ArrayList:它的底层是可变数组,增删慢,查询快。不安全。
LinkedList:它的底层是链表结构,有头和尾,能够模拟队列或者堆栈数据结构。增删快,查询慢。不安全
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接口是Collection接口下的一个子接口。它和List接口相同,都是Collection的子接口。
区别:
List:有脚本、能够重复、拥有特有的ListIterator迭代器
Set:没有脚本、不能包含重复元素,没有特有的迭代器,只能使用Iterator进行遍历。
Set接口没有本身的特有的方法,全部方法所有来自于Collection接口。
重点学习Set接口下的两个实现类:
HashSet:
TreeSet:
此类实现 Set 接口,由哈希表(其实是一个 HashMap 实例)支持。它不保证 set 的迭代顺序;特别是它不保证该顺序恒久不变。此类容许使用 null 元素。
HashSet集合的底层使用的哈希表结构。
若是多个对象它们计算出的哈希值相同,这时在计算机中称为哈希冲突。若是哈希值相同了,这时必须调用对象的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 }
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对象,它们的地址值确定是不相同的。
HashSet保证对象的惟一依赖当前给HashSet集合中保存的对象的hashCode和equals方法。
使用hashCode计算位置,使用equals比较2个对象是否相同。
要保证给HashSet集合中存储的自定义对象中的数据惟一,自定义对象所属的类须要复写Object类中的hashCode和equals方法 。
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 }
基于 TreeMap
的 NavigableSet
实现。使用元素的天然顺序对元素进行排序,或者根据建立 set 时提供的 Comparator
进行排序,具体取决于使用的构造方法。
TreeSet集合它是Set接口的间接实现类。TreeSet集合它也不能存放重复的元素。
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 }
介绍数据结构中的树结构:
树结构:
二叉树:每一个节点最多只能有2个子节点。
非规则二叉树:有点节点可能会有2个子节点,有的只有一个。甚至没有。
普通的树结构:非规则树结构。
二叉树:
若是将自定义对象存储到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方法。若是这个方法返回的结果是零,就说明当前正要往集合中存储的对象和已经在集合中的对象大小同样。这时这个对象就不会被保存到集合中。
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 }
需求:将字符串数据保到TreeSet集合中,要求按照字符串的长度进行排序。
“AAAAA” “aaa”
分析:
自己TreeSet集合能够对存放在其中的任何对象进行排序,依赖的是对象本身的compareTo方法。String类自己已经具有compareTo方法,可是这个方法是按照字符串中每一个字符的编码值大小进行比较。而需求要求按照字符串的长度进行比较。String类中的compareTo方法不能知足需求。
针对上述的问题,自己应该能够定义一个新的类,继承String类,复写compareTo方法,而后使用子类本身的比较方式。可是因为String类被final修饰,不能再有子类。
Java给出另一种处理方案:若是对象自身具有了比较功能,或者对象自身根本就没有比较功能,这时依然须要对这些对象进行排序,咱们能够本身建立一个专门负责比较对象大小的新的比较器对象。
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 }
相同点:Comparator和Comparable:它们均可以提供比较大小的方法。
不一样点:
Comparable:它是让某个类具有比较功能,当建立出这个类的对象,就能够直接使用这个对象中的compareTo方法进行比较大小。Comparable是让对象本身具有了比较功能
Comparator:它是提供比较两个对象大小,可是这个功能和对象自身并无任何的关系。只要将须要比较的两个对象传递给compare方法便可。提供单独的比较器对象,能够比较任意的两个对象