黑马程序员-集合框架(Map和Collections)

——Java培训、Android培训、iOS培训、.Net培训、期待与您交流!——-

一、概述

Map是一种存储键值对的存储容器,而且保证键的唯一性。提供一种以“键”标识“值”的数据存储方式。接口形式为:Map<K,V>,其中K是此映射所维护的键的类型,V是映射值的类型。其有两个常用子类,HashMapTreeMap,另有HashTableHashMap功能类似,是早期版本。三者特点与不同如下:

  • HashMap:JDK1.2版本出现,底层使用哈希表数据结构,允许使用null作为键值和null值,线程非同步。
  • TreeMap:JDK1.2版本出现,底层使用二叉树数据结构,可用于按照键值排序,线程非同步。
  • Hashtable:JDK1.0版本出现,底层使用哈希表数据结构,不允许使用null作为键值,也不允许null作为值,线程同步。

HashMapHashtable的键值需要实现hashCodeequals功能,应为键值是唯一的,如同在HashSet中添加元素一样,因为底层为哈希表结构。

Collections是集合框架中的工具类,其内部有全是一些静态的方法,可以直接使用,如sort(List<T> list)对列表进行排序,max(...)求最大值,min(...)求最小值,binarySearch(...)二分查找等。

二、Map中的共性方法

  • clear()清空Map。
  • containsKey(Object o)判断是否包含key。
  • containsValue(Object o)判断是否包含value。
  • put(K, V)添加键-值对。
  • putAll(Map<? extends K, ? extends V>)添加另一个集合的内容。
  • get(Object key)获取key对应的值。
  • size()获取大小。
  • values()获取所有的值。

keySetentrySet的应用

Map没有想ListSet的那种迭代器遍历方式,Map的遍历一般可以使用keySetentrySet两种方式。

使用keySet遍历Map,这种方式是先获取键的集合对象,然会遍历键的集合,最后根据键的获取对应的值。示例代码如下:

import java.util.*;

class Main {
    public static void main(String[] args) {
        HashMap<String, String> map = new HashMap<String, String>();
        map.put("hello", "hi");
        map.put("key1", "value1");
        map.put("key2", "value2");
        map.put("key3", "value3");

        // 取出键的集合
        Set<String> set = map.keySet();
        Iterator<String> it = set.iterator();
        // 遍历键的集合
        while(it.hasNext()) {
            String key = it.next();
            // 根据键获取值
            System.out.println("(" + key + "," + map.get(key) +")");
        }
    }
}
// 执行结果为
(key1,value1)
(key2,value2)
(key3,value3)
(hello,hi)

另一中Map的遍历方式是通过entrySet实现的。示例代码如下:

import java.util.*;
class Main {
    public static void main(String[] args) {
        HashMap<String, String> map = new HashMap<String, String>();
        map.put("hello", "hi");
        map.put("key1", "value1");
        map.put("key2", "value2");
        map.put("key3", "value3");

        // 取出键-值的集合
        Set<Map.Entry<String, String>> set = map.entrySet();
        // 遍历键-值集合
        Iterator<Map.Entry<String, String>> it = set.iterator();
        while(it.hasNext()) {
            Map.Entry<String, String> entry = it.next();
            // 通过getKey和getValue方法可获取键和值
            System.out.println("(" + entry.getKey() + "," + entry.getValue() +")");
        }
    }
}
// 执行结果为
(key1,value1)
(key2,value2)
(key3,value3)
(hello,hi)

Map使用自定义类作为键

每个学生对应一个地址,学生有姓名和年龄属性。姓名和年龄相同视为同一个学生。学生类Student需要完成hashCodeequals的方法功能,当hashCode的返回值相同且equals返回为true时,认为两个键是同一个键,内容的值被覆盖。可以看到结果无序,且Student(lisi1, 21)的值唯一为tianjin,示例代码如下:

import java.util.*;

class Student {
    private String name;
    private int age;
    Student(String name,int age) {
        this.name = name;
        this.age = age;
    }

    /**
     * 复写hashCode方法
     */
    public int hashCode() {
        return name.hashCode()+age*34;
    }

    /**
     * 复写equals方法
     */
    public boolean equals(Object obj) {
        if(!(obj instanceof Student))
            throw new ClassCastException("类型不匹配");
        Student s = (Student)obj;
        return this.name.equals(s.name) && this.age==s.age;
    }

    public String getName() {
        return name;
    }

    public int getAge() {
        return age;
    }

