Collection集合(2)

本文深入解析Java集合框架,包括迭代器、Set、Map等核心组件的使用方法与工作原理,探讨了不同集合类的特点及其应用场景。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1.  迭代器

     为了方便的处理集合中的元素,Java中出现了一个对象,该对象提供了一些方法专门处理集合中的元素.例如删除和获取集合中的元素.该对象就叫做迭代器(Iterator).
     对 Collection 进行迭代的类,称其为迭代器。还是面向对象的思想,专业对象做专业的事情,迭代器就是专门取出集合元素的对象。但是该对象比较特殊,不能直接创建对象(通过new),该对象是以内部类的形式存在于每个集合类的内部。如何获取迭代器?Collection接口中定义了获取集合类迭代器的方法(iterator()),所以所有的Collection体系集合都可以获取自身的迭代器。
     正是由于每一个容器都有取出元素的功能。这些功能定义都一样,只不过实现的具体方式不同(因为每一个容器的数据结构不一样)所以对共性的取出功能进行了抽取,从而出现了Iterator接口。而每一个容器都在其内部对该接口进行了内部类的实现。也就是将取出方式的细节进行封装。

 

1.1  Iterable

 

     Jdk1.5之后添加的新接口, Collection的父接口. 实现了Iterable的类就是可迭代的.并且支持增强for循环。该接口只有一个方法即获取迭代器的方法iterator()可以获取每个容器自身的迭代器Iterator。(Collection)集合容器都需要获取迭代器(Iterator)于是在5.0后又进行了抽取将获取容器迭代器的iterator()方法放入到了Iterable接口中。Collection接口进程了Iterable,所以Collection体系都具备获取自身迭代器的方法,只不过每个子类集合都进行了重写(因为数据结构不同)

 

Itreable   该接口仅有一个方法,用于返回集合迭代器对象。

Iterator接口定义的方法
Itreator    该接口是集合的迭代器接口类,定义了常见的迭代方法

     1:boolean hasNext() 
                       判断集合中是否有元素,如果有元素可以迭代,就返回true。

     2: E next()  
                       返回迭代的下一个元素,注意: 如果没有下一个元素时,调用next元素会抛出NoSuchElementException

     3: void remove()
                       从迭代器指向的集合中移除迭代器返回的最后一个元素(可选操作)。

 

思考:为什么next方法的返回类型是Object的呢?为了可以接收任意类型的对象,那么返回的时候,不知道是什么类型的就定义为object

1.2   迭代器遍历
1:while循环

 

public static void main(String[] args) {
		ArrayList list = new ArrayList();
		// 增加:add() 将指定对象存储到容器中
		list.add("计算机网络");
		list.add("现代操作系统");
		list.add("java编程思想");
		list.add("java核心技术");
		list.add("java语言程序设计");
		System.out.println(list);
		Iterator it = list.iterator();
		while (it.hasNext()) {
			String next = (String) it.next();
			System.out.println(next);
		}
	}

2. for循环

import java.util.ArrayList;
import java.util.Iterator;

public class Demo2 {
	public static void main(String[] args) {
		ArrayList list = new ArrayList();
		// 增加:add() 将指定对象存储到容器中
		list.add("计算机网络");
		list.add("现代操作系统");
		list.add("java编程思想");
		list.add("java核心技术");
		list.add("java语言程序设计");
		System.out.println(list);

		for (Iterator it = list.iterator(); it.hasNext();) {
             //迭代器的next方法返回值类型是Object,所以要记得类型转换。
			String next = (String) it.next();
			System.out.println(next);
		}
	}
}

3:使用迭代器清空集合

public class Demo1 {
	public static void main(String[] args) {
		Collection coll = new ArrayList();
		coll.add("aaa");
		coll.add("bbb");
		coll.add("ccc");
		coll.add("ddd");
		System.out.println(coll);
		Iterator it = coll.iterator();
		while (it.hasNext()) {
			it.next();
			it.remove();
		}
		System.out.println(coll);
	}
}

细节一:

如果迭代器的指针已经指向了集合的末尾,那么如果再调用next()会返回NoSuchElementException异常

import java.util.ArrayList;
import java.util.Iterator;

public class Demo2 {
	public static void main(String[] args) {
		ArrayList list = new ArrayList();
		// 增加:add() 将指定对象存储到容器中
		list.add("计算机网络");
		list.add("现代操作系统");
		list.add("java编程思想");
		list.add("java核心技术");
		list.add("java语言程序设计");
		System.out.println(list);

		Iterator it = list.iterator();
		while (it.hasNext()) {
			String next = (String) it.next();
			System.out.println(next);
		}
		// 迭代器的指针已经指向了集合的末尾
		// String next = (String) it.next();
		// java.util.NoSuchElementException
	}
}

细节二:

 如果调用remove之前没有调用next是不合法的,会抛出IllegalStateException

import java.util.ArrayList;
import java.util.Iterator;

public class Demo2 {
	public static void main(String[] args) {
		ArrayList list = new ArrayList();
		// 增加:add() 将指定对象存储到容器中
		list.add("计算机网络");
		list.add("现代操作系统");
		list.add("java编程思想");
		list.add("java核心技术");
		list.add("java语言程序设计");
		System.out.println(list);

		Iterator it = list.iterator();
		while (it.hasNext()) {
			// 调用remove之前没有调用next是不合法的
			// it.remove();
			// java.lang.IllegalStateException
			String next = (String) it.next();
			System.out.println(next);
		}

	}
}

4:注意在对集合进行迭代过程中,不允许出现迭代器以外的对元素的操作,因为这样会产生安全隐患,java会抛出异常并发修改异常(ConcurrentModificationException),普通迭代器只支持在迭代过程中的删除动作。

import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;	
public class Demo1 {
	public static void main(String[] args) {
		Collection coll = new ArrayList();
		coll.add("aaa");
		coll.add("bbb");
		coll.add("ccc");
		coll.add("ddd");
		System.out.println(coll);
		Iterator it = coll.iterator();
		while (it.hasNext()) {
			it.next();
			it.remove();
			coll.add("abc"); // 出现了迭代器以外的对元素的操作
		}
		System.out.println(coll);
	}
}

1.3  List特有的迭代器ListIterator
ListIterator<E> listIterator()

