欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

JavaEE 集合 【vaynexiao】

程序员文章站 2024-03-02 22:55:34
...

概括

已学https://edu.51cto.com/course/17053.html汤小洋

集合相关的API都在java.util包中

顺序存储

将元素依次存入,空间分配是连续的,类似数组,有下标,访问效率高,插入和新增元素时后面的所有元素要重新进行处理,效率低,比如ArrayList
JavaEE 集合 【vaynexiao】

链式存储

  • 单向链式:每一个元素空间包括两部分,一份是真正的值,一部分是保存下一份元素的地址,插入和新增一个元素时只需要改变前后两个元素中的地址即可,所以效率高,而访问时需要根据地址顺藤摸瓜找到目标,所以效率低

  • 双向链式:与单向链式相似,比单向链式多一个前一元素地址。
    JavaEE 集合 【vaynexiao】
    JavaEE 集合 【vaynexiao】

List

有序、可重复
ArrayList、LinkedList、Vector、Stack 区别
ArrayList (动态数组),因为基于数组,有下标,所以查询快,但增删较慢,线程同步不安全
LinkedList(双向链表),因为基于链表,访问时要移动指针,查询慢,但正因为链表结构所以增删快
Vector(动态数组),crud都慢,被ArrayList替代。线程异步安全
Stack(堆栈),继承于Vector,先进后出

ArrayList

ArrayList是一个可变长数组,插入数据时,则需要先将原始数组中的数据复制到一个新的数组,随后再将数据赋值到新数组的指定位置(如下图);删除数据时,也是将原始数组中要保留的数据复制到一个新的数组
JavaEE 集合 【vaynexiao】

ArrayList list = new ArrayList();//不指定类型,默认Object
list.add("tom");
list.add(18);
list.add(120.5);
list.add(true);
list.add(new Object());
list.add(null);
List<String> list2 = new ArrayList<>();//指定类型
list2.add("tom");
ArrayList<String> list = new ArrayList<String>();
 
// add() 添加元素
list.add("tom"); // 向末尾添加,有序(元素顺序与放入顺序一致)
list.add("jack");
list.add("mike");
list.add("tom"); // 允许重复
list.add(2, "alice"); // 向指定索引位置插元素,索引从0开始
 
// set() 修改
String str = list.set(0, "lucy"); // 返回被修改的元素,即原来的元素
 
// remove() 删除
boolean flag = list.remove("tom"); // 根据元素值删除,如果有多个相同值,第一个元素,返回boolean,表示成功或失败
String str = list.remove(1); // 根据索引删除,返回被删除的元素
 
// get() 获取
System.out.println(list.get(1)); // 根据索引获取
 
// size() 集合大小/长度,即元素个数
System.out.println(list.size()); 
 
// isEmpty() 是否为空
System.out.println(list.isEmpty());
System.out.println(list.size() == 0);
 
// indexOf() 指定元素在集合中的索引,如果不存在,则返回1(底层使用equals判断,必要时要重写该方法)
System.out.println(list.indexOf("tom")); //第一次出现的位置
System.out.println(list.lastIndexOf("aaa")); //最后一次出现的位置
 
// contains() 是否包含指定元素 (底层使用equals判断,必要时要重写该方法)
System.out.println(list.contains("aaa")); //boolean
 
// clear() 清空
list.clear();
 
// toArray() 将list转换为数组
Object[] arr = list.toArray();  //对象数组
System.out.println(Arrays.toString(arr));
 
// 将数组转换为list 
String[] arr = { "aaa", "bbb", "ccc" }; 
List<String> list2 = Arrays.asList(arr);
List<String> list3 = Arrays.asList("aaa", "bbb", "ccc");
 
// 遍历
List<Integer> list = Arrays.asList(12, 4, 65, 8, 2); 
// 方式1 
for (int i = 0; i < list.size(); i++) { 
    System.out.print(list.get(i)+"\t"); 
}
System.out.println(); 
// 方式2 
for(Integer num:list){ 
    System.out.print(num+"\t"); 
}
System.out.println();
// 方式3,使用Iterator迭代器,用于遍历集合中所有元素的一种类型(只要实现了Iterable接口的类都可以使 用迭代器进行遍历) 
Iterator<Integer> it = list.iterator(); 
while(it.hasNext()){ 
    // 判断是否有下一个元素 
    Integer num = it.next(); //获取下一个元素 
    System.out.print(num+"\t"); 
}

