Java 集合

学习廖雪峰的网站中java集合部分和其他资料中集合部分的学习记录。

List

 

1、在java9中添加了List新的初始化方法:List<> list = List.of();但是使用这种方法初始化的list是定长的,不能在使用add()函数添加元素,返回的list是只读的。

2、遍历list的方法最高效的是使用Iterator。

public class Main {

        public static void main(String[] args) {

                List<String> list = List.of("apple", "pear", "banana");

                for (Iterator<String> it = list.iterator(); it.hasNext(); ) {

                        String s = it.next();

                        System.out.println(s);

                }

        }

}

要记住,通过Iterator遍历List永远是最高效的方式。并且,由于Iterator遍历是如此常用,所以,Java的for each循环本身就可以帮我们使用Iterator遍历。

3、List to array的方法

第一种:直接调用toArray()

        List<String> list = List.of("apple", "pear", "banana");

        Object[] array = list.toArray();

这种方法会丢失类型信息,所以实际应用很少。

第二种:

toArray(T[])传入一个类型相同的ArrayList内部自动把元素复制到传入的Array中:

        List<Integer> list = List.of(12, 34, 56);

        Integer[] array = list.toArray(new Integer[3]);

第三种:

实际上可以传入其他类型的数组,例如我们传入Number类型的数组,返回的仍然是Number类型:

        List<Integer> list = List.of(12, 34, 56);

        Number[] array = list.toArray(new Number[3]);

但是,如果我们传入类型不匹配的数组,例如,String[]类型的数组,由于List的元素是Integer,所以无法放入String数组,这个方法会抛出ArrayStoreException

如果我们传入的数组大小和List实际的元素个数不一致怎么办?根据List接口的文档,我们可以知道:如果传入的数组不够大,那么List内部会创建一个新的刚好够大的数组,填充后返回;如果传入的数组比List元素还要多,那么填充完元素后,剩下的数组元素一律填充null。

一种简洁的写法:Integer[] array = list.toArray(Integer[]::new); //也是java8之后的写法,具体 开始的版本还没有查到

4、array to list

第一:jdk11之前,使用Arrays.asList(),但是这种方法返回的并不是ArrayList或者LinkedList。他返回的list实际上是在Arrays中的一个内部ArrayList类,如果执行正常ArrayList一些操作会报java.lang.UnsupportedOperationException错误。

第二:jdk11之厚,直接使用List.of()就行。

第三种:使用流操作。如果array是Integer[],

        Arrays.stream(array)

                .collect(Collectors.toList())

如果是int[],

        Arrays.stream(array)

                .boxed()

                .collect(Collectors.toList())

 

 

编写equals

如何正确编写equals()方法?equals()方法要求我们必须满足以下条件:

  • 自反性(Reflexive):对于非null的x来说,x.equals(x)必须返回true;
  • 对称性(Symmetric):对于非null的x和y来说,如果x.equals(y)为true,则y.equals(x)也必须为true;
  • 传递性(Transitive):对于非null的x、y和z来说,如果x.equals(y)为true,y.equals(z)也为true,那么x.equals(z)也必须为true;
  • 一致性(Consistent):对于非null的x和y来说,只要x和y状态不变,则x.equals(y)总是一致地返回true或者false;
  • 对null的比较:即x.equals(null)永远返回false。

因此,我们总结一下equals()方法的正确编写方法:

  1. 先确定实例“相等”的逻辑,即哪些字段相等,就认为实例相等;
  2. 用instanceof判断传入的待比较的Object是不是当前类型,如果是,继续比较,否则,返回false;
  3. 对引用类型用Objects.equals()比较,对基本类型直接用==比较。

Map

 

  • HashMap=数组+链表+红黑树,访问速度快
  • HashMap扩容相关的属性:capacity:当前数组容量,始终保持2^n,可以扩容,扩容之后数组大小为当前的2倍。loadFactory:负载因子,默认为0.75.threshold:扩容的阈值,等于capacity*loadFactory。
  • 在Java8中,当链表中的元素超过8个以后,会将链表转换为红黑树。
  • TreeMap可排序,LinkedHashMap记录 插入顺序

 

遍历Map

第一种:对Map来说,要遍历key可以使用for each循环遍历Map实例的keySet()方法返回的Set集合,它包含不重复的key的集合:

public class Main {

    public static void main(String[] args) {

        Map<String, Integer> map = new HashMap<>();

        map.put("apple", 123);

        map.put("pear", 456);

        map.put("banana", 789);

        for (String key : map.keySet()) {

            Integer value = map.get(key);

            System.out.println(key + " = " + value);

        }

    }

}

第二种:

同时遍历keyvalue可以使用for each循环遍历Map对象的entrySet()集合,它包含每一个key-value映射:

public class Main {

    public static void main(String[] args) {

        Map<String, Integer> map = new HashMap<>();

        map.put("apple", 123);

        map.put("pear", 456);

        map.put("banana", 789);

        for (Map.Entry<String, Integer> entry : map.entrySet()) {

            String key = entry.getKey();

            Integer value = entry.getValue();

            System.out.println(key + " = " + value);

        }

    }

}

 

与List不同的是,Map存储的是key-value的映射关系,并且,它不保证顺序

 

Map的内部,对key做比较是通过equals()实现的,这一点和List查找元素需要正确覆写equals()是一样的,即正确使用Map必须保证:作为key的对象必须正确覆写equals()方法。

因此,正确使用Map必须保证:

 

  1. 作为key的对象必须正确覆写equals()方法,相等的两个key实例调用equals()必须返回true;
  2. 作为key的对象还必须正确覆写hashCode()方法,且hashCode()方法要严格遵循以下规范:
  • 如果两个对象相等,则两个对象的hashCode()必须相等;
  • 如果两个对象不相等,则两个对象的hashCode()尽量不要相等。

 

我们在计算hashCode()的时候,经常借助Objects.hash()来计算

 

EnumMap

如果作为key的对象是enum类型,那么,还可以使用Java集合库提供的一种EnumMap,它在内部以一个非常紧凑的数组存储value,并且根据enum类型的key直接定位到内部数组的索引,并不需要计算hashCode(),不但效率最高,而且没有额外的空间浪费。

 

TreeMap

还有一种Map,它在内部会对Key进行排序,这种Map就是SortedMap。注意到SortedMap是接口,它的实现类是TreeMap

SortedMap保证遍历时以Key的顺序来进行排序。

使用TreeMap时,放入的Key必须实现Comparable接口。StringInteger这些类已经实现了Comparable接口,因此可以直接作为Key使用。作为Value的对象则没有任何要求。

如果作为Key的class没有实现Comparable接口,那么,必须在创建TreeMap时同时指定一个自定义排序算法。

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值