类集实际上就属于动态对象数组,那么在实际的开发之中数组的概念出现的几率并不高,99%情况下使用的都是一维数组,并且99%的操作都只是进行简单的for循环处理,但是必须清楚数组本身有一个最大的缺陷:数组的长度是固定的 就是因为此问题的存在,所以才开发出了链表,但是对于链表的实现非常的困难,对于之前写的链表使用的是Object,那么就有一个潜在的问题了:如果设置的数据类型不一样,那么就会操作ClassCastException(取数据的时候会比较方法)
从JDK1.2开始为了解决数组的长度问题,专门提供了动态数组实现框架---java类集框架,所谓的类集的开发框架就是java针对于数据结构的一种实现,而在数据结构之中,最为基础的数据结构就是链表。
回顾:链表的特点
这种节点关系的处理操作,核心就需要一个Node类(保存数据,设置数据)
在进行链表数据查找.删除的时候需要equals()方法支持:
在实际的开发之中对于这些数据结构的使用都有一些共性的特点:存进去,取出来
对于以上给出的链表操作方法,在类集里面还会见到。所以讲解的时候请千万不要忽悠了分析的原理。
Collection集合接口
在Java的类集里面(java.util包)提供有两个最为核心的操作接口:Collection Map接口,其中Collection的接口操作与之前链表的操作形式类似,每一次进行数据操作的时候只能够对单个对象进行处理。
所以Collection是单个集合保存的最大父接口。Collection接口定义如下:public interface Collection<E> extends Iterable<E>
从JDK1.5开始发现Collection接口上追加有泛型引用,这样的直接好处就是可以避免了ClassCastException里面所有的数据保存类型应该想用的。在JDK1.5之前Iterable()方法是直接在Collection接口里定义的,对于此类的常用方法有如下几个:
向集合中添加数据:public boolean add(E e)
向集合中添加一组数据:public boolean addAll(Collection<? extends E> c)
清空数据:public void clear()
查找数据是否存在,需要使用equals:boolean contains(Object o)
删除数据,需要euqas方法:boolean remove(Object o)
取得集合长度:int size()
将集合变为对象数组返回:Object[] toArray()
取得Iterator对象用于输出:Iterator<E> iterator()
在开发中使用比率来讲:add() iterator()两个方法占到了95%以上,其他方法基本用不上。但是需要实际开发中很少会直接使用Collection接口(18年前,使用最多一定是Collection接口),因为Collection接口只是一个存取数据的标准,而并不是区分存储的类型,例如:如果要存放数据可能需要区分重复与不重复。所以在实际的开发之中,往往会去考虑使用Collection接口的子接口:List(允许重复) Set(不允许重复)
Collection接口中有两个重要的方法:add() iteractor() 子接口都有这个方法,
List的集合接口
在实际的开发过程中,List集合接口的使用比率的可以达到Collection系列的80%,在进行集合处理的时候优先考虑的一定是List集合接口,首先观察一下Lsit接口中提供的方法,在这个接口里面有连个扩充方法
根据索引取得数据保存数据:E get(int index)
修改数据:E set(int index,E element)
List接口与Collection接口相比最大的特点在于其有一个get()方法,可以根据索引取得内容,但是List本身还属于一个接口,而如果要取得接口的实例化对象,就必须有子类,在我们List的接口下有三个常用子类:Array Vector LinkedList
最终的操作还是以接口为主,所以所有的方法只参考接口的定义即可。
ArrayList(90%)
ArrayList是一个针对List接口的数组操作实现,那么下面首先利用ArrayList做一些List基本操作。
范例:观察List基本处理
1 package cn.Tony.demo; 2 3 import java.util.ArrayList; 4 import java.util.List; 5 6 public class TestDemo{ 7 public static void main(String[] args) throws Exception { 8 List<String> all=new ArrayList<String>(); 9 all.add("Hello"); 10 all.add("Hello");//重复数据 11 all.add("World"); 12 System.out.println(all); 13 } 14 }
通过此时的观察可以得到证实,咋们的List允许保存重复的数据的
1 package cn.Tony.demo; 2 3 import java.util.ArrayList; 4 import java.util.List; 5 6 public class TestDemo{ 7 public static void main(String[] args) throws Exception { 8 List<String> all=new ArrayList<String>(); 9 System.out.println(all.size()+","+all.isEmpty()); 10 all.add("Hello"); 11 all.add("Hello");//重复数据 12 all.add("World"); 13 all.remove("Hello"); 14 System.out.println(all.size()+","+all.isEmpty()); 15 System.out.println(all.contains("AbC")); 16 System.out.println(all.contains("World")); 17 System.out.println(all); 18 } 19 }
List本身有一个好的支持:它存在一个get()方法,那么利用get()方法利用索引取出数据。
范例:观察List的get()操作
1 package cn.Tony.demo; 2 3 import java.util.ArrayList; 4 import java.util.List; 5 6 public class TestDemo{ 7 public static void main(String[] args) throws Exception { 8 List<String> all=new ArrayList<String>(); 9 all.add("Hello"); 10 all.add("Hello");//重复数据 11 all.add("World"); 12 for(int x=0;x<all.size();x++) { 13 System.out.println(all.get(x)); 14 } 15 } 16 }
但是千万要记住get()是List子接口的。如果你现在使用的不是List而是Collection(虽然这种情况大多数不会发生)那么对于此时的数据取出
你只能讲集合变为对象数组来操作了。
范例:通过Collection进行输出处理
1 package cn.Tony.demo; 2 3 import java.util.ArrayList; 4 import java.util.Arrays; 5 import java.util.Collection; 6 7 public class TestDemo{ 8 public static void main(String[] args) throws Exception { 9 Collection<String> all=new ArrayList<String>(); 10 all.add("Hello"); 11 all.add("Hello");//重复数据 12 all.add("World"); 13 //操作以Object形式返回,那么就有可能需要进行向下转型。那么就有可能操作ClassCastException安全隐患 14 Object[] result=all.toArray();//变为Object对象数组 15 System.out.println(Arrays.toString(result)); 16 } 17 }
此类操作在开发中尽量回避,你们所写的代码,不到万不得已(一般不会出现)不要使用Collection
集合与简单Java类
在实际的开发之中,集合里面保存最多的数据类型,就是简单java类,所以下面针对于简单java类的集合操作做一个说明。
范例:先向集合保存简单java类
1 package cn.Tony.demo; 2 3 import java.util.ArrayList; 4 import java.util.List; 5 6 class Person{ 7 private String name; 8 private Integer age; 9 public Person(String name,Integer age){ 10 this.name=name; 11 this.age=age; 12 } 13 @Override 14 public boolean equals(Object obj) { 15 if(this==obj) { 16 return true; 17 } 18 if(this==null) { 19 return false; 20 } 21 if(!(obj instanceof Person)) { 22 return false; 23 } 24 Person per=(Person)obj;//这个可以向下转型 25 return this.name.equals(per.name)&&this.age.equals(per.age); 26 } 27 @Override 28 public String toString() { 29 return "Person [name=" + name + ", age=" + age + "]"; 30 } 31 } 32 public class TestDemo{ 33 public static void main(String[] args) throws Exception { 34 List<Person> all=new ArrayList<Person>(); 35 all.add(new Person("张三",10)); 36 all.add(new Person("李于",11)); 37 all.add(new Person("挖宝",12)); 38 //对于集合中的remove() contains()方法必须类中有equals支持 39 all.remove(new Person("李于",11)); 40 System.out.println(all.contains(new Person("李于",11))); 41 for(int x=0;x<all.size();x++) { 42 System.out.println(all.get(x)); 43 } 44 } 45 }
从何理论上讲contains() remove()需要equals()支持,但是实际上很多有人真去这么作,也就是说简单java类里面实现equal方法的几率在开发中出现的可能性是很低的。
旧的子类:Vector(1%)
Vecter这个类是JDK1.0的时候就提出了,而ArrayList是JDK1.2提出的。最初的java再开发类集的时候考虑将Vector取消了,因为这个了类的实现机制太古老了,可是后来又考虑有许多人已经习惯于使用Vector了,那么于是对于Vector进行了重新的设计。让其多实现看一个List接口。
范例:使用Vector
1 package cn.Tony.demo; 2 3 import java.util.List; 4 import java.util.Vector; 5 6 public class TestDemo{ 7 public static void main(String[] args) throws Exception { 8 List<String> all=new Vector<String>(); 9 all.add("Hello"); 10 all.add("Hello"); 11 all.add("World"); 12 all.remove("Hello"); 13 System.out.println(all); 14 } 15 }
面试题:请解释ArrayList和Vector的区别?
在以后的使用过程中优先考虑ArrayList
LinkedList子类(5%)
在List接口里面还有一个LinkedList子类,这个子类如果向父接口转型的话,使用的形式和之前没有任何区别。
1 package cn.Tony.demo; 2 3 import java.util.LinkedList; 4 import java.util.List; 5 6 7 public class TestDemo{ 8 public static void main(String[] args) throws Exception { 9 List<String> all=new LinkedList<String>(); 10 all.add("Hello"); 11 all.add("Hello"); 12 all.add("World"); 13 all.remove("Hello"); 14 System.out.println(all); 15 } 16 }
面试题:请解释ArrayList和LinkedList的区别?
ArrayList封装的是一个数组,LinkedList封装的是一个链表实现,ArrayList时间复杂度为1 而LinkedList时间复杂度为n
开发之中考虑的就是ArrayList如果考虑性能就要初始化大小
Set集合接口
Set接口与List最大的不同在于Set接口中的内容是不允许重复的,同时也需要注意一点,Set与List最大的不同在于:Set接口并没有对Collection接口进行扩充,而List对Collection进行了扩充,由于是JDK1.8的原因,所以在Collection接口里面提供有一些default方法,而这些方法并没有在Set接口出现,也就是Set接口面不可能有gfet方法处理的,而在Set子接口里面有两个常用的子类:HashSet TreeSet。
范例:观察HashSet的使用
1 package cn.Tony.demo; 2 3 import java.util.HashSet; 4 import java.util.Set; 5 6 public class TestDemo{ 7 public static void main(String[] args) throws Exception { 8 Set<String> all=new HashSet<String>(); 9 all.add("Hello"); 10 all.add("Hello");//重复元素 11 all.add("World"); 12 all.add("Tony"); 13 all.add("Java"); 14 System.out.println(all); 15 16 } 17 }
范例:观察TreeSet的使用
1 package cn.Tony.demo; 2 3 import java.util.Set; 4 import java.util.TreeSet; 5 6 public class TestDemo{ 7 public static void main(String[] args) throws Exception { 8 Set<String> all=new TreeSet<String>(); 9 all.add("B"); 10 all.add("C");//重复元素 11 all.add("D"); 12 all.add("A"); 13 all.add("E"); 14 System.out.println(all); 15 16 } 17 }
TreeSet使用的一个升序排序的!
集合排序说明(TreeSet)
既然TreeSet子类可以进行排序,所以下面编写一个自己的类希望可以通过TreeSet实现数据排序处理操作。此时如果要进行排序要进行对象数组的排序,在之前就已经明确说明了,对象所在的类一定要实现Comparable接口,而且compareTo()方法,因为只有通过此方法才能知道大小关系,
但是需要提醒的是,如果你现在真实用了Comparable接口大小关系匹配的时候,你就需要当心自己给自己挖坑了,因为所有的属性必须全部比较参数,
范例:使用TreeSet排列
1 package cn.Tony.demo; 2 3 import java.util.Set; 4 import java.util.TreeSet; 5 6 class Person implements Comparable<Person>{ 7 private String name; 8 private Integer age; 9 public Person(String name,Integer age) { 10 this.name=name; 11 this.age=age; 12 } 13 @Override 14 public String toString() { 15 return "Person [name=" + name + ", age=" + age + "]"+" "; 16 } 17 @Override 18 public int compareTo(Person o) { 19 if(this.age>o.age) { 20 return 1; 21 }else if(this.age<o.age) { 22 return -1; 23 }else { 24 return this.name.compareTo(o.name); 25 } 26 } 27 } 28 29 public class TestDemo{ 30 public static void main(String[] args) throws Exception { 31 Set<Person> set=new TreeSet<Person>(); 32 set.add(new Person("张三",20)); 33 set.add(new Person("张三",20));//重复数据 34 set.add(new Person("李四",20));//年龄重复 35 set.add(new Person("王五",19)); 36 System.out.println(set); 37 } 38 }
因为在实际的开发中TreeSet的使用实在是过于麻烦了,在项目的开发里面,简单Java类是根据数据表设计来的,如果一张表的字段暴多,你这个类得写死。
重复元素判断
在使用TreeSet的子类进行数据保存的时候,重复元素的判断依靠的是Comparable接口完成的。但是这并不是全部Set接口重复元素的方式,因为如果使用的是HashSet子类,由于其跟Comparable没有任何关系,所以他判断元素的方式就依靠Object类中的两个方法:
hash码:public int hashCode()
对象比较:public boolean equals(Object obj)
在Java中进行对象比较的操作需要有两步:第一步要通过一个对象的唯一编码找到一个对象的信息,当编码匹配后在调用equals方法进行内容的比较。
1 package cn.Tony.demo; 2 3 import java.util.HashSet; 4 import java.util.Set; 5 6 class Person implements Comparable<Person>{ 7 private String name; 8 private Integer age; 9 public Person(String name,Integer age) { 10 this.name=name; 11 this.age=age; 12 } 13 @Override 14 public String toString() { 15 return "Person [name=" + name + ", age=" + age + "]"+" "; 16 } 17 @Override 18 public int compareTo(Person o) { 19 if(this.age>o.age) { 20 return 1; 21 }else if(this.age<o.age) { 22 return -1; 23 }else { 24 return this.name.compareTo(o.name); 25 } 26 } 27 @Override 28 public int hashCode() { 29 final int prime = 31; 30 int result = 1; 31 result = prime * result + ((age == null) ? 0 : age.hashCode()); 32 result = prime * result + ((name == null) ? 0 : name.hashCode()); 33 return result; 34 } 35 @Override 36 public boolean equals(Object obj) { 37 if (this == obj) 38 return true; 39 if (obj == null) 40 return false; 41 if (getClass() != obj.getClass()) 42 return false; 43 Person other = (Person) obj; 44 if (age == null) { 45 if (other.age != null) 46 return false; 47 } else if (!age.equals(other.age)) 48 return false; 49 if (name == null) { 50 if (other.name != null) 51 return false; 52 } else if (!name.equals(other.name)) 53 return false; 54 return true; 55 } 56 } 57 58 public class TestDemo{ 59 public static void main(String[] args) throws Exception { 60 Set<Person> set=new HashSet<Person>(); 61 set.add(new Person("张三",20)); 62 set.add(new Person("张三",20));//重复数据 63 set.add(new Person("李四",20));//年龄重复 64 set.add(new Person("王五",19)); 65 System.out.println(set); 66 } 67 }
如果要想标识出对象的唯一性,一定需要hashCode() equals()两个方法共同作用
面试题:如果两个对象的hashCode()相同 equals()不同结果是什么?不能
面试题:如果两个对象的hashCode()不相同 equals()相同是什么?不能消除
对象判断必须两个相同才能实现
在很多时候用Set集合的核心目的不是让其进行排序,而是让其进行重复元素的过滤,那么使用TreeSet就没有意义的,重复元素有需要依靠hashCode() equals()方法,如果不是必须的时候,在使用Set接口的时候尽量用系统提供的类去实现,
例如:String Integer
原则:
保存自定义类对象一定用List接口
保存系统类的信息的时候一定使用Set接口