java容器

1.概念

Java API 所提供的一系列类的实例,用于在程序中存放对象。J2SDK所提供的容器API位于java.util包内。
容器API的类图结构如下图所示:
容器API的类图结构

  1. Collection 接口:定义了存取一组对象的方法其子接口Set和List分别定义了存储方式。

Set中的数据对象没有顺序且不可以重复
List中的数据对象有顺序且可以重复

  1. Map 接口定义了存储"键(key)——值(value)"映射对的方法。

2.Collection接口:

2.1.Collection接口中所定义的方法:
int size();//集合的元素个数
void clear();//清空所有集合元素
boolean isEmpty();//判断指定集合的元素size是否为0
boolean contains(Object element);//判断指定集合是否包含对象element
boolean add(Object element);//向集合添加元素element,若指定集合元素改变了则返回true
boolean remove(Object element);//删除集合中的元素对象element,若集合有多个element元素,则只会删除第一个元素
Iterator iterator();//获取遍历容器的迭代器
boolean containsAll(Collection c);//判断指定集合是否包含集合c的所有元素
boolean addAll(Collection c);//把集合c中的元素全部添加到集合中,若指定集合元素改变返回true
boolean removeAll(Collection c);//删除指定集合包含集合c的元素
boolean retainAll(Collection c);//从指定集合中保留包含集合c的元素,其他元素则删除
Object[] toArry();//将集合转换为T类型的数组

实例1:

import java.util.Collection;
import java.util.HashSet;

