3.3、 LinkedHashMap
3.31 LinkedHashMap特点:
Map接口的哈希表和链接列表实现,具有可预知的迭代顺序。此链接列表定义了迭代顺序(即存储的顺序与输出的顺序相同),该迭代顺序通常就是将键插入到映射中的顺序(插入顺序)。此实现不是同步的
注意:
①当key为String或基本数据类型包装类,键相同自动替换旧值为新值 (因为他们已重写了hashCode与equals方法)
②当key为自定义对象,需让其重写hashCode与equals方法才能保证key的唯一性
3.32 LinkedHashMap使用示例
public class LinkedHashMapReview {
public static void main(String[] args) {
test1();
test2();
test3();
}
/**
* 自定义对象为key
* 需让其重写hashCode与equals方法才能保证key的唯一性
*/
private static void test3() {
LinkedHashMap<Info, Integer> map=new LinkedHashMap<Info, Integer>();
map.put(new Info(0, "vvv"), 000);
map.put(new Info(0, "vvv"), 333);
map.put(new Info(1, "ccc"), 111);
System.out.println(map);
// output : 当Info没有重写hashCode与equals方法,
// {Info [id=0, adress=vvv]=0, Info [id=0, adress=vvv]=333, Info [id=1, adress=ccc]=111}
// output : 当Info重写hashCode与equals方法
// {Info [id=0, adress=vvv]=333, Info [id=1, adress=ccc]=111}
}
/**
* 基本数据类型包装类重写了hashCode与equals方法,键相同自动替换旧值为新值
*/
private static void test2() {
LinkedHashMap<Integer, Integer> map=new LinkedHashMap<Integer, Integer>();
map.put(1, 66);
map.put(2, 67);
map.put(3, 68);
map.put(1, 69); // 自动装箱 Integer.valueOf(69)
System.out.println(map);
// output
// {1=69, 2=67, 3=68}
// 输出顺序与存储相同,重复添加已有的键会替换掉旧值
}
/**
* String做key
* String类实现了hashCode与equals方法,键相同自动替换旧值为新值
*/
private static void test1() {
LinkedHashMap<String, String> map=new LinkedHashMap<String, String>();
map.put("aa", "121");
map.put("bb", "122");
map.put("cc", "123");
map.put("aa", "122");
map.put("dd", "122");
map.put("ee", "122");
System.out.println(map);
// output
// {aa=122, bb=122, cc=123, dd=122, ee=122}
// 输出顺序与存储相同,重复添加已有的键会替换掉旧值
}
}
3.4、 Hashtable
Hashtable是同步的,它不允许使用 null 值和 null 键。除此之外与HashMap大致相同,示例略
3.41 使用Properties
Properties类继承自Hashtable,表示了一个持久的属性集,由键值对(key-value)组成。
与Hashtable不同的是,Properties 属性列表中每个键及其对应值都是一个字符串,因此不推荐使用Hashtable的put方法为Properties添加属性。
Properties 可通过store方法保存在流中或通过load方法从流中加载。如下三种方式:
1.通过字节输入输出流
void load(InputStream inStream)
从输入流中读取属性列表(键和元素对)。
void store(OutputStream out, String comments)
以适合使用 load(InputStream) 方法加载到 Properties 表中的格式,将此 Properties 表中的属性列表(键和元素对)写入输出流。
2.通过字符输入输出流
void load(Reader reader)
按简单的面向行的格式从输入字符流中读取属性列表(键和元素对)。
void store(Writer writer, String comments)
以适合使用 load(Reader) 方法的格式,将此 Properties 表中的属性列表(键和元素对)写入输出字符。
3.通过xml
void loadFromXML(InputStream in)
将指定输入流中由 XML 文档所表示的所有属性加载到此属性表中。
void storeToXML(OutputStream os, String comment)
发出一个表示此表中包含的所有属性的 XML 文档。
void storeToXML(OutputStream os, String comment, String encoding)
使用指定的编码发出一个表示此表中包含的所有属性的 XML 文档。
通过如下方法存取键值
String getProperty(String key)
用指定的键在此属性列表中搜索属性。
String getProperty(String key, String defaultValue)
用指定的键在属性列表中搜索属性。
Object setProperty(String key, String value)
调用 Hashtable 的方法 put。
void list(PrintStream out)
将属性列表输出到指定的输出流。
void list(PrintWriter out)
将属性列表输出到指定的输出流。
Set<String> stringPropertyNames()
返回此属性列表中的键集,其中该键及其对应值是字符串,如果在主属性列表中未找到同名的键,则还包括默认属性列表中不同的键。
下面通过示例使用Properties
1.创建一个属性文件
/**
* 创建一个属性文件
* @throws IOException
*/
private static void create() throws IOException {
// 创建一个空的属性文件
Properties prop = new Properties();
// 创建一个文件输出流,用于写出属性文件到本地
FileWriter writer = new FileWriter("config.properties");//亦可以使用FileOutputStream
// 设置属性键与值
prop.setProperty("name", "pecuyu");
prop.setProperty("character", "kind");
// 通过字符输出流将键值对写入属性文件
prop.store(writer, "this is new");
writer.close();
}
2.读取属性文件内容
/**
* 读取一个属性文件
*/
private static void load() throws FileNotFoundException, IOException {
// 创建属性文件
Properties prop=new Properties();
// 从流中读取属性列表到属性文件
prop.load(new FileInputStream("config.properties"));// 亦可使用FileReader
// 通过键取值
String name = prop.getProperty("name");
String character = prop.getProperty("character");
//System.out.println("name="+name+" character="+character);
prop.list(System.out); // 将属性键值对列出并打印到控制台
Set<String> stringPropertyNames = prop.stringPropertyNames();// 键的set集合
for (String key : stringPropertyNames) {
String value = prop.getProperty(key); // 通过键获取值
System.out.println("key="+key+" value="+value);
}
}
3.5、 WeakHashMap
3.51 特点
以弱键 实现的基于哈希表的 Map。在 WeakHashMap 中,当某个键不再正常使用时,将自动移除其条目。更精确地说,对于一个给定的键,其映射的存在并不阻止垃圾回收器对该键的丢弃,这就使该键成为可终止的,被终止,然后被回收。丢弃某个键时,其条目从映射中有效地移除,因此,该类的行为与其他的 Map 实现有所不同。
null 值和 null 键都被支持
3.52 实现注意事项
WeakHashMap 中的值对象由普通的强引用保持。因此应该小心谨慎,确保值对象不会直接或间接地强引用其自身的键,因为这会阻止键的丢弃。注意,值对象可以通过 WeakHashMap 本身间接引用其对应的键;这就是说,某个值对象可能强引用某个其他的键对象,而与该键对象相关联的值对象转而强引用第一个值对象的键。处理此问题的一种方法是,在插入前将值自身包装在 WeakReferences 中,如:m.put(key, new WeakReference(value)),然后,分别用 get 进行解包。
3.6、 TreeMap
3.61 TreeMap特点
- 基于红黑树(Red-Black tree)的 NavigableMap 实现。该映射根据其键的自然顺序进行排序,或者根据创建映射时提供的 Comparator 进行排序,具体取决于使用的构造方法。
- 键值对是红黑树结构,可以保证键的排序和唯一性
- 此实现不是同步的
须为TreeMap提供排序方案
①根据其键的自然顺序进行排序(自定义对象须实现Comparable接口并重写compare方法)
②根据创建映射时提供的Comparator进行排序,具体取决于使用的构造方法。
3.62 分析TreeMap的put方法源码
1、判断Entry是否有元素,没有则new一个,并添加新元素
2、通过自然排序与比较器排序来为TreeMap排序,优先使用Comparator来排序
通过Entry对象来来确保插入元素的唯一性,它建立在compare方法的基础上,此方法返回0时,表示插入的键存在,直接替换旧值并返回。因此在使用TreeMap时,自定义对象须实现Comparable接口并重写compare方法或在创建TreeMap时提供Comparator
cmp = cpr.compare(key, t.key);
if (cmp < 0)
t = t.left;
else if (cmp > 0)
t = t.right;
else
return t.setValue(value);
3、在插入元素后重新调整红黑树(即Entry树)
源码如下
public V put(K key, V value) {
Entry<K,V> t = root;
// 判断Entry是否有元素,没有则new一个
if (t == null) {
compare(key, key); // type (and possibly null) check
root = new Entry<>(key, value, null);
size = 1;
modCount++;
return null;
}
int cmp;
Entry<K,V> parent;
// 通过自然排序与比较器排序
// split comparator and comparable paths
Comparator<? super K> cpr = comparator;
if (cpr != null) {
do {
parent = t;
cmp = cpr.compare(key, t.key);
if (cmp < 0)
t = t.left;
else if (cmp > 0)
t = t.right;
else
return t.setValue(value);
} while (t != null);
}
else {
if (key == null)
throw new NullPointerException();
@SuppressWarnings("unchecked")
Comparable<? super K> k = (Comparable<? super K>) key;
do {
parent = t;
cmp = k.compareTo(t.key);
if (cmp < 0)
t = t.left;
else if (cmp > 0)
t = t.right;
else
return t.setValue(value);
} while (t != null);
}
Entry<K,V> e = new Entry<>(key, value, parent);
if (cmp < 0)
parent.left = e;
else
parent.right = e;
fixAfterInsertion(e);
size++;
modCount++;
return null;
}
3.63 TreeMap使用示例
public class TreeMapReview {
public static void main(String[] args) {
test1();
test2();
}
/**
* 自定义对象做key,需满足以下两个条件之一,否则抛出异常java.lang.ClassCastException:com.yu.bean.Info cannot be cast to java.lang.Comparable
* ①实现Comparable接口并重写compare方法
* ②构造TreeMap对象时,需传入Comparator
* 当两者都有,以Comparator来排序
*/
private static void test2() {
TreeMap<Info, String> map=new TreeMap<Info, String>(new Comparator<Info>() {
@Override
public int compare(Info o1, Info o2) {
int num = o2.getId() - o1.getId();
num = num == 0 ? o2.getAdress().hashCode() - o1.getAdress().hashCode() : num;
return num;
}
});
map.put(new Info(000, "hhh"), "qqq");
map.put(new Info(001, "hhh"), "aaa");
map.put(new Info(002, "hhh"), "zzz");
map.put(new Info(000, "hhh"), "qqq");
System.out.println(map);
}
/**
* String类型或基本类型包装类做key
* String类实现了Comparable接口,可以进行自然排序
*/
private static void test1() {
TreeMap<String, String> map = new TreeMap<String, String>();
map.put("a", "111");
map.put("b", "123");
map.put("c", "121");
map.put("c", "121");
Set<Entry<String, String>> entrySet = map.entrySet();
for (Entry<String, String> entry : entrySet) {
System.out.println("key=" + entry.getKey() + " value="
+ entry.getValue());
}
// output:
// key=a value=111
// key=b value=123
// key=c value=121
}
}
相关推荐
3. **Java集合框架**:详述ArrayList、LinkedList、HashMap、HashSet等容器的使用,以及它们在不同场景下的优缺点。 4. **多线程编程**:涵盖线程的创建、同步、通信,以及并发工具类如Semaphore、CountDownLatch等...
再者,Java集合框架是处理数据结构的关键,包括List(如ArrayList和LinkedList)、Set(如HashSet和TreeSet)、Map(如HashMap和TreeMap)等接口和实现。它们提供了丰富的操作,使得数据组织和操作更加高效。 然后...
这个"Java_Technology_Concept_Map(PDFtoJPGE).jpg"文件很可能是一个详细的Java技术概念图,将这些概念以图表的形式呈现出来,有助于学习者直观理解Java技术体系的全貌和各个部分之间的关联。将PDF转换为JPEG格式是...
"java技术集合体系图"涵盖了Java集合框架的重要概念和组件,对于深入理解Java编程至关重要。下面我们将详细探讨这个话题。 首先,"Collection.jpg"可能是一个展示了Java集合接口层次结构的图表。在Java集合框架中,...
"Java Technology Concept Map" 提供了一种可视化的方式来理解和掌握Java的复杂知识体系。这张海报旨在帮助初学者和有经验的开发者更好地梳理Java的核心概念,将抽象的编程概念与实际的应用场景联系起来。 **Java...
java集合体系结构完结篇-Map集合
1. **集合框架**:Java 1.8中的集合框架是程序设计的核心部分,包括List(如ArrayList和LinkedList)、Set(如HashSet和TreeSet)和Map(如HashMap和TreeMap)接口及其实现。这些接口和类提供了数据存储、查找和操作...
Java知识体系总结 Java是一种广泛使用的面向对象的编程语言,由Sun Microsystems(现已被Oracle公司收购)于1995年推出。它以其“一次编写,到处运行”的特性闻名,适用于开发跨平台的应用程序,包括桌面应用、企业...
java集合体系思维脑图,主要介绍了map、conllection、juc集合
Java的集合体系是Java编程中不可或缺的一部分,它涵盖了多种数据结构和容器,为开发者提供了灵活且高效的存储和操作数据的方式。在本练习中,我们将深入理解并熟练掌握Java集合框架的核心概念。 首先,Java集合主要...
Java是一种广泛使用的高级编程语言,以其面向对象的特性、跨平台的兼容性和强大的功能而闻名。以下是关于Java的一些核心知识点: 1. **面向对象特性**: - 封装:将数据和操作数据的方法绑定在一起,形成一个独立...
7. **集合框架**:包括List(如ArrayList和LinkedList)、Set(如HashSet和TreeSet)和Map(如HashMap和TreeMap),提供了丰富的数据结构和算法。 8. **多线程**:Java内置对多线程的支持,可以创建Thread对象或...
4. **集合框架**:Java集合框架是用于存储和操作对象的工具,包括List、Set、Map等接口以及ArrayList、LinkedList、HashSet、HashMap等实现类。掌握它们的特性和使用场景,以及迭代器、泛型和并发容器的使用。 5. *...
4. **集合框架**:Java集合框架是存储和管理对象的强大工具,包括List(如ArrayList和LinkedList)、Set(如HashSet和TreeSet)和Map(如HashMap和TreeMap)接口及其实现。 5. **输入/输出(I/O)**:Java提供了...
Java集合框架是处理数据集合的重要工具,包括List、Set和Map等接口,以及ArrayList、LinkedList、HashSet、HashMap等实现类。这些集合允许我们动态存储和操作多个对象。 多线程是Java的一大亮点,通过Thread类和...
理解并熟练运用Java集合体系中的List、Set、Map接口及其实现类,对于日常开发和面试来说至关重要,因为它们是许多Java框架和库的基础。在实际项目中,根据需求选择合适的集合类型可以提高代码的效率和可维护性。在...
Map是Java集合框架中的一个重要组成部分,它提供了一种存储键值对(key-value pair)数据结构的方式。与List和Set不同,Map并没有直接继承自`Collection`接口,而是独立于`Collection`体系之外。Map的主要特点是它通过...
在本压缩包文件"Java集合知识体系.zip"中,你将深入理解这个复杂而重要的主题。 首先,我们要了解集合的基本概念。在Java中,集合是用来存储一组对象的容器。它们可以看作是动态大小的数组,允许插入、删除和查找...