---| Iterator
        hasNext()
        next()
        remove()
        ------| ListIterator Iterator子接口 List专属的迭代器
              add(E e)    将指定的元素插入列表(可选操作)。该元素直接插入到 next 返回的下一个元素的前面(如果有)
              void set(E o)   用指定元素替换 next 或 previous 返回的最后一个元素
              hasPrevious()    逆向遍历列表,列表迭代器有多个元素,则返回 true。
              previous()       返回列表中的前一个元素。

Iterator在迭代时,只能对元素进行获取(next())和删除(remove())的操作。对于 Iterator 的子接口ListIterator 在迭代list 集合时,还可以对元素进行添加(add(obj)),修改set(obj)的操作

import java.util.ArrayList;
import java.util.ListIterator;

public class Demo2 {
	public static void main(String[] args) {
		ArrayList list = new ArrayList();
		// 增加:add() 将指定对象存储到容器中
		list.add("计算机网络");
		list.add("现代操作系统");
		list.add("java编程思想");
		list.add("java核心技术");
		list.add("java语言程序设计");
		System.out.println(list);
         // 获取List专属的迭代器
		ListIterator lit = list.listIterator();

		while (lit.hasNext()) {
			String next = (String) lit.next();
			System.out.println(next);
		}

	}
}

倒序遍历

import java.util.ArrayList;
import java.util.ListIterator;

public class Demo2 {
	public static void main(String[] args) {
		ArrayList list = new ArrayList();
		// 增加:add() 将指定对象存储到容器中
		list.add("计算机网络");
		list.add("现代操作系统");
		list.add("java编程思想");
		list.add("java核心技术");
		list.add("java语言程序设计");
		System.out.println(list);
        // 获取List专属的迭代器
		ListIterator lit = list.listIterator();
		while (lit.hasNext()) {
			String next = (String) lit.next();
			System.out.println(next);
		}
		System.out.println("***************");
		while (lit.hasPrevious()) {
			String next = (String) lit.previous();
			System.out.println(next);
		}

	}
}

Set方法:用指定元素替换 next 或 previous 返回的最后一个元素

import java.util.ArrayList;
import java.util.ListIterator;

public class Demo2 {
	public static void main(String[] args) {
		ArrayList list = new ArrayList();
		// 增加:add() 将指定对象存储到容器中
		list.add("计算机网络");
		list.add("现代操作系统");
		list.add("java编程思想");
		list.add("java核心技术");
		list.add("java语言程序设计");
		System.out.println(list);

		ListIterator lit = list.listIterator();
		lit.next(); // 计算机网络
		lit.next(); // 现代操作系统
		System.out.println(lit.next()); // java编程思想
		//用指定元素替换 next 或 previous 返回的最后一个元素
		lit.set("平凡的世界");// 将java编程思想替换为平凡的世界
		System.out.println(list);

	}
}

add方法将指定的元素插入列表,该元素直接插入到 next 返回的元素的后

public class Demo2 {
	public static void main(String[] args) {
		ArrayList list = new ArrayList();
		// 增加:add() 将指定对象存储到容器中
		list.add("计算机网络");
		list.add("现代操作系统");
		list.add("java编程思想");
		list.add("java核心技术");
		list.add("java语言程序设计");
		System.out.println(list);

		ListIterator lit = list.listIterator();
		lit.next(); // 计算机网络
		lit.next(); // 现代操作系统
		System.out.println(lit.next()); // java编程思想
		// 将指定的元素插入列表,该元素直接插入到 next 返回的元素的后
		lit.add("平凡的世界");// 在java编程思想后添加平凡的世界
		System.out.println(list);

	}
}

2.   Set

     Set:注重独一无二的性质,该体系集合可以知道某物是否已近存在于集合中,不会存储重复的元素用于存储无序(存入和取出的顺序不一定相同)元素,值不能复。
     那 Set 接口有哪些基本操作呢?Set 接口中所有的操作都继承自 Collection 接口,也就是说,Set 接口没有自己特有的操作,其所有操作都来源于父接口 Collection。因此,它具有Collection 接口中定义的那些诸如 add、remove 等方法。特别要注意的是,由于 Set 集合中的元素没有顺序,因此 Set 集合中的元素没有下标的概念。因此,和 List 接口不同,Set 接口中没有定义与下标相关的操作。

对象的相等性
     引用到堆上同一个对象的两个引用是相等的。如果对两个引用调用hashCode方法,会得到相同的结果,如果对象所属的类没有覆盖Object的hashCode方法的话,hashCode会返回每个对象特有的序号(java是依据对象的内存地址计算出的此序号),所以两个不同的对象的hashCode值是不可能相等的。
     如果想要让两个不同的Person对象视为相等的,就必须覆盖Object继下来的hashCode方法和equals方法,因为Object  hashCode方法返回的是该对象的内存地址,所以必须重写hashCode方法,才能保证两个不同的对象具有相同的hashCode,同时也需要两个不同对象比较equals方法会返回true
案例:set集合添加元素并使用迭代器迭代元素。

import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;

public class Demo4 {
	public static void main(String[] args) {
		//Set 集合存和取的顺序不一致。
		Set hs = new HashSet();
		hs.add("世界军事");
		hs.add("兵器知识");
		hs.add("舰船知识");
		hs.add("汉和防务");
		System.out.println(hs);
		// [舰船知识, 世界军事, 兵器知识, 汉和防务]
		Iterator it = hs.iterator();
		while (it.hasNext()) {
			System.out.println(it.next());
		}
	}
}

2.1  HashSet

---| Itreable     接口 实现该接口可以使用增强for循环
             ---| Collection      描述所有集合共性的接口
                    ---| List接口        可以有重复元素的集合
                           ---| ArrayList   
                           ---|  LinkedList
                    ---| Set接口         不可以有重复元素的集合
                            ---| HashSet    线程不安全,存取速度快。底层是以哈希表实现的。

HashSet:
     哈希表边存放的是哈希值。HashSet存储元素的顺序并不是按照存入时的顺序(和List显然不同) 是按照哈希值来存的所以取数据也是按照哈希值取得。
