集合

 

/*

 * 我有5个学生,请把这个5个学生的信息存储到数组中,并遍历数组,获取得到每一个学生信息。

 * 学生:Student

 * 成员变量:name,age

 * 构造方法:无参,带参

 * 成员方法:getXxx()/setXxx()

 * 存储学生的数组?自己想想应该是什么样子的?

 * 分析:

 * A:创建学生类。

 * B:创建学生数组(对象数组)

 * C:创建5个学生对象,并赋值。

 * D:C步骤的元素,放到数组中。

 * E:遍历学生数组。

 */

public class ObjectArrayDemo {
public static void main(String[] args) {
// 创建学生数组(对象数组)。
Student[] students = new Student[5];
// for (int x = 0; x < students.length; x++) {
// System.out.println(students[x]);
// }
// System.out.println("---------------------");
 
// 创建5个学生对象,并赋值。
Student s1 = new Student("林青霞", 27);
Student s2 = new Student("风清扬", 30);
Student s3 = new Student("张三", 30);
Student s4 = new Student("赵雅芝", 60);
Student s5 = new Student("王力宏", 35);
 
// 把C步骤的元素,放到数组中。
students[0] = s1;
students[1] = s2;
students[2] = s3;
students[3] = s4;
students[4] = s5;
 
// 看到很相似,就想循环改
// for (int x = 0; x < students.length; x++) {
// students[x] = s + "" + (x + 1);
// }
// 这个是有问题的
 
// 遍历
for (int x = 0; x < students.length; x++) {
//System.out.println(students[x]);

Student s = students[x];
System.out.println(s.getName()+"---"+s.getAge());
}
}
}

 

wKioL1h6LiDQxD-nAADdNAu4ttA690.png 

 

 

 

 

集合类概述

为什么出现集合类?

面向对象语言对事物的体现都是以对象的形式,所以为了方便对多个对象的操作,Java就提供了集合类

 

数组和集合类同是容器,有何不同?

数组虽然也可以存储对象,但长度是固定的集合长度是可变的。数组中可以存储基本数据类型也可以存储对象,集合只能存储对象。

 

集合类的特点

集合只用于存储对象,集合长度是可变的,集合可以存储不同类型的对象

 

wKiom1h6LzqD-GvDAACs7otZY0E168.png

Java 集合可分为 Collection Map 两种体系

Collection接口:

Set元素无序、不可重复的集合

List:元素有序,可重复的集合

 

Map接口

具有映射关系key-value对”的集合

wKiom1h6MEfA6qfnAAHfE4U26vM303.pngwKiom1h6Mc6D5NGsAAERpOeF5yU861.png

Collection 接口

Collection 接口是 ListSet Queue 接口的父接口,该接口里定义的方法既可用于操作 Set 集合,也可用于操作 List Queue 集合

 

JDK不提供此接口的任何直接实现,而是提供更具体的子接口(如:SetList)实现。

 

Java5 之前,Java 集合会丢失容器中所有对象的数据类型,把所有对象都当成 Object 类型处理;从 Java5 增加了泛型以后,Java 集合可以记住容器中对象的数据类型

 

@Test
public void testCollection1() {
Collection coll = new ArrayList();
// 1.size():返回集合中元素的个数
System.out.println(coll.size());
// 2.add(Object obj):向集合中添加一个元素
coll.add(123);
coll.add("AA");
coll.add(new Date());
coll.add("BB");
System.out.println(coll.size());
// 3.addAll(Collection coll):将形参coll中包含的所有元素添加到当前集合中
Collection coll1 = Arrays.asList(1, 2, 3);
coll.addAll(coll1);
System.out.println(coll.size());
// 查看集合元素
System.out.println(coll);
// 4.isEmpty():判断集合是否为空
System.out.println(coll.isEmpty());
// 5.clear():清空集合元素
coll.clear();
System.out.println(coll.isEmpty());
}
 
 
@Test
public void testCollection2() {
Collection coll = new ArrayList();
coll.add(123);
coll.add(new String("AA"));
coll.add(new Date());
coll.add("BB");
// Person p = new Person("MM",23);
coll.add(new Person("MM", 23));
System.out.println(coll);
// 6.contains(Object obj):判断集合中是否包含指定的obj元素。如果包含,返回true,反之返回false
// 判断的依据:根据元素所在的类的equals()方法进行判断
// 明确:如果存入集合中的元素是自定义类的对象。要求:自定义类要重写equals()方法!
boolean b1 = coll.contains(123);
b1 = coll.contains(new String("AA"));
System.out.println(b1);
boolean b2 = coll.contains(new Person("MM", 23));
System.out.println(b2);
// 7.containsAll(Collection coll):判断当前集合中是否包含coll中所有的元素
Collection coll1 = new ArrayList();
coll1.add(123);
coll1.add(new String("AA"));
 
boolean b3 = coll.containsAll(coll1);
System.out.println("#" + b3);
coll1.add(456);
// 8.retainAll(Collection coll):求当前集合与coll的共有的元素,返回给当前集合
coll.retainAll(coll1);
System.out.println(coll);
// 9.remove(Object obj):删除集合中的obj元素。若删除成功,返回true。否则,返回false
boolean b4 = coll.remove("BB");
System.out.println(b4);
 
}
 
@Test
public void testCollection3() {
Collection coll = new ArrayList();
coll.add(123);
coll.add(new String("AA"));
coll.add(new Date());
coll.add("BB");
coll.add(new Person("MM", 23));

Collection coll1 = new ArrayList();
coll1.add(123);
coll1.add(new String("AA"));
// 10.removeAll(Collection coll):从当前集合中删除包含在coll中的元素。
coll.removeAll(coll1);
System.out.println(coll);
//11.equals(Object obj):判断集合中的所有元素是否完全相同
Collection coll2 = new ArrayList();
coll2.add(123);
coll2.add(new String("AA1"));
System.out.println(coll1.equals(coll2));
//12.hashCode():
System.out.println(coll.hashCode());
System.out.println();
//13.toArray() :将集合转化为数组
Object[] obj = coll.toArray();
for(int i = 0;i < obj.length;i++){
System.out.println(obj[i]);
}
System.out.println();
//14.iterator():返回一个Iterator接口实现类的对象,进而实现集合的遍历!
Iterator iterator = coll.iterator();
//方式一:不用
/*System.out.println(iterator.next());
System.out.println(iterator.next());
System.out.println(iterator.next());*/
//方式二:不用
//for(int i = 0;i < coll.size();i++){
//System.out.println(iterator.next());
//}
//方式三:使用
while(iterator.hasNext()){
System.out.println(iterator.next());
}
}

使用迭代器Iterator实现集合的遍历

//正确的写法:使用迭代器Iterator实现集合的遍历
@Test
public void test1(){
Collection coll = new ArrayList();
coll.add(123);
coll.add(new String("AA"));
coll.add(new Date());
coll.add("BB");
coll.add(new Person("MM", 23));

Iterator i = coll.iterator();
while(i.hasNext()){
System.out.println(i.next());
}
}
 
 
//错误的写法
@Test
public void test2(){
Collection coll = new ArrayList();
coll.add(123);
coll.add(new String("AA"));
coll.add(new Date());
coll.add("BB");
coll.add(new Person("MM", 23));

Iterator i = coll.iterator();

while((i.next())!= null){
//java.util.NoSuchElementException
System.out.println(i.next());
}
}
 
 
//使用增强for循环实现集合的遍历
@Test
public void testFor(){
Collection coll = new ArrayList();
coll.add(123);
coll.add(new String("AA"));
coll.add(new Date());
coll.add("BB");
coll.add(new Person("MM", 23));

for(Object i:coll){
System.out.println(i);
}
}

//***********************************************

//使用增强for循环实现数组的遍历

@Test
public void testFor1(){
String[] str = new String[]{"AA","BB","DD"};
for(String s:str){
System.out.println(s);
}
}
 
 
@Test
public void testFor2(){
String[] str = new String[]{"AA","BB","DD"};
for(int i = 0;i < str.length;i++){
str[i] = i + "";
}

for(int i = 0;i < str.length;i++){
System.out.println(str[i]);
}
}
 
//面试题:
@Test
public void testFor3(){
String[] str = new String[]{"AA","BB","DD"};
for(String s : str){
s =  "MM";//此处的s是新定义的局部变量,其值的修改不会对str本身造成影响。
System.out.println(s);
}

for(int i = 0;i < str.length;i++){
System.out.println(str[i]);
}
}

练习题

 

存储字符串并遍历

 
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
 
/*
 * 需求:存储字符串并遍历。
 *
 * 分析:
 * A:创建集合对象
 * B:创建字符串对象
 * C:把字符串对象添加到集合中
 * D:遍历集合
 */
public class CollectionTest {
public static void main(String[] args) {
// 创建集合对象
Collection c = new ArrayList();
 
// 创建字符串对象
// 把字符串对象添加到集合中
c.add("zhang");
c.add("li");
c.add("guo");
c.add("liu");
c.add("duan");
 
// 遍历集合
// 通过集合对象获取迭代器对象
Iterator it = c.iterator();
// 通过迭代器对象的hasNext()方法判断有没有元素
while (it.hasNext()) {
// 通过迭代器对象的next()方法获取元素
String s = (String) it.next();
System.out.println(s);
}
}
}

 

存储自定义对象并遍历

 

public class Student {
private String name;
private int age;
 
public Student() {
super();
}
 
public Student(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;
}
 
}

 

import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
 
/*
 * 需求:存储自定义对象并遍历Student(name,age)
 *
 * 分析:
 * A:创建学生类
 * B:创建集合对象
 * C:创建学生对象
 * D:把学生对象添加到集合对象中
 * E:遍历集合
 */
public class CollectionTest2 {
public static void main(String[] args) {
// 创建集合对象
Collection c = new ArrayList();
 
// 创建学生对象
Student s1 = new Student("貂蝉", 25);
Student s2 = new Student("小乔", 16);
Student s3 = new Student("黄月英", 20);
Student s4 = new Student();
s4.setName("大乔");
s4.setAge(26);
 
// 把学生对象添加到集合对象中
c.add(s1);
c.add(s2);
c.add(s3);
c.add(s4);
c.add(new Student("孙尚香", 18)); // 匿名对象
 
// 遍历集合
Iterator it = c.iterator();
while (it.hasNext()) {
Student s = (Student) it.next();
System.out.println(s.getName() + "---" + s.getAge());
}
}
}

 

 

List接口

Java中数组用来存储数据的局限性

List集合类中元素有序、且可重复,集合中的每个元素都有其对应的顺序索引

List容器中的元素都对应一个整数型的序号记载其在容器中的位置,可以根据序号存取容器中的元素。

JDK APIList接口的实现类常用的有:ArrayListLinkedListVector

 

 