public class aaa {
    public static void main(String args[]) {
        Collection c = new HashSet();
        c.add("Hello");//添加字符串"Hello"
        c.add(new Integer(124));//添加Integer对象
        c.add(new Name1("f3","l3"));//添加Name1对象
        //remove()方法会返回一个boolean值,如果能除去则返回true,否则返回flase
        System.out.println(c.remove(new Name1("f3","l3")));
        System.out.println(c);

    }
}
class Name1 {
    String firstName,lastName;
    public Name1 (String firstName,String lastName) {
        this.firstName = firstName;
        this.lastName = lastName;
    }
    public String getLastName() { return lastName; }
    public String getFirstName() { return firstName;}
    //重写toString方法
    public String toString() {
        return firstName + " " + lastName;
    }
    //重写equals方法,因为Object类中equals的方法是比较两个对象的引用。
    //而我们需要的是比较他的FirstName和lastName是否相同。
    public boolean equals(Object obj) {
    //判断传入的对象是不是Name1类
        if(obj instanceof Name1) {
            return (firstName.equals(((Name1) obj).firstName)
            &&lastName.equals(((Name1) obj).lastName));
        }
        //如果传入的对象不是Name1类,则交给Object类实现equals方法
        return super.equals(obj);
    //重写equals方法一定要同时重写hashCode方法
    //即:如果这个类的对象可能作为键值时,一定要重写hashCode方法
    public int hashCode() {
        return firstName.hashCode();
    }
}


//output:
true
[Hello, 124]

Process finished with exit code 0

2.2.Iterator接口
  1. 所有实现了Collection接口·的容器类都有一个iterator方法用以返回一个实现了Iterator接口的对象。
  2. Iterator对象称作迭代器,用以方便实现容器内元素的遍历操作。
    Iterator接口定义了如下方法:
boolean hasNext();//判断游标右边是否有元素
Object next();//返回游标右边的元素并将游标移动到下一个位置
void remove();//删除游标左边的元素。在执行完Next后该操作只能执行一次

在这里插入图片描述
实例:

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

public class TestA {
    public static void main(String args[]) {
        Collection c = new HashSet();
        c.add(new Name("ffff1","l1"));
        c.add(new Name("f2","lllll2"));
        c.add(new Name("ff3","l3"));
        for(Iterator i = c.iterator() ; i.hasNext() ; ) {
            Name name  = (Name)i.next();
            if(name.getFirstName().length()<=2) {
                i.remove();
                //如果换成 c.remove(name) 会产生例外
                //因为Iterator在遍历时执了 锁定 ,即:Iterator 所遍历的对象 只有 它自己能看、改动等操作.
            }
        }
        System.out.println(c);
    }
}

//output:
[ff3 l3, ffff1 l1]

Process finished with exit code 0

增强的for循环:

优点:
语法简单
缺点:
对于数组:不能方便地访问下标值
对于集合:与使用Iterator相比,不能方便地删除集合中的内容:
其内部实现也是调用Iterator(所以在遍历时会有锁定)

所以,除了用于简单遍历并读出其中的内容外,不建议使用增强的for循环。

实例1:

public class Test02 {
    public static void main(String args[]) {
        int i = 0;
        int a[] = new int[10];
        //要遍历什么类型,r就定义为什么类型
        for(int r : a) {
            r = i++;
        }
        for(int m : a) {
            System.out.print(m + " ");
        }
    }
}


//output:
0 0 0 0 0 0 0 0 0 0 
Process finished with exit code 0
/**
*原因:
*遍历时数组被锁定,所以 r = i++;这行代码是无效的,所以数组中的每个元素的值任然为0。
*/

IDEA会有如下提示:
在这里插入图片描述

实例2:

import java.util.Collection;
import java.util.HashSet;

public class Test02 {
    public static void main(String args[]) {
        Collection c = new HashSet();
        c.add("Hello");
        c.add(new Integer(100));
        c.add(new Name("f1","l1"));
        for(Object r : c) {
            System.out.println(r);
        }
    }
}

//output:
Hello
100
f1 l1

Process finished with exit code 0

2.3.Set接口
  1. Set接口时Collection的子接口,Set接口没有提供额外的方法,但实现Set接口的容器类中的元素是没有顺序的,而且不可以重复。
  2. Set容器可以与数学中“集合”的概念相对应。
  3. J2SDK API中所提供的Set容器类有 HashSet , TreeSet。

实例1:

import java.util.Collection;
import java.util.HashSet;

public class Test02 {
    public static void main(String args[]) {
        Collection c1 = new HashSet();
        Collection c2 = new HashSet();
        c1.add("a"); c1.add("b"); c1.add("c");
        c2.add("b"); c2.add("c"); c2.add("d");
        //把 c1 中的元素复制到 s 中
        Collection s = new HashSet(c1);
        c1.retainAll(c2);//求c1与c2的交集
        c2.addAll(s);//求c2与s(即c1)的并集
        System.out.println(c1);
        System.out.println(c2);
    }
}

实例2:

import java.util.Collection;
import java.util.HashSet;

public class Test02 {
    public static void main(String args[]) {
        Collection c1 = new HashSet();
        c1.add("Hello");
        c1.add("Hello");//元素重复,添加失败
        c1.add(new Name("f1","l1"));
        c1.add(new Name("f1","l1"));//元素重复,添加失败
        System.out.println(c1);
    }
}


//output:
[Hello, f1 l1]
2.4.List接口
  1. List接口是Collection的子接口,实现List接口的容器的类中的元素是有顺序的,而且可以重复。
  2. List容器中的元素都对应一个整数类型的序号记载在容器中的位置,可以根据序号存取容器中的元素。
  3. J2SDK所提供的List容器有 ArrayList (数组) , LinkedList (链表) 等。
    常用方法:
Object get(int index);
Object set(int index,Object e);//把index位置除的元素设为 e ,返回值是这个位置的旧对象。
void add(int index,Object e);//添加一个新元素
Object remove(int index);
int indexOf(Object o);
int lastIndexOf(Object o);

实例1:

import java.util.LinkedList;
import java.util.List;

public class Test02 {
    public static void main(String args[]) {
        List l1 = new LinkedList();

        for(int i = 0; i <= 5l ;i++) {
            l1.add("a"+i);
        }

        System.out.println(l1);
        l1.add(3,"a100");//在下标为3的位置添加字符串 “a100” .把原来位置的元素及其后面的元素向后挤一个位置
        System.out.println(l1);
        Object m = l1.set(6,"a200");//把下标为6的元素设为“a100”,返回原来位置的元素
        System.out.println(l1);
        System.out.println(m);
        System.out.println((String) l1.get(2)+" ");//得到下标为2的元素
        System.out.println(l1.indexOf("a3"));//得到元素为“a3”的下标
        l1.remove(1);//删除下标为1的元素
        System.out.println(l1);
    }
}


//output:
[a0, a1, a2, a3, a4, a5]
[a0, a1, a2, a100, a3, a4, a5]
[a0, a1, a2, a100, a3, a4, a200]
a5
a2 
4
[a0, a2, a100, a3, a4, a200]

Process finished with exit code 0

List的常用算法:

void sort(List);//对List容器内的元素排序
void shuffle(List);//对List容器内的对象进行随机排序
void reverse(List);//对List容器内的对象进行逆序排序
void fill(List,Object);//用一个特定的对象重写整个List容器
void copy(List dest,List src);//将 src List容器内容拷贝到 dest List容器
int binarySearch(List,Object);//对于顺序的List容器,采用二分查找的方法查找特定对象

实例2:

import java.util.Collections;
import java.util.LinkedList;
import java.util.List;

public class Test02 {
    public static void main(String args[]) {
        List l1 = new LinkedList();
        for(int i = 0;i<=9;i++) {
            l1.add("a"+i);
        }
        System.out.println(l1);
        Collections.shuffle(l1);//随机排序
        System.out.println(l1);
        Collections.reverse(l1);//逆序排序
        System.out.println(l1);
        Collections.sort(l1);//排序
        System.out.println(l1);
        System.out.println(Collections.binarySearch(l1,"a5"));//二分查找,找到l1中"a5"的下标
    }
}

//output:
[a0, a1, a2, a3, a4, a5, a6, a7, a8, a9]
[a5, a7, a1, a3, a2, a4, a8, a9, a6, a0]
[a0, a6, a9, a8, a4, a2, a3, a1, a7, a5]
[a0, a1, a2, a3, a4, a5, a6, a7, a8, a9]
5

Process finished with exit code 0

那么上面的算法根据什么来确定容器中的对象的大小顺序?
下面来介绍Comparable接口。

2.5.Comparable接口

所以可以排序的类都实现了java.lang.Comparable接口,Comparable接口中只有一个方法:
public int compareTo(Object obj);
该方法:

返回 0 表示this = obj
返回正数表示 this > obj
返回负数表示 this < obj

实现了Comparable接口的类通过实现compareTo方法从而确定该类对象的排序方式.
实例1:

import java.util.*;

public class aaa {
    public static void main(String args[]) {
        List l1 = new LinkedList();
        l1.add(new Name1("Karl","M"));
        l1.add(new Name1("Steven","Lee"));
        l1.add(new Name1("John","O"));
        l1.add(new Name1("Tom","M"));
        System.out.println(l1);
        Collections.sort(l1);
        System.out.println(l1);
    }
}
//Name1类实现了Comparable接口
class Name1 implements Comparable{
    String firstName,lastName;
    public Name1 (String firstName,String lastName) {
        this.firstName = firstName;
        this.lastName = lastName;
    }
    public String getLastName() { return lastName; }
    public String getFirstName() { return firstName;}
    public String toString() {
        return firstName + " " + lastName;
    }
    
