黑马程序员——Java集合框架--------------------------
---------------------- <a href="http://www.itheima.com"target="blank">ASP.Net+Unity开发</a>、
<a href="http://www.itheima.com"target="blank">.Net培训</a>、期待与您交流! ----------------------
一、基本概念
为什么出现集合:
面向对象的设计对事物的操作是以对象的形式,方便对对象的操作,就对对象就行存储就出现集合。
集合类:集合只用于存储对象,可以存储不同类型的对象
数组:数组也能存取对象,但长度是固定的,可以存储基本数据类型。
二、集合体系结构
1.Collection:顶层集合容器接口。
容器功能:增删改查
package com.itheima.connection;
import java.util.ArrayList;
public class ConnectionDemo {
/**
* @param args
*/
public static void main(String[] args) {
method();
}
public static void method(){
// 创建一个集合容器。,使用Connection接口子类 ArrayList
ArrayList al=new ArrayList<>();
//1.添加 add方法参数类型是Object类型,方便接收任意类型对象,集合存储的都是对象的引用,或地址
al.add("我爱你1");
al.add("我爱你2");
al.add("我爱你3");
al.add("我爱你4");
print("原来集合是:"+al);
//2.删除 remove,清空clear()
al.remove("我爱你3");
print("修改后集合是:"+al);
}
public static void print(Object obj){
System.out.println(obj);
}
}
原来集合是:[我爱你1, 我爱你2, 我爱你3, 我爱你4]
修改后集合是:[我爱你1, 我爱你2, 我爱你4]
交集:
package com.itheima.connection;
import java.util.ArrayList;
public class ConnectionDemo {
/**
* @param args
*/
public static void main(String[] args) {
//method();
method_1();
}
public static void method(){
// 创建一个集合容器。,使用Connection接口子类 ArrayList
ArrayList al=new ArrayList();
//1.添加 add方法参数类型是Object类型,方便接收任意类型对象,集合存储的都是对象的引用,或地址
al.add("我爱你1");
al.add("我爱你2");
al.add("我爱你3");
al.add("我爱你4");
print("原来集合是:"+al);
//2.删除 remove,清空clear()
al.remove("我爱你3");
print("修改后集合是:"+al);
}
public static void method_1(){
// 创建一个集合容器。,使用Connection接口子类 ArrayList
ArrayList al=new ArrayList<>();
//1.添加 add方法参数类型是Object类型,方便接收任意类型对象,集合存储的都是对象的引用,或地址
al.add("我爱你1");
al.add("我爱你2");
al.add("我爱你3");
al.add("我爱你4");
ArrayList al2=new ArrayList<>();
al2.add("我爱她1");
al2.add("我爱你2");
al2.add("我爱他3");
al2.add("我爱你4");
al.retainAll(al2);// 取交集,al 和al2只会保留相同的数据
print("原来集合是:"+al);
print("修改后集合是:"+al2);
}
public static void print(Object obj){
System.out.println(obj);
}
}
打印:
al:[我爱你2, 我爱你4]
al2:[我爱她1, 我爱你2, 我爱他3, 我爱你4]
Iterator :迭代器,集合的取出元素方式。
iterator()该对象必须依赖于容器,每个容器内部结构不同,迭代对象是容器中内部实现的
ArrayList al=new ArrayList<>()
package com.itheima.connection;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
public class InteratorDemo {
/**
* @param args
*/
public static void main(String[] args) {
// 创建一个集合容器。,使用Connection接口子类 ArrayList
ArrayList al=new ArrayList<>();
//1.添加 add方法参数类型是Object类型,方便接收任意类型对象,集合存储的都是对象的引用,或地址
al.add("我爱你1");
al.add("我爱你2");
al.add("我爱你3");
al.add("我爱你4");
Iterator it=al.iterator(); //用于取出集合元素
while(it.hasNext()){
print(it.next());
}
}
public static void print(Object obj){
System.out.println(obj);
}
}
我爱你1
我爱你2
我爱你3
我爱你4
Collection:常见两个子接口:List、Set
2.List集合;元素是有序的,有角标可以重复,该集合有索引。
Set 集合:元素是无序的,不允许重复。
List:凡是可以操作角标的都是特有方法,数组角标从0开始
增加:
add(index,elment)
删除:
remove(index)
修改:
set(index,elment)
查询:
get(index)
三个常见子接口:
|--ArrayList:底层的数据结构是数组,线程不同步,ArrayList替代了Vector,查询元素的速度非常快。
|--LinkedList:的数据结构是链表结构,线程不同步,插入方便,增删元素的速度非常快。
|--Vector:底层的数据结构就是数组,线程同步的,Vector无论查询和增删都巨慢。
package com.itheima.connection;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
public class ListDemo {
/**
* @param args
*/
public static void main(String[] args) {
ListMethod();
}
public static void ListMethod(){
// 创建一个集合容器。,使用Connection接口子类 ArrayList
ArrayList al=new ArrayList<>();
//1.添加 add方法参数类型是Object类型,方便接收任意类型对象,集合存储的都是对象的引用,或地址
al.add("我爱你1");
al.add("我爱你2");
al.add("我爱你3");
al.add("我爱你4");
al,add(1,"喜欢你");
al.remove(2);
al.get(3,)
Iterator it=al.iterator(); //用于取出集合元素
while(it.hasNext()){
print(it.next());
}
}
public static void print(Object obj){
System.out.println(obj);
}
}
ListIterator:
List集合特有的迭代器,列表迭代器,在迭代时不可以通过集合对象的方法修改元素,会发生
并发性异常,迭代时只能用迭代器的方法操作元素,ListItrerator具备增删,改查的方法
package com.itheima.connection;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
public class ListDemo {
/**
* @param args
*/
public static void main(String[] args) {
ListMethod();
}
public static void ListMethod(){
// 创建一个集合容器。,使用Connection接口子类 ArrayList
ArrayList al=new ArrayList();
//1.添加 add方法参数类型是Object类型,方便接收任意类型对象,集合存储的都是对象的引用,或地址
al.add("我爱你1");
al.add("我爱你2");
al.add("我爱你3");
al.add("我爱你4");
al,add(1,"喜欢你");
al.remove(2);
al.get(3,)
ListIterator lit=al.iterator(); //用于取出集合元素
while(lit.hasNext()){//遍历元素
Object obj=lit.next;//取元素
if(obj.equeals("我爱你3")){
lit.set("爱你一万年"); //可迭代器修改元素
}
}
print(lit.next());
//List 特有的取出元素方式
for(int x=0; x<list.size(); x++) {
print("get:"+list.get(x));
}
}
lit.hasPervious //反向遍历
LinkList:特有方法
addFirst(); //第一个位置插入元素
addLast();//添加尾部插入元素
removeFirst()//移除并返回第一个元素
getFirst(); 获取不移除
package com.itheima.connection;
import java.util.Iterator;
import java.util.LinkedList;
public class LinkListDemo {
/**
* @param args
*/
public static void main(String[] args) {
LinkedList link=new LinkedList();
link.addFirst("abc1");
link.addFirst("abc2");
link.addFirst("abc3");
link.addFirst("abc4");
// System.out.println(link);
//System.out.println(link.getFirst()); //返回第一个元素
//System.out.println(link.removeFirst()); //获取元素但会删除
/*
while(!link.isEmpty()){
System.out.print(link.removeLast()); //获取元素但会删除 返回后面元素
}
*/
Iterator it=link.iterator();
while(it.hasNext()){
System.out.print(it.next()); //获取元素但会删除 返回后面元素
}
}
}
练习:使用LinkedList模拟堆栈队列的数据结构
堆栈:先进后出
队列:先进先出
package com.itheima.connection;
import java.util.LinkedList;
public class LinkedTest {
/**
* @param args
*/
public static void main(String[] args) {
DuiLie dl=new DuiLie();
dl.MyAdd("abc1");
dl.MyAdd("abc2");
dl.MyAdd("abc3");
dl.MyAdd("abc4");
while(!dl.isNull()){ //不为空,循环打印出来
System.out.println(dl.myGet());
}
}
}
class DuiLie{
private LinkedList link;
public DuiLie(){
link=new LinkedList();
}
//队列的添加功能
public void MyAdd(Object obj){
link.addLast(obj);
}
public Object myGet(){
//返回Link 对象
return link.removeFirst(); //link.removeLast() 堆栈倒排
}
public boolean isNull(){
return link.isEmpty();
}
}
练习:自定义对象存储到ArrayList 删除重复集合元素,同名同姓为重复 元素
1.对人描述,封装对象
2.定义容器存储 人
3.读取
List 集合判断是否相同,依据的是元素的equals 方法
package com.itheima.connection;
import java.util.ArrayList;
import java.util.Iterator;
public class ArrayListTest {
/**
* @param args
*/
public static void main(String[] args) {
ArrayList<Person> al=new ArrayList<Person>();
al.add(new Person("张三",23)); //Object obj=new Person("张三",23); 强制向上转型,容器不知道具体对象类型
al.add(new Person("李四",27));
al.add(new Person("张三",23));
al.add(new Person("孙六",22));
Iterator it=al.iterator();
while(it.hasNext()){
Person p=(Person) it.next(); //此处要向下强转
print("姓名是:"+p.getName()+"年龄是:"+p.getAge());
}
System.out.println(al.remove(new Person("张三",22)));
}
public static ArrayList SingeElement(ArrayList al){
//定义一个临时容器
ArrayList temp=new ArrayList();
Iterator it=al.iterator();
while(it.hasNext()){
Object obj=it.next();
if(!temp.equals(obj)){
temp.add(obj);
}
}
return temp;
}
public static void print(Object obj){
System.out.println(obj);
}
}
class Person{
private String name;
private int age;
public Person(String name, int age) {
this.name=name;
this.age=age;
}
public boolean equals(Object obj){
if(!(obj instanceof Person)){ //对象是否是特定类的一个Person实例
return false;
}
Person p=(Person)obj;
return this.name.equals(p.name) && this.age==p.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;
}
}
Set接口:元素是无序(存入和取出顺序有可能不一致)、不允许重复。
取出集合元素方式只有一种,迭代器
常见子类接口:
|--HashSet:(哈希赛特)底层数据结构是哈希表,线程是不同步的,无序的,高效率
过程:1.当元素的hashCode值相同时,才继续判断元素的equals是否为true。不存在为false 存储。
2. 如果hashCode值不同,那么不用判断equals,从而提高对象比较的速度。
|--TreeSet:底层的数据结构就是二叉树,可以对Set集合中的元素的进行指定顺序的排序。
HashSet:往HashSet 存储Person 对象,如果名称、年龄都想同视为同一个人,重复元素
package com.itheima.connection;
import java.util.*;
public class HashSetDemo {
/**
* @param args
*/
public static void main(String[] args) {
HashSet hs=new HashSet();
print(hs.add(new Person1("a",22)));
hs.add(new Person1("b",12));
print(hs.add(new Person1("a",22)));
hs.add(new Person1("c",27));
hs.add(new Person1("b",18));
// 判断元素是否重复,先判断的是元素的HashCode值,如果存在不允许添加
print("a:"+hs.contains(new Person("a", 22)));
Iterator it=hs.iterator();
while(it.hasNext()){
Person1 p=(Person1) it.next();
System.out.println(p.getName()+"。。。。。"+p.getAge());
}
}
public static void print(Object obj){
System.out.println(obj);
}
}
class Person1{
private String name;
private int age;
public Person1(String name, int age) {
this.name=name;
this.age=age;
}
public int hashCode(){
System.out.print(this.name+"......hashCode");
return 60;
}
public boolean equals(Object obj){
if(!(obj instanceof Person1)){ //对象是否是特定类的一个Person1实例
return false;
}
Person1 p=(Person1)obj;
return this.name.equals(p.name) && this.age==p.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;
}
}
打印结果:
a......hashCodetrue
b......hashCodea......hashCodefalse
c......hashCodeb......hashCodea:false
b。。。。。18
c。。。。。27
b。。。。。12
a。。。。。22
TreeSet:底层数据是二叉树,可以对集合指定顺序排序,是不同步的。
1.判断元素唯一性方式:CompareTo 方法 return 0 返回0就是相同元素,不保存。
2.实现排序方式一:让元素具备可比较性,元素需要实现Comparable接口,覆盖CompareTo 方法 public int CompareTo(Object obj)
实现排序方式二:让集合具备可比较性,定义一个类实现Comparator接口,覆盖Compare方法 public int Compare(Object obj)
该类对象作为参数传递给TreeSet集合的构成函数
需求:1.创建Person类的name进行排序 (实现Comparable接口)自然排序
往TreeSet集合中存储学生对象,想按照学生年龄自然排序
package com.itheima.connection;
import java.util.HashSet;
import java.util.Iterator;
import java.util.TreeSet;
import javax.management.RuntimeErrorException;
public class TreeSetDemo {
/**
* @param args
*/
public static void main(String[] args) {
TreeSet ts=new TreeSet();
ts.add(new Student("008",22));
ts.add(new Student("007",20));
ts.add(new Student("002",27));
ts.add(new Student("009",20));
Iterator it=ts.iterator();
while(it.hasNext()){
Student s=(Student) it.next();
System.out.println(s.getName()+"。。。。。"+s.getAge());
}
}
}
class Student implements Comparable{ //实现Comparable接口让学生具备可比性
private String name;
private int age;
@Override
public int compareTo(Object obj) {
if(!(obj instanceof Student)){
throw new RuntimeException("这不是个学生对象");
}
Student s=(Student) obj;
System.out.println(this.name+"。。。。比较。。。。。。"+s.name);
if(this.age>s.age){
return 1;
}else if(this.age==s.age){ //主要条件相等,再比较次要条件
return this.name.compareTo(s.name);
}
else{
return -1;
}
}
public Student(String name, int age) {
this.name=name;
this.age=age;
}
public int hashCode(){
System.out.print(this.name+"......hashCode");
return 60;
}
public boolean equals(Object obj){
if(!(obj instanceof Student)){ //对象是否是特定类的一个Student实例
return false;
}
Student p=(Student)obj;
return this.name.equals(p.name) && this.age==p.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;
}
}
打印结果:
008。。。。比较。。。。。。008
007。。。。比较。。。。。。008
002。。。。比较。。。。。。008
009。。。。比较。。。。。。008
009。。。。比较。。。。。。007
007。。。。。20
009。。。。。20
008。。。。。22
002。。。。。27
2.实现定义一个类实现Comparator接口,覆盖Compare方法,根据姓名排序
class MyCompare Implements Comparator{
public int Compare(Object o1,Object o2){
Student st1= (Student) o1
Student st2= (Student) o2
}
}
-----------------------------------------------------------------------------------------------
集合 list set 总结:
Connection:集合根接口
|---List:集合是有序的,元素有索引角标,允许重复。
|---Set :是无序的(存入和取出顺序可能不一致),不允许重复,必须保证元素唯一性
集合框架:集合容器内部结构结构不一样,不断向上抽取,形成集合框架。
集合特点:1.存储对象的容器
2.集合长度是可变的
3.集合中不可以存储基本数据类型
Connection常见方法:
1,添加:
add(object):添加一个元素
addAll(Collection) :添加一个集合中的所有元素。
2,删除:
clear():将集合中的元素全删除,清空集合。
remove(obj) :删除集合中指定的对象。注意:删除成功,集合的长度会改变。 removeAll(collection) :删除部分元素。部分元素和传入Collection一致。
3,判断:
boolean contains(obj) :集合中是否包含指定元素 。
boolean containsAll(Collection) :集合中是否包含指定的多个元素。
boolean isEmpty():集合中是否有元素。
4,获取:
int size():集合中有几个元素。
5,取交集:
boolean retainAll(Collection) :对当前集合中保留和指定集合中的相同的元素。如果两个集合元素相同,返回flase;如果retainAll修改了当前集合,返回true。
6,获取集合中所有元素:
Iterator iterator():迭代器
7,将集合变成数组:toArray();
List:
|--ArrayList:底层是数组数据结构,线程不同步,有索引角标,查询速度快。
|--LinkedList:底层是链表结构,线程不同步,增删速度快
|--Vector:内部数组结构,线程同步,早期出现,增删查询速度都慢,被ArrayList取代。
List 特有方法:
增加:
add(index,elment)
删除:
remove(index)
修改:
set(index,elment)
查询:
get(index)
LinkedList:特有方法
addFirst(): 第一个位置插入元素
removeFirst()//移除并返回第一个元素
addLast():添加尾部插入元素
getFirst(); 获取不移除
Vector:Enumeration en=v.elements(); 获取元素
迭代器:对集合元素进行遍历,取出集合元素(所有Collection容器元素取出的公共接口)
ArrayList al=new ArrayList<>()
Iterator it=al.Iterator()
ListIterator :List集合特有的迭代器,可对元素进行增删改查
ConcurrentModificationException并发修改异常
发生原因:
List 集合在迭代器中添加修改元素会报异常,因为
集合引用和迭代器引用在同时操作元素,通过集合获取到对应的迭代器后,
在迭代中,进行集合引用的元素添加,迭代器并不知道,所以会出现异常情况。
解决办法:
Iterator中只有hasNext,next,remove方法.
所以使用ListIterator 进行增删改查
Set
|--HashSet:(哈希赛特)底层是哈希表,无序、高效、线程不同步
|--LinkedHashSet:HashSet子类,有序的
|--TreeSet:底层是二叉树,对集合元素进行指定顺序排序,线程不同步。
HashSet:保证元素唯一性
1.判断元素是否存在,或者删除元素,底层依据的是hashCode方法和equals方法,
数据存储到HashSet 集合中必须覆盖hashCode方法和equals方法。
2.哈希表确定元素是否相同
a.首先判断两个元素哈希值是否相同,如果hashcode不同,不用再equlals比较 对象内容
b.如果哈希值相同,及判断对象的hashCode方法,再比较对象内容 用equals
TreeSet:集合元素指定顺序排序
1.使元素自身有可比较性:实现Compareable 接口 覆盖其CompareTo方法
2.使集合具备可比较性:需要定义一个实现了Comparator接口的比较器,并覆盖compare方法,
并将该类对象作为实际参数传递给TreeSet集合的构造函数。
Map集合:存储的是一对元素,一个Key 键,一个是值,反应的是键值对应关系,保证集合中键的唯一性。
|--HashMap:底层是哈希表数据结构,有序的,是线程不同步的。可以存储null键,null值。替代了Hashtable
|--HashTable:底层是哈希表数据结构, 是线程同步的,不能存储null键,null值
|--TreeMap:底层二叉树结构,可对元素进行指定顺序排序。
集合方法:
添加。
put(key,value):当存储的键相同时,新的值会替换老的值,并将老值返回。如果键没有重复,返回null。 void putAll(Map);
删除。
void clear():清空
value remove(key) :删除指定键。
判断。
boolean isEmpty():
boolean containsKey(key):是否包含key
boolean containsValue(value) :是否包含value
4,取出。
int size():返回长度 value get(key) :通过指定键获取对应的值。如果返回null,可以判断该键不存在。
当然有特殊情况,就是在hashMap集合中,是可以存储null键null值的。
Collection values():获取map集合中的所有的值。
Map没有迭代器取出集合元素,转换成set
1.获取元素方式一: Set keySet=Map.keySet()
迭代器 Iterator it=keySet.Iterator();
while(it.hasNext()) {
Object key = it.next();
Object value = map.get(key);
System.out.println(key+":"+value);
}
Map 获取集合元素二:Set entrySet=Map.entrySet();
Iterator it=entrySet.Iterator();
while(it.hasNext()) {
Map mp=it.next();
Object key =mp.getKey();
Object value = mp.getValue();
System.out.println(key+":"+value);
}
案例演示
package com.itheima.connection;
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
public class MapDemo {
/**
* @param args
*/
public static void main(String[] args) {
// 创建Map集合
Map<Integer, String> m=new HashMap<Integer, String>();
Method_1(m);
}
public static void Method_1(Map<Integer, String> m){
// Map集合添加元素
m.put(1, "张三");
m.put(2, "李四");
m.put(3, "王五");
m.put(4, "孙猴子");
Collection<String> values=m.values();
//迭代遍历访问元素
Iterator<String> it=values.iterator();
while(it.hasNext()){
System.out.println("访问的元素是:"+it.next());
}
System.out.println("。。。。。。。。。。。。。方式一。。。。。。。。。。。。。。。。。测试。。。。");
System.out.println("通过map的KeySet方法获取Map键所在的Set集合元素,即是通过找到键得到对应值");
Set<Integer> KeySet=m.keySet();
Iterator<Integer> it1=KeySet.iterator();
while(it1.hasNext()){
Integer key=it1.next();// 获取Map集合的键值
String value=m.get(key);
System.out.println("对应的键是:"+key+"值是:"+value);
}
System.out.println("。。。。。。。。。。。。。方式二。。。。。。。。。。。。。。。。。测试。。。。");
System.out.println("将键值的映射关系作为对象存储到Set集合中,关系映射类型就是Map.Entry");
Set<Map.Entry<Integer, String>> entrySet=m.entrySet();
Iterator<Map.Entry<Integer, String>> itr=entrySet.iterator();
while(itr.hasNext()){
Map.Entry<Integer, String> mp=itr.next();
Integer key=mp.getKey();
String value=mp.getValue();
System.out.println("对应的键是:"+key+"值是:"+value);
}
}
}
打印结果:
访问的元素是:张三
访问的元素是:李四
访问的元素是:王五
访问的元素是:孙猴子
。。。。。。。。。。。。。方式一。。。。。。。。。。。。。。。。。测试。。。。
通过map的KeySet方法获取Map键所在的Set集合元素,即是通过找到键得到对应值
对应的键是:1值是:张三
对应的键是:2值是:李四
对应的键是:3值是:王五
对应的键是:4值是:孙猴子
。。。。。。。。。。。。。方式二。。。。。。。。。。。。。。。。。测试。。。。
将键值的映射关系作为对象存储到Set集合中,关系映射类型就是Map.Entry
对应的键是:1值是:张三
对应的键是:2值是:李四
对应的键是:3值是:王五
对应的键是:4值是:孙猴子
TreeMap:(带Tree的就想到二叉树)对集合元素排序,用到比较
方式一:Comparable:覆盖compareTo方法;
方式二:Comparator:覆盖compare方法。
习题练习:
package com.itheima.connection;
import java.util.Iterator;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.TreeMap;
public class TreeMapTest {
/**
* @param args
*/
public static void main(String[] args) {
TreeMap<Students, String> tmp=new TreeMap<Students,String>();
tmp.put(new Students("赵钱孙",23), "朝阳区");
tmp.put(new Students("刘武",29), "哈尔滨");
tmp.put(new Students("王博",23), "东北");
tmp.put(new Students("阿百川",23), "广州");
tmp.put(new Students("菲戈",23), "上海");
Set<Entry<Students, String>> entrySet=tmp.entrySet();
Iterator<Entry<Students, String>> it=entrySet.iterator();
while(it.hasNext()){
Map.Entry<Students,String> me=it.next();
Students key=me.getKey();
String value=me.getValue();
System.out.print(key.getName()+"..."+key.getAge()+"..."+key.getAddress());
}
}
}
class Students{
String name;
int age;
String address;
Students(String name,int age){
this.name=name;
this.age=age;
}
Students(String name,int age,String address){
this.name=name;
this.age=age;
this.address=address;
}
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 getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
}
Map集合与Collection集合的区别:
Map集合:1.Map集合存储的是键值对,反映的是映射对应关系。
2.Map 使用put方法 存储元素
3.Map 取出元素转换成Set,再用迭代取出
Collection :1.存储单个元素
2.存储元素使用的是add()方法
3.Collection 取出元素直接用的是迭代器
---------------------- <a href="http://www.itheima.com"target="blank">ASP.Net+Unity开发</a>、
<a href="http://www.itheima.com"target="blank">.Net培训</a>、期待与您交流! ----------------------
---------------------- <a href="http://www.itheima.com"target="blank">ASP.Net+Unity开发</a>、
<a href="http://www.itheima.com"target="blank">.Net培训</a>、期待与您交流! ----------------------
一、基本概念
为什么出现集合:
面向对象的设计对事物的操作是以对象的形式,方便对对象的操作,就对对象就行存储就出现集合。
集合类:集合只用于存储对象,可以存储不同类型的对象
数组:数组也能存取对象,但长度是固定的,可以存储基本数据类型。
二、集合体系结构
1.Collection:顶层集合容器接口。
容器功能:增删改查
package com.itheima.connection;
import java.util.ArrayList;
public class ConnectionDemo {
/**
* @param args
*/
public static void main(String[] args) {
method();
}
public static void method(){
// 创建一个集合容器。,使用Connection接口子类 ArrayList
ArrayList al=new ArrayList<>();
//1.添加 add方法参数类型是Object类型,方便接收任意类型对象,集合存储的都是对象的引用,或地址
al.add("我爱你1");
al.add("我爱你2");
al.add("我爱你3");
al.add("我爱你4");
print("原来集合是:"+al);
//2.删除 remove,清空clear()
al.remove("我爱你3");
print("修改后集合是:"+al);
}
public static void print(Object obj){
System.out.println(obj);
}
}
原来集合是:[我爱你1, 我爱你2, 我爱你3, 我爱你4]
修改后集合是:[我爱你1, 我爱你2, 我爱你4]
交集:
package com.itheima.connection;
import java.util.ArrayList;
public class ConnectionDemo {
/**
* @param args
*/
public static void main(String[] args) {
//method();
method_1();
}
public static void method(){
// 创建一个集合容器。,使用Connection接口子类 ArrayList
ArrayList al=new ArrayList();
//1.添加 add方法参数类型是Object类型,方便接收任意类型对象,集合存储的都是对象的引用,或地址
al.add("我爱你1");
al.add("我爱你2");
al.add("我爱你3");
al.add("我爱你4");
print("原来集合是:"+al);
//2.删除 remove,清空clear()
al.remove("我爱你3");
print("修改后集合是:"+al);
}
public static void method_1(){
// 创建一个集合容器。,使用Connection接口子类 ArrayList
ArrayList al=new ArrayList<>();
//1.添加 add方法参数类型是Object类型,方便接收任意类型对象,集合存储的都是对象的引用,或地址
al.add("我爱你1");
al.add("我爱你2");
al.add("我爱你3");
al.add("我爱你4");
ArrayList al2=new ArrayList<>();
al2.add("我爱她1");
al2.add("我爱你2");
al2.add("我爱他3");
al2.add("我爱你4");
al.retainAll(al2);// 取交集,al 和al2只会保留相同的数据
print("原来集合是:"+al);
print("修改后集合是:"+al2);
}
public static void print(Object obj){
System.out.println(obj);
}
}
打印:
al:[我爱你2, 我爱你4]
al2:[我爱她1, 我爱你2, 我爱他3, 我爱你4]
Iterator :迭代器,集合的取出元素方式。
iterator()该对象必须依赖于容器,每个容器内部结构不同,迭代对象是容器中内部实现的
ArrayList al=new ArrayList<>()
package com.itheima.connection;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
public class InteratorDemo {
/**
* @param args
*/
public static void main(String[] args) {
// 创建一个集合容器。,使用Connection接口子类 ArrayList
ArrayList al=new ArrayList<>();
//1.添加 add方法参数类型是Object类型,方便接收任意类型对象,集合存储的都是对象的引用,或地址
al.add("我爱你1");
al.add("我爱你2");
al.add("我爱你3");
al.add("我爱你4");
Iterator it=al.iterator(); //用于取出集合元素
while(it.hasNext()){
print(it.next());
}
}
public static void print(Object obj){
System.out.println(obj);
}
}
我爱你1
我爱你2
我爱你3
我爱你4
Collection:常见两个子接口:List、Set
2.List集合;元素是有序的,有角标可以重复,该集合有索引。
Set 集合:元素是无序的,不允许重复。
List:凡是可以操作角标的都是特有方法,数组角标从0开始
增加:
add(index,elment)
删除:
remove(index)
修改:
set(index,elment)
查询:
get(index)
三个常见子接口:
|--ArrayList:底层的数据结构是数组,线程不同步,ArrayList替代了Vector,查询元素的速度非常快。
|--LinkedList:的数据结构是链表结构,线程不同步,插入方便,增删元素的速度非常快。
|--Vector:底层的数据结构就是数组,线程同步的,Vector无论查询和增删都巨慢。
package com.itheima.connection;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
public class ListDemo {
/**
* @param args
*/
public static void main(String[] args) {
ListMethod();
}
public static void ListMethod(){
// 创建一个集合容器。,使用Connection接口子类 ArrayList
ArrayList al=new ArrayList<>();
//1.添加 add方法参数类型是Object类型,方便接收任意类型对象,集合存储的都是对象的引用,或地址
al.add("我爱你1");
al.add("我爱你2");
al.add("我爱你3");
al.add("我爱你4");
al,add(1,"喜欢你");
al.remove(2);
al.get(3,)
Iterator it=al.iterator(); //用于取出集合元素
while(it.hasNext()){
print(it.next());
}
}
public static void print(Object obj){
System.out.println(obj);
}
}
ListIterator:
List集合特有的迭代器,列表迭代器,在迭代时不可以通过集合对象的方法修改元素,会发生
并发性异常,迭代时只能用迭代器的方法操作元素,ListItrerator具备增删,改查的方法
package com.itheima.connection;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
public class ListDemo {
/**
* @param args
*/
public static void main(String[] args) {
ListMethod();
}
public static void ListMethod(){
// 创建一个集合容器。,使用Connection接口子类 ArrayList
ArrayList al=new ArrayList();
//1.添加 add方法参数类型是Object类型,方便接收任意类型对象,集合存储的都是对象的引用,或地址
al.add("我爱你1");
al.add("我爱你2");
al.add("我爱你3");
al.add("我爱你4");
al,add(1,"喜欢你");
al.remove(2);
al.get(3,)
ListIterator lit=al.iterator(); //用于取出集合元素
while(lit.hasNext()){//遍历元素
Object obj=lit.next;//取元素
if(obj.equeals("我爱你3")){
lit.set("爱你一万年"); //可迭代器修改元素
}
}
print(lit.next());
//List 特有的取出元素方式
for(int x=0; x<list.size(); x++) {
print("get:"+list.get(x));
}
}
lit.hasPervious //反向遍历
LinkList:特有方法
addFirst(); //第一个位置插入元素
addLast();//添加尾部插入元素
removeFirst()//移除并返回第一个元素
getFirst(); 获取不移除
package com.itheima.connection;
import java.util.Iterator;
import java.util.LinkedList;
public class LinkListDemo {
/**
* @param args
*/
public static void main(String[] args) {
LinkedList link=new LinkedList();
link.addFirst("abc1");
link.addFirst("abc2");
link.addFirst("abc3");
link.addFirst("abc4");
// System.out.println(link);
//System.out.println(link.getFirst()); //返回第一个元素
//System.out.println(link.removeFirst()); //获取元素但会删除
/*
while(!link.isEmpty()){
System.out.print(link.removeLast()); //获取元素但会删除 返回后面元素
}
*/
Iterator it=link.iterator();
while(it.hasNext()){
System.out.print(it.next()); //获取元素但会删除 返回后面元素
}
}
}
练习:使用LinkedList模拟堆栈队列的数据结构
堆栈:先进后出
队列:先进先出
package com.itheima.connection;
import java.util.LinkedList;
public class LinkedTest {
/**
* @param args
*/
public static void main(String[] args) {
DuiLie dl=new DuiLie();
dl.MyAdd("abc1");
dl.MyAdd("abc2");
dl.MyAdd("abc3");
dl.MyAdd("abc4");
while(!dl.isNull()){ //不为空,循环打印出来
System.out.println(dl.myGet());
}
}
}
class DuiLie{
private LinkedList link;
public DuiLie(){
link=new LinkedList();
}
//队列的添加功能
public void MyAdd(Object obj){
link.addLast(obj);
}
public Object myGet(){
//返回Link 对象
return link.removeFirst(); //link.removeLast() 堆栈倒排
}
public boolean isNull(){
return link.isEmpty();
}
}
练习:自定义对象存储到ArrayList 删除重复集合元素,同名同姓为重复 元素
1.对人描述,封装对象
2.定义容器存储 人
3.读取
List 集合判断是否相同,依据的是元素的equals 方法
package com.itheima.connection;
import java.util.ArrayList;
import java.util.Iterator;
public class ArrayListTest {
/**
* @param args
*/
public static void main(String[] args) {
ArrayList<Person> al=new ArrayList<Person>();
al.add(new Person("张三",23)); //Object obj=new Person("张三",23); 强制向上转型,容器不知道具体对象类型
al.add(new Person("李四",27));
al.add(new Person("张三",23));
al.add(new Person("孙六",22));
Iterator it=al.iterator();
while(it.hasNext()){
Person p=(Person) it.next(); //此处要向下强转
print("姓名是:"+p.getName()+"年龄是:"+p.getAge());
}
System.out.println(al.remove(new Person("张三",22)));
}
public static ArrayList SingeElement(ArrayList al){
//定义一个临时容器
ArrayList temp=new ArrayList();
Iterator it=al.iterator();
while(it.hasNext()){
Object obj=it.next();
if(!temp.equals(obj)){
temp.add(obj);
}
}
return temp;
}
public static void print(Object obj){
System.out.println(obj);
}
}
class Person{
private String name;
private int age;
public Person(String name, int age) {
this.name=name;
this.age=age;
}
public boolean equals(Object obj){
if(!(obj instanceof Person)){ //对象是否是特定类的一个Person实例
return false;
}
Person p=(Person)obj;
return this.name.equals(p.name) && this.age==p.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;
}
}
Set接口:元素是无序(存入和取出顺序有可能不一致)、不允许重复。
取出集合元素方式只有一种,迭代器
常见子类接口:
|--HashSet:(哈希赛特)底层数据结构是哈希表,线程是不同步的,无序的,高效率
过程:1.当元素的hashCode值相同时,才继续判断元素的equals是否为true。不存在为false 存储。
2. 如果hashCode值不同,那么不用判断equals,从而提高对象比较的速度。
|--TreeSet:底层的数据结构就是二叉树,可以对Set集合中的元素的进行指定顺序的排序。
HashSet:往HashSet 存储Person 对象,如果名称、年龄都想同视为同一个人,重复元素
package com.itheima.connection;
import java.util.*;
public class HashSetDemo {
/**
* @param args
*/
public static void main(String[] args) {
HashSet hs=new HashSet();
print(hs.add(new Person1("a",22)));
hs.add(new Person1("b",12));
print(hs.add(new Person1("a",22)));
hs.add(new Person1("c",27));
hs.add(new Person1("b",18));
// 判断元素是否重复,先判断的是元素的HashCode值,如果存在不允许添加
print("a:"+hs.contains(new Person("a", 22)));
Iterator it=hs.iterator();
while(it.hasNext()){
Person1 p=(Person1) it.next();
System.out.println(p.getName()+"。。。。。"+p.getAge());
}
}
public static void print(Object obj){
System.out.println(obj);
}
}
class Person1{
private String name;
private int age;
public Person1(String name, int age) {
this.name=name;
this.age=age;
}
public int hashCode(){
System.out.print(this.name+"......hashCode");
return 60;
}
public boolean equals(Object obj){
if(!(obj instanceof Person1)){ //对象是否是特定类的一个Person1实例
return false;
}
Person1 p=(Person1)obj;
return this.name.equals(p.name) && this.age==p.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;
}
}
打印结果:
a......hashCodetrue
b......hashCodea......hashCodefalse
c......hashCodeb......hashCodea:false
b。。。。。18
c。。。。。27
b。。。。。12
a。。。。。22
TreeSet:底层数据是二叉树,可以对集合指定顺序排序,是不同步的。
1.判断元素唯一性方式:CompareTo 方法 return 0 返回0就是相同元素,不保存。
2.实现排序方式一:让元素具备可比较性,元素需要实现Comparable接口,覆盖CompareTo 方法 public int CompareTo(Object obj)
实现排序方式二:让集合具备可比较性,定义一个类实现Comparator接口,覆盖Compare方法 public int Compare(Object obj)
该类对象作为参数传递给TreeSet集合的构成函数
需求:1.创建Person类的name进行排序 (实现Comparable接口)自然排序
往TreeSet集合中存储学生对象,想按照学生年龄自然排序
package com.itheima.connection;
import java.util.HashSet;
import java.util.Iterator;
import java.util.TreeSet;
import javax.management.RuntimeErrorException;
public class TreeSetDemo {
/**
* @param args
*/
public static void main(String[] args) {
TreeSet ts=new TreeSet();
ts.add(new Student("008",22));
ts.add(new Student("007",20));
ts.add(new Student("002",27));
ts.add(new Student("009",20));
Iterator it=ts.iterator();
while(it.hasNext()){
Student s=(Student) it.next();
System.out.println(s.getName()+"。。。。。"+s.getAge());
}
}
}
class Student implements Comparable{ //实现Comparable接口让学生具备可比性
private String name;
private int age;
@Override
public int compareTo(Object obj) {
if(!(obj instanceof Student)){
throw new RuntimeException("这不是个学生对象");
}
Student s=(Student) obj;
System.out.println(this.name+"。。。。比较。。。。。。"+s.name);
if(this.age>s.age){
return 1;
}else if(this.age==s.age){ //主要条件相等,再比较次要条件
return this.name.compareTo(s.name);
}
else{
return -1;
}
}
public Student(String name, int age) {
this.name=name;
this.age=age;
}
public int hashCode(){
System.out.print(this.name+"......hashCode");
return 60;
}
public boolean equals(Object obj){
if(!(obj instanceof Student)){ //对象是否是特定类的一个Student实例
return false;
}
Student p=(Student)obj;
return this.name.equals(p.name) && this.age==p.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;
}
}
打印结果:
008。。。。比较。。。。。。008
007。。。。比较。。。。。。008
002。。。。比较。。。。。。008
009。。。。比较。。。。。。008
009。。。。比较。。。。。。007
007。。。。。20
009。。。。。20
008。。。。。22
002。。。。。27
2.实现定义一个类实现Comparator接口,覆盖Compare方法,根据姓名排序
class MyCompare Implements Comparator{
public int Compare(Object o1,Object o2){
Student st1= (Student) o1
Student st2= (Student) o2
}
}
-----------------------------------------------------------------------------------------------
集合 list set 总结:
Connection:集合根接口
|---List:集合是有序的,元素有索引角标,允许重复。
|---Set :是无序的(存入和取出顺序可能不一致),不允许重复,必须保证元素唯一性
集合框架:集合容器内部结构结构不一样,不断向上抽取,形成集合框架。
集合特点:1.存储对象的容器
2.集合长度是可变的
3.集合中不可以存储基本数据类型
Connection常见方法:
1,添加:
add(object):添加一个元素
addAll(Collection) :添加一个集合中的所有元素。
2,删除:
clear():将集合中的元素全删除,清空集合。
remove(obj) :删除集合中指定的对象。注意:删除成功,集合的长度会改变。 removeAll(collection) :删除部分元素。部分元素和传入Collection一致。
3,判断:
boolean contains(obj) :集合中是否包含指定元素 。
boolean containsAll(Collection) :集合中是否包含指定的多个元素。
boolean isEmpty():集合中是否有元素。
4,获取:
int size():集合中有几个元素。
5,取交集:
boolean retainAll(Collection) :对当前集合中保留和指定集合中的相同的元素。如果两个集合元素相同,返回flase;如果retainAll修改了当前集合,返回true。
6,获取集合中所有元素:
Iterator iterator():迭代器
7,将集合变成数组:toArray();
List:
|--ArrayList:底层是数组数据结构,线程不同步,有索引角标,查询速度快。
|--LinkedList:底层是链表结构,线程不同步,增删速度快
|--Vector:内部数组结构,线程同步,早期出现,增删查询速度都慢,被ArrayList取代。
List 特有方法:
增加:
add(index,elment)
删除:
remove(index)
修改:
set(index,elment)
查询:
get(index)
LinkedList:特有方法
addFirst(): 第一个位置插入元素
removeFirst()//移除并返回第一个元素
addLast():添加尾部插入元素
getFirst(); 获取不移除
Vector:Enumeration en=v.elements(); 获取元素
迭代器:对集合元素进行遍历,取出集合元素(所有Collection容器元素取出的公共接口)
ArrayList al=new ArrayList<>()
Iterator it=al.Iterator()
ListIterator :List集合特有的迭代器,可对元素进行增删改查
ConcurrentModificationException并发修改异常
发生原因:
List 集合在迭代器中添加修改元素会报异常,因为
集合引用和迭代器引用在同时操作元素,通过集合获取到对应的迭代器后,
在迭代中,进行集合引用的元素添加,迭代器并不知道,所以会出现异常情况。
解决办法:
Iterator中只有hasNext,next,remove方法.
所以使用ListIterator 进行增删改查
Set
|--HashSet:(哈希赛特)底层是哈希表,无序、高效、线程不同步
|--LinkedHashSet:HashSet子类,有序的
|--TreeSet:底层是二叉树,对集合元素进行指定顺序排序,线程不同步。
HashSet:保证元素唯一性
1.判断元素是否存在,或者删除元素,底层依据的是hashCode方法和equals方法,
数据存储到HashSet 集合中必须覆盖hashCode方法和equals方法。
2.哈希表确定元素是否相同
a.首先判断两个元素哈希值是否相同,如果hashcode不同,不用再equlals比较 对象内容
b.如果哈希值相同,及判断对象的hashCode方法,再比较对象内容 用equals
TreeSet:集合元素指定顺序排序
1.使元素自身有可比较性:实现Compareable 接口 覆盖其CompareTo方法
2.使集合具备可比较性:需要定义一个实现了Comparator接口的比较器,并覆盖compare方法,
并将该类对象作为实际参数传递给TreeSet集合的构造函数。
Map集合:存储的是一对元素,一个Key 键,一个是值,反应的是键值对应关系,保证集合中键的唯一性。
|--HashMap:底层是哈希表数据结构,有序的,是线程不同步的。可以存储null键,null值。替代了Hashtable
|--HashTable:底层是哈希表数据结构, 是线程同步的,不能存储null键,null值
|--TreeMap:底层二叉树结构,可对元素进行指定顺序排序。
集合方法:
添加。
put(key,value):当存储的键相同时,新的值会替换老的值,并将老值返回。如果键没有重复,返回null。 void putAll(Map);
删除。
void clear():清空
value remove(key) :删除指定键。
判断。
boolean isEmpty():
boolean containsKey(key):是否包含key
boolean containsValue(value) :是否包含value
4,取出。
int size():返回长度 value get(key) :通过指定键获取对应的值。如果返回null,可以判断该键不存在。
当然有特殊情况,就是在hashMap集合中,是可以存储null键null值的。
Collection values():获取map集合中的所有的值。
Map没有迭代器取出集合元素,转换成set
1.获取元素方式一: Set keySet=Map.keySet()
迭代器 Iterator it=keySet.Iterator();
while(it.hasNext()) {
Object key = it.next();
Object value = map.get(key);
System.out.println(key+":"+value);
}
Map 获取集合元素二:Set entrySet=Map.entrySet();
Iterator it=entrySet.Iterator();
while(it.hasNext()) {
Map mp=it.next();
Object key =mp.getKey();
Object value = mp.getValue();
System.out.println(key+":"+value);
}
案例演示
package com.itheima.connection;
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
public class MapDemo {
/**
* @param args
*/
public static void main(String[] args) {
// 创建Map集合
Map<Integer, String> m=new HashMap<Integer, String>();
Method_1(m);
}
public static void Method_1(Map<Integer, String> m){
// Map集合添加元素
m.put(1, "张三");
m.put(2, "李四");
m.put(3, "王五");
m.put(4, "孙猴子");
Collection<String> values=m.values();
//迭代遍历访问元素
Iterator<String> it=values.iterator();
while(it.hasNext()){
System.out.println("访问的元素是:"+it.next());
}
System.out.println("。。。。。。。。。。。。。方式一。。。。。。。。。。。。。。。。。测试。。。。");
System.out.println("通过map的KeySet方法获取Map键所在的Set集合元素,即是通过找到键得到对应值");
Set<Integer> KeySet=m.keySet();
Iterator<Integer> it1=KeySet.iterator();
while(it1.hasNext()){
Integer key=it1.next();// 获取Map集合的键值
String value=m.get(key);
System.out.println("对应的键是:"+key+"值是:"+value);
}
System.out.println("。。。。。。。。。。。。。方式二。。。。。。。。。。。。。。。。。测试。。。。");
System.out.println("将键值的映射关系作为对象存储到Set集合中,关系映射类型就是Map.Entry");
Set<Map.Entry<Integer, String>> entrySet=m.entrySet();
Iterator<Map.Entry<Integer, String>> itr=entrySet.iterator();
while(itr.hasNext()){
Map.Entry<Integer, String> mp=itr.next();
Integer key=mp.getKey();
String value=mp.getValue();
System.out.println("对应的键是:"+key+"值是:"+value);
}
}
}
打印结果:
访问的元素是:张三
访问的元素是:李四
访问的元素是:王五
访问的元素是:孙猴子
。。。。。。。。。。。。。方式一。。。。。。。。。。。。。。。。。测试。。。。
通过map的KeySet方法获取Map键所在的Set集合元素,即是通过找到键得到对应值
对应的键是:1值是:张三
对应的键是:2值是:李四
对应的键是:3值是:王五
对应的键是:4值是:孙猴子
。。。。。。。。。。。。。方式二。。。。。。。。。。。。。。。。。测试。。。。
将键值的映射关系作为对象存储到Set集合中,关系映射类型就是Map.Entry
对应的键是:1值是:张三
对应的键是:2值是:李四
对应的键是:3值是:王五
对应的键是:4值是:孙猴子
TreeMap:(带Tree的就想到二叉树)对集合元素排序,用到比较
方式一:Comparable:覆盖compareTo方法;
方式二:Comparator:覆盖compare方法。
习题练习:
package com.itheima.connection;
import java.util.Iterator;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.TreeMap;
public class TreeMapTest {
/**
* @param args
*/
public static void main(String[] args) {
TreeMap<Students, String> tmp=new TreeMap<Students,String>();
tmp.put(new Students("赵钱孙",23), "朝阳区");
tmp.put(new Students("刘武",29), "哈尔滨");
tmp.put(new Students("王博",23), "东北");
tmp.put(new Students("阿百川",23), "广州");
tmp.put(new Students("菲戈",23), "上海");
Set<Entry<Students, String>> entrySet=tmp.entrySet();
Iterator<Entry<Students, String>> it=entrySet.iterator();
while(it.hasNext()){
Map.Entry<Students,String> me=it.next();
Students key=me.getKey();
String value=me.getValue();
System.out.print(key.getName()+"..."+key.getAge()+"..."+key.getAddress());
}
}
}
class Students{
String name;
int age;
String address;
Students(String name,int age){
this.name=name;
this.age=age;
}
Students(String name,int age,String address){
this.name=name;
this.age=age;
this.address=address;
}
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 getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
}
Map集合与Collection集合的区别:
Map集合:1.Map集合存储的是键值对,反映的是映射对应关系。
2.Map 使用put方法 存储元素
3.Map 取出元素转换成Set,再用迭代取出
Collection :1.存储单个元素
2.存储元素使用的是add()方法
3.Collection 取出元素直接用的是迭代器
---------------------- <a href="http://www.itheima.com"target="blank">ASP.Net+Unity开发</a>、
<a href="http://www.itheima.com"target="blank">.Net培训</a>、期待与您交流! ----------------------