`

java编程思想笔记(十) 集合容器深入

阅读更多

1.散列与散列码(hashcode)

hashcode基本就是把对象转换成了一串数字,常用的功能就是在集合容器里把这一串数字作为数组的下标,以实现快速插入到数组的功能,这样性能就能有效的提升。

当使用HashSet,HashMap这些集合容器存对象时,如果该对象不是java的8种基本类型中的,那就要重写hashcode和equals方法,不然后面会出现找不到该对象等等问题。

 

class Person {
	private String name;
	private int age;

	public Person(String name, int age) {
		super();
		this.name = name;
		this.age = age;
	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public int getAge() {
		return age;
	}

	public void setAge(int age) {
		this.age = age;
	}
}

public class Test1{
	public static void main(String[] args) {
	Map<Person,Integer> map = new HashMap<Person, Integer>();
	map.put(new Person("hhm", 12), 1);
	map.put(new Person("yyh", 18), 2);
	map.put(new Person("hyh", 20), 3);
	System.out.println(map.containsKey(new Person("hhm",12)));
}

 

 

输出:false

输出false是因为底层调用了默认hashcode和equals方法,而默认的方法无法判断是否相等。

 

重写hashcode和equals方法:

 

class Person {
	private String name;
	private int age;

	public Person(String name, int age) {
		super();
		this.name = name;
		this.age = age;
	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public int getAge() {
		return age;
	}

	public void setAge(int age) {
		this.age = age;
	}

	@Override
	public int hashCode() {
		return this.name.hashCode() ^ (this.age * 10);
	}

	@Override
	public boolean equals(Object obj) {
		if (obj == null)
			return false;

		Person p = (Person) obj;
		return this.getName().equals(p.getName()) && this.getAge() == p.age;
	}

}
public class Test1{
    public static void main(String[] args) {
		Map<Person,Integer> map = new HashMap<Person, Integer>();
		map.put(new Person("hhm", 12), 1);
		map.put(new Person("yyh", 18), 2);
		map.put(new Person("hyh", 20), 3);
		System.out.println(map.containsKey(new Person("hhm",12)));
     }
}

 

输出:true

 

重写hashcode方法要求保证每个对象都是不同的hashcode码

重写equals方法的要求:
1.自反性:对于任何非空引用x,x.equals(x)应该返回true。
2.对称性:对于任何引用x和y,如果x.equals(y)返回true,那么y.equals(x)也应该返回true。
3.传递性:对于任何引用x、y和z,如果x.equals(y)返回true,y.equals(z)返回true,那么x.equals(z)也应该返回true。
4.一致性:如果x和y引用的对象没有发生变化,那么反复调用x.equals(y)应该返回同样的结果。
5.非空性:对于任意非空引用x,x.equals(null)应该返回false。

 

2.Arrays.asList()方法产生的List是一个固定长度的数组,只支持不改变长度的操作,任何试图改变其底层数据结构长度的操作(如,增加,删除等操作)都会抛出UnsupportedOperationException异常。

为了使Arrays.asList()方法产生的List集合长度可变,可以将其作为集合容器的构造方法参数,如:

Set set = new HashSet(Arrays.asList(newint[]{1,23}));

或者将其作为Collections.addAll()方法的参数,如:

Collections.addAll(Arrays.asList(new int[]{1,23}));

 

3.SortedSet是一个对其元素进行排序了的Set,SortedSet接口有以下方法:

(1).Comparator comparator():

返回此Set中元素进行排序的比较器,如果该方法返回null,则默认使用自然排序。

(2).Object first():

返回Set中第一个(最低)元素。

(3).Object last():

返回Set中最后一个(最高)元素。

(4).SortedSet subset(fromElement, toElement):

返回此Set中从fromElement(包括)到toElement(不包括)的子Set。

(5).SortedSet headset(toElement):

返回此Set中元素严格小于toElement的子Set。

(6).SortedSet tailSet(fromElement):

返回此Set中元素大于等于fromElement的子Set。

3.SortedMap是一个根据Key排序的Map,SortedMap接口有以下方法:

(1).Comparator comparator():

返回此Map中key进行排序的比较器,如果返回的是null,则该Map的key使用自然排序。

(2).T firstKey():

返回此Map中第一个(最低)key。

(3).T lastKey();

返回此Map中最后一个(最高)key。

(4).SortedMap subMap(fromKey, toKey):

返回此Map中key从fromKey(包括)到toKey(不包括)的子Map。

(5).SortedMap headMap(toKey):

返回此Map中key严格小于toKey的子Map。

(6).SortedMap tailMap(fromKey):

返回此Map中key大于等于fromKey的Map。

 

4.创建只读集合容器:

List,Set和Map类型的集合容器都可以通过下面的方法创建为只读,即只可以访问,不能添加,删除和修改。

 

static Collection<String> data = new ArrayList<String>();  
data.add(“test”);  
static Map<String, String> m = new HashMap<String, String>();  
m.put(“key”, “value”);  

//只读集合
Collection<String> c = Collections.unmodifiableCollection(new ArrayList<String>(data));  
System.out.println(c); //可以访问  
//c.add(“test2”);只读,不可添加  

//只读List
List<String> list = Collections.unmodifiableList(new ArrayList<String>(data));  
System.out.println(list.get(0)); //可以访问  
//list.remove(0);只读,不可删除  

//只读Set和Map,和上面相似,使用Collections.unmodifiableList()

 

5.线程同步集合容器:

Java集合容器中,Vector,HashTable等比较古老的集合容器是线程安全的,即处理了多线程同步问题。

而Java2之后对Vector和HashTable的替代类ArrayList,HashSet,HashMap等一些常用的集合容器都是非线程安全的,即没有进行多线程同步处理。

Java中可以通过以下方法方便地将非线程安全的集合容器进行多线程同步:

(1).线程同步集合:

Collection<String> c= Collections.synchronizedCollection(newArrayList<String>());

(2).线程同步List:

List<String> c= Collections.synchronizedList(newArrayList<String>());

(3).线程同步Set:

Set<String> c= Collections.synchronizedSet(newHashSet<String>());

(4).线程同步Map:

Map<String> c= Collections.synchronizedMap(newHashMap<String, String>());

 

6.队列

Queue实现类如下,部分排序不同,性能相似:

 

public class QueueBehavior {
	private static int count = 10;

	static <T> void test(Queue<T> queue, Generator<T> gen) {
		for (int i = 0; i < count; i++)
			queue.offer(gen.next());
		while (queue.peek() != null)
			System.out.print(queue.remove() + " ");
		System.out.println();
	}

	static class Gen implements Generator<String> {
		String[] s = ("one two three four five six seven " + "eight nine ten")
				.split(" ");
		int i;

		public String next() {
			return s[i++];
		}
	}

	public static void main(String[] args) {
		test(new LinkedList<String>(), new Gen());
		test(new PriorityQueue<String>(), new Gen());
		test(new ArrayBlockingQueue<String>(count), new Gen());
		test(new ConcurrentLinkedQueue<String>(), new Gen());
		test(new LinkedBlockingQueue<String>(), new Gen());
		test(new PriorityBlockingQueue<String>(), new Gen());
	}
} /* Output:
one two three four five six seven eight nine ten
eight five four nine one seven six ten three two
one two three four five six seven eight nine ten
one two three four five six seven eight nine ten
one two three four five six seven eight nine ten
eight five four nine one seven six ten three two
*///:~

 

优先级队列PriorityQueue需要通过Comparable比较来排序

LinkedList可做双向队列使用

 

6.Collections常用方法:

http://www.cnblogs.com/Eason-S/p/5786066.html

 

7.对象的强引用、软引用、弱引用和虚引用:

JDK1.2以前版本中,只存在一种引用——正常引用,即对象强引用,如果一个对象被一个引用变量所指向,则该对象是可触及(reached)的状态,JVM垃圾回收器不会回收它,弱一个对象不被任何引用变量指向,则该对象就处于不可触及的状态,垃圾回收器就会回收它。

从JDK1.2版本之后,为了更灵活的控制对象生命周期,引入了四种引用:强引用(java.lang.ref.Reference)、软引用(java.lang.ref.SoftReference)、弱引用(java.lang.ref.WeakReference)和虚引用(java.lang.ref.PhantomReference):

(1). 强引用(java.lang.ref.Reference):

    即Java程序中普遍使用的正常对象引用,存放在内存中得对象引用栈中,如果一个对象被强引用,则说明程序还在使用它,垃圾回收器不会回收,当内存不足时,JVM抛出内存溢出异常使程序异常终止。

(2). 软引用(java.lang.ref.SoftReference):

如果一个对象只具有软引用,则内存空间足够,垃圾回收器也不会回收它;如果内存空间不足了,就会回收这些对象的内存。只要垃圾回收器没有回收它,该对象就可以被程序使用。软引用可用来实现内存敏感的高速缓存。

软引用可以和一个引用队列(ReferenceQueue)联合使用,如果软引用所引用的对象被垃圾回收器回收,JVM就会把这个软引用加入到与之关联的引用队列中。

(3). 弱引用(java.lang.ref.WeakReference):

弱引用用来实现内存中对象的标准映射,即为了节约内存,对象的实例可以在一个程序内多处使用。

弱引用与软引用的区别在于:只具有弱引用的对象拥有更短暂的生命周期。在垃圾回收器线程扫描它所管辖的内存区域的过程中,一旦发现了只具有弱引用的对象,不管当前内存空间足够与否,都会回收它的内存。不过,由于垃圾回收器是一个优先级很低的后台线程,因此不一定会很快发现那些只具有弱引用的对象。

弱引用也可以和一个引用队列(ReferenceQueue)联合使用,如果弱引用所引用的对象被垃圾回收,Java虚拟机就会把这个弱引用加入到与之关联的引用队列中。

(4). 虚引用(java.lang.ref.PhantomReference):

“虚引用”顾名思义,就是形同虚设,与其他几种引用都不同,虚引用并不会决定对象的生命周期。如果一个对象仅持有虚引用,那么它就和没有任何引用一样,在任何时候都可能被垃圾回收器回收。

虚引用主要用来跟踪对象被垃圾回收器回收的活动。虚引用与软引用和弱引用的一个区别在于:虚引用必须和引用队列 (ReferenceQueue)联合使用。当垃圾回收器准备回收一个对象时,如果发现它还有虚引用,就会在回收对象的内存之前,把这个虚引用加入到与之 关联的引用队列中。

ReferenceQueue queue = new ReferenceQueue ();

PhantomReference pr = new PhantomReference (object, queue);

   JVM中,对象的引用往往都是很复杂的,各个对象之间相互引用形成一个内存引用树,java中某个对象是否可触及,有以下两条判断原则:

a.单条引用路径可及性判断:在这条路径中,最弱的一个引用决定对象的可及性。

b.多条引用路径可及性判断:几条路径中,最强的一条的引用决定对象的可及性。

软引用,弱引用,虚引用例子如下:

package com.test.reference;  
//测试对象  
class VeryBig {  
    private static final int SIZE = 10000;  
    private long[] la = new long[SIZE];  
    private String ident;  
  
    public VeryBig(String id) {  
        ident = id;  
    }  
  
    public String toString() {  
        return ident;  
    }  
  
    protected void finalize() {  
        System.out.println("Finalizing " + ident);  
    }  
}  
  
package com.test.reference;  
  
import java.lang.ref.PhantomReference;  
import java.lang.ref.Reference;  
import java.lang.ref.ReferenceQueue;  
import java.lang.ref.SoftReference;  
import java.lang.ref.WeakReference;  
import java.util.LinkedList;  
  
public class TestReferences {  
    //引用队列  
    private static ReferenceQueue<VeryBig> rq = new ReferenceQueue<VeryBig>();  
    //检查引用队列是否为空  
    public static void checkQueue() {  
        //强引用,轮询引用队列,看是否有可以的对象引用  
        Reference<? extends VeryBig> inq = rq.poll();  
        if (inq != null)  
            //如果有可以使用的对象引用,则打印出该引用指向的对象  
            System.out.println("In queue: " + inq.get());  
    }  
  
    public static void main(String[] args) {  
        int size = 2;  
        //创建存放VeryBig对象的软引用集合  
        LinkedList<SoftReference<VeryBig>> sa = new LinkedList<SoftReference<VeryBig>>();  
        for (int i = 0; i < size; i++) {  
            //将对象和软引用添加到引用队列中  
            sa.add(new SoftReference<VeryBig>(new VeryBig("Soft " + i), rq));  
            System.out.println("Just created: " + sa.getLast());  
            checkQueue();  
        }  
//创建存放VeryBig对象的弱引用集合  
        LinkedList<WeakReference<VeryBig>> wa = new LinkedList<WeakReference<VeryBig>>();  
        for (int i = 0; i < size; i++) {  
            //将对象和弱引用添加到引用队列中  
            wa.add(new WeakReference<VeryBig>(new VeryBig("Weak " + i), rq));  
            System.out.println("Just created: " + wa.getLast());  
            checkQueue();  
        }  
        SoftReference<VeryBig> s = new SoftReference<VeryBig>(new VeryBig(  
                "Soft"));  
        WeakReference<VeryBig> w = new WeakReference<VeryBig>(new VeryBig(  
                "Weak"));  
        //垃圾回收器回收,在回收之前调用对象的finalize()方法  
        System.gc();  
//创建存放VeryBig对象的虚引用集合  
        LinkedList<PhantomReference<VeryBig>> pa = new LinkedList<PhantomReference<VeryBig>>();  
        for (int i = 0; i < size; i++) {  
            //将对象和虚引用添加到引用队列中  
            pa.add(new PhantomReference<VeryBig>(new VeryBig("Phantom " + i),  
                    rq));  
            System.out.println("Just created: " + pa.getLast());  
            checkQueue();  
        }  
    }  
}  

 输出结果为:

Just created:java.lang.ref.SoftReference@757aef

Just created:java.lang.ref.SoftReference@d9f9c3

Just created:java.lang.ref.WeakReference@9cab16

Just created:java.lang.ref.WeakReference@1a46e30

In queue: null

Finalizing Weak 0

Finalizing Weak

Finalizing Weak 1

Just created:java.lang.ref.PhantomReference@3e25a5

In queue: null

Just created:java.lang.ref.PhantomReference@19821f

注意:由于System.gc()只是通知JVM虚拟机可以进行垃圾回收器可以进行垃圾回收了,但是垃圾回收器具体什么时候允许说不清楚,所以这个输出结果只是个参考,每次运行的结果Finalize方法的执行顺序不太一样。

从程序可以看出,尽管对象被引用,垃圾回收器还是回收了被引用对象,引用队列总是创建一个包含null对象的引用。

 

8.WeakHashMap:

WeakHashMap专门用于存放弱引用,WeakHashMap很容易实现弱引用对象标准映射功能。

在WeakHashMap中,只存储一份对象的实例及其值,当程序需要对象实例值时,WeakHashMap从现有的映射中找出已存在的对象值映射。

由于弱引用节约内存的技术,WeakHashMap允许垃圾回收器自动清除器存放的key和value。WeakHashMap自动将其中存放的key和value包装为弱引用,当key不再被使用时,垃圾回收器自动回收该key和value。

0
0
分享到:
评论

相关推荐

    Java编程思想笔记(全)

    ### Java编程思想笔记知识点概述 #### 第 1 章 对象导论 在这一章节中,主要介绍了Java中的基本概念——对象。对象是面向对象编程的核心,它封装了数据和行为。本章首先解释了对象的概念,接着讨论了如何创建对象...

    Java编程思想学习笔记

    在讨论Java编程思想学习笔记时,首先需要了解的是Java语言的平台无关性,而这一特性正是通过Java虚拟机(JVM)得以实现的。JVM作为Java程序设计的关键组成部分,对于Java开发人员来说是必须掌握的基础知识。在该学习...

    java编程思想读书笔记.rar

    《Java编程思想》是 Bruce Eckel 的经典之作,这本书深入浅出地介绍了Java语言的核心概念和技术,对于初学者和有经验的程序员来说都是极好的学习资源。以下是对书中的主要知识点进行的详细解读: 1. **Java语言基础...

    非常好的java笔记适合初学者

    总的来说,这份"非常好的java笔记"是初学者学习Java编程的理想教材,它将引导读者逐步掌握编程基础,理解面向对象编程思想,以及熟悉Java特性和库的使用。通过系统的阅读和实践,初学者能够建立起坚实的Java编程基础...

    Java JDK 6学习笔记——ppt简体版

    总的来说,Java JDK 6学习笔记对于初学者而言是一份非常实用的学习资源,它将理论知识与实践应用相结合,帮助读者快速上手Java编程,并为后续深入学习和开发打下坚实基础。通过详细阅读和反复实践,初学者可以逐步...

    Java学习笔记适合java初学者使用

    【Java学习笔记】是针对Java初学者的一套全面的学习资源,旨在帮助新手快速掌握Java编程基础知识。这份资料包含了丰富的学习内容,如Java语言的核心概念、语法特性、面向对象编程思想等,同时也融入了实践性的练习,...

    java私塾学习笔记整理

    ### Java私塾学习笔记整理 #### 第一章:Java入门 ...以上内容涵盖了Java基础知识的重要方面,从语言基础到高级特性,以及常见的开发技术和工具,帮助读者全面了解Java编程的基础知识和技术要点。

    java学习笔记JDK6.0课件和代码

    Java是世界上最流行的编程语言之一,尤其在企业级应用开发领域占据主导地位。JDK(Java Development Kit)是Java...随着Java技术的不断发展,虽然JDK 6.0已经过时,但它仍然是初学者理解和掌握Java编程思想的宝贵资源。

    Java JDK 8学习笔记 带完整书签(不是页码书签哦)

    对于那些想要提升Java编程技能的开发者来说,这本书是不可多得的参考资料。 总的来说,《Java JDK 8学习笔记》是一本全面覆盖Java 8新特性的指南,它通过深入浅出的讲解和丰富的实例,帮助读者掌握Java 8的核心概念...

    张龙 java se课程笔记

    【Java SE课程笔记详解】 Java SE(Standard Edition)是Java平台的核心版本,它为开发桌面应用、服务器端...通过深入学习和实践,你可以扎实掌握Java编程基础,为进一步深入学习Java EE或Android开发打下坚实的基础。

    良葛格java学习笔记

    【良葛格java学习笔记】是一份专为新手设计的Java编程学习资料,旨在帮助初学者从零开始了解和掌握Java这门...通过系统学习这份笔记,新手可以逐步熟悉Java编程环境,理解面向对象编程思想,并具备解决实际问题的能力。

    java学习笔记整理

    为了开发软件,需要选择合适的计算机语言、开发工具以及编程思想。计算机语言主要分为三类:机器语言、汇编语言和高级语言。高级语言是面向用户的编程语言,它更接近人类自然语言,易于理解和编写。常见的高级语言有...

    全套达内学习笔记(java)

    【CoreJava.zip】:核心Java是Java编程的基础,可能包括了Java SE(标准版)中的核心概念和技术,如IO流、NIO(非阻塞I/O)、多线程、并发编程、集合框架的深入探讨、泛型、枚举、Lambda表达式、Stream API等。...

    java 后端学习笔记.zip

    1. **基础语法**:包括Java编程语言的基本语法,如变量、数据类型、运算符、控制结构、类和对象等。这是所有Java编程的基础,无论是在前端还是后端,都需要扎实掌握。 2. **面向对象编程**:Java是一种完全面向对象...

    JAVA学习笔记.zip

    这份"JAVA学习笔记.zip"压缩包文件显然包含了关于Java编程的详细资料,可能是笔记、教程或者示例代码,旨在帮助学习者掌握Java的基础知识和高级特性。 首先,让我们从基础开始。Java的基础包括语法结构、数据类型、...

    java离线文档系列.7z

    "java编程思想(完整版).chm"是基于经典的《Thinking in Java》一书的电子版,这本书由Bruce Eckel撰写,深入讲解了面向对象的设计原则和编程实践,是许多Java开发者案头必备的参考书。 最后,"Think In Java.chm...

    Java学习的详细心得笔记

    Java学习的详细心得笔记是一份宝贵的资源,特别适合那些刚刚踏入Java编程领域的初学者。这份笔记涵盖了许多关键知识点,旨在帮助读者系统地理解和掌握Java语言的基础及进阶内容。以下是一些主要的学习要点: 1. **...

    C++ JAVA笔记讲义

    在IT行业中,C++和Java是两种...同时,笔记中可能还包含了作者的学习心得和经验分享,这对于理解编程思想、提高编程技能将大有裨益。无论是准备面试、巩固基础还是解决实际问题,这都将是一份非常有价值的参考资料。

    CoreJava学习笔记

    ### CoreJava学习笔记 #### 一、JAVA特点与运行原理 **JAVA特点:** 1. **简单性**:Java的设计者们将C++语言中许多不易理解和容易混淆的部分去除,使得Java更容易理解与掌握。 2. **面向对象**:Java几乎一切都...

Global site tag (gtag.js) - Google Analytics