HashSet不存入重复元素的规则.使用hashcode和equals
     由于Set集合是不能存入重复元素的集合。那么HashSet也是具备这一特性的。HashSet如何检查重复?HashSet会通过元素的hashcode()和equals方法进行判断元素师否重复。
     当你试图把对象加入HashSet时,HashSet会使用对象的hashCode来判断对象加入的位置。同时也会与其他已经加入的对象的hashCode进行比较,如果没有相等的hashCode,HashSet就会假设对象没有重复出现。
     简单一句话,如果对象的hashCode值是不同的,那么HashSet会认为对象是不可能相等的。
     因此我们自定义类的时候需要重写hashCode,来确保对象具有相同的hashCode值。如果元素(对象)的hashCode值相同,是不是就无法存入HashSet中了? 当然不是,会继续使用equals 进行比较.如果 equals为true 那么HashSet认为新加入的对象重复了,所以加入失败。如果equals 为false那么HashSet 认为新加入的对象没有重复.新元素可以存入.

总结:
     元素的哈希值是通过元素的hashcode方法 来获取的, HashSet首先判断两个元素的哈希值,如果哈希值一样,接着会比较equals方法 如果 equls结果为true ,HashSet就视为同一个元素。如果equals 为false就不是同一个元素。
     哈希值相同equals为false的元素是怎么存储呢,就是在同样的哈希值下顺延(可以认为哈希值相同的元素放在一个哈希桶中)。也就是哈希一样的存一列。

 

图1:hashCode值不相同的情况
图2:hashCode值相同,但equals不相同的情况。

 

    HashSet:通过hashCode值来确定元素在内存中的位置。一个hashCode位置上可以存放多个元素。
    当hashcode() 值相同equals() 返回为true 时,hashset 集合认为这两个元素是相同的元素.只存储一个(重复元素无法放入)。调用原理:先判断hashcode 方法的值,如果相同才会去判断equals 如果不相同,是不会调用equals方法的。

HashSet到底是如何判断两个元素重复??

    通过hashCode方法和equals方法来保证元素的唯一性,add()返回的是boolean类型
    判断两个元素是否相同,先要判断元素的hashCode值是否一致,只有在该值一致的情况下,才会判断equals方法,如果存储在HashSet中的两个对象hashCode方法的值相同equals方法返回的结果是true,那么HashSet认为这两个元素是相同元素,只存储一个(重复元素无法存入)。
    注意:HashSet集合在判断元素是否相同先判断hashCode方法,如果相同才会判断equals。如果不相同,是不会调用equals方法的。

HashSet 和ArrayList集合都有判断元素是否相同的方法,
boolean contains(Object o)
HashSet使用hashCode和equals方法,ArrayList使用了equals方法

练习:使用HashSet存储字符串,并尝试添加重复字符串
      回顾String类的equals()、hashCode()两个方法。
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;
 
public class Demo4 {
	public static void main(String[] args) {
		// Set 集合存和取的顺序不一致。
		Set hs = new HashSet();
		hs.add("世界军事");
		hs.add("兵器知识");
		hs.add("舰船知识");
		hs.add("汉和防务");

		// 返回此 set 中的元素的数量
		System.out.println(hs.size()); // 4

		// 如果此 set 尚未包含指定元素,则返回 true
		boolean add = hs.add("世界军事"); // false
		System.out.println(add);

		// 返回此 set 中的元素的数量
		System.out.println(hs.size());// 4
		Iterator it = hs.iterator();
		while (it.hasNext()) {
			System.out.println(it.next());
		}
	}
}

 使用HashSet存储自定义对象,并尝试添加重复对象(对象的重复的判定)

package cn.itcast.gz.map;

import java.util.HashSet;
import java.util.Iterator;

public class Demo4 {
	public static void main(String[] args) {
		HashSet hs = new HashSet();
		hs.add(new Person("jack", 20));
		hs.add(new Person("rose", 20));
		hs.add(new Person("hmm", 20));
		hs.add(new Person("lilei", 20));
		hs.add(new Person("jack", 20));

		Iterator it = hs.iterator();
		while (it.hasNext()) {
			Object next = it.next();
			System.out.println(next);
		}
	}
}

class Person {
	private String name;
	private int age;

	Person() {

	}

	public Person(String name, int age) {

		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() {
		System.out.println("hashCode:" + this.name);
		return this.name.hashCode() + age * 37;
	}

	@Override
	public boolean equals(Object obj) {
		System.out.println(this + "---equals---" + obj);
		if (obj instanceof Person) {
			Person p = (Person) obj;
			return this.name.equals(p.name) && this.age == p.age;
		} else {
			return false;
		}
	}

	@Override
	public String toString() {

		return "Person@name:" + this.name + " age:" + this.age;
	}

}


2.2   TreeSet

---| Set接口	    无序,不可以重复的集合
        ---| HashSet  线程不安全,存取速度快。底层是以hash表实现的。
        ---| TreeSet  红-黑树的数据结构,默认对元素进行自然排序(String)。如果在比较的时候两个对象返回值为0,那么元素重复。

案例:使用TreeSet集合存储字符串元素,并遍历

 

import java.util.TreeSet;

public class Demo5 {
	public static void main(String[] args) {
		TreeSet ts = new TreeSet();
		ts.add("ccc");
		ts.add("aaa");
		ts.add("ddd");
		ts.add("bbb");

		System.out.println(ts); // [aaa, bbb, ccc, ddd]

	}
}

红黑树算法的规则: 左小右大。
既然TreeSet可以自然排序,那么TreeSet必定是有排序规则的。

 

1:让存入的元素自定义比较规则。

 

2:给TreeSet指定排序规则。
  方式一:元素自身具备比较性
     元素自身具备比较性,需要元素实现Comparable接口,重写compareTo方法,也就是让元素自身具备比较性,这种方式叫做元素的自然排序也叫做默认排序。
  方式二:容器具备比较性
     当元素自身不具备比较性,或者自身具备的比较性不是所需要的。那么此时可以让容器自身具备。需要定义一个类实现接口Comparator,重写compare方法,并将该接口的子类实例对象作为参数传递给TreeMap集合的构造方法。

 

     注意:当Comparable比较方式和Comparator比较方式同时存在时,以Comparator的比较方式为主;

 

     注意:在重写compareTo或者compare方法时,必须要明确比较的主要条件相等时要比较次要条件。(假设姓名和年龄一直的人为相同的人,如果想要对人按照年龄的大小来排序,如果年龄相同的人,需要如何处理?不能直接return 0,因为可能姓名不同(年龄相同姓名不同的人是不同的人)。此时就需要进行次要条件判断(需要判断姓名),只有姓名和年龄同时相等的才可以返回0.)

 

通过return 0来判断唯一性。

 