    public boolean equals(Object obj) {
        if(obj instanceof Name1) {
            return (firstName.equals(((Name1) obj).firstName)
            &&lastName.equals(((Name1) obj).lastName));
        }
        return super.equals(obj);
    }
   
    public int hashCode() {
        return firstName.hashCode();
    }
   
    public int compareTo(Object o) {
        Name1 n = (Name1)o;
        int lastCmp =
                lastName.compareTo(n.getLastName());
        return
                (lastCmp != 0 ? lastCmp :
                firstName.compareTo(n.getFirstName()));
    }
}

//output:
[Karl M, Steven Lee, John O, Tom M]
[Steven Lee, Karl M, Tom M, John O]

Process finished with exit code 0

3.Map接口

实现 Map 接口的类用来存储 键——值 对。
Map 接口的实现类有 HashMap 和 TreeMap 等。
Map 类中存储的 键——值 对通过键来标识,所以键值不能重复

常用方法:

Object put(Object key,Object value)//把key对应的值替换为value,返回值为key对应的旧值
Object get(Object key)//得到key所对应的值
Object remove(Object key)//除去key所对应的值,同时key也被除去
boolean containsKey(Object key)//是否包含key
boolean containsValue(Object value)//是否包含value
int size()//返回键值对的数量
boolean isEmpty()//是否为空
void putAll(Map t)//把 t 中的元素都加进去
void clear()//清除

实例:

import java.util.HashMap;
import java.util.Map;

public class Test05 {
    public static void main(String args[]) {
        Map m1 = new HashMap();
        Map m2 = new HashMap();
        m1.put("one",new Integer(1));
        m1.put("two",new Integer(2));
        m1.put("three",new Integer(3));
        m2.put("A",new Integer(1));
        m2.put("B",new Integer(2));
        System.out.println(m1.size());//输出 m1 中键值对的数量
        System.out.println(m1.containsKey("one"));//输出 m1 中是否有键"one"
        System.out.println
                (m2.containsValue(new Integer(1)));//输出 m2 中是否有值 new Integer(1)
        if(m1.containsKey("two")) {
            int i = ((Integer)m1.get("two")).intValue();//因为get方法返回的是Object 类型,所以需要强转
            System.out.println(i);//输出 m1 中键 "two" 对应的值
        }
        Map m3 = new HashMap(m1);//把 m1 中的元素都复制到 m3 中
        m3.putAll(m2);//把 m2 中的元素都添加到 m3 中
        System.out.println(m3);
    }
}



//output:
3
true
true
2
{A=1, B=2, two=2, three=3, one=1}

Process finished with exit code 0

有了自动打包和解包(Auto-boxing/unboxing),会让我们更方便地使用Map。

boxing(自动打包):自动将基础类型转换为对象
unboxing(自动解包):自动将对象转换为基础类型

如上述例子可以写为:

import java.util.HashMap;
import java.util.Map;

public class Test05 {
    public static void main(String args[]) {
        Map m1 = new HashMap();
        Map m2 = new HashMap();
        //自动打包
        m1.put("one",1);
        m1.put("two",2);
        m1.put("three",3);
        m2.put("A",1);
        m2.put("B",2);
        System.out.println(m1.size());
        System.out.println(m1.containsKey("one"));
        System.out.println
                (m2.containsValue(1));//自动打包
        if(m1.containsKey("two")) {
            int i = (Integer) m1.get("two");//自动解包
            System.out.println(i);
        }
        Map m3 = new HashMap(m1);
        m3.putAll(m2);
        System.out.println(m3);
    }
}

4.如何选择数据结构?

衡量的标准:

Array : 读快改慢
Linked : 改快读慢
Hash : 两者之间

5.Generic (泛型)

使用泛型的原因:JDK1.4 以前的类型不明确

装入集合的类型都被当作 Object 对待,从而失去了自己的实际类型
从集合中取出时往往需要转型,效率低,容易产生错误

解决方法

在定义集合的时候同时定义集合中对象的类型,在运行时由程序自己来判断类型是否正确
可以在定义Collection时指定
可以在循环时用Iterator指定

泛型的优点

增强程序的可读性和稳定性。

实例1:


实例2:

import java.util.HashMap;
import java.util.Map;

public class Test07 {
    public static void main(String[] args) {
        //使用泛型
        Map<String,Integer> m1 = new HashMap<String,Integer>();
        m1.put("one",1);
        m1.put("two",2);
        m1.put("three",3);
        if(m1.containsKey("two")) {
            //因为使用了泛型,返回的对象一定的是 Integer 类型,所以在调用get方法时无需强转,
            int i = m1.get("two");
            System.out.println(i);
        }
    }
}

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值