    public String toString() {
        return name+":"+age;
    }
}
class Main {
    public static void main(String[] args) {
        HashMap<Student, String> map = new HashMap<Student, String>();

        map.put(new Student("lisi1",21),"beijing");
        map.put(new Student("lisi1",21),"tianjin");
        map.put(new Student("lisi2",22),"shanghai");
        map.put(new Student("lisi3",23),"nanjing");
        map.put(new Student("lisi4",24),"wuhan");

        // 获取键-值集合
        Set<Map.Entry<Student,String>> entrySet = map.entrySet();
        // 获取键-值集合迭代器
        Iterator<Map.Entry<Student,String>> it = entrySet.iterator();
        // 遍历集合
        while(it.hasNext()) {
            Map.Entry<Student,String> entry = it.next();
            // 打印学生和对应的地址
            System.out.println(entry.getKey() + "/" + entry.getValue());
        }
    }
}
// 执行结果为
lisi4:24/wuhan
lisi2:22/shanghai
lisi1:21/tianjin
lisi3:23/nanjing

TreeMap使用简介

TreeSet类似,TreeSet是对值按一定顺序排序,而TreeMap则是对键进行按一定顺序排序。同样的,作为TreeMap键的类需要实现Comparable接口或者在创建TreeMap对象时指定比较器(实现Comparator接口的类)。下面通过一个实例来说明,例子内容为统计一串字符串中各个字母出现的次数,并按照字母顺序输出,这里自定义一个类CharKey作为键,让其实现Comparable接口,并覆写hashCode(不过这里用不到)与equals方法:

import java.util.*;
import java.lang.*;
class CharKey implements Comparable<CharKey> {
    private String key;
    public CharKey(char key) {
        this.key = String.valueOf(key);
    }

    public int compareTo(CharKey o) {
        return this.key.compareTo(o.getKey());
    }

    public String getKey() {
        return this.key;
    }

    // 用第一个字符的Unicode代码点作为哈希值
    public int hashCode() {
        return this.key.codePointAt(0);
    }

    // 判断字符是否相同
    public boolean equals(Object o) {
        if(!(o instanceof CharKey)) {
            throw new RuntimeException("类型不匹配");
        }
        CharKey key = (CharKey) o;
        return this.key.equals(key.getKey());
    }
}

class Main {
    public static void main(String[] args) {
        // 待统计字符串
        String str = "sdfgzxcvasdfxcvdf";

        // 创建TreeMap对象,CharKey作为键,Integer作为值
        TreeMap<CharKey, Integer> map = new TreeMap<CharKey, Integer>();

        // 扫描字符串,统计各个字母出现的次数
        for(int i=0; i<str.length(); i++) {

            // 构造第i个字母的键
            CharKey key = new CharKey(str.charAt(i));
            if(map.get(key) == null) { // 键不存在则是第一次,直接添加1
                map.put(key, 1);
            } else {
                // 键存在,则将值取出再加1放入
                map.put(key, map.get(key)+1);
            }
        }

        // 遍历统计的结果
        Set<Map.Entry<CharKey, Integer>> entrySet = map.entrySet();
        Iterator<Map.Entry<CharKey, Integer>> it = entrySet.iterator();
        while(it.hasNext()) {
            Map.Entry<CharKey, Integer> entry = it.next();
            CharKey key = entry.getKey();
            Integer value = entry.getValue();
            System.out.println(key.getKey()+"("+ value +")");
        }
    }
}
// 执行结果为
a(1)
c(2)
d(3)
f(3)
g(1)
s(2)
v(2)
x(2)
z(1)

三、Collections使用简介

Collectionsjava.util包中为集合框架提供的工具类,其内部全部是静态函数,如sort(对List进行排序),完全的定义为:public static <T extends Comparable<? super T>> void sort(List<T> list)也就是说T需要时实现Comparable接口,且T的父类实现了Comparable接口(即使用父类的排序方法),或者使用sort(List<T> list, Comparator<? super T> c)来指定比较器来实现自定义的数据比较。

import java.util.*;
class Main {
    public static void main(String[] args) {
        ArrayList<String> list = new ArrayList<String>();
        list.add("hello");
        list.add("z");
        list.add("haje");
        list.add("vssddda");
        list.add("abcdef");

        // 排序前的list
        System.out.println(list);

        Collections.sort(list);

        // 排序后的list
        System.out.println(list);
    }
}
// 执行结果如下(排序前后的list)
[hello, z, haje, vssddda, abcdef]
[abcdef, haje, hello, vssddda, z]