     问题:为什么使用TreeSet存入字符串,字符串默认输出是按升序排列的?因为字符串实现了一个接口,叫做Comparable 接口.字符串重写了该接口的compareTo 方法,所以String对象具备了比较性.那么同样道理,我的自定义元素(例如Person类,Book类)想要存入TreeSet集合,就需要实现该接口,也就是要让自定义对象具备比较性.
存入TreeSet集合中的元素要具备比较性.
     比较性要实现Comparable接口,重写该接口的compareTo方法
TreeSet属于Set集合,该集合的元素是不能重复的,TreeSet如何保证元素的唯一性
通过compareTo或者compare方法中的来保证元素的唯一性。
     添加的元素必须要实现Comparable接口。当compareTo()函数返回值为0时,说明两个对象相等,此时该对象不会添加进来。

比较器接口
----| Comparable
               compareTo(Object o)     元素自身具备比较性
----| Comparator
               compare( Object o1, Object o2 )	给容器传入比较器

 

TreeSet集合排序的两种方式:

 

一,让元素自身具备比较性。
也就是元素需要实现Comparable接口,覆盖compareTo 方法。
这种方式也作为元素的自然排序,也可称为默认排序。
年龄按照搜要条件,年龄相同再比姓名。

import java.util.TreeSet;

public class Demo4 {
	public static void main(String[] args) {
		TreeSet ts = new TreeSet();
		ts.add(new Person("aa", 20, "男"));
		ts.add(new Person("bb", 18, "女"));
		ts.add(new Person("cc", 17, "男"));
		ts.add(new Person("dd", 17, "女"));
		ts.add(new Person("dd", 15, "女"));
		ts.add(new Person("dd", 15, "女"));


		System.out.println(ts);
		System.out.println(ts.size()); // 5

	}
}

class Person implements Comparable {
	private String name;
	private int age;
	private String gender;

	public Person() {

	}

	public Person(String name, int age, String gender) {

		this.name = name;
		this.age = age;
		this.gender = gender;
	}

	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 String getGender() {
		return gender;
	}

	public void setGender(String gender) {
		this.gender = gender;
	}

	@Override
	public int hashCode() {
		return name.hashCode() + age * 37;
	}

	public boolean equals(Object obj) {
		System.err.println(this + "equals :" + obj);
		if (!(obj instanceof Person)) {
			return false;
		}
		Person p = (Person) obj;
		return this.name.equals(p.name) && this.age == p.age;

	}

	public String toString() {
		return "Person [name=" + name + ", age=" + age + ", gender=" + gender
				+ "]";
	}

	@Override
	public int compareTo(Object obj) {
		
		Person p = (Person) obj;
		System.out.println(this+" compareTo:"+p);
		if (this.age > p.age) {
			return 1;
		}
		if (this.age < p.age) {
			return -1;
		}
		return this.name.compareTo(p.name);
	}

}


 int是基本类型,不是对象,没有方法; string是对象
int没有hashCode方法

假如A的值大于B,你返回1。
假如A的值大于B,你返回-1。

二,让容器自身具备比较性,自定义比较器。

需求:当元素自身不具备比较性,或者元素自身具备的比较性不是所需的。
那么这时只能让容器自身具备。
定义一个类实现Comparator 接口,覆盖compare方法。
并将该接口的子类对象作为参数传递给TreeSet集合的构造函数。
当Comparable比较方式,及Comparator比较方式同时存在,以Comparator比较方式为主。

import java.util.Comparator;
import java.util.TreeSet;

public class Demo5 {
	public static void main(String[] args) {
		TreeSet ts = new TreeSet(new MyComparator());
		ts.add(new Book("think in java", 100));
		ts.add(new Book("java 核心技术", 75));
		ts.add(new Book("现代操作系统", 50));
		ts.add(new Book("java就业教程", 35));
		ts.add(new Book("think in java", 100));
		ts.add(new Book("ccc in java", 100));

		System.out.println(ts); 
	}
}

class MyComparator implements Comparator {

	public int compare(Object o1, Object o2) {
		Book b1 = (Book) o1;
		Book b2 = (Book) o2;
		System.out.println(b1+" comparator "+b2);
		if (b1.getPrice() > b2.getPrice()) {
			return 1;
		}
		if (b1.getPrice() < b2.getPrice()) {
			return -1;
		}
		return b1.getName().compareTo(b2.getName());
	}

}

class Book {
	private String name;
	private double price;

	public Book() {

	}

	public String getName() {
		return name;
	}

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

	public double getPrice() {
		return price;
	}

	public void setPrice(double price) {
		this.price = price;
	}

	public Book(String name, double price) {

		this.name = name;
		this.price = price;
	}