List 集合里添加了一些根据索引来操作集合元素的方法

wKiom1h6NNCzw982AAGgn0lFPTA858.png 

List实现类之一:ArrayList

ArrayList List 接口的典型实现类

本质上,ArrayList是对象引用的一个变长数组

ArrayList 是线程不安全的,而 Vector 是线程安全的,即使为保证 List 集合线程安全,也不推荐使用Vector

 

Arrays.asList() 方法返回的 List 集合既不是 ArrayList 实例,也不是 Vector 实例。 Arrays.asList()  返回值是一个固定长度的 List 集合

 

 

List实现类之二:LinkedList

对于频繁的插入或删除元素的操作,建议使用LinkedList类,效率较高

 

List 实现类之三:Vector

Vector 是一个古老的集合,JDK1.0就有了。大多数操作与ArrayList相同,区别之处在于Vector是线程安全的。

在各种list中,最好把ArrayList作为缺省选择。当插入、删除频繁时,使用LinkedListVector总是比ArrayList慢,所以尽量避免使用。


public class TestList {

//ArrayList:List的主要实现类
/*
 * List中相对于Collection,新增加的方法
 *  void add(int index, Object ele):在指定的索引位置index添加元素ele
boolean addAll(int index, Collection eles)
Object get(int index):获取指定索引的元素
Object remove(int index):删除指定索引位置的元素
Object set(int index, Object ele):设置指定索引位置的元素为ele
int indexOf(Object obj):返回obj在集合中首次出现的位置。没有的话,返回-1
int lastIndexOf(Object obj):返回obj在集合中最后一次出现的位置.没有的话,返回-1
List subList(int fromIndex, int toIndex):返回从fromIndex到toIndex结束的左闭右开一个子list

List常用的方法:增(add(Object obj)) 删(remove) 改(set(int index,Object obj))
查(get(int index)) 插(add(int index, Object ele)) 长度(size())
 */
@Test
public void testList2(){
List list = new ArrayList();
list.add(123);
list.add(456);
list.add(new String("AA"));
list.add(new String("GG"));
list.add(456);
System.out.println(list.indexOf(456));
System.out.println(list.lastIndexOf(456));
System.out.println(list.indexOf(123) == list.lastIndexOf(123));
System.out.println(list.indexOf(444));

List list1 = list.subList(0, 3);
System.out.println(list1);
}

@Test
public void testList1(){
List list = new ArrayList();
list.add(123);
list.add(456);
list.add(new String("AA"));
list.add(new String("GG"));
System.out.println(list);
list.add(0,555);
System.out.println(list);
Object obj = list.get(1);
System.out.println(obj);
list.remove(0);
System.out.println(list.get(0));
list.set(0, 111);
System.out.println(list.get(0));
}
}

List案例

List集合存储字符串并遍历。

import java.util.Iterator;
import java.util.List;
import java.util.ArrayList;
 
/*
 * 需求:List集合存储字符串并遍历。
 */
public class ListDemo {
public static void main(String[] args) {
// 创建集合对象
List list = new ArrayList();
 
// 创建字符串并添加字符串
list.add("hello");
list.add("world");
list.add("java");
 
// 遍历集合
Iterator it = list.iterator();
while (it.hasNext()) {
String s = (String) it.next();
System.out.println(s);
}
}
}

存储自定义对象并遍历

public class Student {
// 成员变量
private String name;
private int age;
 
// 构造方法
public Student() {
super();
}
 
public Student(String name, int age) {
super();
this.name = name;
this.age = age;
}
 
// 成员方法
// getXxx()/setXxx()
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;
}
}
 
mport java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
 
/*
 * 存储自定义对象并遍历
 */
public class ListDemo {
public static void main(String[] args) {
// 创建集合对象
List list = new ArrayList();
 
// 创建学生对象
Student s1 = new Student("白骨精", 30);
Student s2 = new Student("蜘蛛精", 40);
Student s3 = new Student("观音姐姐", 22);
 
// 把学生对象添加到集合对象中
list.add(s1);
list.add(s2);
list.add(s3);
 
// 遍历
Iterator it = list.iterator();
while (it.hasNext()) {
Student s = (Student) it.next();
System.out.println(s.getName() + "---" + s.getAge());
}
}
}

List集合的特有功能

import java.util.ArrayList;
import java.util.List;
 
/*
 * List集合的特有功能:
 * A:添加功能
 * void add(int index,Object element):在指定位置添加元素
 * B:获取功能
 * Object get(int index):获取指定位置的元素
 * D:删除功能
 * Object remove(int index):根据索引删除元素,返回被删除的元素
 * E:修改功能
 * Object set(int index,Object element):根据索引修改元素,返回被修饰的元素
 */
public class ListDemo {
public static void main(String[] args) {
// 创建集合对象
List list = new ArrayList();
 
// 添加元素
list.add("hello");
list.add("world");
list.add("java");
 
// void add(int index,Object element):在指定位置添加元素
// list.add(1, "android");//没有问题
// IndexOutOfBoundsException
// list.add(11, "javaee");//有问题
// list.add(3, "javaee"); //没有问题
// list.add(4, "javaee"); //有问题
 
// Object get(int index):获取指定位置的元素
// System.out.println("get:" + list.get(1));
// IndexOutOfBoundsException
// System.out.println("get:" + list.get(11));
 
// Object remove(int index):根据索引删除元素,返回被删除的元素
// System.out.println("remove:" + list.remove(1));
// IndexOutOfBoundsException
// System.out.println("remove:" + list.remove(11));
 
// Object set(int index,Object element):根据索引修改元素,返回被修饰的元素
System.out.println("set:" + list.set(1, "javaee"));
 
System.out.println("list:" + list);
}
}

 

List遍历功能

 

import java.util.ArrayList;
import java.util.List;
 
/*
 * List集合的特有遍历功能:
 * size()和get()方法结合使用
 */
public class ListDemo2 {
public static void main(String[] args) {
// 创建集合对象
List list = new ArrayList();
 
// 添加元素
list.add("hello");
list.add("world");
list.add("java");
 
// Object get(int index):获取指定位置的元素
// System.out.println(list.get(0));
// System.out.println(list.get(1));
// System.out.println(list.get(2));
// IndexOutOfBoundsException
// System.out.println(list.get(3));
 
// 用循环改进
// for (int x = 0; x < 3; x++) {
// System.out.println(list.get(x));
// }
// 如果元素过多,数起来就比较麻烦,所以我们使用集合的一个长度功能:size()
// 最终的遍历方式就是:size()和get()
for (int x = 0; x < list.size(); x++) {
// System.out.println(list.get(x));
 
String s = (String) list.get(x);
System.out.println(s);
}
}
}

 

List:(面试题List的子类特点)

ArrayList:

底层数据结构是数组,查询快,增删慢。

线程不安全,效率高。

Vector:

底层数据结构是数组,查询快,增删慢。

线程安全,效率低。

LinkedList:

底层数据结构是链表,查询慢,增删快。

线程不安全,效率高。


List有三个儿子,我们到底使用谁呢?

看需求(情况)


要安全吗?

要:Vector(即使要安全,也不用这个了,后面有替代的)

不要:ArrayList或者LinkedList

查询多:ArrayList

增删多:LinkedList


如果你什么都不懂,就用ArrayList

 

 

 

 

作业:

1:集合的由来?

2:集合和数组的区别?

3:Collection集合的功能概述?

4:Collection集合存储字符串并遍历?(迭代器)

5:Collection集合存储自定义对象并遍历?(迭代器)

6:List集合的特有功能?

7:List集合存储字符串并遍历?(迭代器和普通for)

8:List集合存储自定义对象并遍历?(迭代器和普通for)

11:List集合的子类特点

ArrayList:

Vector:

LinkedList:

12:List的三个儿子你准备使用谁?请说明理由。

 

 

ArrayList

ArrayList类概述

底层数据结构是数组,查询快,增删慢

线程不安全,效率高

 

ArrayList案例

 

import java.util.ArrayList;
import java.util.Iterator;
 
/*
 * List的子类特点:
 * ArrayList:
 * 底层数据结构是数组,查询快,增删慢
 * 线程不安全,效率高
 * Vector:
 * 底层数据结构是数组,查询快,增删慢
 * 线程安全,效率低
 * LinkedList:
 *  底层数据结构是链表,查询慢,增删快
 * 线程不安全,效率高
 *
 * 案例:
 * 使用List的任何子类存储字符串或者存储自定义对象并遍历。
 *
 * ArrayList的使用。
 * 存储字符串并遍历
 */
public class ArrayListDemo {
public static void main(String[] args) {
// 创建集合对象
ArrayList array = new ArrayList();
 
// 创建元素对象,并添加元素
array.add("hello");
array.add("world");
array.add("java");
 
// 遍历
Iterator it = array.iterator();
while (it.hasNext()) {
String s = (String) it.next();
System.out.println(s);
}
 
System.out.println("-----------");
 
for (int x = 0; x < array.size(); x++) {
String s = (String) array.get(x);
System.out.println(s);
}
}
}

 

 

 

集合对象

 
import java.util.ArrayList;
import java.util.Iterator;
 
/*
 * ArrayList存储自定义对象并遍历
 */
public class ArrayListDemo2 {
public static void main(String[] args) {
// 创建集合对象
ArrayList array = new ArrayList();
 
// 创建学生对象
Student s1 = new Student("武松", 30);
Student s2 = new Student("鲁智深", 40);
Student s3 = new Student("林冲", 36);
Student s4 = new Student("杨志", 38);
 
// 添加元素
array.add(s1);
array.add(s2);
array.add(s3);
array.add(s4);
 
// 遍历
Iterator it = array.iterator();
while (it.hasNext()) {
Student s = (Student) it.next();
System.out.println(s.getName() + "---" + s.getAge());
}
 
System.out.println("----------------");
 
for (int x = 0; x < array.size(); x++) {
// ClassCastException 注意,千万要搞清楚类型
// String s = (String) array.get(x);
// System.out.println(s);
 
Student s = (Student) array.get(x);
System.out.println(s.getName() + "---" + s.getAge());
}
}
}

Vector类概述及使用

Vector类概述

  底层数据结构是数组,查询快,增删慢

  线程安全,效率低

Vector类特有功能

  public void addElement(E obj)

  public E elementAt(int index)

  public Enumeration elements()

Vector案例

 存储字符串并遍历

 存储自定义对象并遍历

 

 

import java.util.Enumeration;
import java.util.Vector;
 
/*
 * Vector的特有功能:
 * 1:添加功能
 * public void addElement(Object obj)--add()
 * 2:获取功能
 * public Object elementAt(int index)--  get()
 * public Enumeration elements()--Iterator iterator()
 * boolean hasMoreElements()hasNext()
 * Object nextElement()next()
 *
 * JDK升级的原因:
 * A:安全
 * B:效率
 * C:简化书写
 */
