Java的双列集合的基础知识
双列集合的特点
- 键值对存储:双列集合一次存储一对数据,即键和值。这一对数据通常被称为键值对或键值对对象,在Java中,它们被表示为Entry对象。
- 键的唯一性:在双列集合中,键(Key)必须是唯一的,不允许重复。这是双列集合的一个重要特性,因为它确保了每个键都能唯一地映射到一个值。如果尝试插入一个已经存在的键,将会替换原有键对应的值。
- 值的可重复性:与键不同,值(Value)在双列集合中是可以重复的。这意味着多个键可以映射到相同的值。
- 键与值的一一对应关系:在双列集合中,每个键都唯一地对应一个值,形成一对一的映射关系。这种关系使得通过键可以快速找到对应的值。
- 支持null值:双列集合中的键和值都可以为空(null)。这意味着你可以在集合中存储空对象作为键或值。
- 无序性:双列集合的迭代顺序通常是不确定的,即不保证按照存入顺序或者按照某种排序规则进行遍历。具体的迭代顺序取决于具体的实现类。
Java中的Map接口是双列集合的顶层接口,它定义了一系列用于操作键值对的方法。常见的Map实现类包括HashMap、LinkedHashMap、TreeMap等,它们各自具有不同的特性和适用场景。例如,HashMap基于哈希表实现,提供了快速的插入、删除和查找操作;TreeMap基于红黑树实现,可以对键进行排序;而LinkedHashMap则保持了键值对的插入顺序。
总结来说,双列集合在Java中是一种强大的数据结构,通过键值对的映射关系实现了高效的数据存储和检索功能。
Map
在Java中,Map接口提供了一系列常见的方法来操作键值对。以下是一些常用的Map方法:
-
put(K key, V value)
: 将指定的键值对存储到Map中。如果键已经存在,则替换对应的值,并返回之前与该键相关联的值;如果键不存在,则直接添加键值对,并返回null。 -
get(Object key)
: 返回与指定键关联的值。如果Map中不包含该键,则返回null。 -
remove(Object key)
: 从Map中删除指定键的映射关系,并返回与该键相关联的值。如果键不存在,则返回null。 -
containsKey(Object key)
: 检查Map是否包含指定的键。如果存在,则返回true;否则返回false。 -
containsValue(Object value)
: 检查Map是否包含指定的值。如果存在,则返回true;否则返回false。 -
size()
: 返回Map中键值对的数量。 -
isEmpty()
: 检查Map是否为空。如果Map不包含任何键值对,则返回true;否则返回false。 -
keySet()
: 返回一个包含Map中所有键的Set集合。 -
values()
: 返回一个包含Map中所有值的Collection集合。 -
entrySet()
: 返回一个包含Map中所有键值对的Set集合。这个集合的每个元素都是Map.Entry类型的对象,表示一个键值对。 -
putAll(Map<? extends K, ? extends V> m)
: 将指定Map中的所有映射关系复制到当前Map中。如果当前Map已经包含与指定Map中的键相同的键,则这些键的对应值将被替换。 -
clear()
: 删除Map中的所有键值对。
这些方法提供了对Map的基本操作,包括添加、删除、查找键值对,以及检查Map的状态等。需要注意的是,Map中的键是唯一的,不能有重复的键。如果有重复的键被插入,那么后插入的值会覆盖先插入的值。
Java中的Map接口有多个实现类,如HashMap、TreeMap、LinkedHashMap等,它们各自具有不同的特点和性能。在实际使用中,可以根据具体需求选择合适的实现类。
map的第一种遍历方式:键找值
package com.mohuanan.exercise;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import java.util.function.Consumer;
public class Demo01 {
public static void main(String[] args) {
//map的第一种遍历方式:键找值
//创建实现Map的对象
Map<String, String> map = new HashMap<>();
//添加元素
map.put("莫华南", "广西");
map.put("莫华棋", "广东");
map.put("莫华程", "北京");
//获取map集合里面的所有的键
//存储在单列集合里面
//keySet()方法的返回值是实现了Set的实现类对象
Set<String> keys = map.keySet();
//使用增强for遍历单列集合
/*for (String key : keys) {
//根据键找到对应的值
//key表示里面的每一个元素(键)
String string = map.get(key);
System.out.println(key + "=" + string);
}*/
//使用迭代器遍历单列集合
Iterator<String> iterator = keys.iterator();
while (iterator.hasNext()) {
String keyString = iterator.next();
String valueString = map.get(keyString);
System.out.println(keyString + "=" + valueString);
}
System.out.println("-----------");
//使用lambda表达式进行遍历
keys.forEach(s ->{
String valueString = map.get(s);
System.out.println(s + "=" + valueString);
});
}
}
tring);
}
}
}
在Java中,不是每一个集合实现类的对象都有iterator()
方法。但是,所有的集合框架接口(Collection
, Set
, List
, Queue
, Deque
等)都继承了Iterable
接口,而Iterable
接口定义了iterator()
方法。因此,任何实现了这些集合框架接口的类都必须提供iterator()
方法的实现。
这意味着,如果你有一个实现了Collection
, Set
, List
, Queue
, Deque
等接口的类的对象,那么你可以调用它的iterator()
方法来获取一个迭代器(Iterator
),然后使用该迭代器来遍历集合中的元素。
这里有几个例子来说明这一点:
ArrayList
,LinkedList
,HashSet
,TreeSet
,PriorityQueue
等都是实现了集合框架接口的类,因此它们都有iterator()
方法。- 自定义的类如果实现了集合框架接口(比如通过实现
List
或Set
接口),那么它也必须提供iterator()
方法的实现。
然而,有一些类可能不是集合框架的一部分,或者可能只是简单地持有对象的集合,但并不实现集合框架接口。这样的类可能就没有iterator()
方法。在这种情况下,如果你想要遍历这些类的对象,你可能需要手动编写遍历逻辑,或者使用其他机制(如循环或递归)来访问对象的元素。
总的来说,如果一个类实现了Java集合框架中的某个接口,那么它就应该有iterator()
方法,因为这是接口定义的一部分。但如果一个类不是集合框架的一部分,那么它可能就没有这个方法。
当接口继承另一个接口时,它确实继承了被继承接口的所有抽象方法。在Java中,接口是一种引用类型,它是方法的集合,这些方法默认都是抽象的(即没有方法体)。一个接口可以继承另一个或多个接口,这被称为接口的多重继承。
当一个接口继承另一个接口时,它会自动包含被继承接口中声明的所有方法。这意味着,实现该接口的类必须提供所有这些方法的实现。如果接口A继承了接口B,那么任何实现接口A的类也必须实现接口B中定义的所有方法。
例如:
public interface InterfaceA {
void methodA();
}
public interface InterfaceB extends InterfaceA {
void methodB();
}
public class MyClass implements InterfaceB {
@Override
public void methodA() {
// 实现InterfaceA中的methodA方法
}
@Override
public void methodB() {
// 实现InterfaceB中的methodB方法
}
}
在上面的例子中,InterfaceB
继承了 InterfaceA
,因此 InterfaceB
包含了 methodA()
和 methodB()
两个方法。任何实现 InterfaceB
的类(如 MyClass
)都必须提供这两个方法的实现。
这种机制允许接口构建复杂的层次结构,从而可以组合多个接口的功能到一个接口中,进而简化类的实现。
第二种遍历方式 键值对
package com.mohuanan.exercise;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import java.util.function.Consumer;
public class Demo02 {
public static void main(String[] args) {
//创建实现Map的对象
Map<String, String> map = new HashMap<>();
//添加元素
map.put("莫华南", "广西");
map.put("莫华棋", "广东");
map.put("莫华程", "北京");
//第二种遍历方式 键值对
//entries存储的是所有的键值对对象
Set<Map.Entry<String, String>> entries = map.entrySet();
//1.使用增强for遍历Set集合
for (Map.Entry<String, String> entry : entries) {
//Map.Entry Entry是Map里面的内部接口 里面右getKey()方法
String key = entry.getKey();
String value = entry.getValue();
System.out.println(key+" "+value);
}
System.out.println("-----------------------");
//2. 使用迭代器遍历Set集合
Iterator<Map.Entry<String, String>> iterator = entries.iterator();
while(iterator.hasNext()){
Map.Entry<String, String> next = iterator.next();
System.out.println(next);
}
System.out.println("--------------------");
//3. 使用lambda表达式遍历Set集合
entries.forEach(stringStringEntry-> System.out.println(stringStringEntry));
}
}
第三种遍历方式 使用lambda表达式
package com.mohuanan.exercise;
import java.util.HashMap;
import java.util.Map;
import java.util.function.BiConsumer;
public class Demo03 {
public static void main(String[] args) {
//第三种遍历方式 使用lambda表达式
//创建一个双列集合
Map<String,String> map = new HashMap<>();
//添加元素
map.put("aaa","111");
map.put("bbb","222");
map.put("ccc","333");
//遍历双列集合
map.forEach((key,value)-> System.out.println(key+"="+value));
}
}
HashMap
-
是map的实现类对象
-
没有额外需要学习的方法,直接使用Map里面的方法就可以了
-
特点都是由键决定的:无序,不重复,无索引
-
HashMap和HashSet底层原理是一模一样的,都是哈希表结构
LinkedHashMap
- 由键决定,有序(就是存和取的顺序是一样的,底层是使用双链表),不重复,无索引
TreeMap
- 不重复,无索引,可排序
- 对键进行排序
- 排序的规则1: 实现Comparable接口,指定比较规则,2: 创建集合时
package com.mohuanan.test;
import java.util.Map;
import java.util.Set;
import java.util.TreeMap;
public class Test02 {
public static void main(String[] args) {
//创建TreeMap对象
//因为Student是自定义对象
//所以要重写Student里面的equals和hashCode
TreeMap<Student, String> tm = new TreeMap<>((o1, o2) -> {
int i = o1.getAge() - o2.getAge();
i = i == 0 ? o1.getName().compareTo(o2.getName()) : i;
return i;
});
//创建Student对象
Student s1 = new Student("eee", 18);
Student s2 = new Student("add", 12);
Student s3 = new Student("ad", 12);
tm.put(s1, "广西");
tm.put(s2, "北京");
tm.put(s3, "广东");
//遍历集合
Set<Map.Entry<Student, String>> entries = tm.entrySet();
for (Map.Entry<Student, String> entry : entries) {
System.out.println(entry);
}
}
}
可变参数
-
方法的形参个数是可以改变的
-
格式: 数据类型…名字 例子int…a
package com.mohuanan.test;
public class Test04 {
public static void main(String[] args) {
int sum = getSum(1,2,3,4,5,6,7,8,9);
System.out.println(sum);
}
//可变参数
//底层就是一个数组
//最多只能写一个可变参数
//并且可变参数只能写在最后
public static int getSum(int i ,double b ,int...args){
int sum = 0;
//System.out.println(args);
//遍历数组
for (int arg : args) {
sum = sum + arg;
}
return sum;
}
}
Collections
- 不是接口,是一个工具类
Collections是Java的一个工具类,它包含了对集合类(如
List、
Set、
Map`等)进行操作的静态方法。这个类不能被实例化,它提供了一组静态方法来操作或返回集合的视图,而不是直接修改集合的内容。
常用的方法
- 排序和搜索
sort(List<T> list)
: 对列表进行排序(元素必须实现Comparable
接口)。binarySearch(List<? extends Comparable<? super T>> list, T key)
: 对已排序的列表进行二分搜索。
- 修改集合
shuffle(List<?> list)
: 对列表进行随机排序。reverse(List<?> list)
: 反转列表中的元素顺序。rotate(List<?> list, int distance)
: 将列表中的元素循环右移指定的距离。addAll(Collection<? super T> c, T... elements)
: 将所有指定元素添加到指定集合中。fill(List<? super T> list, T obj)
: 使用指定对象替换列表中的所有元素。
- 同步控制
synchronizedList(List<T> list)
: 返回由指定列表支持的同步(线程安全的)列表。synchronizedSet(Set<T> s)
: 返回由指定集合支持的同步(线程安全的)集合。synchronizedMap(Map<K,V> m)
: 返回由指定映射支持的同步(线程安全的)映射。
- 其他
max(Collection<? extends T> coll)
: 根据元素的自然顺序返回给定集合中的最大元素。min(Collection<? extends T> coll)
: 根据元素的自然顺序返回给定集合中的最小元素。frequency(Collection<?> c, Object o)
: 返回指定集合中指定元素的出现次数。disjoint(Collection<?> c1, Collection<?> c2)
: 如果两个指定集合没有公共元素,则返回true
。emptyList()
,emptySet()
,emptyMap()
: 返回不可变的空集合视图。
使用的注意事项
- 线程安全:默认的集合类(如
ArrayList
、HashSet
、HashMap
)不是线程安全的。如果你在多线程环境中使用它们,并且需要保证操作的原子性,你应该使用Collections
的同步方法或者使用并发集合(如CopyOnWriteArrayList
、ConcurrentHashMap
等)。 - 排序:使用
sort()
方法对列表进行排序时,列表中的元素必须实现Comparable
接口,并且compareTo()
方法必须被正确地实现。否则,将会抛出ClassCastException
。 - 二分搜索:使用
binarySearch()
方法进行二分搜索时,列表必须已经是有序的。如果列表未排序,则结果将是未定义的。 - 空指针异常:像
sort()
、binarySearch()
等方法可能会抛出NullPointerException
,如果传入的集合或列表是null
的话。在使用这些方法之前,确保传入的集合或列表不是null
。 - 性能:虽然
Collections
中的方法提供了很多便利,但它们可能会带来一些性能开销。在使用之前,请考虑是否有更高效的替代方案。