Java--容器(Collection)(一)

容器这篇,我主要从理论理解角度写的,代码可能偏少,因为集合里的方法太多 了但是这些点都是写代码时应当注意的点。

一、层次结构

Java--容器(Collection)(一)_第1张图片
学完了面向对象部分,上述图的层次结构应该不生疏了,这里简单的做些说明。

  • Collection函数库与数组的区别:
    1). 数组的容量有限,而Collection库的容量而自己调整;
    2). Collection函数库只能用来存放对象,而数组没有这样的限制
    • Collection库是java中的集合框架,collection接口是这个集合框架中的根接口,Colletction代表一组对象.接口是一种规范.Collection接口是一组允许重复的没有顺序的对象;Collection接口下的set接口(不允许重复,无指定顺序,若重复则会覆盖)和list接口(允许重复,有序);Map接口是一组成对的键-值对象(key-value)不能有重复的key,但可有重复value,通过一个对象找另外一个对象.

二、分别介绍

1 . List的三个实现类
List接口里允许重复和有序
Java--容器(Collection)(一)_第2张图片
查看源码时我们会发现LinkedList里居然还有索引index,这是因为LinkedList类继承了Collection类
2. Set
Set接口里不允许重复,无指定顺序,若重复则会覆盖
- set接口虽然是Collection的子接口,但是其没有提供额外的方法, 猜想: hashSet类是数组+链表,TreeSet类是树
- TreeSet实现的Set接口,故数据元素不可重复(这里去除重复的方式是比较元素是否等于0,故这里无需重写hashCode和equals方法),另外TreeSet的元素是排序的。(对比:HashSet的元素必须重写hashCode和equals方法)

public class Person {                                   
    private String name;// 名称 
    private int age;// 年龄 

    public Person() {                                   
        super();                                        
        // TODO Auto-generated constructor stub 
    }                                                   
    public Person(String name, int age) {               
        super();                                        
        this.name = name;                               
        this.age = age;                                 
    }                                                   
    public String getName() {                           
        return name;                                    
    }                                                   
    public void setName(String name) {                  
        this.name = name;                               
    }                                                   
    public int getAge() {                               
        return age;                                     
    }                                                   
    public void setAge(int age) {                       
        this.age = age;                                 
    }                                                   
    @Override                                           
    public String toString() {                          
        return "姓名:" + name + ", 年龄:" + age + "\n";         }                                                   
}   

public class TestTreeSet {
    public static void main(String[] args) {
        Person p1 = new Person("张三", 33);
        Person p2 = new Person("李四", 22);
        Person p3 = new Person("王五", 44);
        Person p4 = new Person("赵六", 66);

        // 依次存放到TreeSet容器中,使用排序业务类
        TreeSet<Person> persons = new TreeSet<Person>(
                new Comparator<Person>(){
                    @Override
                    public int compare(Person o1, Person o2) {
                        return o1.getAge() - o2.getAge();
                    }
                });
        persons.add(p1);
        // TreeSet在添加数据的时候一边添加一边排序
        // 而Collections.sort方式是在数据添加完后再排序
        persons.add(p2);
        persons.add(p3);
        persons.add(p4);
        System.out.println(persons);

        // TreeSet数据的更改不会影响排序,因为数据是一边添加一边排序的
        p4.setAge(0);
        System.out.println(persons);

        // TreeSet数据的更改不会影响排序,导致更改可能出现数据的重复,而此时已经无法检测了。
        // 因此建议使用TreeSet时不要随意修改数据,此时可以使用final关键字来避免失误
        p3.setName("张三");
        p3.setAge(33);
    }
}



public class Person {                                      
    private final String name;// 名称 
    private final int age;// 年龄 

    public Person() {                                      
        super();                                           
        name = null;// 添加了final关键字必须初始化一个值 
        age = 0;                                           
    }                                                      
    public Person(String name, int age) {                  
        super();                                           
        this.name = name;                                  
        this.age = age;                                    
    }                                                      
    // 添加了final关键字,无法提供set方法来修改数据 
    public String getName() {                              
        return name;                                       
    }                                                      
    public int getAge() {                                  
        return age;                                        
    }                                                      
}                

TreeSet确保元素实体可以排序,排序的比较器是public Treeset(Comparator<? super E>comparator)

3 . Map
(1). 底层实现是:数组+链表(例如LinkedList[] arr = new LinkedList[9]);
(2). Java中没有指针,但是可以通过个对象(即创建的节点)的属性来保存相关连接关系,其中key和value都可以是任何引用类型的数据;
(3). hashCode()是根据每个对象的地址生成的一个哈希码,每个对象的地址唯一,所以这个哈希码也唯一;
(4). 对于hashCode()与equals()配套重写的原因说明:java中规定两个对象的内容相同时(即euqals()为true时)其hashCode一定也得相同,所以hashCode和equals方法是得同时重写的;
(5). 重头戏:其子类HashMap和HashTable

  • 常用方法的注意点:
    A. put(成对存放)和putAll();
    B. get():get()方法是通过equals来进行对象比较的,返回的是Object,转型时必须转型为相应的值的对象类型;
    C. remove();
    D. containKey(是否包含key),containValue(是否包含value)

  • HashTable和HashMap的区别
    -1. 线程安全性:HashTable中的方法是同步的,而HashMap中的方法在缺省的情况下是非同步的,即HashTable较HashMap是线程安全的。在多线程并发的情况下,HashTable可以直接使用,而HashMap需要自己增加同步处理,即HashMap是Hashtable的轻量级实现。
    -2. 继承不同:public class Hashtable extends Dictionary implements Map;
    public class HashMap extends AbstractMap implements Map
    -3. key-value的null值问题:Hashtable中,key和value都不允许出现null值;而在HashMap中,null可以作为键,这样的键只有一个;可以有一个或多个键所对应的值为null。当get()方法返回null值时,即既可以表示 HashMap中没有该键,也可以表示该键所对应的值为null。因此,在HashMap中不能由get()方法来判断HashMap中是否存在某个键, 而应该用containsKey()方法来判断。
    -4. 遍历方式不同:Hashtable使用了 Iterator;HashMap也使用了Iterator,而由于历史原因,Hashtable还使用了Enumeration的方式 。
    -5. 哈希值的使用不同:HashTable直接使用对象的hashCode。而HashMap重新计算hash值。
    -6. 扩容方式不同:Hashtable和HashMap它们两个内部实现方式的数组的初始大小和扩容的方式。HashTable中hash数组默认大小是11,增加的方式是 old*2+1。HashMap中hash数组的默认大小是16,而且一定是2的指数。
    (6). TreeMap:与Set一样,Map中也有排序的类TreeMap

  • 确保Key可以排序
  • 提供key比较器:public TreeMap(Comparator

你可能感兴趣的:(Java--容器(Collection)(一))