binarySearch的使用,使用binarySearch的前提必须对list进行排序,否则无法正常使用,其返回值为所查找的元素的位置,如果元素不存在,那么返回的为(-(插入点) - 1),如这个值为index,那么~index即为这个元素正在该插入的位置。同样binarySearch也可以指定自定义比较器。示例代码如下:

import java.util.*;
class Main {
    public static void main(String[] args) {
        ArrayList<String> list = new ArrayList<String>();
        list.add("hello");
        list.add("z");
        list.add("haje");
        list.add("vssddda");
        list.add("abcdef");

        Collections.sort(list);
        int index = Collections.binarySearch(list, "b");

        /* 返回值为元素的位置,如果不存在则返回负数index,
           然而~index则表示元素应该插入的位置 */
        System.out.println("Index:" + ~index);
    }
}

使用Collections.reverseOreder()获取,默认逆序比较器。或者Collections.reverseOrder(比较器)将指定比较器转化为逆序比较器。synchronizeCollection()synchronizedList()...使集合具有多线程访问能力,shuffle(List)将集合随机打乱等等。

四、Arrays使用简介

Arrays为数组操作的一个工具类,功能有asList()将数组转换为集合,但是不能对此集合进行增删操作,否则会报UnsupportedOperationException异常。

对基本数据类型和非基本数据类型的不同写法:

// 基本数据类型数组转集合
int[] nums = {1, 3, 2};
List<int[]> list = Arrays.asList(nums);

// 基本数据类型数组转集合
int[] strs = {"hello", "hi", "oo"};
List<String> list = Arrays.asList(strs);

集合转成数组,使用toArray(t[] t)方法可以将集合转为数组,这里的参数数组的大小如果小于list.size()那么方法会重新创建一个长度为list.size()大小的数组,然后返回,如果大于list.size(),那么会使用参数的数组,并将其返回,示例代码如下:

ArrayList<String> list = new ArrayList<String>();
list.add("hello");
list.add("hi");
String[] strs = list.toArray(new String[0]);

五、JDK1.5新特性

1.泛型:再上一篇集合框架已经介绍过了,即提高了程序的安全性。

2.增强for循环:格式为for(数据类型 变量:被遍历Collection或数组)。与传统for循环的区别在于,增强型for必须有被遍历的对象,且无法访问下标。示例代码如下:

ArrayList<String> list = new ArrayList<String>();
for(String s : list) {
    // 操作
}

int[] arr = {2, 3, 4};
for(int i : arr) {
    // 操作
}

3.自动装箱/自动拆箱:在上一篇博客已经介绍过。

4.可变参数:当方法的参数类型相同且不确定有多少个时,可以使用可变参数。注意:当还有其他参数时,可变参数必须放在参数列表的最后面,如show(String, int...),示例代码如下:

show(1, 2, 3);
show();
show(1, 2, 3, 4, 5, 6);

public void show(int... arr) {
    // arr就是一个数组
}

5.静态导入:如Arrays类内部全部是静态方法,可以将其直接导入使用,不需要再指明方法名,但是需要注意的是当有方法重名时,需要指明所属类,当类重名时,需要指明所属包。示例代码如下:

import java.util.*;
import static java.util.Arrays.*;
class Main {
    public static void main(String[] args) {
        int[] arr = {2, 4, 2, 1, 9, 8};
        // 直接调用Arrays内的静态方法sort
        sort(arr);
        System.out.println(Arrays.toString(arr));
    }
}

六、其他对象

  • System类,不能被实例化,内部全是静态方法,常用的有一些内部对象,如inout用于标准输入输出。一些系统相关方法,如currentTimeMillis()用于获取系统时间(1970年1月1日到现在的毫秒数),getProperties()获取虚拟机环境信息等。
  • Rumtime类,通过getRuntime()获取对象,可以通过Rumtime对象执行系统命令,如getRuntime().exec("cmd");,通过destory()杀掉进程等。
  • Date类,可以通过SimpleDateFormatDate类转变成自定义格式。
  • Calendar类,通过getInstance()获取实例,然后可以通过get(Calendar.YEAR)获取年份或者其他等。
  • Math类,一些常用方法ceil(double )上取整,floor(double )下取整,random()返回[0, 1)之间的浮点数值。
  • Random类,可以很方便地产生伪随机数。
时间: 2024-10-16 04:06:45

黑马程序员-集合框架(Map和Collections)的相关文章

黑马程序员-----集合框架类(三) Map集合

