Java SE 21th Collections Framework

来源:互联网 发布:建立寝室学生信息表sql 编辑:程序博客网 时间:2024/06/08 04:12

Java SE 21th day: Collections Framework

1、知识点

2、具体内容

2.1 类集框架(重点

       所谓的类集指的是一个动态的对象数组,因为对象数组本身存在了长度的问题,所以在最早的时候是使用了链表程序完成了动态对象数组的开发,但是这种开发是很困难的,尤其是对于那些使用者而言,所以在JDK 1.2之后专门引入了集合框架的概念,为用户提供了大量的数据结构的实现类。

       在这些集合框架之中,主要是使用接口定义操作的方法,核心的操作接口:Collection、List、Set、Map、Iterator、Enumeration。

       在JDK 1.5之后,为了防止出现安全隐患(ClassCastException,像最早的链表一样,都使用Object保存,那么就一定会有向下转型),所以对于所有的集合操作接口重新进行了定义,增加了泛型的声明。

2.2 单值保存的最大父接口:Collection(重点

       所谓单值保存,指的是每次只向集合之中保存一个对象的信息,这一点与最早编写的链表操作的功能是一样的,java.util.Collection定义了这些操作的最大父类标准,在此接口中一共定义了15个方法,核心方法如下:

No

方法名称

类型

描述

1

boolean add(E e)

普通

增加一个对象

2

void clear()

普通

清空数据

3

boolean contains(Object o)

普通

进行比较

4

Iterator<E> iterator()

普通

将所有的集合变为Iterator接口输出

5

boolean isEmpty()

普通

判断集合中是否保存了内容

6

boolean remove(Object o)

普通

从集合中删除一个元素

7

int size()

普通

返回集合中保存数据的个数

8

Object[] toArray()

普通

将集合变为对象数组后返回

9

<T> T[] toArray(T[] a)

普通

将集合变为对象数组后返回

       在Collection接口中定义的这些常用方法,实际上在之前编写链表程序的时候大部分都实现过了,所以对于集合操作而言,如果之前的图书大厦程序写熟练了,那么集合基本上就会了。

       但是,虽然Collection是集合操作的最大父接口,可是真正应用的并不是这个接口,而是这个接口的两个子接口:List、Set。

2.3 允许保存重复的接口:List(重点)

       List是Collection接口的子接口,此接口对Collection接口做了大量的扩充,但是这些扩充的方法之中,只有两个还可以稍微算是有用的方法:

No

方法名称

类型

描述

1

E get(int index)

普通

得到指定位置的内容

2

ListIterator<E> listIterator()

普通

为ListInterator接口实例化

       但是List依然是接口,那么按照面向对象的概念来讲,如果要想实例化接口对象,则一定要采用接口的子类,而在List接口中有两个常用的子类:ArrayList、Vector。

2.3.1 新的子类:ArrayList,90%使用率

       ArrayList类是List接口使用最多的一个子类,这个类的定义如下:

public class ArrayList<E>

extends AbstractList<E>

implements List<E>,RandomAccess, Cloneable, Serializable

       这个类是AbstractList抽象类的子类,而AbstractList类的定义结构如下:

public abstract class AbstractList<E>
extends AbstractCollection<E>
implements List<E>

       ArrayList重复实现List<E>接口只是为了突出显示,让人知道罢了。

下面就使用这个类进行List接口和Collection接口的操作演示。

范例:增加和输出数据

package framework;

import java.util.ArrayList;

import java.util.List;

 

public class CollectionDemo {

    public static void main(String[] args) {

        List<String> all = new ArrayList<String>();

        System.out.println("Are the collections NULL? " + all.isEmpty());

        all.add("Choi");

        all.add("Choi"); //重复数据

        all.add("Charlene");

        all.add("SoYeon");

        System.out.println("Are the collections NULL? " + all.isEmpty());

        System.out.println(all);

    }

}

Are the collections NULL? true

Are the collections NULL? false

[Choi, Choi, Charlene, SoYeon]

修改代码,使用循环输出每一个对象:

package framework;

import java.util.ArrayList;

import java.util.List;

 

public class CollectionDemo {

    public static void main(String[] args) {

        List<String> all = new ArrayList<String>();

        System.out.println("Are the collections NULL? " + all.isEmpty());

        all.add("Choi");

        all.add("Choi");  //重复数据

        all.add("Charlene");

        all.add("SoYeon");

        System.out.println("Are the collections NULL? " + all.isEmpty());          for (int i = 0; i <all.size(); i++) {

            System.out.println(all.get(i));

        }

    }

}

Are the collections NULL? true

Are the collections NULL? false

Choi

Choi

Charlene

SoYeon

这种集合操作与之前的链表开发是完全一样的。

       既然List接口是Collection接口的子类,那么对于ArrayList类而言,也肯定可以为Collection父接口进行对象的实例化操作,而这一操作的核心问题就在于Collection接口中并没有像List接口中定义的get()方法,所以只能全部的数据变为对象之后进行输出。

package framework;

 

import java.util.ArrayList;

import java.util.Collection;

import java.util.List;

 

public class CollectionDemo {

    public static void main(String[] args) {

        Collection<String> all = new ArrayList<String>();

        System.out.println("Are the collections NULL? " + all.isEmpty());

        all.add("Choi");

        all.add("Choi"); // 重复数据

        all.add("Charlene");

        all.add("SoYeon");

        System.out.println("Are the collections NULL? " + all.isEmpty());

        Object obj[] = all.toArray();// 变为对象数组

        for (int i = 0; i < obj.length; i++) {

            String str = (String) obj[i];//向下转型,存在安全隐患

            System.out.println(str);

        }

    }

}

Are the collections NULL? true

Are the collections NULL? false

Choi

Choi

Charlene

SoYeon

       为了避免这种安全隐患的操作,所以在JDK 1.5之后又引入了一个新的将数据变为对象数组的操作方法。

package framework;

 

import java.util.ArrayList;

import java.util.Collection;

import java.util.List;

 

public class CollectionDemo {

    public static void main(String[] args) {

        Collection<String> all = new ArrayList<String>();

        System.out.println("Are the collections NULL? " + all.isEmpty());

        all.add("Choi");

        all.add("Choi"); // 重复数据

        all.add("Charlene");

        all.add("SoYeon");

        System.out.println("Are the collections NULL? " + all.isEmpty());

        String str[] = all.toArray(new String[] {});//符合语法

        for (int i = 0; i < str.length; i++) {

            System.out.println(str[i]);

        }

    }

}

Are the collections NULL? true

Are the collections NULL? false

Choi

Choi

Charlene

SoYeon

       通过上面的操作可以发现,虽然此时可以成功的完成了问题,也可以成功的避免了安全隐患,可是从操作代码上而言,并不如List接口方便,所以这种操作在开发之中是不会出现的,而集合的输出操作也不是像之前使用的List中的size()和get()方法共同完成的,以后会有其他的标准输出形式。

2.3.2 旧的子类:Vector

       ArrayList是新的子类,而Vector是一个旧的子类,是在JDK 1.0的时候就已经存在了,但是观察一下Vector类的定义结构:

public class Vector<E>
extends AbstractList<E>
implements List<E>, RandomAccess, Cloneable, Serializable

       发现Vector的定义结构与ArrayList基本上是一样的,而且所有的操作肯定对于子类用户只是关注构造方法,所有的方法应该以父接口为标准。

package framework;

 

import java.util.Vector;

 

public class CollectionDemo {

    public static void main(String[] args) {

        Vector<String> all = new Vector<String>();

        System.out.println("If the collections are NULL? " + all.isEmpty());

        all.add("Choi");

        all.add("Choi"); // 重复数据

        all.add("Charlene");

        all.add("SoYeon");

        System.out.println("If the collections are NULL? " + all.isEmpty());

        System.out.println(all);

    }

}

If the collections are NULL? true

If the collections are NULL? false

[Choi, Choi, Charlene, SoYeon]

       通过代码的编写与运行根本就看不出ArrayList和Vector类的两者的区别,而这两者本身也的确有着很大的区别,但是从代码的编写上看不出。

2.3.3 ArrayList和Vector的区别(面试题)

       ArrayList和Vector同时作为List接口的子类,肯定两者有两者的使用特点,那么下面通过一张表格进行说明。

No

区别点

ArrayList

Vector

1

推出时间

JDK1.2时推出,属于新的类

JDK1.0时推出,属于旧的类

2

性能

采用异步处理方式,性能较高

采用同步处理方式,性能相对较低

3

线程安全性

非线程安全的操作

线程安全的操作

4

输出

Iterator、ListIterator、foreach

Iterator、ListIterator、foreach、Enumeration

       所以从两者的使用上而言,开发之中主要使用ArrayList子类。

2.4 不允许保存重复数据的子接口:Set(重点)

       Set接口也是Collection的一个常用子接口,与List子接口不同的是,Set集合之中不允许保存任何重复的内容,而在Set接口中也有两个子接口:HashSet、TreeSet。

       Set接口并没有将Collection接口进行扩充,只是与Collection保持同样的功能。

2.4.1 散列存放的子类:HashSet

       所谓的散列实际上就是指无序。

package framework;

 

import java.util.HashSet;

import java.util.Set;

 

public class CollectionDemo {

    public static void main(String[] args) {

        Set<String> all =new HashSet<String>();

        all.add("Choi");

        all.add("Choi"); // 重复数据

        all.add("Charlene");

        all.add("SoYeon");

        System.out.println(all);

    }

}

[SoYeon, Choi, Charlene]

       现在通过程序运行之后,可以发现,集合之中没有任何重复的数据存在,而且与List接口那样的插入顺序及保存顺序相比,是没有任何排列顺序的。

2.4.2 排序存放的子类:TreeSet

       TreeSet肯定是树排序,其原理就非常类似于之前讲解的二叉树程序。

package framework;

 

import java.util.Set;

import java.util.TreeSet;

 

public class CollectionDemo {

    public static void main(String[] args) {

        Set<String> all = newTreeSet<String>();

        all.add("Therese");

        all.add("Choi"); // 重复数据

        all.add("Charlene");

        all.add("SoYeon");

        all.add("JiYeon");

        System.out.println(all);

    }

}

[Charlene, Choi, JiYeon, SoYeon, Therese]

       TreeSet保存的内容的确是排序了,所以HashSet和TreeSet的区别也比较明确了。

2.4.3 关于排序的说明

       既然TreeSet子类可以进行数据的排序,那么就意味着可以对任意的类对象排序,但是如果现在要想保存的是用户自定义的对象,则这个对象所在的类必须满足如下两点:

n  对象所在的类必须实现Comparable接口;

n  在TreeSet子类之中,如果要进行排序的话,则应该将一个类的所有属性进行比较,只有完全一样之后才会认为是同一个对象,而如果只比较了部分属性,那么结果就不准确了。

package framework;

 

import java.util.Set;

import java.util.TreeSet;

 

class Vehicleimplements Comparable<Vehicle> {

    private Stringname;

    private int speed;

 

    public Vehicle(String name,int speed) {

        this.name = name;

        this.speed = speed;

    }

 

    @Override

    public String toString() {

        return"交通工具的名字:" +this.name +",速度:" +this.speed +"\n";

    }

 

    @Override

    public int compareTo(Vehicle o) {

        if (this.speed > o.speed) {

            return 1;

        } else if (this.speed < o.speed) {

            return -1;

        //这里不需要设置“this.speed=o.speedreturn 0”,因为Set接口不允许重复值

        } else {

            returnthis.name.compareTo(o.name); //调用String类的compareTo()

        }

    }

}

 

public class CollectionDemo {

    public static void main(String[] args) {

        Set<Vehicle> all = new TreeSet<Vehicle>();

        all.add(new Vehicle("Ferrari", 450));

        all.add(new Vehicle("Porsche", 560));

        all.add(new Vehicle("Ferrari", 450));//重复数据

        all.add(new Vehicle("Lamborghini", 620));

        all.add(new Vehicle("Chevrolet", 620));

        all.add(new Vehicle("Benz", 380));

        System.out.println(all);

    }

}

[交通工具的名字:Benz,速度:380

, 交通工具的名字:Ferrari,速度:450

, 交通工具的名字:Porsche,速度:560

, 交通工具的名字:Chevrolet,速度:620

, 交通工具的名字:Lamborghini,速度:620

]

       只要是多个对象排序,都要使用Comparable接口,与之前的所有操作都完全一样,但是本程序同时也完成了相同对象的过滤,可是这种相同对象的判断,并不是标准的做法。

       我们知道,TreeSet和HashSet都属于Set接口,如果TreeSet现在可以实现对象的去重功能了,那么把程序中的TreeSet改为HashSet也应该可以实现对象的去重功能,但是经过试验,这是无法实现的,设置连Set接口中的其他方法(如remove()),HashSet类此时都无法实现。

2.4.4 关于重复元素的说明

       首先回顾一下讲解自定义链表的时候,删除和查找数据的时候依靠的是equals()方法,但是对于Set集合而言,如果要想进行重复元素的判断,则必须依靠两种方法:

对象比较:public boolean equals(Object obj);

对象编码:public int hashCode();

在进行重复元素判断,查找(contains())、删除(remove())等操作之前,会首先利用hashCode()判断对象的编码,之后如果编码相同,再进行各个属性的比较,但是对于这种编码应该是有一个自己的计算公式。

package framework;

 

import java.util.HashSet;

import java.util.Set;

import java.util.TreeSet;

 

class Vehicle { //不需要实现Comparable接口

    private Stringname;

    private int speed;

 

    public Vehicle(String name,int speed) {

        this.name = name;

        this.speed = speed;

    }

 

    @Override

    public String toString() {

        return"交通工具的名字:" +this.name +",速度:" +this.speed +"\n";

    }

 

    @Override

    public int hashCode() {

        final int prime = 31;

        int result = 1;

        result = prime * result + ((name ==null) ? 0 : name.hashCode());

        result = prime * result + speed;

        return result;

    }

 

    @Override

    public boolean equals(Object obj) {

        if (this == obj)

            return true;

        if (obj ==null)

            return false;

        if (getClass() != obj.getClass())

            return false;

        Vehicle other = (Vehicle) obj;

        if (name ==null) {

            if (other.name !=null)

                returnfalse;

        } else if (!name.equals(other.name))

            return false;

        if (speed != other.speed)

            return false;

        return true;

    }

}

 

public class CollectionDemo {

    public static void main(String[] args) {

        Set<Vehicle> all = newHashSet<Vehicle>();

        all.add(new Vehicle("Ferrari", 450));

        all.add(new Vehicle("Porsche", 560));

        all.add(new Vehicle("Ferrari", 450));// 重复数据

        all.add(new Vehicle("Lamborghini", 620));

        all.add(new Vehicle("Chevrolet", 620));

        all.add(new Vehicle("Benz", 380));

        all.remove(new Vehicle("Lamborghini", 620));

        System.out.println(all);

    }

}

[交通工具的名字:Porsche,速度:560

, 交通工具的名字:Benz,速度:380

, 交通工具的名字:Ferrari,速度:450

, 交通工具的名字:Chevrolet,速度:620

]

     这也就是在之前所强调的,一个完整的简单Java类应该覆写Object类中的三个方法:toString()、equals()、hashCode(),在任何的系统之中,如果要查找对象、删除对象必须使用hashCode()和equals()。而上面例子TreeSet比较特殊一些,使用Comparable接口就可以完成了。

面试题:请解释一下Object类及各个主要方法:

n  Object是所有类的父类,可以接收所有的应用数据类型;

n  Object类的主要方法:

取得对象编码:public int hashCode();

对象比较:public boolean equals(Object other);

对象输出:public String toString();

对象克隆:public Object clone() throws CloneNotSupportedException;

对象收尾工作:public void finalize() throws Throwable;

取得Class对象:public Class<?>getClass();

线程等待:public void wait() throws InterruptedException;

唤醒一个等待线程:public void notify();

唤醒全部等待线程:public void notifyAll();

2.5 集合的输出(重点

     之前的所有操作只是完成了集合数据的增加功能,而如果现在要想进行输出,有四种输出方法:Iterator、ListIterator、Enumeration、foreach。

2.5.1 迭代输出:Iterator(核心中的核心

       Iterator接口是专门为输出准备的一个操作接口,在此接口中定义了两个主要的方法:

n  判断是否还有数据:boolean hasNext();

n  取出数据:E next();

如果要想取得Iterator接口的实例对象必须依靠Collection接口的iterator()方法(Iterator<E>iterator()),既然此方法定义在了Collection接口之中,那么List和Set子接口也肯定都有。

package framework;

 

import java.util.ArrayList;

import java.util.Iterator;

import java.util.List;

 

public class CollectionDemo {

    public static void main(String[] args) {

        List<String> all = new ArrayList<String>();

        all.add("Charlene");

        all.add("Theresa");

        all.add("Cyndi");

        Iterator<String> iter = all.iterator();

        while (iter.hasNext()) {

            System.out.println(iter.next());

        }

    }

}

Charlene

Theresa

Cyndi

       不管何种情况下,一定要记住,只要是对于集合的输出操作永远都使用Iterator接口完成。

2.5.2 双向迭代:ListIterator(了解)

       Iterator只支持由前向后的输出,如果现在想要完成双向的输出就必须使用Iterator的子接口——ListIterator完成,可是要想取得本接口的实例化对象就不能再利用Collection接口了,在List子接口中存在这样的方法:ListIterator<E>listIterator()。

package framework;

 

import java.util.ArrayList;

import java.util.List;

import java.util.ListIterator;

 

public class CollectionDemo {

    public static void main(String[] args) {

        List<String> all = new ArrayList<String>();

        all.add("Charlene");

        all.add("Theresa");

        all.add("Cyndi");

        ListIterator<String> iter = all.listIterator();

        System.out.print("由前往后输出");

        while (iter.hasNext()) {

            System.out.print(iter.next() +"");

        }

        System.out.print("\n由后往前输出:");

        while (iter.hasPrevious()) {

            System.out.print(iter.previous() +"");

        }

    }

}

由前往后输出Charlene、Theresa、Cyndi、

由后往前输出:Cyndi、Theresa、Charlene、

       但是在进行由后向前输出操作之前,一定要先进行由前向后的输出,这种输出一般没有参考性,知道就行了。

2.5.3 废弃的输出:Enumeration(重点

       Enumeration最早的时候被人称为枚举输出,实际上也是最早JDK所提供的一个输出接口,但是这个接口已经被废除了,可是有一些古老的操作方法还是要使用Enumeration,这个接口在JDK 1.5之后也增加了泛型,里面有两个方法:

n  判断是否有下一个元素:boolean hasMoreElements();

n  取出数据:E nextElement();

可是如果想要为这个接口实例化也不是Collection、List、Set接口中所规定的方法,而是使用了Vector子类中的一个方法:public Enumeration<E>elements()。

package framework;

 

import java.util.Enumeration;

import java.util.Vector;

 

public class CollectionDemo {

    public static void main(String[] args) {

        Vector<String> all =new Vector<String>();

        all.add("Charlene");

        all.add("Theresa");

        all.add("Cyndi");

        Enumeration<String> enu = all.elements();

        while (enu.hasMoreElements()) {

            System.out.print(enu.nextElement() +"");

        }

    }

}

       从功能上讲,Enumeration的输出和Iterator使用形式很相似,但是却不如Iterator使用广泛,Enumeration只在必须使用的地方才使用,而集合输出的标准操作还是使用Iterator接口。

2.5.4 JDK 1.5的新支持——foreach(了解)

       在之前讲解JDK 1.5新特性的时候已经讲解过了foreach的操作,实际上就是一个增强的for循环,这种循环除了可以进行数组的输出之外,也可以进行集合的输出操作。

package framework;

 

import java.util.ArrayList;

import java.util.List;

 

public class CollectionDemo {

    public static void main(String[] args) {

        List<String> all = new ArrayList<String>();

        all.add("Charlene");

        all.add("Theresa");

        all.add("Cyndi");

        for (String str : all) {

            System.out.print(str +"");

        }

    }

}

Charlene、Theresa、Cyndi、

       这种语法虽然简洁,但是别使,标准的开发就是Iterator。

2.6 保存二元偶对象:Map(重点

       所谓的二元偶对象就是指的是同时保存一对对象,例如:结婚登记肯定不能少于两个人,因为要一起注册,一起保存信息,所以所谓的二元偶对象指的就是两个相关的对象,而这两个相关对象也存在着:key = value的形式。

       例如,如果说现在要想保存一个电话本的信息:

n  张三(key),123456(value);

n  李四(key),789012(value);

如果现在要查找张三的电话,肯定是先找到张三对应的key,之后再找到对应的电话:123456(value),而这种功能就使用Map接口完成,本接口所定义的方法如下:

No

方法名称

类型

描述

1

V put(K key, V value)

普通

向集合中保存对象

2

V get(Object key)

普通

根据指定的key从集合中取得对应的value

3

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

普通

将所有的集合变为Set集合

4

Set<K> keySet()

普通

取得所有的KEY,按照Set集合返回

5

int size()

普通

元素个数

       而在开发之中使用最多的两个Map接口的子类就是:HashMap、Hashtable。

2.6.1 新的子类:HashMap

       HashMap是Map接口中使用最多的一个子类,以HashMap为例说明Map接口的基本功能。

package framework;

 

import java.util.HashMap;

import java.util.Map;

 

public class CollectionDemo {

    public static void main(String[] args) {

        Map<Integer, String> map = newHashMap<Integer, String>();

        map.put(1, "Charlene");

        map.put(null,null);//设置null

        map.put(1, "Yumiko");// key重复,用新的内容覆盖旧的内容

        map.put(2, "Selina");

        map.put(3, "Hebe");

        System.out.println(map);

        System.out.println(map.get(1));

        System.out.println(map.get(10));//不存在

    }

}

{null=null, 1=Yumiko, 2=Selina, 3=Hebe}

Yumiko

null

       可以发现HashMap的操作过程与之前的List集合的功能很相似,唯一不同的是现在保存的是一对数据。

范例:取得全部的key

package framework;

 

import java.util.HashMap;

import java.util.Iterator;

import java.util.Map;

import java.util.Set;

 

public class CollectionDemo {

    public static void main(String[] args) {

        Map<Integer, String> map = new HashMap<Integer, String>();

        map.put(1, "Charlene");

        map.put(null,null);//设置null

        map.put(1, "Yumiko");// key重复,用新的内容覆盖旧的内容

        map.put(2, "Selina");

        map.put(3, "Hebe");

        Set<Integer> set = map.keySet();// 取得全部的key

        Iterator<Integer> iter = set.iterator();

        while (iter.hasNext()) {

            Integer key = iter.next();

            System.out.println(key +"→" + map.get(key));

        }

    }

}

null→null

1→Yumiko

2→Selina

3→Hebe

       一定要注意,以上虽然输出了Map中的全部数据,但是标准的Map输出操作并不会使用此类方法。

2.6.2 旧的子类:Hashtable

       在JDK 1.0的时候实际上也推出过一个与Map接口类似功能的类——Hashtable,此类现在在JDK 1.2之后也变为了Map接口的子类,所以从使用上而言与HashMap没太大区别。

package framework;

 

import java.util.Hashtable;

import java.util.Iterator;

import java.util.Map;

import java.util.Set;

 

public class CollectionDemo {

    public static void main(String[] args) {

        Map<Integer, String> map = newHashtable<Integer, String>();

        map.put(1, "Charlene");

        map.put(1, "Yumiko");// key重复,用新的内容覆盖旧的内容

        map.put(2, "Selina");

        map.put(3, "Hebe");

        Set<Integer> set = map.keySet(); // 取得全部的key

        Iterator<Integer> iter = set.iterator();

        while (iter.hasNext()) {

            Integer key = iter.next();

            System.out.println(key +"→" + map.get(key));

        }

    }

}

3→Hebe

2→Selina

1→Yumiko

       与HashMap的不同之处从表面上讲只是不能保存null内容。

2.6.3  HashMap和Hashtable的区别(面试题)

       HashMap和Hashtable同时作为Map接口的子类,肯定两者有两者的使用特点,那么下面通过一张表格进行说明。

No

区别点

HashMap

Hashtable

1

推出时间

JDK1.2时推出,属于新的类

JDK1.0时推出,属于旧的类

2

性能

采用异步处理方式,性能较高

采用同步处理方式,性能相对较低

3

线程安全性

非线程安全的操作

线程安全的操作

4

设置null

允许设置

不允许设置,否则出现NullPointerException

       所以从两者的使用上而言,开发之中主要使用HashMap子类。

2.6.4 使用Iterator输出Map集合(核心

       对于集合而言,所有的操作标准做法是使用Iterator接口输出,但是Map集合不像Collection集合那样,直接提供了iterator()方法,所以如果想使用Iterator接口输出Map集合数据的话,则首先必须明白Collection和Map保存数据的特点。

       Map.Entry接口的定义如下:

public static interfaceMap.Entry<K,V>

       既然接口的定义上使用了“static”关键字,那么这个Map.Entry接口就属于Map的一个内部接口,而且这个内部接口使用了static定义,表示是一个外部接口,而在这个接口中有两个主要方法:

取得包装的key:K getKey();

取得包装的value:V getValue();

       于是,下面就可以按照如下的固定步骤使用Iterator完成Map接口数据的输出:

1.      使用Map接口中的entrySet()方法将全部数据变为Set集合;

2.      使用Set接口中的iterator()方法取得Iterator接口的实例化对象,并进行迭代输出;

3.      通过Iteratro接口的next()方法可以取得一个Map.Entry对象,以进行key和value的分离。

范例:使用Iterator输出Map集合。

package framework;

 

import java.util.Hashtable;

import java.util.Iterator;

import java.util.Map;

import java.util.Set;

 

public class CollectionDemo {

    public static void main(String[] args) {

        Map<Integer, String> map = new Hashtable<Integer, String>();

        map.put(1, "Charlene");

        map.put(2, "Yumiko");

        map.put(3, "Selina");

        map.put(4, "Hebe");

        Set<Map.Entry<Integer, String>> set = map.entrySet();

        Iterator<Map.Entry<Integer, String>> iter = set.iterator();

        while (iter.hasNext()) {

            Map.Entry<Integer, String> me = iter.next();

            System.out.println(me.getKey() +" → " + me.getValue());

        }

    }

}

4 → Hebe

3 → Selina

2 → Yumiko

1 → Charlene

       本程序作为以后开发的绝对核心程序,一定要充分的理解。

2.6.5 关于Map中key的说明

       通过Map接口的定义可以发现,在Map集合之中,key和value的类型都可以通过外部指定,所以用户也可以使用一个自己定义的类完成,但是这个类必须满足以下要求:

很明显通过Map的get()方法是一个查找过程,既然是查找肯定要存在判断和比较,所以必须覆写hashCode()方法和equals()方法。

范例:不满足以上条件的开发

package framework;

 

import java.util.HashMap;

import java.util.Map;

 

class Vehicle {

    private Stringname;

 

    public Vehicle(String name) {

        this.name = name;

    }

 

    @Override

    public String toString() {

        return"车的名字:" +this.name;

    }

}

 

public class CollectionDemo {

    public static void main(String[] args) {

        Map<String, Vehicle> map = new HashMap<String, Vehicle>();

        map.put(new String("PS"),new Vehicle("Porsche"));

        System.out.println(map.get(new String("PS")));

    }

}

车的名字:Porsche

       现在功能是完成了,但如果反过来呢?即,通过Vehicle类来查找String类数据。修改后的main类:

public class CollectionDemo {

    public static void main(String[] args) {

        Map<Vehicle, String> map =new HashMap<Vehicle, String>();

        map.put(new Vehicle("Porsche"),new String("PS"));

        System.out.println(map.get(new Vehicle("Porsche")));

    }

}

null

       可以发现,此时功能并不能在意想中实现,那按照条件更新程序,即覆写hashCode()和equals()方法,其他不变:

package framework;

 

import java.util.HashMap;

import java.util.Map;

 

class Vehicle {

    private Stringname;

 

    public Vehicle(String name) {

        this.name = name;

    }

 

    @Override

    public String toString() {

        return"车的名字:" +this.name;

    }

 

    @Override

    public int hashCode() {

        final int prime = 31;

        int result = 1;

        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;

        Vehicle other = (Vehicle) obj;

        if (name ==null) {

            if (other.name !=null)

                returnfalse;

        } else if (!name.equals(other.name))

            return false;

        return true;

    }

}

 

public class CollectionDemo {

    public static void main(String[] args) {

        Map<Vehicle, String> map = new HashMap<Vehicle, String>();

        map.put(new Vehicle("Porsche"),new String("PS"));

        System.out.println(map.get(new Vehicle("Porsche")));

    }

}

PS

以后在进行代码开发的时候,所有的key的类型全部都设置为String是最合适的。

另外需要提醒的是:Collection接口的数据主要是作为保存和全部输出操作的,而Map接口的作用除了保存之外,主要的功能是进行数据的查找。

2.7 集合工具类:Collections(了解)

       在java.util包中存在一个Collections类,但是此类定义上与Collection接口没有任何关系,但是这个类却提供了许多与集合有关的操作。

package framework;

 

import java.util.ArrayList;

import java.util.Collections;

import java.util.List;

 

public class CollectionsDemo {

    public static void main(String[] args) {

        List<String> all = new ArrayList<String>();

        Collections.addAll(all, "A", "B", "C","D", "E", "F");

        Collections.reverse(all);//反转

        System.out.println(all);

    }

}

[F, E, D, C, B, A]

面试题:请解释Collection和Collections的关系?

       两者之间在定义上没有直接的关系,Collection是单值集合的操作最大父接口,而Collections只是一个集合的工具操作类。

2.8 栈操作(理解)

       栈是一种先进后出的数据结构实现,例如:网页上有后退按钮,编辑器上也有撤销操作,而在Java中使用Stack类进行栈的操作,此类是Vector的子类,这个类主要使用两个方法:

入栈操作:public E push(E item)

出栈操作:public E pop()

范例:实现栈操作

package framework;

 

import java.util.ArrayList;

import java.util.Collections;

import java.util.List;

 

publicclass CollectionsDemo {

    publicstatic void main(String[] args) {

        List<String> all = new ArrayList<String>();

        Collections.addAll(all, "A", "B", "C", "D", "E", "F");

        Collections.reverse(all);//反转

        System.out.println(all);

    }

}有问题!!!

D

C

B

A

Thread [main] (Suspended (exception EmptyStackException))  

    Stack<E>.peek() line: 85   

    Stack<E>.pop() line: 67

    CollectionDemo.main(String[]) line: 16 

       栈这种功能类一般使用不到,这个的使用还是看项目要求。

2.9 属性操作(重点)

       在Windows中存在属性文件,例如Windows的启动配置文件是boot.ini文件,这种属性的信息就可以通过Properties类完成,这个类的定义如下:

public class Properties
extends Hashtable<Object,Object>

       此类是Hashtable的子类,可是这个时候的泛型没用,所以都将其设置为Object,因为所有的属性内容的类型都是String型的数据,而在这个类中有如下几个主要方法;

No

方法名称

类型

描述

1

public String getProperty(String key)

普通

根据指定的key取得返回属性,如果没有返回null

2

public String getProperty(String key, String defaultValue)

普通

根据指定的key取得返回属性,如果没有返回默认值

3

public Object setProperty(String key, String value)

普通

设置属性

4

public void store(OutputStream out, String comments) throws IOException

普通

使用输出流输出属性内容

5

public void load(InputStream inStream) throws IOException

普通

使用输入流读取属性内容

范例:属性的设置和取得

package framework;

 

import java.util.Properties;

 

public class PropertyDemo {

    public static void main(String[] args) {

        Properties pro = new Properties();

        pro.setProperty("CC","Charlene_Choi");

        pro.setProperty("TF", "Theresa_Fu");

        pro.setProperty("SY", "So_Yeon");

        pro.setProperty("CW", "Cyndi_Wang");

        System.out.println(pro.getProperty("TF"));

        System.out.println(pro.getProperty("CC"));

        System.out.println(pro.getProperty("CA"));

        System.out.println(pro.getProperty("CB","DefaultNot Found!"));

    }

}

Theresa_Fu

Charlene_Choi

null

Default:Not Found!

       另外,所有的属性可以输出到属性文件之中,所有的属性文件指的就是后缀是“*.properties”的文件。

package framework;

 

import java.io.File;

import java.io.FileOutputStream;

import java.util.Properties;

 

public class PropertyDemo {

    public static void main(String[] args)throws Exception {

        Properties pro = new Properties();

        pro.setProperty("CC", "Charlene_Choi");

        pro.setProperty("TF", "Theresa_Fu");

        pro.setProperty("SY", "So_Yeon");

        pro.setProperty("CW", "Cyndi_Wang");

        pro.setProperty("JY", "朴智妍");// 中文

        File file = new File("d:" + File.separator +"stars.properties");

        pro.store(new FileOutputStream(file),"Stars Info");

        /*

         * 当然,我们也可以使用打印流输出,等价:

         * PrintStream ps = new PrintStream(file);

         * pro.store(ps, "StarsInfo");

         */

    }

}

       输出结果:

       可以看到,对于中文的存储是使用UNICODE编码存储的。

范例:通过制定的输入流读取文件内容

package framework;

 

import java.io.File;

import java.io.FileInputStream;

import java.util.Properties;

 

public class PropertyDemo {

    public static void main(String[] args)throws Exception {

        Properties pro = new Properties();

        File file = new File("d:" + File.separator +"stars.properties");

        pro.load(new FileInputStream(file));

        System.out.println(pro.getProperty("CC"));

        System.out.println(pro.getProperty("JY"));

        System.out.println(pro.getProperty("ABC"));

 

    }

}

Charlene_Choi

朴智妍

null

       当然,现在用户也可以直接操作属性文件以增加新的内容,但是如果有中文,则必须转码,使用JDK所提供的“native2ascii.exe”操作命令完成。如下:

       属性文件以后在开发之中,肯定是要经常使用到的,如果要保存的是中文,则必须转码,等学到Struts的时候就能明白此问题发生所在了。

3、总结

1、一定要记清楚各个操作接口的特点及常用子类;

2、Iterator永远是作为集合的标准输出;

3、Object类中的equal()、toString()的核心操作。

4、Java SE核心知识点

       在Java SE之中所讲解的全部内容目的:不是做Java SE开发的,因为这种开发是需要进行图形界面编写的,但是图形界面在Java中基本不用了,所以Java

1.        图书大厦:作为接口程序的总结点;

2.        异常处理的标准格式:try…catch…finally、throws、throw、异常的处理流程;

3.        JDK 1.5之后的一些新技术,能看懂就行了;

4.        设计模式:Singleton、Factory、Proxy;

5.        多线程的两种实现方式以及区别:→ Android

6.        String、基本数据类型(包装类)、Date之间(SimpleDateFormat)互相转换;

7.        正则表达式,数据验证肯定使用正则:正则符号、String类的支持;

8.        比较器的操作(Comparable)只是作为Java SE讲解使用的,如果以后不会用TreeSet比较器则没用;

9.        如果现在传入了完整的“包.类”、属性或方法名称的时候一定要记住是反射操作;

10.    文件拷贝程序的实现,必须灵活编写; →Struts服务

11.    PrintStream、Scanner、对象序列化;

12.    JDBC中PrepareStatement、Connection、DriverManager、ResultSet的使用、数据的CRUD、统计、分页(ROWNUM);

13.    集合的基本操作,现在主要以:List、Map、Iterator为主,必须清楚各个接口和各个子类的继承关系、主要的使用特点;

14.    程序和现实生活的关系,引用表示;

15.    简单Java类的开发原则以及与表的关系。

网页制作:HTML显示操作、表格的操作、表单的编写,不用开发工具,自己手工写。

WEB:HTML + JavaScript + JSP + Servlet + Tomcat +EL + JSTL + Java SE核心

0 0
原创粉丝点击