Java类集框架

  类集实际上就属于动态对象数组,那么在实际的开发之中数组的概念出现的几率并不高,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 + "]"+"\n";
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 + "]"+"\n";
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接口

posted on 2019-03-19 21:22  朽木zidiao  阅读(167)  评论(0编辑  收藏  举报

导航