	@Override
	public String toString() {
		return "Book [name=" + name + ", price=" + price + "]";
	}

}

TreeSet练习
将字符串中的数值进行排序。
例如String str="8 10 15 5 2 7";    2,5,7,8,10,15

使用 TreeSet完成。 
      思路:1,将字符串切割。
           2,可以将这些对象存入TreeSet集合。          
              因为TreeSet自身具备排序功能。
public class Demo5 {
	public static void main(String[] args) {
		String str = "8 10 15 5 2 7";
		String[] strs = str.split(" ");
		TreeSet ts = new TreeSet();
		for (int x = 0; x < strs.length; x++) {
			int y = Integer.parseInt(strs[x]);
			ts.add(y);
		}
		System.out.println(ts);
	}
}


2.3   LinkedHashSet

HashSet 的特点是元素不可重复且元素无顺序。某些情况下,我们依然需要元素不可以重复,但是希望按照我们加入 Set 的先后顺序来加入这些元素。这个时候,我们就可以使用
LinkedHashSet。
例如下面的例子:

import java.util.*;
	public class TestLinkedHashSet {
	  public static void main(String args[]){
	        Set set = new LinkedHashSet();
		set.add("hello");
		set.add("world");
		set.add("java");
		set.add("hello");

		Iterator iter = set.iterator();
		while(iter.hasNext()){
		   System.out.println(iter.next());
	}
   }
}
输出结果如下:
hello
world
java
我们可以看到,字符串的打印顺序和它们添加到 LinkedHashSet 中的顺序是一致的。
同时,hello 字符串被添加了两次,但只打印了一次。
要注意的是,如果要使用 LinkedHashSet 的话,也必须正确的覆盖对象的 hashCode 和
equals 方法。

 

3   Map

Map学习体系:
  ---| Map  接口    将键映射到值的对象。一个映射不能包含重复的键;每个键最多只能映射到一个值。
             ---| HashMap  采用哈希表实现,所以无序
             ---| TreeMap   可以对健进行排序
- --|Hashtable:
        底层是哈希表数据结构,线程是同步的,不可以存入null键,null值。
        效率较低,被HashMap 替代。
 ---|HashMap:
        底层是哈希表数据结构,线程是不同步的,可以存入null键,null值。
        要保证键的唯一性,需要覆盖hashCode方法,和equals方法。
      ---| LinkedHashMap:
             该子类基于哈希表又融入了链表。可以Map集合进行增删提高效率。
 ---|TreeMap:
        底层是二叉树数据结构。可以对map集合中的键进行排序。需要使用Comparable或者Comparator 进行比较排序。return 0,来判断键的唯一性。

 

常见方法

1、添加:
1、V put(K key, V value)    (这个方法是把一个键值对放入 Map 中。如果键不存在,则在 Map 中新增一个键值对。如果键已存在,则把新值替换旧值。
  例如,有如下代码:
  System.out.println(map.get(“2002”));
  map.put(“2002”, “Brazil”);
  System.out.println(map.get(“2002”));
  map.put(“2002”, “China”);
  System.out.println(map.get(“2002”));
    在第一个输出语句中,由于 Map 中不存在以 2002 作为键的键值对,因此第一个输出语句输出为 null。
    之后,调用 put 方法。此时,由于 Map 中不存在 2002 这个键,因此会在 Map 中增加一个新的键值对。第二个输出语句就会输出“Brazil”。之后,再次调用 put 方法。此时,由于在 Map 中 2002 这个键已经存在,因此会用新值“China”替换旧值“Brazil”。于是,第三个输出语句就会输出“China”。        
2、putAll(Map<? extends K,? extends V> m)  从指定映射中将所有映射关系复制到此映射中(可选操作)。

3、删除
        1、remove()   删除关联对象,指定key对象
        2、remove(Object key)   这个方法根据一个键,删除一个键值对。
        3、clear()   清空集合对象

4、获取
      1:value get(key);  可以用于判断键是否存在的情况。当指定的键不存在的时候,返回的是null。

5、判断:
        1、boolean isEmpty()   长度为0返回true否则false
        2、boolean containsKey(Object key)  判断集合中是否包含指定的key
        3、boolean containsValue(Object value)  判断集合中是否包含指定的value

6、长度:
    Int size()

7、Set keySet()
   这个方法返回所有键的集合。由于在 Map 中,键没有顺序,且不可以重复,因此所有的键对象组成的就是一个 Set。也就是说,keySet 方法返回的是一个 Set,这个Set 就是所有键对象的集合。

8、Collection values()
   values 方法返回类型是一个 Collection,返回的是所有值对象的集合。

9、entrySet
   这个方法返回值类型是一个 Set 集合,集合中放的是 Map.Entry 类型。这个方法是用来做键值对遍历的

添加:
该案例使用了HashMap,建立了学生姓名和年龄之间的映射关系。并试图添加重复的键。

public class Demo2 { 
	public static void main(String[] args) { // 定义一个Map的容器对象
		Map<String, Integer > map1 = new HashMap<String, Integer >(); 
		map1.put("jack", 20); 
		map1.put("rose", 18); 
		map1.put("lucy", 17); 
		map1.put("java", 25);
		System.out.println(map1);
		map1.put("jack", 30); 
		// 添加重复的键值(值不同),会返回集合中刚添加的(添加键)的值
        
        //使用返回的形式的话(直接在输出函数中添加),会返回上一个
		//System.out.println(map1.put("jack", 100)); //30
		System.out.println(map1);
		Map<String, Integer> map2 = new HashMap<String, Integer>(); 
		map2.put("张三丰", 100); 
		map2.put("虚竹", 20); 
		System.out.println("map2:" + map2); 
		// 从指定映射中将所有映射关系复制到此映射中。
		map1.putAll(map2); System.out.println("map1:" + map1); 
	} 
}

 
输出:
{java=25, rose=18, lucy=17, jack=20}
20       添加重复的键值(值不同),会返回集合中原有(重复键)的值
{java=25, rose=18, lucy=17, jack=30}      输出的时候hi替换原来的值
map2:{张三丰=100, 虚竹=20}
map1:{java=25, 张三丰=100, rose=18, lucy=17, jack=30, 虚竹=20}

删除:

// 删除:
		// remove() 删除关联对象,指定key对象
		// clear() 清空集合对象

		Map<String, Integer> map1 = new HashMap<String, Integer>();
		map1.put("jack", 20);
		map1.put("rose", 18);
		map1.put("lucy", 17);
		map1.put("java", 25);
		System.out.println(map1);				
// 指定key,返回删除的键值对映射的值。
		System.out.println("value:" + map1.remove("java"));
		map1.clear();
		System.out.println("map1:" + map1);
// 指定key,返回删除的键值对映射的值。
		System.out.println("value:" + map1.remove("java"));
		map1.clear();
		System.out.println("map1:" + map1);

 

输出:
{java=25, rose=18, lucy=17, jack=20}
value:25
map1:{}

 

获取:

// 获取:
		// V get(Object key) 通过指定的key对象获取value对象
		// int size() 获取容器的大小
		Map<String, Integer> map1 = new HashMap<String, Integer>();
		map1.put("jack", 20);
		map1.put("rose", 18);
		map1.put("lucy", 17);
		map1.put("java", 25);
		System.out.println(map1);
		// V get(Object key) 通过指定的key对象获取value对象
		// int size() 获取容器的大小
		System.out.println("value:" + map1.get("jack"));
		System.out.println("map.size:" + map1.size());

判断:

// 判断:
		// boolean isEmpty() 长度为0返回true否则false
		// boolean containsKey(Object key) 判断集合中是否包含指定的key
		// boolean containsValue(Object value)

		Map<String, Integer> map1 = new HashMap<String, Integer>();
		map1.put("jack", 20);
		map1.put("rose", 18);
		map1.put("lucy", 17);
		map1.put("java", 25);
		System.out.println(map1);
		System.out.println("isEmpty:" + map1.isEmpty());
		System.out.println("containskey:" + map1.containsKey("jack"));
		System.out.println("containsvalues:" + map1.containsValue(100));

3.2 遍历
与之前一样,在真正开始讲解遍历之前,首先先使用一个 Map 接口的实现类:HashMap。
创建相应的 HashMap 对象,并放入一些初始值,如下面代码所示:

 

import java.util.*;
    public class TestMap {
     public static void main(String args[]){
	Map map = new HashMap();
	map.put("2006", "Italy");
	map.put("2002", "Brazil");
	map.put("1998", "France");
	map.put("1994", "Brazil");
   }
}

 

在这个 Map 的基础上,我们开始对 Map 进行遍历。
由于 Map 管理的是键值对,因此对于 Map 而言,有多种遍历的方式:键遍历、键值遍历、利用 Map.Entry 进行键值遍历。

3.3 键遍历与键值遍历
键遍历指的是遍历所有的键。键遍历的实现非常简单:通过调用 Map 接口中的 keySet方法,就能获得所有键的集合。然后,就可以像遍历普通 Set 一样遍历所有键对象的集合。
键遍历参考代码如下:

 

  Set set = map.keySet();
  Iterator iter = set.iterator();
    while(iter.hasNext()){
    System.out.println(iter.next());
 }

 

键遍历输出结果如下:
2006
1998
2002
1994

 

可以看到,键遍历输出了集合中所有的键,并且,键并没有顺序。
在键遍历的基础上更进一步,能够遍历所有的键值对。思路如下:
利用键遍历能够遍历所有的键,而在遍历键的时候,可以使用 get 方法,通过键找到对应的值。
键值遍历的参考代码如下:

 

 Set set = map.keySet();
  Iterator iter = set.iterator();
  while(iter.hasNext()){
    Object key = iter.next();
    Object value = map.get(key);
    System.out.println(key + "--->" + value);
 }

 

键值遍历的结果如下:
2006--->Italy
1998--->France
2002--->Brazil
1994--->Brazil
可以看到,键值遍历时能够输出键值对这种一一对应的关系。

 

3.4  值遍历
除了键遍历以及键值遍历之外,Map 接口还有一种遍历方式:值遍历。值遍历表示的是遍历 Map 中所有的值对象。与键遍历类似,我们对 Map 进行值遍历的思路也很简单:首
先利用 Map 的 values()方法获得 Map 中所有值的集合。需要注意的是,values()方法返回的是一个 Collection 类型的对象,因此,应当用迭代遍历的方式,遍历这个 Collection。参考

代码如下:

 

 

  Collection conn = map.values();
  Iterator iter = conn.iterator();
   while(iter.hasNext()){
   System.out.println(iter.next());
 }

 

这样,我们就遍历了 Map 中的所有值。输出结果如下:
Italy
France
Brazil
Brazil

 

遍历Map的方式:
1、将map 集合中所有的键取出存入set集合。
              Set<K> keySet()   返回所有的key对象的Set集合再通过get方法获取键对应的值。
2、 values() ,获取所有的值.
              Collection<V> values()不能获取到key对象
3、 Map.Entry对象  推荐使用   重点
              Set<Map.Entry<k,v>> entrySet()
将map 集合中的键值映射关系打包成一个对象Map.Entry对象通过Map.Entry 对象的getKey,getValue获取其键和值。

第一种方式:使用keySet

将Map转成Set集合(keySet()),通过Set的迭代器取出Set集合中的每一个元素(Iterator)就是Map集合中的所有的键,再通过get方法获取键对应的值。

import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;

public class Demo2 {
	public static void main(String[] args) {
		Map<Integer, String> map = new HashMap<Integer, String>();
		map.put(1, "aaaa");
		map.put(2, "bbbb");
		map.put(3, "cccc");
		System.out.println(map);

		//
		// 获取方法:
		// 第一种方式: 使用keySet
		// 需要分别获取key和value,没有面向对象的思想
		// Set<K> keySet() 返回所有的key对象的Set集合

		Set<Integer> ks = map.keySet();
		Iterator<Integer> it = ks.iterator();
		while (it.hasNext()) {
			Integer key = it.next();
			String value = map.get(key);
			System.out.println("key=" + key + " value=" + value);
		}
	}
}

第二种方式:通过values 获取所有值,不能获取到key对象

public static void main(String[] args) {
		Map<Integer, String> map = new HashMap<Integer, String>();
		map.put(1, "aaaa");
		map.put(2, "bbbb");
		map.put(3, "cccc");
		System.out.println(map);
// 第二种方式:
		// 通过values 获取所有值,不能获取到key对象
		// Collection<V> values()

		Collection<String> vs = map.values();
		Iterator<String> it = vs.iterator();
		while (it.hasNext()) {
			String value = it.next();
			System.out.println(" value=" + value);
		}
}

第三种方式: Map.Entry

       在 Map 接口中,有一个方法叫做 entrySet。这个方法返回一个 Set 集合,这个集合中装
的元素的类型是 Map.Entry 类型。
   Map.Entry 是 Map 接口的一个内部接口。这个接口封装了 Map 中的一个键值对。在这
个接口中,主要定义了这样几个方法:
   1)getKey() : 获得该键值对中的键
   2)getValue(): 获得该键值对中的值
   3)setValue():修改键值对中的值

 