LinkedList

既然LinkedList是一个由相互引用的节点组成的双向链表,那么当把数据插入至该链表某个位置时,该数据就会被组装成一个新的节点,随后只需改变链表中对应的两个节点之间的引用关系,使它们指向新节点,即可完成插入(如下图);同样的道理,删除数据时,只需删除对应节点的引用即可。

因此,在添加或删除数据的时候,ArrayList经常需要复制数据到新的数组,而LinkedList只需改变节点之间的引用关系,这就是LinkedList在添加和删除数据的时候通常比ArrayList要快的原因

因为是双向链式存储,所以当需要频繁的插入和删除元素时可以使用LinkedList,但访问较慢

常用方法:具有List的所有方法,同时具有一些额外的方法

LinkedList是一种队列,实现Queue接口,所有实现Queue的类都是一个队列

先进先出
JavaEE 集合 【vaynexiao】

LinkedList<String> s = new LinkedList<String>();
s.add("11");//stack add和push作用类似
s.add("22");
s.add("33");
s.addFirst("first");
s.addLast("last");//直接插入到最后一个,但如果后面继续添加爱元素就不是最后一个了
s.add("44");
System.out.println(s.get(0));//根据index获取
System.out.println(s.getFirst());
System.out.println(s.getLast());
System.out.println(s.get(s.size()-1));
System.out.println(s.remove());//删除第一个
System.out.println(s.removeFirst());
System.out.println(s.removeLast());

Vector

Vector和ArrayList非常相似,都是使用数组实现的,用法基本相同

Vector:
1,同步的,线程安全,方法基本都是被synchronized关键字修饰的
2,因为是同步的,所以执行效率低,影响性能
3,可以使用Iterator或Enumeration遍历
ArrayList:
1,异步的,线程不安全
2,因为是异步的,所以相比较Vector,执行效率高
3,不能使用Enumeration遍历

Vector已过时,不建议使用,为了安全时,作为替代可以使用Collections.synchronizedList

遍历方法:for、foreach、Iterator、Enumeration(建议使用Iterator)

/*
* 使用Enumeration枚举,适用于Vector、Hashtable、Properties等集合,已过时
*/
Enumeration<Integer> e = nums.elements();
while (e.hasMoreElements()) { // 判断是否还有更多元素
    Integer num = e.nextElement(); // 获取元素
    System.out.print(num + "\t");
}

Stack

Stack继承自Vector
特点:先进后出
常用方法:具有List的所有方法,同时具有栈的操作方法
JavaEE 集合 【vaynexiao】

    Stack<String> s = new Stack<String>();
    s.add("a");//stack add 和 push 作用类似
    s.push("b");
    s.push("c");
    System.out.println(s.firstElement());//由于 Stack 是先进后出,取第一个元素用此特殊方法
    System.out.println(s.peek());//查看栈顶元素,并不会弹出
    System.out.println(s.pop());//出栈,取出栈顶元素
    System.out.println(s.pop());
    System.out.println(s.empty());//false

Set

特点:
无序(元素顺序与放入顺序无关),不能按索引访问元素
不可重复(集合中不允许出现重复的元素)
实现类:HashSet、TreeSet

实现类:HashSet、TreeSet

Set里的元素是不能重复的,那么用什么方法来区分重复与否呢?是用==还是equals()?它们有何区别?用contains来区分是否有重复的对象,还是都不用。
在比较时先调用hashCode方法,如果不相同,证明不相等。
如果相同,再调用equals方法,如果equals方法相同,证明相等,不相同,证明不相等。

HashSet

HashSet是一种哈希算法的集合,以哈希表的形式存储
数据结构:哈希表(哈希散列表)
JavaEE 集合 【vaynexiao】
特点:操作速度更快,效率更高,根据哈希算法进行快速的查找(根据hashCode()方法的返回值,确定其存放位置)