public class VectorDemo {
public static void main(String[] args) {
// 创建集合对象
Vector v = new Vector();
 
// 添加功能
v.addElement("hello");
v.addElement("world");
v.addElement("java");
 
// 遍历
for (int x = 0; x < v.size(); x++) {
String s = (String) v.elementAt(x);
System.out.println(s);
}
 
System.out.println("------------------");
 
Enumeration en = v.elements(); // 返回的是实现类的对象
while (en.hasMoreElements()) {
String s = (String) en.nextElement();
System.out.println(s);
}
}
}

 

 

LinkedList类概述及使用

LinkedList类概述

   底层数据结构是链表,查询慢,增删快

   线程不安全,效率高

LinkedList类特有功能

  public void addFirst(E e)addLast(E e)

  public E getFirst()getLast()

  public E removeFirst()public E removeLast()

 LinkedList案例

存储字符串并遍历

存储自定义对象并遍历

import java.util.LinkedList;
 
/*
 * LinkedList的特有功能:
 * A:添加功能
 * public void addFirst(Object e)
 * public void addLast(Object e)
 * B:获取功能
 * public Object getFirst()
 * public Obejct getLast()
 * C:删除功能
 * public Object removeFirst()
 * public Object removeLast()
 */
public class LinkedListDemo {
public static void main(String[] args) {
// 创建集合对象
LinkedList link = new LinkedList();
 
// 添加元素
link.add("hello");
link.add("world");
link.add("java");
 
// public void addFirst(Object e)
// link.addFirst("javaee");
// public void addLast(Object e)
// link.addLast("android");
 
// public Object getFirst()
// System.out.println("getFirst:" + link.getFirst());
// public Obejct getLast()
// System.out.println("getLast:" + link.getLast());
 
// public Object removeFirst()
System.out.println("removeFirst:" + link.removeFirst());
// public Object removeLast()
System.out.println("removeLast:" + link.removeLast());
 
// 输出对象名
System.out.println("link:" + link);
}
}

去除集合中字符串的重复值(字符串的内容相同)

import java.util.ArrayList;
import java.util.Iterator;
 
/*
 * ArrayList去除集合中字符串的重复值(字符串的内容相同)
 *
 * 分析:
 * A:创建集合对象
 * B:添加多个字符串元素(包含内容相同的)
 * C:创建新集合
 * D:遍历旧集合,获取得到每一个元素
 * E:拿这个元素到新集合去找,看有没有
 * 有:不搭理它
 * 没有:就添加到新集合
 * F:遍历新集合
 */
public class ArrayListDemo {
public static void main(String[] args) {
// 创建集合对象
ArrayList array = new ArrayList();
 
// 添加多个字符串元素(包含内容相同的)
array.add("hello");
array.add("world");
array.add("java");
array.add("world");
array.add("java");
array.add("world");
array.add("world");
array.add("world");
array.add("world");
array.add("java");
array.add("world");
 
// 创建新集合
ArrayList newArray = new ArrayList();
 
// 遍历旧集合,获取得到每一个元素
Iterator it = array.iterator();
while (it.hasNext()) {
String s = (String) it.next();
 
// 拿这个元素到新集合去找,看有没有
if (!newArray.contains(s)) {
newArray.add(s);
}
}
 
// 遍历新集合
for (int x = 0; x < newArray.size(); x++) {
String s = (String) newArray.get(x);
System.out.println(s);
}
}
}

 

方案二

import java.util.ArrayList;
import java.util.Iterator;
 
/*
 * 需求:ArrayList去除集合中字符串的重复值(字符串的内容相同)
 * 要求:不能创建新的集合,就在以前的集合上做。
 */
public class ArrayListDemo2 {
public static void main(String[] args) {
// 创建集合对象
ArrayList array = new ArrayList();
 
// 添加多个字符串元素(包含内容相同的)
array.add("hello");
array.add("world");
array.add("java");
array.add("world");
array.add("java");
array.add("world");
array.add("world");
array.add("world");
array.add("world");
array.add("java");
array.add("world");
 
// 由选择排序思想引入,我们就可以通过这种思想做这个题目
// 拿0索引的依次和后面的比较,有就把后的干掉
// 同理,拿1索引...
for (int x = 0; x < array.size() - 1; x++) {
for (int y = x + 1; y < array.size(); y++) {
if (array.get(x).equals(array.get(y))) {
array.remove(y);
y--;
}
}
}
 
// 遍历集合
Iterator it = array.iterator();
while (it.hasNext()) {
String s = (String) it.next();
System.out.println(s);
}
}
}

去除集合中自定义对象的重复值(对象的成员变量值都相同)

import java.util.ArrayList;
import java.util.Iterator;
 
/*
 * 需求:去除集合中自定义对象的重复值(对象的成员变量值都相同)
 *
 * 我们按照和字符串一样的操作,发现出问题了。
 * 为什么呢?
 * 我们必须思考哪里会出问题?
 * 通过简单的分析,我们知道问题出现在了判断上。
 * 而这个判断功能是集合自己提供的,所以我们如果想很清楚的知道它是如何判断的,就应该去看源码。
 * contains()方法的底层依赖的是equals()方法。
 * 而我们的学生类中没有equals()方法,这个时候,默认使用的是它父亲Object的equals()方法
 * Object()的equals()默认比较的是地址值,所以,它们进去了。因为new的东西,地址值都不同。
 * 按照我们自己的需求,比较成员变量的值,重写equals()即可。
 * 自动生成即可。
 */
public class ArrayListDemo3 {
public static void main(String[] args) {
// 创建集合对象
ArrayList array = new ArrayList();
 
// 创建学生对象
Student s1 = new Student("林青霞", 27);
Student s2 = new Student("林志玲", 40);
Student s3 = new Student("凤姐", 35);
Student s4 = new Student("芙蓉姐姐", 18);
Student s5 = new Student("翠花", 16);
Student s6 = new Student("林青霞", 27);
Student s7 = new Student("林青霞", 18);
 
// 添加元素
array.add(s1);
array.add(s2);
array.add(s3);
array.add(s4);
array.add(s5);
array.add(s6);
array.add(s7);
 
// 创建新集合
ArrayList newArray = new ArrayList();
 
// 遍历旧集合,获取得到每一个元素
Iterator it = array.iterator();
while (it.hasNext()) {
Student s = (Student) it.next();
 
// 拿这个元素到新集合去找,看有没有
if (!newArray.contains(s)) {
newArray.add(s);
}
}
 
// 遍历新集合
for (int x = 0; x < newArray.size(); x++) {
Student s = (Student) newArray.get(x);
System.out.println(s.getName() + "---" + s.getAge());
}
}
}
 
public class Student {
private String name;
private int age;
 
public Student() {
super();
}
 
public Student(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 boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Student other = (Student) obj;
if (age != other.age)
return false;
if (name == null) {
if (other.name != null)
return false;
} else if (!name.equals(other.name))
return false;
return true;
}
 
}

 

总结:

Try{

}catcher(){

}finally{

 

}

我们抛出异常Exception

 

Collection-----List 有序的可以重复---Arraylist

Collection a = new ArrayList

迭代器

List list = new ArrayList();

List.get();

For(int i=0i<list.size();i++){

  List.get(i)

}

ToString

 

 

            -----Set  无序不可重复



集合

泛型概述及使用

1泛型是一种特殊的类型,它把指定类型的工作推迟到客户端代码声明并实例化类或方法的时候进行。

   也被称为参数化类型,可以把类型当作参数一样传递过来,在传递过来之前我不明确,但是在使用的时候我就用明确了。

2泛型的好处

A:提高了程序的安全性

B:将运行期遇到的问题转移到了编译期

C:省去了类型强转的麻烦

 

import java.util.ArrayList;
import java.util.Iterator;
 
/*
 * ArrayList存储字符串并遍历
 *
 * 我们按照正常的写法来写这个程序, 结果确出错了。
 * 为什么呢?
 * 因为我们开始存储的时候,存储了String和Integer两种类型的数据。
 * 而在遍历的时候,我们把它们都当作String类型处理的,做了转换,所以就报错了。
 * 但是呢,它在编译期间却没有告诉我们。
 * 所以,我就觉得这个设计的不好。
 * 回想一下,我们的数组
 * String[] strArray = new String[3];
 * strArray[0] = "hello";
 * strArray[1] = "world";
 * strArray[2] = 10;
 * 集合也模仿着数组的这种做法,在创建对象的时候明确元素的数据类型。这样就不会在有问题了。
 * 而这种技术被称为:泛型。
 *
 * 泛型:是一种把类型明确的工作推迟到创建对象或者调用方法的时候才去明确的特殊的类型。参数化类型,把类型当作参数一样的传递。
 * 格式:
 * <数据类型>
 * 此处的数据类型只能是引用类型。
 * 好处:
 * A:把运行时期的问题提前到了编译期间
 * B:避免了强制类型转换
 * C:优化了程序设计,解决了×××警告线
 */
public class GenericDemo {
public static void main(String[] args) {
// 创建
ArrayList<String> array = new ArrayList<String>();
 
// 添加元素
array.add("hello");
array.add("world");
array.add("java");
// array.add(new Integer(100));
//array.add(10); // JDK5以后的自动装箱
// 等价于:array.add(Integer.valueOf(10));
 
// 遍历
Iterator<String> it = array.iterator();
while (it.hasNext()) {
// ClassCastException
// String s = (String) it.next();
String s = it.next();
System.out.println(s);
}
 
// 看下面这个代码
// String[] strArray = new String[3];
// strArray[0] = "hello";
// strArray[1] = "world";
// strArray[2] = 10;
}
}

 

 

代码演示

 

import java.util.ArrayList;
import java.util.Iterator;
 
/*
 * 泛型在哪些地方使用呢?
 * 看API,如果类,接口,抽象类后面跟的有<E>就说要使用泛型。一般来说就是在集合中使用。
 */
public class ArrayListDemo {
public static void main(String[] args) {
// 用ArrayList存储字符串元素,并遍历。用泛型改进代码
ArrayList<String> array = new ArrayList<String>();
 
array.add("hello");
array.add("world");
array.add("java");
 
Iterator<String> it = array.iterator();
while (it.hasNext()) {
String s = it.next();
System.out.println(s);
}
System.out.println("-----------------");
 
for (int x = 0; x < array.size(); x++) {
String s = array.get(x);
System.out.println(s);
}
}
}

 

 

代码演示二

import java.util.ArrayList;
import java.util.Iterator;
 
/*
 * 需求:存储自定义对象并遍历。
 *
 * A:创建学生类
 * B:创建集合对象
 * C:创建元素对象
 * D:把元素添加到集合
 * E:遍历集合
 */
