Set集合

第八篇

Set集合

特点:无序,不重复。

存储时采用了hash算法机制,计算存储位置。

HashCode方法

Object是引用类型的父类,提供了hashCode()方法以及equals()方法,因此我们在定义类型时,一般都重写hashCode和equals方法。

重写的重要性:

equals方法我们用来判断集合中的元素是否重复,hashCode方法我们在使用Set集合时,必须要重写,因为,我们采用的hash算法计算Set集合元素的存储位置。

int hashCode():

Object提供的方法是通过地址计算hash值,不可控。

我们需要在自定义类中重写此方法。

重写原则:尽可能的让所有成员变量都参与运算尽可能的减少hash值的碰撞。            

public int hashCode(){

int result = 7;--定义一个局部变量,进行初始化

int prime = 53 --定义一个局部变量,赋值为素数

result = prime*result+field1;

result = prime*result+field2;

return result;

}

Set集合的遍历

因为Set集合是无序的,无下标可言,因此不能使用经典for循环。我们可以使用迭代器原理。

 (1) 调用集合的iterator()获取迭代器

 (2) 使用foreach循环

Set集合的元素

不能轻易修改参与hash值算法的成员变量,否则容易引起内存溢出。

原因:成员变量修改后,会出现新的hash值,但是存储位置还在原hash值的位置上。因此操作时,找不到具体的存储位置。                 

子类:

HashSet:无序,不重复,底层使用hash算法计算存储位置。增加删除时效率高 。   

LinkedHashSet:是HashSet的子类,底层使用hash算法计算存储位置,同时使用链表来维护顺序,顺序与添加顺序一致。在查看检索时,效率比较高。  

TreeSet:是SortedSet子接口的实现类,使用二叉树的数据结构维护元素的顺序。

 

Map接口:集合框架中的另一个父接口

Map集合:用于储存一一对应的元素数据,第一个对象可以作为索引,第二个对象作为值,我们称之为key-value,键值对。

储存数据的特点

 (1)以key-value形式进行存储。

 (2)key与value都必须是引用类型

 (3)key可以为null。

 (4)key与value是单向一对一映射。

 (5)key不能重复

存储机制

Map是基于数组和链表的数据结构进行存储数据。

作为key的对象采用了hash算法计算存储的数组 (散列数组,散列桶)的位置.如果计算出来的位置,数组中此位置没有元素,就可以添加到散列桶内,如果有元素,key的equals方法返回值为false,就会存储在散列桶元素对应的单向链表中。

如果key的equals方法返回true,就进行替换(覆盖)。

PS:使用Map集合,做为key的数据类型应该重写equals和HashCode方法  

常用方法:

V  put(K k,V v):作用:用于存储一对key-value.  返回被替换的value值,如果不是替换就返回null

V  get(K k):作用:通过key对象,获取对应的value对象,如果集合中没有此key,返回null

Map集合的遍历

Set<K>  keySet();

     用于获取Map中所有的key对象,返回一个Set集合

Set<Entry<K,V>>  entrySet();

     将key-value封装成内部类对象,返回Entry对象的Set集合                       

Collection<V> values();

     将map集合中的所有value封装到一个Collection集合中。

装载因子和HashMap的优化

装载因子:DEFAULT_LOAD_FACTOR = 0.75f

默认容量:DEFAULT_INITIAL_CAPACITY 

         16,就是数组的容量

   元素个数: size   

当我们创建一个HashMap对象时,底层数组的初始容量为16。当存储的数据的个数 size/DEFAULT_INITIAL_CAPACITY等于DEFAULT_LOAD_FACTOR时,数组开始扩容。此时最佳。

如果小于0.75扩容,比较占内存。

如果大于0.75扩容,操作的元素比较多。

public V put(K key, V value) {

  return putVal(hash(key), key, value, false, true);

}

--->