HashSet判断元素是否重复的过程:
1. 添加元素时首先调用要存入对象的hashCode()方法,获取hashCode值
2. 根据hashCode值,使用哈希算法确定在哈希表中的存放位置
3. 判断该位置是否已经有元素:
如果该位置没有元素,则直接将元素放入该位置 ——>结束
如果该位置已经有元素,则调用已有对象的equals方法和要放入的对象进行比较:
如果返回true,则认为是重复元素,舍弃要放入的元素 ——>结束
如果返回false,则在当前位置下,以链表的形式追加 ——>结束
总结:
1,判断重复的依据:当添加的两个元素的hashCode()返回值相同,并且equals()返回值为true,则认为是重复的相同元素
2,向Set集合中添加元素时,需要重写hashCode()和equals()方法,防止相同元素被添加到Set集合中

HashSet<String> set = new HashSet<String>();
set.add("aaa"); // 无序
set.add("bbb");
set.add("ccc");
set.add("ddd");
set.add("aaa"); // 相同的元素不会添加到set集合中
System.out.println(set);
 
//Set集合不能按索引访问,即没有get(index)方法,因为元素的存储顺序是无序的,
//不保证元素的顺序与放入的顺序一致,所以没有索引
/*
 * 常用方法
 */
// size()、isEmpty()、clear()、remove、contains()、iterator()、toArray()
// addAll() 将list转换为set
List<String> list = Arrays.asList("a", "b", "c", "a", "b", "a");
set.addAll(list);//(当set为空时,addAll一个list可以达到去重作用)
HashSet<String> set2 = new HashSet<String>(list);//单参构造
System.out.println(set2);
 
// 判断元素是否重复,是根据hashcode值,没有重写hashcode方法时默认使用object的hashcode方法,获取到的是内存地址,
Set<Student> set=new HashSet<Student>();
Student s1 = new Student(1001, "tom");
Student s2 = new Student(1001, "tom");
set.add(s1);
set.add(s2);
System.out.println(set);
 
student这种引用类必须重写hashcode和equals方法
@Override
public int hashCode() {
    System.out.println("Student.hashCode()");
    final int prime = 31;
    int result = 1;
    result = prime * result + ((name == null) ? 0 : name.hashCode());
    result = prime * result + no;
    return result;
}
@Override
public boolean equals(Object obj) {
    System.out.println("Student.equals()");
    if (this == obj)
        return true;
    if (obj == null)
        return false;
    if (getClass() != obj.getClass())
        return false;
    Student other = (Student) obj;
    if (name == null) {
        if (other.name != null)
            return false;
    } else if (!name.equals(other.name))
        return false;
    if (no != other.no)
        return false;
    return true;
}

TreeSet

TreeSet是用于对元素进行排序的有序集合类,不允许有重复的元素,与插入顺序无关,插入后会排序
数据结构:二叉树

TreeSet会对元素进行排序,排序的依据:
1. 元素本身具有的自然顺序(按照ASCII码排序)
让引用类型对象实现 Comparable 接口,实现compareTo()方法,让对象自身具有可比较性
2. 提供一个比较器,根据比较器进行排序
定义一个比较器,实现 Comparator 接口的类,实现compare()方法
在创建TreeSet时传入比较器
注意:两种排序依据同时存在,优先比较器

TreeSet判断重复的依据:当添加的两个元素的compareTo()返回值为0时,则认为是相同元素

       /*
     * User类要实现接口,implements Comparable<User>,重写compareTo()方法,指定比较的方式
     * 升序:如果该对象大于、小于或等于指定对象,则分别返回正整数、负整数或零
     * 降序:如果该对象大于、小于或等于指定对象,则分别返回负整数、正整数或零
     */
    @Override
    public int compareTo(User o) {
        // 根据年龄比较,升序
        if(this.age>o.getAge()){
            return 1;
        }else if(this.age<o.getAge()){
            return -1;
        }else{
            //如果年龄相同,则按分数比较,降序
            if(this.score>o.getScore()){
                return -1;
            }else if(this.score<o.getScore()){
                return 1;
            }else{
                //如果分数相同,则按姓名比较
                return this.name.compareTo(o.getName()); //调用String中的compareTo()方法
            }
        }
    }