public class ArrayListDemo2 {
public static void main(String[] args) {
// 创建集合对象
// JDK7的新特性:泛型推断。
// ArrayList<Student> array = new ArrayList<>();
// 但是我不建议这样使用。
ArrayList<Student> array = new ArrayList<Student>();
 
// 创建元素对象
Student s1 = new Student("曹操", 40); // 后知后觉
Student s2 = new Student("蒋干", 30); // 不知不觉
Student s3 = new Student("诸葛亮", 26);// 先知先觉
 
// 添加元素
array.add(s1);
array.add(s2);
array.add(s3);
 
// 遍历
Iterator<Student> it = array.iterator();
while (it.hasNext()) {
Student s = it.next();
System.out.println(s.getName() + "---" + s.getAge());
}
System.out.println("------------------");
 
for (int x = 0; x < array.size(); x++) {
Student s = array.get(x);
System.out.println(s.getName() + "---" + s.getAge());
}
}
}
 
 
public class Student {
// 姓名
private String name;
// 年龄
private int age;
 
public Student() {
super();
}
 
public Student(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;
}
 
}

 

为什么会有泛型呢?

早期的Object类型可以接收任意的对象类型,但是在实际的使用中,会有类型转换的问题。也就存在这隐患,所以Java提供了泛型来解决这个安全问题。1.5

 

泛型应用

泛型类

把泛型定义在类上

格式:public class 类名<泛型类型1,>

注意:泛型类型必须引用类型

泛型方法

把泛型定义在方法上

格式:public <泛型类型> 返回类型 方法名(泛型类型 .)

泛型接口

把泛型定义在接口上

格式:public  interface 接口名<泛型类型1>

 

public class ObjectTool {
private Object obj;
 
public Object getObj() {
return obj;
}
 
public void setObj(Object obj) { // Object obj = new Integer(30);
this.obj = obj;
}
}
 
/*
 * 早期的时候,我们使用Object来代表任意的类型。
 * 向上转型是没有任何问题的,但是在向下转型的时候其实隐含了类型转换的问题。
 * 也就是说这样的程序其实并不是安全的。所以Java在JDK5后引入了泛型,提高程序的安全性。
 */
public class ObjectToolDemo {
public static void main(String[] args) {
ObjectTool ot = new ObjectTool();
 
// 正常使用
ot.setObj(new Integer(27));
Integer i = (Integer) ot.getObj();
System.out.println("年龄是:" + i);
 
ot.setObj(new String("林青霞"));
String s = (String) ot.getObj();
System.out.println("姓名是:" + s);
 
System.out.println("---------");
ot.setObj(new Integer(30));
// ClassCastException
String ss = (String) ot.getObj();
System.out.println("姓名是:" + ss);
}
}

 

把泛型定义在类上

/*
 * 泛型类:把泛型定义在类上
 */
public class ObjectTool<T> {
private T obj;
 
public T getObj() {
return obj;
}
 
public void setObj(T obj) {
this.obj = obj;
}
}
 
/*
 * 泛型类的测试
 */
public class ObjectToolDemo {
public static void main(String[] args) {
// ObjectTool ot = new ObjectTool();
//
// ot.setObj(new String("风清扬"));
// String s = (String) ot.getObj();
// System.out.println("姓名是:" + s);
//
// ot.setObj(new Integer(30));
// Integer i = (Integer) ot.getObj();
// System.out.println("年龄是:" + i);
 
// ot.setObj(new String("林青霞"));
// // ClassCastException
// Integer ii = (Integer) ot.getObj();
// System.out.println("姓名是:" + ii);
 
System.out.println("-------------");
 
ObjectTool<String> ot = new ObjectTool<String>();
// ot.setObj(new Integer(27)); //这个时候编译期间就过不去
ot.setObj(new String("林青霞"));
String s = ot.getObj();
System.out.println("姓名是:" + s);
 
ObjectTool<Integer> ot2 = new ObjectTool<Integer>();
// ot2.setObj(new String("风清扬"));//这个时候编译期间就过不去
ot2.setObj(new Integer(27));
Integer i = ot2.getObj();
System.out.println("年龄是:" + i);
}
}

泛型方法:把泛型定义在方法上

 

//public class ObjectTool<T> {
 public void show(String s) {
 System.out.println(s);
 }

 public void show(Integer i) {
 System.out.println(i);
 }

 public void show(Boolean b) {
 System.out.println(b);
 }
//
//public void show(T t) {
//System.out.println(t);
//}
// }
 
/*
 * 泛型方法:把泛型定义在方法上
 */
public class ObjectTool {
public <T> void show(T t) {
System.out.println(t);
}
}
 
public class ObjectToolDemo {
public static void main(String[] args) {
// ObjectTool ot = new ObjectTool();
// ot.show("hello");
// ot.show(100);
// ot.show(true);
 
// ObjectTool<String> ot = new ObjectTool<String>();
// ot.show("hello");
//
// ObjectTool<Integer> ot2 = new ObjectTool<Integer>();
// ot2.show(100);
//
// ObjectTool<Boolean> ot3 = new ObjectTool<Boolean>();
// ot3.show(true);
 
// 如果还听得懂,那就说明泛型类是没有问题的
// 但是呢,谁说了我的方法一定要和类的类型的一致呢?
// 我要是类上没有泛型的话,方法还能不能接收任意类型的参数了呢?
 
// 定义泛型方法后
ObjectTool ot = new ObjectTool();
ot.show("hello");
ot.show(100);
ot.show(true);
}
}

把泛型定义在接口上

/*
 * 泛型接口:把泛型定义在接口上
 */
public interface Inter<T> {
public abstract void show(T t);
}
 
 
//实现类在实现接口的时候
//第一种情况:已经知道该是什么类型的了
 
//public class InterImpl implements Inter<String> {
//
//@Override
//public void show(String t) {
//System.out.println(t);
//}
// }
 
//第二种情况:还不知道是什么类型的
public class InterImpl<T> implements Inter<T> {
 
@Override
public void show(T t) {
System.out.println(t);
}
}
 
public class InterDemo {
public static void main(String[] args) {
// 第一种情况的测试
// Inter<String> i = new InterImpl();
// i.show("hello");
 
// // 第二种情况的测试
Inter<String> i = new InterImpl<String>();
i.show("hello");
 
Inter<Integer> ii = new InterImpl<Integer>();
ii.show(100);
}
}

泛型高级(通配符)

泛型通配符<?>

任意类型,如果没有明确,那么就是Object以及任意的Java类了

? extends E

向上限定,E及其子类

? super E

向下限定,E及其父类

 

 

import java.util.ArrayList;
import java.util.Collection;
 
/*
 * 泛型高级(通配符)
 * ?:任意类型,如果没有明确,那么就是Object以及任意的Java类了
 * ? extends E:向下限定,E及其子类
 * ? super E:向上限定,E极其父类
 */
public class GenericDemo {
public static void main(String[] args) {
// 泛型如果明确的写的时候,前后必须一致
Collection<Object> c1 = new ArrayList<Object>();
// Collection<Object> c2 = new ArrayList<Animal>();
// Collection<Object> c3 = new ArrayList<Dog>();
// Collection<Object> c4 = new ArrayList<Cat>();
 
// ?表示任意的类型都是可以的
Collection<?> c5 = new ArrayList<Object>();
Collection<?> c6 = new ArrayList<Animal>();
Collection<?> c7 = new ArrayList<Dog>();
Collection<?> c8 = new ArrayList<Cat>();
 
// ? extends E:向下限定,E及其子类
// Collection<? extends Animal> c9 = new ArrayList<Object>();
Collection<? extends Animal> c10 = new ArrayList<Animal>();
Collection<? extends Animal> c11 = new ArrayList<Dog>();
Collection<? extends Animal> c12 = new ArrayList<Cat>();
 
// ? super E:向上限定,E极其父类
Collection<? super Animal> c13 = new ArrayList<Object>();
Collection<? super Animal> c14 = new ArrayList<Animal>();
// Collection<? super Animal> c15 = new ArrayList<Dog>();
// Collection<? super Animal> c16 = new ArrayList<Cat>();
}
}
class Animal {
}
class Dog extends Animal {
}
class Cat extends Animal {
}

 

可变参数概述及使用

可变参数概述

   定义方法的时候不知道该定义多少个参数

格式

   修饰符 返回值类型 方法名(数据类型…  变量名){}

注意

  这里的变量其实是一个数组

  如果一个方法有可变参数,并且有多个参数,那么,可变参数肯定是最后一个

/*
 * 可变参数:定义方法的时候不知道该定义多少个参数
 * 格式:
 * 修饰符 返回值类型 方法名(数据类型…  变量名){
 *
 * }
 *
 * 注意:
 * 这里的变量其实是一个数组
 * 如果一个方法有可变参数,并且有多个参数,那么,可变参数肯定是最后一个
 */
public class ArgsDemo {
public static void main(String[] args) {
// 2个数据求和
int a = 10;
int b = 20;
int result = sum(a, b);
System.out.println("result:" + result);
 
// 3个数据的求和
int c = 30;
result = sum(a, b, c);
System.out.println("result:" + result);
 
// 4个数据的求和
int d = 30;
result = sum(a, b, c, d);
System.out.println("result:" + result);
 
// 需求:我要写一个求和的功能,到底是几个数据求和呢,我不太清楚,但是我知道在调用的时候我肯定就知道了
// 为了解决这个问题,Java就提供了一个东西:可变参数
result = sum(a, b, c, d, 40);
System.out.println("result:" + result);
 
result = sum(a, b, c, d, 40, 50);
System.out.println("result:" + result);
}
 
public static int sum(int... a) {
// System.out.println(a);
//return 0;
 
int s = 0;

for(int x : a){
s +=x;
}

return s;
}
 
// public static int sum(int a, int b, int c, int d) {
// return a + b + c + d;
// }
//
// public static int sum(int a, int b, int c) {
// return a + b + c;
// }
//
// public static int sum(int a, int b) {
// return a + b;
// }
}

 

集合的嵌套遍历

 wKiom1h6IGei6WgnAABrhbo5vUs631.png

 
public class Student {
private String name;
private int age;
 
public Student() {
super();
}
 
public Student(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;
}
 
}

 

 

/*

 * 集合的嵌套遍历

 * 需求:

 * 我们班有学生,每一个学生是不是一个对象。所以我们可以使用一个集合表示我们班级的学生。ArrayList<Student>

 * 但是呢,我们旁边是不是还有班级,每个班级是不是也是一个ArrayList<Student>

 * 而我现在有多个ArrayList<Student>。也要用集合存储,怎么办呢?

 * 就是这个样子的:ArrayList<ArrayList<Student>>

 */