public static void main(String[] args) {
		Map<Integer, String> map = new HashMap<Integer, String>();
		map.put(1, "aaaa");
		map.put(2, "bbbb");
		map.put(3, "cccc");
		System.out.println(map);
		// 第三种方式: Map.Entry对象 推荐使用 重点
		// Set<Map.Entry<K,V>> entrySet()
		

		// 返回的Map.Entry对象的Set集合 Map.Entry包含了key和value对象
		Set<Map.Entry<Integer, String>> es = map.entrySet();

		Iterator<Map.Entry<Integer, String>> it = es.iterator();

		while (it.hasNext()) {
			
			// 返回的是封装了key和value对象的Map.Entry对象
			Map.Entry<Integer, String> en = it.next();

			// 获取Map.Entry对象中封装的key和value对象
			Integer key = en.getKey();
			String value = en.getValue();

			System.out.println("key=" + key + " value=" + value);
		}
	}

4、实现类 

4.1  LinkedHashMap
   Map 接口主要的实现类就是 HashMap 和 LinkedHashMap,此外还有一个使用较少的Hashtable。
   HashMap 的特点是:在判断键是否重复的时候,采用的算法是 Hash 算法,因此要求作
为 HashMap 的键的对象,也应该正确覆盖 equals 方法和 hashCode 方法。
   LinkedHashMap 和 HashMap 之间的区别有点类似于 LinkedHashSet 和 HashSet 之间的区别:LinkedHashMap 能够保留键值对放入 Map 中的顺序。
   例如,如果我 们把上一 小节的例 子中, Map 接 口的实现 类由 HashMap 改为