黑马程序员-----集合框架类(三) Map集合 1.1 Map集合:该集合存储键值对.一对一对往里存.而且要保证键的唯一性. 1,添加. put(K key, V value) putAll(Map<? extends K,? extends V> m) 2,删除. clear() remove(Object key) 3,判断. containsValue(Object value) containsKey(Object key) isEmpty() 4,获取. get(Object ke

黑马程序员-集合框架

集合:面向对象语言对事物的体现都是以对象的形式,所以为了方便对多个对象的操作,就对对象进行存储,集合就是存储对象最常用的一种方式. 集合框架: Java集合框架是指java的集合类.Collection 接口是一组允许重复的对象.Set 接口继承 Collection,但不允许重复,使用自己内部的一个排列机制. List 接口继承 Collection,允许重复,以元素安插的次序来放置元素,不会重新排列.Map接口是一组成对的键-值对象,即所持有的是key-value pairs.Map中不能有

黑马程序员-----集合框架类(一)

1.1 为什么出现集合类? 面向对象语言对事物的体现都是以对象的形式,所以为了方便对多个对象的操作,就对对象进行存储,集合就是存储对象最常用的一种方式. 1.2 数组和集合类同是容器,有何不同? 数组虽然也可以存储对象,但长度是固定的:集合长度是可变的.数组中可以存储基本数据类型,集合只能存储对象. 1.3 集合类的特点 集合只用于存储对象 集合长度是可变的 集合可以存储不同类型的对象. 1.4 集合框架的构成及分类: 2.1 Collection接口: Collection定义了集合框架的共性

黑马程序员-----集合框架类(四) 高级for循环、方法的可变参数及静态导入

1.1 高级for循环(示例1) 格式:for(数据类型 变量名 : 被遍历的集合(Collection)或者数组){ } 对集合进行遍历.只能获取集合元素.但是不能对集合进行操作. 迭代器除了遍历,还可以进行remove集合中元素的动作.如果是用ListIterator,还可以在遍历过程中对集合进行增删改查的动作. 1.1.2 传统for和高级for有什么区别呢? 高级for有一个局限性.必须有被遍历的目标. 1 示例1: 2 import java.util.*; 3 4 class For

黑马程序员——集合(map)

package com.yang.ex2; import java.util.Collection; import java.util.HashMap; import java.util.Map; /*集合Map:该集合存储键值对,一对一对的往里面存,而且要保证键的唯一性 * 1.添加 * put(K key ,V value) * putAll * 2.删除 * clear() * remove(Object key) * 3.判断 * containsKey/Value * boolean

黑马程序员——集合框架类总结

------Java培训.Android培训.iOS培训..Net培训.期待与您交流! ------- 为什么会出现集合类? Java语言是面向对象的语言,所有命令都是操作对象的,有集合类的出现就可以操作对象 数组和集合类的区别是什么呢? 数组中可以存储基本类型的数据,也可以存储对象,集合类只能存储对象 集合类的特点有什么? 集合只适用于存储对象,长度是可变化的,集合可以存储不同类型的集合. 集合类Collection接口,子类接口有List接口和Set接口,List接口下含有ArrayList

黑马程序员-集合框架(List和Set)

一.概述 集合是一种可变数据项的容器,具有统一的父类接口Collection<E>(Map并没有继承之),与其子集合的关系如下 图,集合的特点是长度可变,可以存储多种类型的对象(不加泛型时).这也是与数组的两点最大的不同. java集合类关系图 Collection最为根接口,List.Set.Queue接口均直接继承自它,Map接口虽然不是直接继承自Collection,但是接口中使用到了Collection,即Map的数据也是使用Collection存储的. 研究集合必不可少的是先研究Co

黑马程序员——集合框架(一)

package com.yang.ex; import java.util.ArrayList; /*集合类: * 面向对象语言的体现都在对象行使,为了方便对对象操作,集合就是最常见的储存对象 * * 数组与集合类的不同: * 数组的长度是固定的,并且类型是固定的的,但是集合的长度是可变的.数组中可以储存基本数据类型,但是集合智能存储对象 * * 集合类的特点: * 集合只用于储存对象,集合的长度是可变的.集合合一储存不同类型的对象 * 每一个容器对数据的存储方式都有不同 * 每一个存储方式称为

黑马程序员——集合基础知识(Map)

Map概念 要同时存储两个元素,他们之间有映射关系,每个键不能重复,每个键只能映射到一个值. 存储键值对,并且键是唯一的. 1.添加. put()如果添加的键原来有值,后添加的值会覆盖前面的值,并返回之前的值. 2.删除 remove()按键删除. 3.判断 4.获取 get(object key) size() value()拿值value返回的是值的集合... HashTable 底层是哈西数据结构,不可以存入null键null值,线程同步. HashMap 底层是哈西表数据结构,允许使用n