public class ArrayListDemo {
public static void main(String[] args) {
// 创建大集合
ArrayList<ArrayList<Student>> bigArrayList = new ArrayList<ArrayList<Student>>();
 
// 创建第一个班级的学生集合
ArrayList<Student> firstArrayList = new ArrayList<Student>();
// 创建学生
Student s1 = new Student("唐僧", 30);
Student s2 = new Student("孙悟空", 29);
Student s3 = new Student("猪八戒", 28);
Student s4 = new Student("沙僧", 27);
Student s5 = new Student("白龙马", 26);
// 学生进班
firstArrayList.add(s1);
firstArrayList.add(s2);
firstArrayList.add(s3);
firstArrayList.add(s4);
firstArrayList.add(s5);
// 把第一个班级存储到学生系统中
bigArrayList.add(firstArrayList);
 
// 创建第二个班级的学生集合
ArrayList<Student> secondArrayList = new ArrayList<Student>();
// 创建学生
Student s11 = new Student("诸葛亮", 30);
Student s22 = new Student("司马懿", 28);
Student s33 = new Student("周瑜", 26);
// 学生进班
secondArrayList.add(s11);
secondArrayList.add(s22);
secondArrayList.add(s33);
// 把第二个班级存储到学生系统中
bigArrayList.add(secondArrayList);
 
// 创建第三个班级的学生集合
ArrayList<Student> thirdArrayList = new ArrayList<Student>();
// 创建学生
Student s111 = new Student("宋江", 40);
Student s222 = new Student("吴用", 35);
Student s333 = new Student("高俅", 30);
Student s444 = new Student("李师师", 22);
// 学生进班
thirdArrayList.add(s111);
thirdArrayList.add(s222);
thirdArrayList.add(s333);
thirdArrayList.add(s444);
// 把第三个班级存储到学生系统中
bigArrayList.add(thirdArrayList);
 
// 遍历集合
for (ArrayList<Student> array : bigArrayList) {
for (Student s : array) {
System.out.println(s.getName() + "---" + s.getAge());
}
}
}
}

 

获取101-20之间的随机数,要求不能重复

 用数组实现,但是数组的长度是固定的,长度不好确定。

  所以我们使用集合实现。

 

/*

 * 获取101-20之间的随机数,要求不能重复

 *

 * 用数组实现,但是数组的长度是固定的,长度不好确定。

 * 所以我们使用集合实现。

 *

 * 分析:

 * A:创建产生随机数的对象

 * B:创建一个存储随机数的集合。

 * C:定义一个统计变量。从0开始。

 * D:判断统计遍历是否小于10

 * :先产生一个随机数,判断该随机数在集合中是否存在。

 * 如果不存在:就添加,统计变量++

 * 如果存在:就不搭理它。

 * 否:不搭理它

 * E:遍历集合

 */

public class RandomDemo {
public static void main(String[] args) {
// 创建产生随机数的对象
Random r = new Random();
 
// 创建一个存储随机数的集合。
ArrayList<Integer> array = new ArrayList<Integer>();
 
// 定义一个统计变量。从0开始。
int count = 0;
 
// 判断统计遍历是否小于10
while (count < 10) {
//先产生一个随机数
int number = r.nextInt(20) + 1;

//判断该随机数在集合中是否存在。
if(!array.contains(number)){
//如果不存在:就添加,统计变量++。
array.add(number);
count++;
}
}

//遍历集合
for(Integer i : array){
System.out.println(i);
}
}
}

键盘录入多个数据,以0结束,要求在控制台输出这多个数据中的最大值

 

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Scanner;
 
/*
 * 键盘录入多个数据,以0结束,要求在控制台输出这多个数据中的最大值
 *
 * 分析:
 * A:创建键盘录入数据对象
 * B:键盘录入多个数据,我们不知道多少个,所以用集合存储
 * C:以0结束,这个简单,只要键盘录入的数据是0,我就不继续录入数据了
 * D:把集合转成数组
 * E:对数组排序
 * F:获取该数组中的最大索引的值
 */
public class ArrayListDemo {
public static void main(String[] args) {
// 创建键盘录入数据对象
Scanner sc = new Scanner(System.in);
 
// 键盘录入多个数据,我们不知道多少个,所以用集合存储
ArrayList<Integer> array = new ArrayList<Integer>();
 
// 以0结束,这个简单,只要键盘录入的数据是0,我就不继续录入数据了
while (true) {
System.out.println("请输入数据:");
int number = sc.nextInt();
if (number != 0) {
array.add(number);
} else {
break;
}
}
 
// 把集合转成数组
// public <T> T[] toArray(T[] a)
Integer[] i = new Integer[array.size()];
// Integer[] ii = array.toArray(i);
array.toArray(i);
// System.out.println(i);
// System.out.println(ii);
 
// 对数组排序
// public static void sort(Object[] a)
Arrays.sort(i);
 
// 获取该数组中的最大索引的值
System.out.println("数组是:" + arrayToString(i) + "最大值是:"
+ i[i.length - 1]);
}
 
public static String arrayToString(Integer[] i) {
StringBuilder sb = new StringBuilder();
 
sb.append("[");
for (int x = 0; x < i.length; x++) {
if (x == i.length - 1) {
sb.append(i[x]);
} else {
sb.append(i[x]).append(", ");
}
}
sb.append("]");
 
return sb.toString();
}
}

Set接口概述

Set接口概述

一个不包含重复元素 collection

Set案例

存储字符串并遍历

存储自定义对象并遍历

 

import java.util.HashSet;
import java.util.Set;
 
/*
 * Collection
 * |--List
 * 有序(存储顺序和取出顺序一致),可重复
 * |--Set
 * 无序(存储顺序和取出顺序不一致),唯一
 *
 * HashSet:它不保证 set 的迭代顺序;特别是它不保证该顺序恒久不变。
 * 注意:虽然Set集合的元素无序,但是,作为集合来说,它肯定有它自己的存储顺序,
 * 而你的顺序恰好和它的存储顺序一致,这代表不了有序,你可以多存储一些数据,就能看到效果。
 */
public class SetDemo {
public static void main(String[] args) {
// 创建集合对象
Set<String> set = new HashSet<String>();
 
// 创建并添加元素
set.add("hello");
set.add("java");
set.add("world");
set.add("java");
set.add("world");
 
// 增强for
for (String s : set) {
System.out.println(s);
}
}
}

 

HashSet类概述

不保证 set 的迭代顺序

特别是它不保证该顺序恒久不变

 

HashSet如何保证元素唯一性

底层数据结构是哈希表(元素是链表的数组)

哈希表依赖于哈希值存储

添加功能底层依赖两个方法:

   int hashCode()

   boolean equals(Object obj)

 

import java.util.HashSet;
 
/*
 * HashSet:存储字符串并遍历
 * 问题:为什么存储字符串的时候,字符串内容相同的只存储了一个呢?
 * 通过查看add方法的源码,我们知道这个方法底层依赖 两个方法:hashCode()和equals()。
 * 步骤:
 * 首先比较哈希值
 * 如果相同,继续走,比较地址值或者走equals()
 * 如果不同,就直接添加到集合中
 * 按照方法的步骤来说:
 * 先看hashCode()值是否相同
 * 相同:继续走equals()方法
 * 返回true:说明元素重复,就不添加
 * 返回false:说明元素不重复,就添加到集合
 * 不同:就直接把元素添加到集合
 * 如果类没有重写这两个方法,默认使用的Object()。一般来说不同相同。
 * 而String类重写了hashCode()和equals()方法,所以,它就可以把内容相同的字符串去掉。只留下一个。
 */
public class HashSetDemo {
public static void main(String[] args) {
// 创建集合对象
HashSet<String> hs = new HashSet<String>();
 
// 创建并添加元素
hs.add("hello");
hs.add("world");
hs.add("java");
hs.add("world");
 
// 遍历集合
for (String s : hs) {
System.out.println(s);
}
}
}
 
查看源码结构
 
interface Collection {
...
}
 
interface Set extends Collection {
...
}
 
class HashSet implements Set {
private static final Object PRESENT = new Object();
private transient HashMap<E,Object> map;

public HashSet() {
map = new HashMap<>();
}

public boolean add(E e) { //e=hello,world
        return map.put(e, PRESENT)==null;
    }
}
 
class HashMap implements Map {
public V put(K key, V value) { //key=e=hello,world

//看哈希表是否为空,如果空,就开辟空间
        if (table == EMPTY_TABLE) {
            inflateTable(threshold);
        }
        
        //判断对象是否为null
        if (key == null)
            return putForNullKey(value);
        
        int hash = hash(key); //和对象的hashCode()方法相关
        
        //在哈希表中查找hash值
        int i = indexFor(hash, table.length);
        for (Entry<K,V> e = table[i]; e != null; e = e.next) {
        //这次的e其实是第一次的world
            Object k;
            if (e.hash == hash && ((k = e.key) == key || key.equals(k))) {
                V oldValue = e.value;
                e.value = value;
                e.recordAccess(this);
                return oldValue;
                //走这里其实是没有添加元素
            }
        }
 
        modCount++;
        addEntry(hash, key, value, i); //把元素添加
        return null;
    }
    
    transient int hashSeed = 0;
    
    final int hash(Object k) { //k=key=e=hello,
        int h = hashSeed;
        if (0 != h && k instanceof String) {
            return sun.misc.Hashing.stringHash32((String) k);
        }
 
        h ^= k.hashCode(); //这里调用的是对象的hashCode()方法
 
        // This function ensures that hashCodes that differ only by
        // constant multiples at each bit position have a bounded
        // number of collisions (approximately 8 at default load factor).
        h ^= (h >>> 20) ^ (h >>> 12);
        return h ^ (h >>> 7) ^ (h >>> 4);
    }
}
 
 
hs.add("hello");
hs.add("world");
hs.add("java");
hs.add("world");
 
 
 
public class Student {
private String name;
private int age;
 
public Student() {
super();
}
 
public Student(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() {
final int prime = 31;
int result = 1;
result = prime * result + age;
result = prime * result + ((name == null) ? 0 : name.hashCode());
return result;
}
 
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Student other = (Student) obj;
if (age != other.age)
return false;
if (name == null) {
if (other.name != null)
return false;
} else if (!name.equals(other.name))
return false;
return true;
}
 
// @Override
// public int hashCode() {
// // return 0;
// // 因为成员变量值影响了哈希值,所以我们把成员变量值相加即可
// // return this.name.hashCode() + this.age;
// // 看下面
// // s1:name.hashCode()=40,age=30
// // s2:name.hashCode()=20,age=50
// // 尽可能的区分,我们可以把它们乘以一些整数
// return this.name.hashCode() + this.age * 15;
// }
//
// @Override
// public boolean equals(Object obj) {
// // System.out.println(this + "---" + obj);
// if (this == obj) {
// return true;
// }
//
// if (!(obj instanceof Student)) {
// return false;
// }
//
// Student s = (Student) obj;
// return this.name.equals(s.name) && this.age == s.age;
// }
//
// @Override
// public String toString() {
// return "Student [name=" + name + ", age=" + age + "]";
// }
 
}
import java.util.HashSet;
 