TreeSet<User> set = new TreeSet<User>(new UserComparator()); // 传入比较器
set.add(new User("aaa", 24, 90));
set.add(new User("bbb", 21, 92));
set.add(new User("ccc", 18, 60));
set.add(new User("ddd", 28, 89));
set.add(new User("eee", 21, 99));
set.add(new User("fff", 21, 99));
System.out.println(set);
        
/*
 * 自定义一个比较器,用来比较User对象
 */
public class UserComparator implements Comparator<User> {
    @Override
    public int compare(User u1, User u2) {
        // 根据分数进行比较,降序
        if(u1.getScore()>u2.getScore()){
            return -1;
        }else if(u1.getScore()<u2.getScore()){
            return 1;
        }
        return 0;
    }
}

Map

Map是专门用来处理 键值映射数据 的一种集合,可以根据key键实现对value值的操作

  • 是一种映射关系,称为键值对(keyvalue)
  • key必须是唯一,不允许重复, 一个key只能对应一个value,但一个value可以有多个key与之对应
  • 不保证元素的顺序与插入的顺序一致,不能按索引访问元素
    实现类:HashMap、Hashtable、Properties
    HashMap TreeMap Hashtable LinkedHashMap区别
    HashMap: 异步处理,性能高,非线程安全操作,具有很快的访问速度。最多只允许一条记录的key为Null(多条会覆盖);允许多条记录的value为 Null,HashTable相反。
    TreeMap:是有序的,能够把它保存的记录根据键(key)排序,默认升序,也可以指定排序的比较器,当用Iterator 遍历TreeMap时,得到的记录是排过序的。因为要排序所以TreeMap不允许key的值为null,value可以为空。非同步的。要排序就要实现compare接口很麻烦。一般不用。
    Hashtable:与 HashMap类似,不同的是:key和value的值均不允许为null;它支持线程的同步,也就是任一时刻只有一个线程能写Hashtable,因此也导致了Hashtale在写入时会比较慢。
    LinkedHashMap:保存了记录的插入顺序,在用Iterator遍历LinkedHashMap时,先得到的记录肯定是先插入的.在遍历的时候会比HashMap慢。key和value均允许为空,非同步的。
    JavaEE 集合 【vaynexiao】

map的key使用自定义类的对象时

此时必须覆写hashCode(),equals(),建议使用String Interger,这两个类已经覆写过了,所以工作中频繁使用。

API

clear() 从 Map 中删除所有映射
remove(Object key) 从 Map 中删除键和关联的值
put(Object key, Object value) 将指定值与指定键相关联
putAll(Map t) 将指定 Map 中的所有映射复制到此 map
entrySet() 返回 Map 中所包含映射的 Set 视图。Set 中的每个元素都是一个 Map.Entry 对象,可以使用 getKey() 和 getValue() 方法(还有一个 setValue() 方法)访问后者的键元素和值元素
keySet() 返回 Map 中所包含键的 Set 视图。删除 Set 中的元素还将删除 Map 中相应的映射(键和值)
values() 返回 map 中所包含值的 Collection 视图。删除 Collection 中的元素还将删除 Map 中相应的映射(键和值)
get(Object key) 返回与指定键关联的值
containsKey(Object key) 如果 Map 包含指定键的映射,则返回 true
containsValue(Object value) 如果此 Map 将一个或多个键映射到指定值,则返回 true
isEmpty() 如果 Map 不包含键-值映射,则返回 true
size() 返回 Map 中的键-值映射的数目

HashMap

HashMap是一种基于哈希算法的Map集合,以哈希表形式存储

  • 数据结构:哈希表
  • 特点:查找元素时效率高
Map<Integer,String> map = new HashMap<Integer,String>();
    map.put(001, "张三");
    map.put(002, "李四");
    map.put(003, "王五");
       map.put(null, null); // key-value都可以为null
    map.put(001, "赵六"); // key是唯一的,当key已存在时表示修改对应key的value
// get() 获取
String value = map.get(5); // 根据key获取对应的value
System.out.println(value);
// remove() 删除
map.remove(2); //根据key删除对应的键值对
// containsKey() 判断是否包含指定的key
System.out.println(map.containsKey(11));
// containsValue() 判断是否包含指定的value
System.out.println(map.containsValue("xxx"));
// isEmpty() 判断是否为空
System.out.println(map.isEmpty());
// size() 元素个数
System.out.println(map.size());
// clear() 清空
map.clear();
 
