一、Collection
数据多了用对象存,对象多了用集合存。
集合和数组一样,存储的都是地址。
集合类
为什么出现集合类?
面向对象语言对事物的体现都是以对象的形式,所以为了方便对多个对象的操作,就对
对象进行存储,集合就是存储对象最常用的一种方式。
数组和集合类同是容器,有何不同?
数组虽然也可以存储对象,但长度的固定的;集合长度是可变的。
数组中可以存储基本数据类型,集合只能存储对象。
集合类的特点?
集合只用于存储对象,集合长度是可变的,集合可以存储不同类型的对象。
为什么会出现这么多容器(集合)呢?
因为每个容器对数据的存储方式都不同。这个存储方式称之为:数据结构。
集合内数据获取:
把取出方式定义在集合的内部,这样取出方式就可以直接访问集合内部的元素。
那么取出方式就定义成内部类。而每一个容器的数据结构不同,所以取出的动作
细节也不一样,但是都有共性内容:判断和取出。那么可以将共性抽取。
那么这些内部类都符合一个规则,该规则是Iterator。如何获取集合的取出对象呢:
通过一个对外提供的方法:interator();
什么的类集框架?
1、类集框架是一组类和接口;
2、位于java.util包中;
3、主要用于用户存储和管理对象;
4、主要分为三大类:集合、列表和映射
什么是集合(Set):集合中的对象不按特定的方式排序,并且没有重复对象。
什么是列表(List):集合中对象按照索引位置排序,可以有重复的对象。
什么是映射(Map):集合中的每一个元素包含一个键对象和一个值对象,键不可以重复,值可以重复。
代码:
package collection;
/*
1、add方法的参数类型是object,以便接收任意类型的对象。
2、集合中存储的都是对象的引用(地址)
什么是迭代器:
其实就是集合的取出元素的方式。
collection:
--List:元素是有序的,元素是可以重复的。因为该集合体系有索引。
--ArrayList:底层的数据结构使用的是数组结构。
特点:查询、修改速度很快,但是增加、删除稍慢。
线程不同步。java1.2版本出现。
--LinkedList:底层使用的是链表数据结构。
特点:增加、删除速度很快,但是查询、修改稍慢。
--Vector:底层使用的是数组数据结构。线程同步,增删改查速度慢。
java1.0版本出现。被ArrayList替代。
--Set:元素是无序的,元素是不可以重复的,集合中没有索引。
*/
import java.util.ArrayList;
import java.util.Iterator;
class CollectionDemo{
public static void main(String[] args){
//method_1();
//method_2();
method_get();
}
public static void method_get(){
ArrayList<Object> al = new ArrayList<Object>();
al.add("java01");//add(obj);
al.add("java02");
al.add("java03");
al.add("java04");
//sop(al);
/*//获取迭代器,用于取出集合中的元素
Iterator it = al.iterator();
while(it.hasNext()){
sop(it.next());
}
*/
for(Iterator<Object> it = al.iterator(); it.hasNext();){
sop(it.next());
}
}
public static void method_2(){
//创建一个集合容器,使用collection接口的子类。ArrayList
ArrayList<String> al1 = new ArrayList<String>();
al1.add("java01");//add(obj);
al1.add("java02");
al1.add("java03");
al1.add("java04");
ArrayList<String> al2 = new ArrayList<String>();
al2.add("java01");//add(obj);
al2.add("java02");
al2.add("java05");
al2.add("java06");
//取交集,al1中只会保留和al2中相同的元素
al1.retainAll(al2);
sop("al1:" + al1);
sop("al2:" + al2);
//al1.removeAll(al2);
}
public static void method_1(){
//创建一个集合容器,使用collection接口的子类。ArrayList
ArrayList<String> al = new ArrayList<String>();
//1、添加元素
al.add("java01");//add(obj);
al.add("java02");
al.add("java03");
al.add("java04");
//打印原集合
sop(al);
//3、删除元素
al.remove("java02");
//2、获取个数。集合长度
sop("size:" + al.size());
//打印移除后集合
sop(al);
//4、判断元素
sop("java03是否存在:" + al.contains("java03"));
sop("集合是否为空:" + al.isEmpty());
//清空集合
al.clear();
}
//输出对象
public static void sop(Object obj){
System.out.println(obj);
}
}
二、List
package collection.list;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.ListIterator;
/*
collection:
--List:元素是有序的,元素是可以重复的。因为该集合体系有索引。
--ArrayList:底层的数据结构使用的是数组结构。
特点:查询、修改速度很快,但是增加、删除稍慢。
线程不同步。java1.2版本出现。
--LinkedList:底层使用的是链表数据结构。
特点:增加、删除速度很快,但是查询、修改稍慢。
--Vector:底层使用的是数组数据结构。线程同步,增删改查速度慢。
java1.0版本出现。被ArrayList替代。
--Set:元素是无序的,元素是不可以重复的,集合中没有索引。
List:
特有方法:凡是可以操作角标的方法都是改体系特有的方法。
增:add(index,element);
assAll(index,collection);
删:remove(index);
改:set(index,element);
查:get(index);
subList(from,to);
listItetator();
List集合特有的迭代器。ListIterator是Iterator的子接口。
在迭代时。不可以通过集合对象的方法操作集合中的元素。因为会发生
ConcurrentModificationException异常。
所以,在迭代器时,只能用迭代器的放过操作元素,可是Iterator方法是有限的,
只能对元素进行判断、取出和删除操作,如果想要其他操作如添加、修改等,就需要
使用其子接口ListIterator
该接口只能通过List集合的Iterator方法获取。
*/
class ListDemo{
public static void main(String[] args){
//演示列表迭代器
ArrayList<String> al = new ArrayList<String>();
al.add("java01");
al.add("java02");
al.add("java03");
//在迭代过程中,准备添加后删除元素
ListIterator<String> li = al.listIterator();
while(li.hasNext()){
Object obj = li.next();
if(obj.equals("java02"))
//li.add("java009");//添加
li.set("java006");//替换
}
sop("hasNext:" + li.hasNext());//正向判断
sop("hasPrevious:" + li.hasPrevious());//逆向判断
sop(al);
}
public static void method_1(){
ArrayList<String> al = new ArrayList<String>();
//添加元素
al.add("java01");
al.add("java02");
al.add("java03");
sop("原集合是:" + al);
//在指定位置添加元素
al.add(1,"java09");
sop("添加元素后集合:" + al);
//删除指定位置的元素
al.remove(2);
sop("删除元素后集合:" + al);
//修改元素
al.set(2,"java007");
sop("修改元素后集合:" + al);
//通过角标获取元素
sop("get(1):" + al.get(1));
//获取所有元素
for(int x = 0; x < al.size(); x++){
System.out.println("al(" + x + ")=" + al.get(x) );
}
//用迭代器获取元素
for(Iterator<String> it = al.iterator(); it.hasNext();){
sop("next:" + it.next());
}
//通过index获取对象的位置
sop("index" + al.indexOf("java02"));
//获取子串
List<String> sub = al.subList(1,3);
sop("sub=" + sub);
}
//封装打印对象
public static void sop(Object obj){
System.out.println(obj);
}
}
====ArrayList===
练习一:
package collection.list;
import java.util.ArrayList;
import java.util.Iterator;
/*
练习:
去除ArrayList集合中的重复元素
*/
class ArrayListTest{
public static void main(String[] args){
ArrayList<Object> al = new ArrayList<Object>();
al.add("java01");
al.add("java02");
al.add("java01");
al.add("java03");
al.add("java02");
al.add("java04");
/*
在迭代时,循环中的next调用一次,就要hasNext判断一次。
Iterator it = al.iterator();
while(it.hasNext()){// 判断一次hasNext,使用两次next,可能出现元素不存在异常。
sop(it.next() + "......." + it.next());
}
*/
sop(al);
al = singleElement(al);
sop(al);
}
public static ArrayList<Object> singleElement(ArrayList<Object> al){//去除重复元素
//定义一个临时容器
ArrayList<Object> newAl = new ArrayList<Object>();
Iterator<Object> it = al.iterator();
while(it.hasNext()){
Object obj = it.next();
if(!newAl.contains(obj))//将元素添加到新容器中(重复的不存)
newAl.add(obj);
}
return newAl;
}
public static void sop(Object obj){
System.out.println(obj);
}
}
练习二:
package collection.list;
/*
练习:(重要)
将自定义对象作为元素存到ArrayList集合中,并去除重复元素
比如:存人对象。同姓名同年龄的视为同一个人,为重复对象。
思路:
1、对人描述,将数据封装进人对象。
2、定义容器,将人存入。
3、取出。
4、去除重复对象。
*******List集合判断元素是否相同,依据的是元素的equals方法。**********
*/
import java.util.*;
class ArrayListTest2{
public static void main(String[] args){
ArrayList<Object> al = new ArrayList<Object>();//创建一个集合
al.add(new Person("lisi01",30));//集合中添加对象
al.add(new Person("lisi02",30));
al.add(new Person("lisi03",30));
al.add(new Person("lisi01",30));
al.add(new Person("lisi02",35));
al.add(new Person("lisi04",30));
System.out.println("---------去除重复对象前--------------");
sopArrayList(al);
System.out.println("---------去除重复对象后--------------");
al = singleElement(al);
sopArrayList(al);
System.out.println("---------移除一个元素--------------");
//调用Person的equals方法,判断移除元素是否与集合内元素相同
al.remove(new Person("lisi04",30));
sopArrayList(al);
}
//打印集合中对象的内容
public static void sopArrayList(ArrayList<Object> al){
Iterator<Object> it = al.iterator();
while(it.hasNext()){
Person p = (Person)it.next();//向下转型
sop(p.getName() + "......" + p.getAge());
}
}
//打印对象
public static void sop(Object obj){
System.out.println(obj);
}
//去除集合内重复的对象元素
public static ArrayList<Object> singleElement(ArrayList<Object> al){
//定义一个临时容器
ArrayList<Object> newAl = new ArrayList<Object>();
Iterator<Object> it = al.iterator();
while(it.hasNext()){//遍历集合中的对象。
Object obj = it.next();
if(!newAl.contains(obj))//依据对象的equals方法进行判断
newAl.add(obj);
}
return newAl;
}
}
//创建一个Person类
class Person{
private String name;
private int age;
Person(String name,int age){
this.name = name;
this.age = age;
}
public String getName(){
return name;
}
public int getAge(){
return age;
}
//覆写equals方法,判断对象是否相同
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;
}
}
===LinkedList===
package collection.list;
import java.util.LinkedList;
/*
LinkedList特有方法:
addFirst();
addLast();
作为第一个(最后一个)元素,添加到集合中
getFirst();
getLast();
获取元素,但不删除元素。会出现NoSuchElementException
removeFirst();
removeLast();
获取元素,并删除元素。如果集合中没有元素,会出现NoSuchElementException
在JDK1.6出现了替换方法:
offerFirst();
offerLast();
作为第一个(最后一个)元素,添加到集合中
peekFirst();
peekLast();
获取元素,但不删除元素。如果集合中没有元素,会返回null
pollFirst();
pollLast();
获取元素,并删除元素。如果集合中没有元素,会返回null
*/
class LinkedListDemo{
public static void main(String[] args){
LinkedList<Object> link = new LinkedList<Object>();
link.addFirst("java01");
link.addFirst("java02");
link.addFirst("java03");
link.addFirst("java04");
sop(link);
}
public static void sop(Object obj){
System.out.println(obj);
}
}
练习:
package collection.list;
import java.util.LinkedList;
/*
---------------------必须掌握(重要)-----------------------------
练习:使用LinkedList模拟一个堆栈或者队列数据结构
堆栈:先进后出 如同一个杯子
队列:先进先出 First in, First out FIFO如同一个水管
*/
class LinkedListTest{
public static void main(String[] args){
Queue dl = new Queue();
dl.myAdd("java01");//作为第一个元素添加到集合中
dl.myAdd("java02");
dl.myAdd("java03");
dl.myAdd("java04");
while(!dl.isNull())
System.out.println(dl.myGet());//获取最后一个元素
}
}
class Queue{
private LinkedList<Object> link;
Queue(){//生成一个链表对象
link = new LinkedList<Object>();
}
public void myAdd(Object obj){//作为第一个元素添加
link.addFirst(obj);
}
public Object myGet(){//获取最后一个元素,并移除
return link.removeLast();
}
public boolean isNull(){//判断集合是否为空
return link.isEmpty();
}
}
===Vector===
package collection.list;
import java.util.Enumeration;
import java.util.Vector;
/*
枚举就是vector特有的取出方式。
发现枚举和迭代器很像。其实枚举和迭代是一样的。
因为枚举的名称以及方法的名称都过长,所以枚举被迭代器取代了。
枚举就郁郁而终了。
*/
class VectorDemo{
public static void main(String[] args){
Vector<String> v = new Vector<String>();
v.add("java01");
v.add("java02");
v.add("java03");
v.add("java04");
Enumeration<String> en = v.elements();
while(en.hasMoreElements()){
System.out.println(en.nextElement());
}
}
}
三、Set
===HashSet===
package set;
import java.util.HashSet;
import java.util.Iterator;
/*
|--Set:元素是无序的(存入和取出的顺序不一定一致),元素不可以重复。
|-HashSet:底层数据结构是哈希表。
HashSet是如何保证元素唯一性的呢?
是通过元素的两个方法,hashCode和equals来完成的。
如果元素的HashCode值相同,才会判断equals是否为true。
如果元素的HashCode值不同,就不会调用equals方法。
注意:对于判断元素是否存在,以及删除等操作,依赖的方法是元素
的hashCode和equals方法。先判断hashCode方法,如果相同再判断equals方法。
|-TreeSet:可以对set集合中的元素进行排序。
Set集合的功能和Collection是一致的。
*/
public class HashSetDemo {
/**
* @param args
*/
public static void main(String[] args) {
// TODO Auto-generated method stub
HashSet<String> hs = new HashSet<String>();
hs.add("java04");//添加元素
hs.add("java05");
System.out.println(hs.add("java01"));//添加元素,并打印元素是否存在的值
hs.add("java02");
hs.add("java03");
hs.add("java03");
System.out.println(hs.add("java01"));//元素已经存在,打印出false
for(Iterator<String> it = hs.iterator(); it.hasNext();){//遍历集合
System.out.println(it.next());
}
}
}
练习:
package set;
import java.util.HashSet;
import java.util.Iterator;
/*
练习:
往HashSet集合中存入自定义对象(人对象)
姓名和年龄相同视为同一个人,为重复元素。
HashSet是如何保证元素唯一性的呢?
是通过元素的两个方法,hashCode和equals来完成的。
如果元素的HashCode值相同,才会判断equals是否为true。
如果元素的HashCode值不同,就不会调用equals方法。
*/
class HashSetTest{
public static void main(String[] args){
//创建HashSet集合
HashSet<PersonHashSet> hs = new HashSet<PersonHashSet>();
sop("\n---------添加元素-----------");
hs.add(new PersonHashSet("a1",11));
hs.add(new PersonHashSet("a2",12));
hs.add(new PersonHashSet("a3",13));
hs.add(new PersonHashSet("a4",14));
sop("\n---------重复添加一个元素-----------");
hs.add(new PersonHashSet("a2",12));
//判断是否包含一个元素
sop("\n---------是否包含一个指定元素-----------");
sop(hs.contains(new PersonHashSet("a4",14)));
//移除一个元素
sop("\n---------移除一个元素-----------");
hs.remove(new PersonHashSet("a3",13));
sop("\n---------打印集合中的元素-----------");
for(Iterator<PersonHashSet> it = hs.iterator(); it.hasNext();){//遍历集合
PersonHashSet p = (PersonHashSet)it.next();
sop(p.getName() + "......" + p.getAge());
}
}
public static void sop(Object obj){//打印对象
System.out.println(obj);
}
}
//创建一个Person类
class PersonHashSet{
private String name;
private int age;
PersonHashSet(String name,int age){
this.name = name;
this.age = age;
}
public String getName(){
return name;
}
public int getAge(){
return age;
}
//覆写HashCode方法,判断对象是否相同,如果HashCode相同,再判断equals方法
public int hashCode(){
System.out.println(this.name + "-------hashCode");//测试哪个对象调用hashCode方法
return name.hashCode() + age*39;
}
//覆写equals方法,判断对象是否相同
public boolean equals(Object obj){
if(!(obj instanceof PersonHashSet))//判断对象是否是Person类对象
return false;
PersonHashSet p = (PersonHashSet)obj;//向下转型
//测试哪个对象调用equals方法,并和哪个对象做比较
System.out.println(this.name + "----equals---" + p.name);
return this.name.equals(p.name) && this.age == p.age;
}
}
===TreeSet===
package set;
import java.util.Iterator;
import java.util.TreeSet;
/*
|--Set:元素是无序的(存入和取出的顺序不一定一致),元素不可以重复。
|-HashSet:底层数据结构是哈希表。
HashSet是如何保证元素唯一性的呢?
是通过元素的两个方法,hashCode和equals来完成的。
如果元素的HashCode值相同,才会判断equals是否为true。
如果元素的HashCode值不同,就不会调用equals方法。
注意:对于判断元素是否存在,以及删除等操作,依赖的方法是元素
的hashCode和equals方法。先判断hashCode方法,如果相同再判断equals方法。
|-TreeSet:底层数据结构是二叉树。可以对set集合中的元素进行排序。
二叉树是保证元素唯一性的依据。
用compareTo方法的返回值判断大小。
TreeSet排序:
第一种方式:让元素自身具备比较性。元素需要实现comparable接口,
覆盖compareTo方法。这种方式也成为元素的自然顺序或默认顺序。
第二种方式:当元素自身不具备比较性时,或者具备的比较性不是需要的时候,
需要让集合自身具备比较性。
在集合一初始化时,就有了比较方式。
Set集合的功能和Collection是一致的。
记住:排序时当主要条件相同时一定要判断次要条件。
练习:
需求:(第一种排序方式)
往TreeSet集合中存储自定义对象学生。
按照学生年龄进行排序。
*/
public class TreeSetDemo {
/**
* @param args
*/
public static void main(String[] args) {
TreeSet<Student> ts = new TreeSet<Student>();
ts.add(new Student("张三",26));
ts.add(new Student("李四01",23));
ts.add(new Student("王五",20));
ts.add(new Student("李四02",23));//年龄相同时,比较姓名
ts.add(new Student("小王",20));
ts.add(new Student("王五",20));//重复元素不会重新存储
for(Iterator<Student> it = ts.iterator(); it.hasNext();){//遍历集合
Student s = (Student)it.next();
System.out.println(s.getName() + "-----" + s.getAge());
}
}
}
//实现compareable接口,该接口强制让对象具备比较性
class Student implements Comparable<Object>{
private String name;
private int age;
Student(String name,int age){
this.setName(name);
this.setAge(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;
}
//覆写compareTo方法,定义按年龄排序的方法
public int compareTo(Object o) {
if(!(o instanceof Student))//判断是否是相同类,不是相同类抛异常
throw new RuntimeException("输入的类不是Student类");
Student s = (Student)o;
// System.out.println(this.name + "-----compareTo------" + s.name);
if(this.age > s.age)
return 1;
//如果年龄相同,按照姓名进行排序。字符串本身有自带的compareTo方法。
if(this.age == s.age){
return this.name.compareTo(s.name);
}
return -1;
}
}
package set;
import java.util.Comparator;
import java.util.Iterator;
import java.util.TreeSet;
/*
* 当元素自身不具备比较性,或者具备的比较性不是所需要的,这时就需要让容器自身具备比较性。
*
* 思路:
* 1、定义一个类,实现comparator接口,并覆盖compare方法,做为比较器。
* 2、定义了比较器,将比较器对象作为参数传递给TreeSet集合的构造函数。
*
* 练习:(第二种排序方式)
* 需求:
* 1、往TreeSet集合中存储自定义对象学生。
2、按照学生年龄进行排序。
3、现在需求改变,需要按照姓名来排序,但又不能修改原有的排序代码
* 注意:当两种排序都存在时,以比较器为主。
*
*
*/
public class TreeSetDemo2 {
/**
* @param args
*/
public static void main(String[] args) {
//将比较器作为参数传递给集合
TreeSet<Student> ts = new TreeSet<Student>(new MyCompare());
ts.add(new Student("李四01",26));
ts.add(new Student("李四04",23));
ts.add(new Student("李四02",20));
ts.add(new Student("李四02",23));//姓名相同,比较年龄
ts.add(new Student("李四03",20));
ts.add(new Student("李四04",23));//对象重复,不会添加
for(Iterator<Student> it = ts.iterator(); it.hasNext();){//遍历集合
Student s = (Student)it.next();
System.out.println(s.getName() + "-----" + s.getAge());
}
}
}
//自定义比较器
class MyCompare implements Comparator<Object>{
public int compare(Object o1, Object o2) {
Student s1 = (Student)o1;
Student s2 = (Student)o2;
int num = s1.getName().compareTo(s2.getName());
if(num == 0){
return s1.getAge()-s2.getAge();//这种方法也可行
//调用Integer类是compareTo方法
//return new Integer(s1.getAge()).compareTo(new Integer(s2.getAge()));
}
return num;
}
}
练习:
package set;
import java.util.Comparator;
import java.util.Iterator;
import java.util.TreeSet;
/*
练习:
按照字符串长度排序
思路:字符串本身具备比较性,但是它的比较方式不是所需要的,这时就只能使用比较器
*/
public class TreeSetTest {
public static void main(String[] args) {
// TODO Auto-generated method stub
TreeSet<String> ts = new TreeSet<String>(new StringLengthComparator());
ts.add("abcd");
ts.add("abd");
ts.add("cd");
ts.add("d");
ts.add("adbcd");
ts.add("aacd");
for(Iterator<String> it = ts.iterator(); it.hasNext();){//遍历集合
System.out.println(it.next());
}
}
}
class StringLengthComparator implements Comparator<Object>{
public int compare(Object o1, Object o2) {
String s1 = (String)o1;
String s2 = (String)o2;
int num = new Integer(s1.length()).compareTo(new Integer(s2.length()));
if(num == 0)
return s1.compareTo(s2);
return num;
}
}