/*
 * 需求:存储自定义对象,并保证元素的唯一性
 * 要求:如果两个对象的成员变量值都相同,则为同一个元素。
 *
 * 目前是不符合我的要求的:因为我们知道HashSet底层依赖的是hashCode()和equals()方法。
 * 而这两个方法我们在学生类中没有重写,所以,默认使用的是Object类。
 * 这个时候,他们的哈希值是不会一样的,根本就不会继续判断,执行了添加操作。
 */
public class HashSetDemo2 {
public static void main(String[] args) {
// 创建集合对象
HashSet<Student> hs = new HashSet<Student>();
 
// 创建学生对象
Student s1 = new Student("林青霞", 27);
Student s2 = new Student("柳岩", 22);
Student s3 = new Student("王祖贤", 30);
Student s4 = new Student("林青霞", 27);
Student s5 = new Student("林青霞", 20);
Student s6 = new Student("范冰冰", 22);
 
// 添加元素
hs.add(s1);
hs.add(s2);
hs.add(s3);
hs.add(s4);
hs.add(s5);
hs.add(s6);
 
// 遍历集合
for (Student s : hs) {
System.out.println(s.getName() + "---" + s.getAge());
}
}
}

wKioL1h6JCjzzpD9AADP_cxi1y8565.png 

 

 

集合存储自定义对象并遍历

public class Dog {
private String name;
private int age;
private String color;
private char sex;
 
public Dog() {
super();
}
 
public Dog(String name, int age, String color, char sex) {
super();
this.name = name;
this.age = age;
this.color = color;
this.sex = sex;
}
 
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 getColor() {
return color;
}
 
public void setColor(String color) {
this.color = color;
}
 
public char getSex() {
return sex;
}
 
public void setSex(char sex) {
this.sex = sex;
}
 
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + age;
result = prime * result + ((color == null) ? 0 : color.hashCode());
result = prime * result + ((name == null) ? 0 : name.hashCode());
result = prime * result + sex;
return result;
}
 
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Dog other = (Dog) obj;
if (age != other.age)
return false;
if (color == null) {
if (other.color != null)
return false;
} else if (!color.equals(other.color))
return false;
if (name == null) {
if (other.name != null)
return false;
} else if (!name.equals(other.name))
return false;
if (sex != other.sex)
return false;
return true;
}
 
}
import java.util.HashSet;
 
/*
 * HashSet集合存储自定义对象并遍历。如果对象的成员变量值相同即为同一个对象
 *
 * 注意了:
 * 你使用的是HashSet集合,这个集合的底层是哈希表结构。
 * 而哈希表结构底层依赖:hashCode()和equals()方法。
 * 如果你认为对象的成员变量值相同即为同一个对象的话,你就应该重写这两个方法。
 * 如何重写呢?不同担心,自动生成即可。
 */
public class DogDemo {
public static void main(String[] args) {
// 创建集合对象
HashSet<Dog> hs = new HashSet<Dog>();
 
// 创建狗对象
Dog d1 = new Dog("秦桧", 25, "红色", '男');
Dog d2 = new Dog("高俅", 22, "黑色", '女');
Dog d3 = new Dog("秦桧", 25, "红色", '男');
Dog d4 = new Dog("秦桧", 20, "红色", '女');
Dog d5 = new Dog("魏忠贤", 28, "白色", '男');
Dog d6 = new Dog("李莲英", 23, "×××", '女');
Dog d7 = new Dog("李莲英", 23, "×××", '女');
Dog d8 = new Dog("李莲英", 23, "×××", '男');
 
// 添加元素
hs.add(d1);
hs.add(d2);
hs.add(d3);
hs.add(d4);
hs.add(d5);
hs.add(d6);
hs.add(d7);
hs.add(d8);
 
// 遍历
for (Dog d : hs) {
System.out.println(d.getName() + "---" + d.getAge() + "---"
+ d.getColor() + "---" + d.getSex());
}
}
}

 

LinkedHashSet类概述

LinkedHashSet类概述

元素有序唯一

链表保证元素有序

哈希表保证元素唯一

import java.util.LinkedHashSet;

 

/*

 * LinkedHashSet:底层数据结构由哈希表和链表组成。

 * 哈希表保证元素的唯一性。

 * 链表保证元素有(存储和取出是一致)

 */

public class LinkedHashSetDemo {
public static void main(String[] args) {
// 创建集合对象
LinkedHashSet<String> hs = new LinkedHashSet<String>();
 
// 创建并添加元素
hs.add("hello");
hs.add("world");
hs.add("java");
hs.add("world");
hs.add("java");
 
// 遍历
for (String s : hs) {
System.out.println(s);
}
}
}

 

 

TreeSet类概述

TreeSet类概述

使用元素的自然顺序对元素进行排序

或者根据创建 set 时提供的 Comparator 进行排序

具体取决于使用的构造方法。

 

import java.util.TreeSet;
 
/*
 * TreeSet:能够对元素按照某种规则进行排序。
 * 排序有两种方式
 * A:自然排序
 * B:比较器排序
 *
 * TreeSet集合的特点:排序和唯一
 *
 * 通过观察TreeSet的add()方法,我们知道最终要看TreeMap的put()方法。
 */
public class TreeSetDemo {
public static void main(String[] args) {
// 创建集合对象
// 自然顺序进行排序
TreeSet<Integer> ts = new TreeSet<Integer>();
 
// 创建元素并添加
// 20,18,23,22,17,24,19,18,24
ts.add(20);
ts.add(18);
ts.add(23);
ts.add(22);
ts.add(17);
ts.add(24);
ts.add(19);
ts.add(18);
ts.add(24);
 
// 遍历
for (Integer i : ts) {
System.out.println(i);
}
}
}

 

自定义类型的使用

/*

 * 如果一个类的元素要想能够进行自然排序,就必须实现自然排序接口

 */