遍历HashMap的三种方式:
    通过keySet()获取所有key的集合,然后遍历所有的key
    通过values()获取所有value的集合,然后遍历所有的value
    通过entrySet()获取所有的key-value的集合,然后遍历所有的key-value键值对
HashMap<Integer, Student> map = new HashMap<Integer, Student>();
Student stu1 = new Student(1001, "tom");
Student stu2 = new Student(1002, "jack");
Student stu3 = new Student(1003, "mike");
// 将学号作为key,将学生对象作为value
map.put(stu1.getNo(), stu1);
map.put(stu2.getNo(), stu2);
map.put(stu3.getNo(), stu3);
 
 
// 方式1:遍历所有的key
for (Integer key : map.keySet()) {
    Student value = map.get(key);
    System.out.println("key:" + key + ",value:" + value);
}
 
// 方式2:遍历所有的value
for (Student value : map.values()) {
    System.out.println(value);
}
 
/*
* 方式3:遍历所有的key-value
* Map.Entry就表示key-value
* 返回一个Set集合,Set集合的泛型是Map.Entry类型
* Map.Entry(Entry接口是Map接口的内部接口)的泛型是Map集合的泛型
Map.Entry是Map声明的一个内部接口,此接口为泛型,定义为Entry<K,V>。它表示Map中的一个实体(一个key-value对)。
接口中有getKey(),getValue方法,效率高,以后尽量使用这种方式。
*/
Set<Map.Entry<Integer, Student>> entries = map.entrySet();
Iterator<Entry<Integer, Student>> it = entries.iterator();
while(it.hasNext()){
    Entry<Integer, Student> entry = it.next(); //获取Entry(key、value)
    Integer key = entry.getKey();
    Student value = entry.getValue();
    System.out.println("key:"+key+",value:"+value);
}
面试题:统计一个字符串中每个字符出现的次数
String str = "asdfjk2348ujysdjf89234-8-asjsf";
        
//定义map  integer保存出现的次数
Map<String, Integer> map = new HashMap<String, Integer>();
 
// 方式1  for循环逐个进行统计
for (int i = 0; i < str.length(); i++) {
    String c = str.charAt(i) + "";
    if (!map.containsKey(c)) {
        // 如果从示出现过,则次数指定为1
        map.put(c, 1);
    } else {
        // 如果出现该字符,则次数+1
        int count = map.get(c);//第一次出现时value为1
        count++;//以后就每次+1
        map.put(c, count);
    }
    //map.put(c, map.containsKey(c)?map.get(c)+1:1);
}
System.out.println(map);
 
// 方式2    取出第一个字符,然后变化的长度就是该字符出现次数
while(!str.isEmpty()){
    String c = str.charAt(0)+"";
    String newStr = str.replace(c, "");
    map.put(c,str.length()-newStr.length());
    str=newStr;
}
System.out.println(map);
 
// 方式3    类似方式1,只不过用Character保存key
String str2 = "asdfjk2348ujysdjf89234-8-asjsf";
Map<Character, Integer> map2 = new HashMap<Character, Integer>();
for(int i=0;i<str2.length();i++){
    char c = str2.charAt(i);
    if(map2.containsKey(c)){
        map2.put(c, map2.get(c)+1);
    }else{
        map2.put(c, 1);
    }
}
System.out.println(map2);

Hashtable

Hashtable和HashMap非常相似,用法基本相同,区别:
Hashtable
同步的,线程安全
key和value都不允许为null
可以使用Iterator或Enumeration遍历
HashMap
异步的,线程不安全的
key和value都可以为null
不能使用Enumeration遍历

Hashtable<Integer, String> table = new Hashtable<Integer, String>();
table.put(1, "tom");
table.put(2, "jack");
table.put(3, "alice");
// table.put(null,null); //key-value都不允许为null,编译不报错,运行时报NullPointerException
 
// 遍历
// table.keySet();
// table.values();
// table.entrySet();
// 使用Enumeration:keys()、elements()
Enumeration<Integer> keys = table.keys();  // 获取key的枚举实例
while(keys.hasMoreElements()){
    Integer key = keys.nextElement();
    String value = table.get(key);
    System.out.println("key:"+key+",value:"+value);
}
Enumeration<String> values = table.elements(); // 获取value的枚举实例
System.out.println(table);