LinkedHashMap,修改后的完整的代码如下:

   import java.util.*;
   public class TestLinkedHashMap {
     public static void main(String args[]){
	Map map = new LinkedHashMap();
	map.put("2002", "Brazil");
	map.put("1998", "France");
	map.put("1994", "Brazil");
	map.put("2006", "Italy");

	Set set = map.keySet();
	Iterator iter = set.iterator();
	while(iter.hasNext()){
	  Object key = iter.next();
	  Object value = map.get(key);
	  System.out.println(key + "--->" + value);
	}
   }
}
键值遍历之后,输出结果如下:
2002--->Brazil
1998--->France
1994--->Brazil
2006--->Italy

可以看到,进行键值遍历时,输出的顺序,与我们在 Map 中进行 put 的顺序相同。这就是 LinkedHashMap 的特点,这个类能够保留键值对放入 Map 中的顺序。
4.2   HashMap

底层是哈希表数据结构,线程是不同步的,可以存入null键,null值。要保证键的唯一性,需要覆盖hashCode方法,和equals方法。
案例:自定义对象作为Map的键。

package cn.itcast.gz.map;

import java.util.HashMap;
import java.util.Iterator;
import java.util.Map.Entry;
import java.util.Set;

public class Demo3 {
	public static void main(String[] args) {
		HashMap<Person, String> hm = new HashMap<Person, String>();
		hm.put(new Person("jack", 20), "1001");
		hm.put(new Person("rose", 18), "1002");
		hm.put(new Person("lucy", 19), "1003");
		hm.put(new Person("hmm", 17), "1004");
		hm.put(new Person("ll", 25), "1005");
		System.out.println(hm);
		System.out.println(hm.put(new Person("rose", 18), "1006"));

		Set<Entry<Person, String>> entrySet = hm.entrySet();
		Iterator<Entry<Person, String>> it = entrySet.iterator();
		while (it.hasNext()) {
			Entry<Person, String> next = it.next();
			Person key = next.getKey();
			String value = next.getValue();
			System.out.println(key + " = " + value);
		}
	}
}

class Person {
	private String name;
	private int age;

	Person() {

	}

	public Person(String name, int age) {

		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() + age * 37;
	}

	@Override
	public boolean equals(Object obj) {
		if (obj instanceof Person) {
			Person p = (Person) obj;
			return this.name.equals(p.name) && this.age == p.age;
		} else {
			return false;
		}
	}

	@Override
	public String toString() {

		return "Person@name:" + this.name + " age:" + this.age;
	}

}
}

4.3、TreeMap

 

TreeMap的排序,TreeMap可以对集合中的键进行排序。如何实现键的排序?
方式一:元素自身具备比较性
       和TreeSet一样原理,需要让存储在键位置的对象实现Comparable接口,重写compareTo方法,也就是让元素自身具备比较性,这种方式叫做元素的自然排序也叫做默认排序。
方式二:容器具备比较性
       当元素自身不具备比较性,或者自身具备的比较性不是所需要的。那么此时可以让容器自身具备。需要定义一个类实现接口Comparator,重写compare方法,并将该接口的子类实例对象作为参数传递给TreeMap集合的构造方法。
       注意:当Comparable比较方式和Comparator比较方式同时存在时,以Comparator的比较方式为主;
       注意:在重写compareTo或者compare方法时,必须要明确比较的主要条件相等时要比较次要条件。(假设姓名和年龄一直的人为相同的人,如果想要对人按照年龄的大小来排序,如果年龄相同的人,需要如何处理?不能直接return 0,以为可能姓名不同(年龄相同姓名不同的人是不同的人)。此时就需要进行次要条件判断(需要判断姓名),只有姓名和年龄同时相等的才可以返回0.)
       通过return 0来判断唯一性。

 

import java.util.TreeMap;

public class Demo4 {
	public static void main(String[] args) {
		TreeMap<String, Integer> tree = new TreeMap<String, Integer>();
		tree.put("张三", 19);
		tree.put("李四", 20);
		tree.put("王五", 21);
		tree.put("赵六", 22);
		tree.put("周七", 23);
		tree.put("张三", 24);
		System.out.println(tree);
		System.out.println("张三".compareTo("李四"));//-2094
	}
}

自定义元素排序

package cn.itcast.gz.map;

import java.util.Comparator;
import java.util.Iterator;
import java.util.Map.Entry;
import java.util.Set;
import java.util.TreeMap;

public class Demo3 {
	public static void main(String[] args) {
		TreeMap<Person, String> hm = new TreeMap<Person, String>(
				new MyComparator());
		hm.put(new Person("jack", 20), "1001");
		hm.put(new Person("rose", 18), "1002");
		hm.put(new Person("lucy", 19), "1003");
		hm.put(new Person("hmm", 17), "1004");
		hm.put(new Person("ll", 25), "1005");
		System.out.println(hm);
		System.out.println(hm.put(new Person("rose", 18), "1006"));

		Set<Entry<Person, String>> entrySet = hm.entrySet();
		Iterator<Entry<Person, String>> it = entrySet.iterator();
		while (it.hasNext()) {
			Entry<Person, String> next = it.next();
			Person key = next.getKey();
			String value = next.getValue();
			System.out.println(key + " = " + value);
		}
	}
}

class MyComparator implements Comparator<Person> {

	@Override
	public int compare(Person p1, Person p2) {
		if (p1.getAge() > p2.getAge()) {
			return -1;
		} else if (p1.getAge() < p2.getAge()) {
			return 1;
		}
		return p1.getName().compareTo(p2.getName());
	}

}

class Person implements Comparable<Person> {
	private String name;
	private int age;

	Person() {

	}