public class Student implements Comparable<Student> {
private String name;
private int age;
 
public Student() {
super();
}
 
public Student(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 compareTo(Student s) {
// return 0;
// return 1;
// return -1;
 
// 这里返回什么,其实应该根据我的排序规则来做
// 按照年龄排序,主要条件
int num = this.age - s.age;
// 次要条件
// 年龄相同的时候,还得去看姓名是否也相同
// 如果年龄和姓名都相同,才是同一个元素
int num2 = num == 0 ? this.name.compareTo(s.name) : num;
return num2;
}
}
import java.util.TreeSet;
 
/*
 * TreeSet存储自定义对象并保证排序和唯一。
 *
 * A:你没有告诉我们怎么排序
 * 自然排序,按照年龄从小到大排序
 * B:元素什么情况算唯一你也没告诉我
 * 成员变量值都相同即为同一个元素
 */
public class TreeSetDemo2 {
public static void main(String[] args) {
// 创建集合对象
TreeSet<Student> ts = new TreeSet<Student>();
 
// 创建元素
Student s1 = new Student("linqingxia", 27);
Student s2 = new Student("zhangguorong", 29);
Student s3 = new Student("wanglihong", 23);
Student s4 = new Student("linqingxia", 27);
Student s5 = new Student("liushishi", 22);
Student s6 = new Student("wuqilong", 40);
Student s7 = new Student("fengqingy", 22);
 
// 添加元素
ts.add(s1);
ts.add(s2);
ts.add(s3);
ts.add(s4);
ts.add(s5);
ts.add(s6);
ts.add(s7);
 
// 遍历
for (Student s : ts) {
System.out.println(s.getName() + "---" + s.getAge());
}
}
}

条件不一样比较的方式也不一样

/*

 * 如果一个类的元素要想能够进行自然排序,就必须实现自然排序接口

 */

public class Student implements Comparable<Student> {
private String name;
private int age;
 
public Student() {
super();
}
 
public Student(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 compareTo(Student s) {
// 主要条件 姓名的长度
int num = this.name.length() - s.name.length();
// 姓名的长度相同,不代表姓名的内容相同
int num2 = num == 0 ? this.name.compareTo(s.name) : num;
// 姓名的长度和内容相同,不代表年龄相同,所以还得继续判断年龄
int num3 = num2 == 0 ? this.age - s.age : num2;
return num3;
}
}

 

import java.util.TreeSet;
 
/*
 * 需求:请按照姓名的长度排序
 */
public class TreeSetDemo {
public static void main(String[] args) {
// 创建集合对象
TreeSet<Student> ts = new TreeSet<Student>();
 
// 创建元素
Student s1 = new Student("linqingxia", 27);
Student s2 = new Student("zhangguorong", 29);
Student s3 = new Student("wanglihong", 23);
Student s4 = new Student("linqingxia", 27);
Student s5 = new Student("liushishi", 22);
Student s6 = new Student("wuqilong", 40);
Student s7 = new Student("fengqingy", 22);
Student s8 = new Student("linqingxia", 29);
 
// 添加元素
ts.add(s1);
ts.add(s2);
ts.add(s3);
ts.add(s4);
ts.add(s5);
ts.add(s6);
ts.add(s7);
ts.add(s8);
 
// 遍历
for (Student s : ts) {
System.out.println(s.getName() + "---" + s.getAge());
}
}
}

比较器排序原理

import java.util.Comparator;
 
public class MyComparator implements Comparator<Student> {
 
@Override
public int compare(Student s1, Student s2) {
// int num = this.name.length() - s.name.length();
// this -- s1
// s -- s2
// 姓名长度
int num = s1.getName().length() - s2.getName().length();
// 姓名内容
int num2 = num == 0 ? s1.getName().compareTo(s2.getName()) : num;
// 年龄
int num3 = num2 == 0 ? s1.getAge() - s2.getAge() : num2;
return num3;
}
 
}
 
public class Student {
private String name;
private int age;
 
public Student() {
super();
}
 
public Student(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;
}
}
import java.util.Comparator;
import java.util.TreeSet;
 
/*
 * 需求:请按照姓名的长度排序
 *
 * TreeSet集合保证元素排序和唯一性的原理
 * 唯一性:是根据比较的返回是否是0来决定。
 * 排序:
 * A:自然排序(元素具备比较性)
 * 让元素所属的类实现自然排序接口 Comparable
 * B:比较器排序(集合具备比较性)
 * 让集合的构造方法接收一个比较器接口的子类对象 Comparator
 */
public class TreeSetDemo {
public static void main(String[] args) {
// 创建集合对象
// TreeSet<Student> ts = new TreeSet<Student>(); //自然排序
// public TreeSet(Comparator comparator) //比较器排序
// TreeSet<Student> ts = new TreeSet<Student>(new MyComparator());
 
// 如果一个方法的参数是接口,那么真正要的是接口的实现类的对象
// 而匿名内部类就可以实现这个东西
TreeSet<Student> ts = new TreeSet<Student>(new Comparator<Student>() {
@Override
public int compare(Student s1, Student s2) {
// 姓名长度
int num = s1.getName().length() - s2.getName().length();
// 姓名内容
int num2 = num == 0 ? s1.getName().compareTo(s2.getName())
: num;
// 年龄
int num3 = num2 == 0 ? s1.getAge() - s2.getAge() : num2;
return num3;
}
});
 
// 创建元素
Student s1 = new Student("linqingxia", 27);
Student s2 = new Student("zhangguorong", 29);
Student s3 = new Student("wanglihong", 23);
Student s4 = new Student("linqingxia", 27);
Student s5 = new Student("liushishi", 22);
Student s6 = new Student("wuqilong", 40);
Student s7 = new Student("fengqingy", 22);
Student s8 = new Student("linqingxia", 29);
 
// 添加元素
ts.add(s1);
ts.add(s2);
ts.add(s3);
ts.add(s4);
ts.add(s5);
ts.add(s6);
ts.add(s7);
ts.add(s8);
 
// 遍历
for (Student s : ts) {
System.out.println(s.getName() + "---" + s.getAge());
}
}
}

编写一个程序,获取10120的随机数,要求随机数不能重复

import java.util.HashSet;
import java.util.Random;
 
/*
 * 编写一个程序,获取10个1至20的随机数,要求随机数不能重复。
 *
 * 分析:
 * A:创建随机数对象
 * B:创建一个HashSet集合
 * C:判断集合的长度是不是小于10
 * 是:就创建一个随机数添加
 * 否:不搭理它
 * D:遍历HashSet集合
 */
public class HashSetDemo {
public static void main(String[] args) {
// 创建随机数对象
Random r = new Random();
 
// 创建一个Set集合
HashSet<Integer> ts = new HashSet<Integer>();
 
// 判断集合的长度是不是小于10
while (ts.size() < 10) {
int num = r.nextInt(20) + 1;
ts.add(num);
}
 
// 遍历Set集合
for (Integer i : ts) {
System.out.println(i);
}
}
}

键盘录入5个学生信息(姓名,语文成绩,数学成绩,英语成绩),按照总分从高到低输出到控制台

public class Student {
// 姓名
private String name;
// 语文成绩
private int chinese;
// 数学成绩
private int math;
// 英语成绩
private int english;
 
public Student(String name, int chinese, int math, int english) {
super();
this.name = name;
this.chinese = chinese;
this.math = math;
this.english = english;
}
 
public Student() {
super();
}
 
public String getName() {
return name;
}
 
public void setName(String name) {
this.name = name;
}
 
public int getChinese() {
return chinese;
}
 
public void setChinese(int chinese) {
this.chinese = chinese;
}
 
public int getMath() {
return math;
}
 
public void setMath(int math) {
this.math = math;
}
 
public int getEnglish() {
return english;
}
 
public void setEnglish(int english) {
this.english = english;
}
 
public int getSum() {
return this.chinese + this.math + this.english;
}
}
 
/*
 * 键盘录入5个学生信息(姓名,语文成绩,数学成绩,英语成绩),按照总分从高到低输出到控制台
 *
 * 分析:
 * A:定义学生类
 * B:创建一个TreeSet集合
 * C:总分从高到底如何实现呢?
 * D:键盘录入5个学生信息
 * E:遍历TreeSet集合
 */
public class TreeSetDemo {
public static void main(String[] args) {
// 创建一个TreeSet集合
TreeSet<Student> ts = new TreeSet<Student>(new Comparator<Student>() {
@Override
public int compare(Student s1, Student s2) {
// 总分从高到低
int num = s2.getSum() - s1.getSum();
// 总分相同的不一定语文相同
int num2 = num == 0 ? s1.getChinese() - s2.getChinese() : num;
// 总分相同的不一定数序相同
int num3 = num2 == 0 ? s1.getMath() - s2.getMath() : num2;
// 总分相同的不一定英语相同
int num4 = num3 == 0 ? s1.getEnglish() - s2.getEnglish() : num3;
// 姓名还不一定相同呢
int num5 = num4 == 0 ? s1.getName().compareTo(s2.getName())
: num4;
return num5;
}
});
 
System.out.println("学生信息录入开始");
// 键盘录入5个学生信息
for (int x = 1; x <= 5; x++) {
Scanner sc = new Scanner(System.in);
System.out.println("请输入第" + x + "个学生的姓名:");
String name = sc.nextLine();
System.out.println("请输入第" + x + "个学生的语文成绩:");
String chineseString = sc.nextLine();
System.out.println("请输入第" + x + "个学生的数学成绩:");
String mathString = sc.nextLine();
System.out.println("请输入第" + x + "个学生的英语成绩:");
String englishString = sc.nextLine();
 
// 把数据封装到学生对象中
Student s = new Student();
s.setName(name);
s.setChinese(Integer.parseInt(chineseString));
s.setMath(Integer.parseInt(mathString));
s.setEnglish(Integer.parseInt(englishString));
 
// 把学生对象添加到集合
ts.add(s);
}
System.out.println("学生信息录入完毕");
 
System.out.println("学习信息从高到低排序如下:");
System.out.println("姓名\t语文成绩\t数学成绩\t英语成绩");
// 遍历集合
for (Student s : ts) {
System.out.println(s.getName() + "\t" + s.getChinese() + "\t"
+ s.getMath() + "\t" + s.getEnglish());
}
}
}

总结

 

Set集合(理解)

(1)Set集合的特点

无序,唯一

(2)HashSet集合(掌握)

A:底层数据结构是哈希表(是一个元素为链表的数组)

B:哈希表底层依赖两个方法:hashCode()equals()

  执行顺序:

首先比较哈希值是否相同

相同:继续执行equals()方法

返回true:元素重复了,不添加

返回false:直接把元素添加到集合

不同:就直接把元素添加到集合

C:如何保证元素唯一性的呢?

hashCode()equals()保证的

D:开发的时候,代码非常的简单,自动生成即可。

E:HashSet存储字符串并遍历

F:HashSet存储自定义对象并遍历(对象的成员变量值相同即为同一个元素)

(3)TreeSet集合

A:底层数据结构是红黑树(是一个自平衡的二叉树)

B:保证元素的排序方式

a:自然排序(元素具备比较性)

让元素所属的类实现Comparable接口

b:比较器排序(集合具备比较性)

让集合构造方法接收Comparator的实现类对象

C:把我们讲过的代码看一遍即可

(4)案例:

A:获取无重复的随机数

B:键盘录入学生按照总分从高到底输出


3:Collection集合总结(掌握)

Collection

|--List有序,可重复

|--ArrayList

底层数据结构是数组,查询快,增删慢。

线程不安全,效率高

|--Vector

底层数据结构是数组,查询快,增删慢。

线程安全,效率低

|--LinkedList

底层数据结构是链表,查询慢,增删快。

线程不安全,效率高

|--Set无序,唯一

|--HashSet

底层数据结构是哈希表。

如何保证元素唯一性的呢?

依赖两个方法:hashCode()equals()

开发中自动生成这两个方法即可

|--LinkedHashSet

底层数据结构是链表和哈希表

由链表保证元素有序

由哈希表保证元素唯一

|--TreeSet

底层数据结构是红黑树。

如何保证元素排序的呢?

自然排序

比较器排序

如何保证元素唯一性的呢?

根据比较的返回值是否是0来决定


4:针对Collection集合我们到底使用谁呢?(掌握)

唯一吗?

是:Set

排序吗?

是:TreeSet

否:HashSet

如果你知道是Set,但是不知道是哪个Set,就用HashSet


否:List

要安全吗?

是:Vector

否:ArrayList或者LinkedList

查询多:ArrayList

增删多:LinkedList

如果你知道是List,但是不知道是哪个List,就用ArrayList


如果你知道是Collection集合,但是不知道使用谁,就用ArrayList


如果你知道用集合,就用ArrayList


5:在集合中常见的数据结构(掌握)

ArrayXxx:底层数据结构是数组,查询快,增删慢

LinkedXxx:底层数据结构是链表,查询慢,增删快

HashXxx:底层数据结构是哈希表。依赖两个方法:hashCode()equals()

TreeXxx:底层数据结构是二叉树。两种方式排序:自然排序和比较器排序

 

 

Map接口概述

Map接口概述

将键映射到值的对象

一个映射不能包含重复的键

每个键最多只能映射到一个值

 

Map接口和Collection接口的不同

Map是双列的,Collection是单列的

Map的键唯一,Collection的子体系Set是唯一的

Map集合的数据结构值针对键有效,跟值无关