Properties类

一般只用来存储字符串键值对
Properties p = new Properties();
// 一般不会这样用
// p.put(1, “tom”);
// p.get(1);
// setProperty() 设置属性
p.setProperty(“name”, “admin”);
p.setProperty(“age”, “20”);
p.setProperty(“sex”, “male”);
// getProperty() 获取属性
System.out.println(p.getProperty(“name”)); // 根据属性名获取属性值,返回String类型
// 遍历
// p.keySet()
// p.values()
// p.entrySet()
Enumeration keys = p.keys();
// Enumeration values = p.elements();
//Enumeration<?> keys = p.propertyNames(); // ?是泛型通配符
while(keys.hasMoreElements()){
String key = (String) keys.nextElement();
String value = p.getProperty(key);
System.out.println(key+"="+value);
}

属性文件
以 .properties 为后缀
内容格式: 属性名=属性值
只支持ISO88591字符集,不支持中文,但Eclipse会自动进行编码转换
Properties p2 = new Properties();
// 加载属性文件(实际上,只要文件内容是:属性名=属性值 的格式,都可以加载,与文件的后缀名无关)
p2.load(
Test03_Properties.class // 获取当前类的Class对象
.getClassLoader() // 获取类加载器,用于加载classpath类路径下的资源,即src目录下
.getResourceAsStream(“data.properties”) // 加载类路径下的指定的文件
); // 暂时记住,固定写法
//p2.load(Test03_Properties.class.getClassLoader().getResourceAsStream(“data.properties”));
System.out.println(p2);
System.out.println(p2.getProperty(“name”));

获取系统的属性集合
Properties p3 = System.getProperties();
Enumeration e = p3.keys();
while(e.hasMoreElements()){
String key = (String) e.nextElement();
String value=p3.getProperty(key);
System.out.println(key+"="+value);
}
System.out.println(System.getProperty(“java.home”));;
System.out.println(System.getProperty(“file.encoding”));

Collection

Collections工具类提供了集合操作的相关方法,如排序、查找、求最大值、最小值等
类似于Arrays工具类

List<Integer> list=new ArrayList<>();
list.add(12);
list.add(3);
list.add(8);
list.add(5);
list.add(11);
System.out.println(list);
Collections.addAll(list, 111,222,333); // addAll() 添加多个元素 boolean
System.out.println(Collections.max(list)); // max() 最大值
System.out.println(Collections.min(list)); // min() 最小值
// sort() 排序,默认升序
// Collections.sort(list);
Collections.sort(list, new Comparator<Integer>() { // 自定义比较器来指定排序规则
   @Override
   public int compare(Integer o1, Integer o2) {
       // 降序
       if(o1>o2){
           return 1;
       }else if(o1<o2){
           return 1;
       }
       return 0;
   }
});

Collections.reverse(list); // reverse() 反转
Collections.replaceAll(list, 111, 666); // replaceAll() 替换,将所有的111替换为666
Collections.swap(list, 0, list.size()-1); // swap() 两个下标的元素交换位置
Collections.fill(list, 0); // fill() 将已存在的元素全部填充为指定值 / 初始化

Collections和Collection区别:

java.util.Collection 是集合类的上级接口,继承与他的接口主要有 Set 和 List.
java.util.Collections 是一个工具类(Arrays类专门用来操作数组的工具类)。它包含有各种有关集合操作的静态方法(对集合的搜索、排序、线程安全化等)