final V putVal(int hash, K key, V value, boolean onlyIfAbsent,boolean evict) {

/**/         

     Node<K,V>[] tab; Node<K,V> p; int n, i;

        if ((tab = table) == null || (n = tab.length) == 0)

            /* 没有存储元素,*/

            n = (tab = resize()).length;

        if ((p = tab[i = (n - 1) & hash]) == null)

            tab[i] = newNode(hash, key, value, null);

        else {

            Node<K,V> e; K k;

            if (p.hash == hash &&

                ((k = p.key) == key || (key != null && key.equals(k))))

                e = p;

            else if (p instanceof TreeNode)

                e = ((TreeNode<K,V>)p).putTreeVal(this, tab, hash, key, value);

            else {

                for (int binCount = 0; ; ++binCount) {

                    if ((e = p.next) == null) {

                        /* hash碰撞 */

                        p.next = newNode(hash, key, value, null);

                        if (binCount >= TREEIFY_THRESHOLD - 1) // -1 for 1st

                            treeifyBin(tab, hash);

                        break;

                    }

                    if (e.hash == hash &&

                        ((k = e.key) == key || (key != null && key.equals(k))))

                        break;

                    p = e;

                }

            }

            if (e != null) { // existing mapping for key

                V oldValue = e.value;

                if (!onlyIfAbsent || oldValue == null)

                    e.value = value;

                afterNodeAccess(e);

                return oldValue;

            }

        }

        ++modCount;

        if (++size > threshold)

            resize();

        afterNodeInsertion(evict);

        return null;

    }

         

      内部类Node,封装了一个key-value数据,同时还存储了下一个节点的引用 。 

  static class Node<K,V> implements Map.Entry<K,V> {

        final int hash;

        final K key;

        V value;

        Node<K,V> next;



        Node(int hash, K key, V value, Node<K,V> next) {

            this.hash = hash;

            this.key = key;

            this.value = value;

            this.next = next;

        }                  

 

Map接口的子类:

HashMap与HashTable的区别

   (1)HashTable是一个古老的类。不建议使用

   (2)HashTable是一个线程安全的类,HashMap线程不安全

   (3)HashTable的key不能是null,HashMap可以是null

LinkedHashMap:是HashMap子类,使用链表来维护key-value的顺序,在迭代时顺序与添加顺序一致。

TreeMap

是SortedMap子接口的实现类,使用了二叉树的数据结构维护 填入集合的顺序。

    (1)自然排序:

      往TreeMap里添加的key对象,可以实现Comparable接口。重写 compareTo方法

    (2)定制排序:做为key对象的数据类型,可以不实现Comparabel接口。

需要创建一个比较器Comparator对象,实现compare方法

Properties:

是HashTable的子类型,用于封装属性文件的key-value信息,因为在文件里写的都是字符串,因此Properties的key与value都是字符串类型

 

File类型

   java.io.File类型,可以对硬盘上的文件以及目录,进行操作。

      如查看文件/目录的属性信息,创建,删除文件/目录。此类型不能查看和修改文件里的内容。

常用构造器:

   File(String pathname):

            指定一个路径,创建一个File对象

路径:

            (1)文件的路径,要写到文件的扩展名为止

            (2)目录的路径,要写到当前目录的名称为止         

    

常用方法:

 boolean exists():判断指定的路径是否存在

  boolean isFile();判断指定路径是不是文件

boolean isDirectory();判断指定路径是不是目录

String getName());获取文件/目录名称

long lastModified();获取文件/目录的最后修改时间

boolean isAbsolute();判断指定路径是不是绝对路径

String getAbsolutePath();获取绝对路径

String getParent();获取父目录的路径

long length();获取文件大小文件/目录创建方法:

boolean createNewFile();创建文件

boolean mkdir();创建目录

boolean mkdirs();创建多级目录

文件/目录的删除方法

boolean delete()

       可以删除文件,删除目录时,需要目录下没有文件或子目录

File[] listFiles()

    获取目录里的file对象

javaBean规范:程序开发者默认遵循的一种规范

    (1)提供两个构造器

    (2)给成员变量提供get/set方法

       String name

       getName()

       setName(String name);

       Bean:豆子的意思,get/set方法名上的后续单词称之为bean.

                     在命名方法时,作为bean的单词首字母要大写,成员变量要尽可能的与bean名一致,首字母小写。

    (3)重写hashCode方法和equals方法

    (4)重写toString()       

 

递归:

递归思想:分成递与归。一层层递进,最后再一层层归。

两种递归

      (1) 方法调用自己   

      (2)  方法A调用方法B,方法B调用A

  举例:

     n*(n-1)*......*1                   

 

 z = f(n) 计算n的阶乘

   = n*f(n-1)

   = n*(n-1)*f(n-2)

   = n*(n-1)*......*1

   

   f(n)是一个函数:

           里的逻辑:

            n*f(n-1)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值