	public Person(String name, int age) {

		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() + age * 37;
	}

	@Override
	public boolean equals(Object obj) {
		if (obj instanceof Person) {
			Person p = (Person) obj;
			return this.name.equals(p.name) && this.age == p.age;
		} else {
			return false;
		}
	}

	@Override
	public String toString() {

		return "Person@name:" + this.name + " age:" + this.age;
	}

	@Override
	public int compareTo(Person p) {

		if (this.age > p.age) {
			return 1;
		} else if (this.age < p.age) {
			return -1;
		}
		return this.name.compareTo(p.name);
	}

}

注意:Set的元素不可重复,Map的键不可重复,如果存入重复元素如何处理
Set元素重复元素不能存入add方法返回false
Map的重复健将覆盖旧键,将旧值返回。

 

5、  Collections  类与 与 Comparable

 

   在 java.util 包中,提供了一个 Collections 的类(注意这个类的名字,与我们的 Collection接口只相差最后一个字母 s)。这个类中所有的方法都是静态方法,也就是说,Collections类所有方法都能够通过类名直接调用。这个类为我们提供了很多使用的功能,例如:sort 方法,这个方法能够对 List 进行排序。再例如,max 方法可以找到集合中的最大值,而 min方法可以找到集合中的最小值,等等。
   调用 Collections.sort 方法,可以对一个 List 进行排序。与在接口那一章中讲述的一样,要想对 List 进行排序,就要求 List 中的对象实现 Comparable 接口。

5.1、  Collections与Arrays
集合框架中的工具类:特点:该工具类中的方法都是静态的。
Collections:常见方法:

1、  对list进行二分查找:
      前提该集合一定要有序。
      int binarySearch(list,key);
       //必须根据元素自然顺序对列表进行升级排序
      //要求list 集合中的元素都是Comparable 的子类。
      int binarySearch(list,key,Comparator);
2,对list集合进行排序。
    sort(list); 
    //对list进行排序,其实使用的事list容器中的对象的compareTo方法
    sort(list,comaprator);
    //按照指定比较器进行排序
3,对集合取最大值或者最小值。
   max(Collection)
   max(Collection,comparator)
   min(Collection)
   min(Collection,comparator)
4, 对list集合进行反转。
   reverse(list);
5, 对比较方式进行强行逆转。
   Comparator reverseOrder();
   Comparator reverseOrder(Comparator);
6, 对list集合中的元素进行位置的置换。
   swap(list,x,y);
7, 对list集合进行元素的替换。如果被替换的元素不存在,那么原集合不变。
   replaceAll(list,old,new);
8, 可以将不同步的集合变成同步的集合。
   Set synchronizedSet(Set<T> s)
   Map synchronizedMap(Map<K,V> m)
   List synchronizedList(List<T> list)
9.  如果想要将集合变数组:
   可以使用Collection 中的toArray 方法。注意:是Collection不是Collections工具类
   传入指定的类型数组即可,该数组的长度最好为集合的size。

 

Arrays:用于对数组操作的工具类

1, 二分查找,数组需要有序
    binarySearch(int[])
    binarySearch(double[])
2, 数组排序
    sort(int[])
    sort(char[])……
2, 将数组变成字符串。
    toString(int[])
3, 复制数组。
    copyOf();
4, 复制部分数组。
    copyOfRange():
5, 比较两个数组是否相同。
    equals(int[],int[]);
6, 将数组变成集合。
    List asList(T[]);
    这样可以通过集合的操作来操作数组中元素,
    但是不可以使用增删方法,add,remove。因为数组长度是固定的,会出现
    UnsupportOperationExcetion。
    可以使用的方法:contains,indexOf。。。
    如果数组中存入的基本数据类型,那么asList会将数组实体作为集合中的元素。
    如果数组中的存入的引用数据类型,那么asList会将数组中的元素作为集合中的元素。

 

 

import java.util.ArrayList;
import java.util.Collections;
import java.util.Arrays;
import java.util.List;
class Demo1 
{
	public static void main(String[] args)
	{
		ArrayList<Integer> list = new ArrayList<Integer>();
		list.add(4);
		list.add(3);
		list.add(1);
		list.add(2);
		list.add(3);
		// 排序
		Collections.sort(list);
		// 折半查找的前提是排序好的元素
		System.out.println( Collections.binarySearch( list , 8 ) );  // 找不到返回-插入点-1
		// 反序集合输出
		Collections.reverse( list );
		System.out.println( list );
		// 求最值
		System.out.println( Collections.max( list ) );   // 4
		// fill()  使用指定的元素替换指定集合中的所有元素
		// Collections.fill( list, 5 );
		System.out.println( list );

		// 将数组转换为集合
		Integer is[] = new  Integer[]{6,7,8};
		List<Integer> list2 =  Arrays.asList(is);
		list.addAll( list2 );
		System.out.println( list );

		// 将List转换为数组
		Object [] ins =  list.toArray();
		System.out.println( Arrays.toString( ins ) );
   

	}
} 

 


 

 

集合的练习
问题: 定义一个Person数组,将Person数组中的重复对象剔除?
思路:
1. 描述一个Person类
2. 将数组转换为Arrays.asList() List
3. Set addAll( list )
4. hashCode()且equals()

import java.util.Arrays;
import java.util.Set;
import java.util.List;
import java.util.HashSet;

// 1. 描述Person类
class Person {
	public String name;
	public int age;

	public Person() {
	}

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

	public String toString() {

		return getClass().getName() + " : name=" + this.name + " age="
				+ this.age;

	}

	// 4. 重写hashCode和equals()
	public int hashCode() {

		return this.age;
	}

	public boolean equals(Object o) {
		Person p = null;
		if (o instanceof Person)
			p = (Person) o;
		return this.name.equals(p.name) && (this.age == p.age);
	}
}

class Demo2 {
	public static void main(String[] args) {
		Person[] ps = new Person[] { new Person("jack", 34),
				new Person("lucy", 20), new Person("lili", 10),
				new Person("jack", 34) };
		// 遍历数组
		System.out.println(Arrays.toString(ps));
		// 2. 将自定义对象数组转换为List集合
		List<Person> list = Arrays.asList(ps);
		// 3. 将List转换为Set
		Set<Person> set = new HashSet<Person>();
		set.addAll(list);
		System.out.println(set);

	}
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值