面试题:
/*
* 统计一个字符串中每个字符出现的次数,保存到HashMap集合中
* 
* 通过排序,打印输出次数最多的前三个字符及次数
*/
String str = "asdfjk2348aaaauj;sdjf89234-8-asjsf";
Map<String, Integer> map = new HashMap<String, Integer>();
for (int i = 0; i < str.length(); i++) {
    String c = str.charAt(i) + "";
    map.put(c, map.containsKey(c) ? map.get(c) + 1 : 1);
}
System.out.println(map);
// 获取所有键值对的集合
Set<Entry<String, Integer>> entries = map.entrySet();
// 将set集合转换为list集合
ArrayList<Entry<String, Integer>> list = new ArrayList<Entry<String, Integer>>(entries);
Collections.sort(list,new Comparator<Entry<String, Integer>>() {
    @Override
    public int compare(Entry<String, Integer> o1,
            Entry<String, Integer> o2) {
        if(o1.getValue()>o2.getValue()){
            return -1;
        }else if(o1.getValue()<o2.getValue()){
            return 1;
        }
        return 0;
    }
});
System.out.println(list);
System.out.println("出现次数最多的前三个字符及次数:");
for(int i=0;i<3;i++){
    Entry<String, Integer> entry = list.get(i);
    System.out.println(entry.getKey()+"="+entry.getValue());
}

Iterator、ListIterator
1、遍历
使用Iterator,可以遍历所有集合,如Map,List,Set;但只能顺序遍历集合中的元素。
使用ListIterator,只能遍历List实现的对象,可以顺序、逆序遍历集合中的元素。
2、添加元素
Iterator无法向集合中添加、修改元素,只能遍历; 而ListIteror可以向集合添加、修改元素。
3、索引
Iterator无法获取集合中元素的索引;而使用ListIterator可以获取。
Connection接口有一个重要方法Iterator,迭代器,用来遍历集合,常见方法有hasNext(),next()
//如果先逆序迭代会报错,因为此时指针在最前面,必须先顺序在逆序

List<String> list2 = new ArrayList<String>();
list2.add("hello");
list2.add("wolrd");
list2.add("abc");
list2.add("hello");
     ListIterator<String> li = list2.listIterator();
     while(li.hasNext()){
         System.out.println(li.next());
     }
     System.out.println("list中用while遍历  顺序迭代end.............");
     while(li.hasPrevious()){
         System.out.println(li.previous());
     }
     System.out.println("list中用while遍历  逆序迭代end.............");
具体案例
        // 使用for
//      for (int i = list.size() - 1; i >= 0; i--) {   // 1,使用倒序遍历
//          int num = list.get(i);
//          if (num % 3 == 0) {
//              // list.remove(i); // 2,当参数为int时表示按索引删除
//              list.remove(new Integer(num)); // 当参数为Integer包装类型时按元素值删除
//          }
//      }
        
        /*
         * 问题:使用foreach或iterator进行循环时,不能直接对集合进行remove()操作,报错ConcurrentModificationException
         * 解决:
         * 1.使用for循环
         * 2.使用iterator提供的remove()方法
         */
        // foreach
//      for (Integer num : list) {
//          if(num%3==0){
//              list.remove(new Integer(num)); //报错ConcurrentModificationException
//          }
//      }
        
        //iterator
        Iterator<Integer> it = list.iterator();
        while (it.hasNext()) {
            Integer num = it.next(); // 报错ConcurrentModificationException
            if(num%3==0){
                //list.remove(num);
                it.remove(); // 使用迭代器时如果要删除迭代的元素,必须使用迭代器的删除方法,表示删除当前迭代的元素
            }
        }

数组 集合 的区别

数组:
1. 数组可以存储基本数据类型和对象
2. 数组长度固定
3. 数组在定义时必须指定数组元素类型
4. 数组中无法直接获取实际存储的元素个数,只知道总长度 int[] nums=new int[50];
5. 数组是有序的分配连续空间
集合:
1. 集合只能存储对象(可以以包装类的形式存储基本数据类型)
2. 集合长度可以动态改变
3. 集合中元素默认为Object类型
4. 集合中可以直接通过size()获取实际存储的元素个数
5. 集合有多个存储方式适应不同的场合
6. 集合以接口和类的形式存在,具有封装、继承、多态等特性

HashMap Hashtable ConcurrentHashmap可以存null吗

Hashtable ConcurrentHashmap不支持key或者value为null,因为支持并发;
ConcurrentHashmap和Hashtable都是支持并发的,这样会有一个问题,当你通过get(k)获取对应的value时,如果获取到的是null时,你无法判断,它是put(k,v)的时候value为null,还是这个key从来没有做过映射。HashMap是非并发的,可以通过contains(key)来做这个判断。而支持并发的Map在调用m.contains(key)和m.get(key),m可能已经不同了。

HashMap kv都行

相关标签: JavaEE