   Collection集合的数据结构是针对元素有效

 

import java.util.HashMap;
import java.util.Map;
 
/*
 * 作为学生来说,是根据学号来区分不同的学生的,那么假设我现在已经知道了学生的学号,我要根据学号去获取学生姓名,请问怎么做呢?
 * 如果采用前面讲解过的集合,我们只能把学号和学生姓名作为一个对象的成员,然后存储整个对象,将来遍历的时候,判断,获取对应的名称。
 * 但是呢,如果我都能把学生姓名拿出来了,我还需要根据编号去找吗?
 * 针对我们目前的这种需求:仅仅知道学号,就想知道学生姓名的情况,Java就提供了一种新的集合 Map。
 * 通过查看API,我们知道Map集合的一个最大的特点,就是它可以存储键值对的元素。这个时候存储我们上面的需求,就可以这样做
 * 学号1姓名1
 * 学号2 姓名2
 * 学号3姓名3
 * 学号2(不行)姓名4
 * 学号4               姓名4
 * Map集合的特点:
 * 将键映射到值的对象。一个映射不能包含重复的键;每个键最多只能映射到一个值。
 *
 * Map集合和Collection集合的区别?
 * Map集合存储元素是成对出现的,Map集合的键是唯一的,值是可重复的。可以把这个理解为:夫妻对
 * Collection集合存储元素是单独出现的,Collection的儿子Set是唯一的,List是可重复的。可以把这个理解为:光棍(11.11)
 *
 * 注意:
 * Map集合的数据结构值针对键有效,跟值无关
 * HashMap,TreeMap等会讲。
 *Collection集合的数据结构是针对元素有效
 *
 * Map集合的功能概述:
 * 1:添加功能
 * V put(K key,V value):添加元素。这个其实还有另一个功能?先不告诉你,等会讲
 * 如果键是第一次存储,就直接存储元素,返回null
 * 如果键不是第一次存在,就用值把以前的值替换掉,返回以前的值
 * 2:删除功能
 * void clear():移除所有的键值对元素
 * V remove(Object key):根据键删除键值对元素,并把值返回
 * 3:判断功能
 * boolean containsKey(Object key):判断集合是否包含指定的键
 * boolean containsValue(Object value):判断集合是否包含指定的值
 * boolean isEmpty():判断集合是否为空
 * 4:获取功能
 * Set<Map.Entry<K,V>> entrySet():???
 * V get(Object key):根据键获取值
 * Set<K> keySet():获取集合中所有键的集合
 * Collection<V> values():获取集合中所有值的集合
 * 5:长度功能
 * int size():返回集合中的键值对的对数
 */
public class MapDemo {
public static void main(String[] args) {
// 创建集合对象
Map<String, String> map = new HashMap<String, String>();
 
// 添加元素
// V put(K key,V value):添加元素。这个其实还有另一个功能?先不告诉你,等会讲
// System.out.println("put:" + map.put("文章", "马伊俐"));
// System.out.println("put:" + map.put("文章", "姚笛"));
 
map.put("邓超", "孙俪");
map.put("黄晓明", "杨颖");
map.put("周杰伦", "蔡依林");
map.put("刘恺威", "杨幂");
 
// void clear():移除所有的键值对元素
// map.clear();
 
// V remove(Object key):根据键删除键值对元素,并把值返回
// System.out.println("remove:" + map.remove("黄晓明"));
// System.out.println("remove:" + map.remove("黄晓波"));
 
// boolean containsKey(Object key):判断集合是否包含指定的键
// System.out.println("containsKey:" + map.containsKey("黄晓明"));
// System.out.println("containsKey:" + map.containsKey("黄晓波"));
 
// boolean isEmpty():判断集合是否为空
// System.out.println("isEmpty:"+map.isEmpty());

//int size():返回集合中的键值对的对数
System.out.println("size:"+map.size());
 
// 输出集合名称
System.out.println("map:" + map);
}
}

 

 

 

常用获取方法

V get(Object key)

Set<K> keySet()

Collection<V> values()

Set<Map.Entry<K,V>> entrySet()

 

import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
 
/*
 * 获取功能:
 * V get(Object key):根据键获取值
 * Set<K> keySet():获取集合中所有键的集合
 * Collection<V> values():获取集合中所有值的集合
 */
public class MapDemo2 {
public static void main(String[] args) {
// 创建集合对象
Map<String, String> map = new HashMap<String, String>();
 
// 创建元素并添加元素
map.put("邓超", "孙俪");
map.put("黄晓明", "杨颖");
map.put("周杰伦", "蔡依林");
map.put("刘恺威", "杨幂");
 
// V get(Object key):根据键获取值
System.out.println("get:" + map.get("周杰伦"));
System.out.println("get:" + map.get("周杰")); // 返回null
System.out.println("----------------------");
 
// Set<K> keySet():获取集合中所有键的集合
Set<String> set = map.keySet();
for (String key : set) {
System.out.println(key);
}
System.out.println("----------------------");
 
// Collection<V> values():获取集合中所有值的集合
Collection<String> con = map.values();
for (String value : con) {
System.out.println(value);
}
}
}

 

Map集合的遍历。

方式1:根据键找值

  获取所有键的集合

  遍历键的集合,获取到每一个键

  根据键找值

方式2:根据键值对对象找键和值

  获取所有键值对对象的集合

  遍历键值对对象的集合,获取到每一个键值对对象

  根据键值对对象找键和值

 

 

 

import java.util.HashMap;
import java.util.Map;
import java.util.Set;
 
/*
 * Map集合的遍历。
 * Map -- 夫妻对
 * 思路:
 * A:把所有的丈夫给集中起来。
 * B:遍历丈夫的集合,获取得到每一个丈夫。
 * C:让丈夫去找自己的妻子。
 *
 * 转换:
 * A:获取所有的键
 * B:遍历键的集合,获取得到每一个键
 * C:根据键去找值
 */
public class MapDemo3 {
public static void main(String[] args) {
// 创建集合对象
Map<String, String> map = new HashMap<String, String>();
 
// 创建元素并添加到集合
map.put("杨过", "小龙女");
map.put("郭靖", "黄蓉");
map.put("杨康", "穆念慈");
map.put("陈玄风", "梅超风");
 
// 遍历
// 获取所有的键
Set<String> set = map.keySet();
// 遍历键的集合,获取得到每一个键
for (String key : set) {
// 根据键去找值
String value = map.get(key);
System.out.println(key + "---" + value);
}
}
}

 

遍历第二种方法

import java.util.HashMap;
import java.util.Map;
import java.util.Set;
 
/*
 * Map集合的遍历。
 * Map -- 夫妻对
 *
 * 思路:
 * A:获取所有结婚证的集合
 * B:遍历结婚证的集合,得到每一个结婚证
 * C:根据结婚证获取丈夫和妻子
 *
 * 转换:
 * A:获取所有键值对对象的集合
 * B:遍历键值对对象的集合,得到每一个键值对对象
 * C:根据键值对对象获取键和值
 *
 * 这里面最麻烦的就是键值对对象如何表示呢?
 * 看看我们开始的一个方法:
 * Set<Map.Entry<K,V>> entrySet():返回的是键值对对象的集合
 */
public class MapDemo4 {
public static void main(String[] args) {
// 创建集合对象
Map<String, String> map = new HashMap<String, String>();
 
// 创建元素并添加到集合
map.put("杨过", "小龙女");
map.put("郭靖", "黄蓉");
map.put("杨康", "穆念慈");
map.put("陈玄风", "梅超风");
 
// 获取所有键值对对象的集合
Set<Map.Entry<String, String>> set = map.entrySet();
// 遍历键值对对象的集合,得到每一个键值对对象
for (Map.Entry<String, String> me : set) {
// 根据键值对对象获取键和值
String key = me.getKey();
String value = me.getValue();
System.out.println(key + "---" + value);
}
}
}


wKioL1h6LCexkJJrAADGj20L69c528.png 

 

 

 

HashMap

HashMap类概述

  键是哈希表结构,可以保证键的唯一性

HashMap案例

  HashMap<String,String>

  HashMap<Integer,String>

  HashMap<String,Student>

  HashMap<Student,String>

 

import java.util.HashMap;
import java.util.Set;
 
/*
 * HashMap:是基于哈希表的Map接口实现。
 * 哈希表的作用是用来保证键的唯一性的。
 *
 * HashMap<String,String>
 * 键:String
 * 值:String
 */
public class HashMapDemo {
public static void main(String[] args) {
// 创建集合对象
HashMap<String, String> hm = new HashMap<String, String>();
 
// 创建元素并添加元素
// String key1 = "it001";
// String value1 = "马云";
// hm.put(key1, value1);
 
hm.put("it001", "马云");
hm.put("it003", "马化腾");
hm.put("it004", "乔布斯");
hm.put("it005", "张朝阳");
hm.put("it002", "裘伯君"); // wps
hm.put("it001", "比尔盖茨");
 
// 遍历
Set<String> set = hm.keySet();
for (String key : set) {
String value = hm.get(key);
System.out.println(key + "---" + value);
}
}
}

第二种

import java.util.HashMap;
import java.util.Set;
 
/*
 * HashMap<Integer,String>
 * 键:Integer
 * 值:String
 */
public class HashMapDemo2 {
public static void main(String[] args) {
// 创建集合对象
HashMap<Integer, String> hm = new HashMap<Integer, String>();
 
// 创建元素并添加元素
// Integer i = new Integer(27);
// Integer i = 27;
// String s = "林青霞";
// hm.put(i, s);
 
hm.put(27, "林青霞");
hm.put(30, "风清扬");
hm.put(28, "张三");
hm.put(29, "林青霞");
 
// 下面的写法是八进制,但是不能出现8以上的单个数据
// hm.put(003, "hello");
// hm.put(006, "hello");
// hm.put(007, "hello");
// hm.put(008, "hello");
 
// 遍历
Set<Integer> set = hm.keySet();
for (Integer key : set) {
String value = hm.get(key);
System.out.println(key + "---" + value);
}
 
// 下面这种方式仅仅是集合的元素的字符串表示
// System.out.println("hm:" + hm);
}
}

 

存放学生对象 

public class Student {
private String name;
private int age;
 
public Student() {
super();
}
 
public Student(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() {
final int prime = 31;
int result = 1;
result = prime * result + age;
result = prime * result + ((name == null) ? 0 : name.hashCode());
return result;
}
 
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Student other = (Student) obj;
if (age != other.age)
return false;
if (name == null) {
if (other.name != null)
return false;
} else if (!name.equals(other.name))
return false;
return true;
}
 
}
import java.util.HashMap;
import java.util.Set;
 
/*
 * HashMap<String,Student>
 * 键:String学号
 * 值:Student 学生对象
 */
public class HashMapDemo3 {
public static void main(String[] args) {
// 创建集合对象
HashMap<String, Student> hm = new HashMap<String, Student>();
 
// 创建学生对象
Student s1 = new Student("周星驰", 58);
Student s2 = new Student("刘德华", 55);
Student s3 = new Student("梁朝伟", 54);
Student s4 = new Student("刘嘉玲", 50);
 
// 添加元素
hm.put("9527", s1);
hm.put("9522", s2);
hm.put("9524", s3);
hm.put("9529", s4);
 
// 遍历
Set<String> set = hm.keySet();
for (String key : set) {
// 注意了:这次值不是字符串了
// String value = hm.get(key);
Student value = hm.get(key);
System.out.println(key + "---" + value.getName() + "---"
+ value.getAge());
}
}
}

第二种方法

import java.util.HashMap;
import java.util.Set;
 
/*
 * HashMap<Student,String>
 * 键:Student
 * 要求:如果两个对象的成员变量值都相同,则为同一个对象。
 * 值:String
 */
public class HashMapDemo4 {
public static void main(String[] args) {
// 创建集合对象
HashMap<Student, String> hm = new HashMap<Student, String>();
 
// 创建学生对象
Student s1 = new Student("貂蝉", 27);
Student s2 = new Student("王昭君", 30);
Student s3 = new Student("西施", 33);
Student s4 = new Student("杨玉环", 35);
Student s5 = new Student("貂蝉", 27);
 
// 添加元素
hm.put(s1, "8888");
hm.put(s2, "6666");
hm.put(s3, "5555");
hm.put(s4, "7777");
hm.put(s5, "9999");
 
// 遍历
Set<Student> set = hm.keySet();
for (Student key : set) {
String value = hm.get(key);
System.out.println(key.getName() + "---" + key.getAge() + "---"
+ value);
}
}
}