java 集合与泛型

java 集合与泛型
java 集合与泛型

Collection 接口及实现类

Java 语言的Collection 接口及实现类是在java.util 包中定义的,其中定义了多个接口和类,它们统称为Java 集合框架(Java Collection Framework )。

Java 集合框架由两种类型构成,一个是Collection ,另一个是Map 。Collection 对象用于存放一组对象,Map 对象用于存放一组关键字/值的对象。Collection 和Map 是最基本的接口,它们又有子接口,这些接口的层次关系如图1所示。

图1 Java 集合框架的接口继承关系

1.1 Collection 接口及操作

Collection 接口是所有集合类型的根接口,它有三个子接口:Set 接口、List 接口和Queue 接口。

Collection 接口的定义如下:

public interface Collection extends Iterable {

// 基本操作

int size();

boolean isEmpty();

boolean contains(Object element);

boolean add(E element);

boolean remove(Object element);

Iterator iterator();

// 批量操作

boolean containsAll(Collection c);

boolean addAll(Collection c);

boolean removeAll(Collection c);

boolean retainAll(Collection c);

void clear();

// 数组操作

Object[] toArray();

T[] toArray(T[] a);

}

说明 从JDK 1.5开始,Java 开始支持范型(generics )的概念。在Collection 接口

的声明中,就表示该接口支持范型,它指的是集合中的对象类型。这样,当我们声明一个Collection 实例时,应该使用这种方式指明包含在集合中的对象类型。这可以使编译器在编译时检查存入集合的对象类型是否正确,从而减少运行时错误。

Collection 接口中定义的方法主要包括三类:集合操作、批量操作和数组操作。

1. 基本操作

实现基本操作的方法有size(),它返回集合中元素的个数;isEmpty()方法返回集合是否为空;contains()方法返回集合中是否包含指定的对象;add()方法和remove()方法实现向集合中添加元素和删除元素的功能;iterator()方法用来返回Iterator对象。

通过基本操作可以检索集合中的元素。检索集合中的元素有两种方法:使用增强的for 循环和使用Iterator迭代对象。

(1)使用增强的for循环

使用增强的for循环不但可以遍历数组的每个元素,还可以遍历集合的每个元素。下面的代码打印集合的每个元素:

for (Object o : collection)

System.out.println(o);

(2)使用迭代器

迭代器是一个可以遍历集合中每个元素的对象。通过调用集合对象的iterator()方法可以得到Iterator对象,再调用Iterator对象的方法就可以遍历集合中的每个元素。

Iterator接口的定义如下:

public interface Iterator {

boolean hasNext();

E next();

void remove();

}

该接口的hasNext()方法返回迭代器中是否还有对象;next()方法返回迭代器中下一个对象;remove()方法删除迭代器中的对象,该方法同时从集合中删除对象。

假设c为一个Collection对象,要访问c中的每个元素,可以按下列方法实现:

Iterator it = c.iterator();

while (it.hasNext()){

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

}

2. 批量操作

实现批量操作的方法有containsAll(),它返回集合中是否包含指定集合中的所有元素;addAll()方法和removeAll()方法将指定集合中的元素添加到集合中和从集合中删除指定的集合元素;retainAll()方法删除集合中不属于指定集合中的元素;clear()方法删除集合中所有元素。

3. 数组操作

toArray()方法可以实现集合与数组的转换。该方法可以实现将集合元素转换成数组元素。无参数的toArray()方法实现将集合转换成Object类型的数组。有参数的toArray()方法将集合转换成指定类型的对象数组。

例如,假设c是一个Collection对象,下面的代码将c中的对象转换成一个新的Object 数组,数组的长度与集合c中的元素个数相同。

Object[] a = c.toArray();

假设我们知道c中只包含String对象,可以使用下面代码将其转换成String数组,它的长度与c中元素个数相同:

String[] a = c.toArray(new String[0]);

1.2 Set接口及实现类

Set接口是Collection的子接口,Set接口对象类似于数学上的集合概念,其中不允许有

重复的元素。Set接口没有定义新的方法,只包含从Collection接口继承的方法。Set接口有几个常用的实现类,它们的层次关系如图2所示:

图2 Set接口及实现类的层次结构

Set接口的常用的实现类有:HashSet类、TreeSet类和LinkedHashSet类。

1. HashSet类与LinkedHashSet类

HashSet类是抽象类AbstractSet的子类,它实现了Set接口,HashSet使用哈希方法存储元素,具有最好的性能,但元素没有顺序。

HashSet类的构造方法有:

?HashSet() 创建一个空的哈希集合,装填因子(load factor)是0.75。

?HashSet(Collection c) 用指定的集合c的元素创建一个哈希集合。

?HashSet(int initialCapacity) 创建一个哈希集合,并指定的集合初始容量。

?HashSet(int initialCapacity, float loadFactor) 创建一个哈希集合,并指定的集合初始容量和装填因子。

LinkedHashSet类是HashSet类的子类。该实现与HashSet的不同之处是它对所有元素维护一个双向链表,该链表定义了元素的迭代顺序,这个顺序是元素插入集合的顺序。

下面的程序从命令行输入若干英文单词,输出每个重复的单词,不同单词的个数及消除重复单词后的列表。

程序FindDups.java

import java.util.*;

public class FindDups {

public static void main(String args[]) {

Set hs = new HashSet();

for (String a : args)

if (!hs.add(a))

System.out.println("Duplicate: " + a);

System.out.println(hs.size()+" distinct words: "+hs);

}

}

_____________________________________________________________________________▃

如果使用下面命令运行程序:

C:\>java FindDups i came i saw i left

会得到下面结果:

Duplicate: i

Duplicate: i

4 distinct words: [i, left, saw, came]

由于上面程序中使用的实现类为HashSet,它并不保证集合中元素的顺序。

注意该程序对集合的声明中使用了泛型的方法,即加上了,如果去掉

,该程序在JDK 5.0下也能成功编译,但会显示下面的提示:

Note: D:\java\FindDups.java uses unchecked or unsafe operations.

Note: Recompile with -Xlint:unchecked for details.

该提示说明程序中使用了未检查的或不安全的操作,如果要知道详细细节,可以

带-Xlint:unchecked参数重新编译该程序。

2. 用集合对象实现集合运算

对于Set对象的批量操作方法,可以实现标准集合代数运算。假设s1和s2是Set对象,下面的操作可实现相关的集合运算。

s1.containAll(s2):如果s2是s1的子集,该方法返回true;

s1.addAll(s2):实现集合s1与s2的并运算;

s1.retainAll(s2):实现集合s1与s2的交运算;

s1.removeAll(s2):实现集合s1与s2的差运算。

为了计算两个集合的并、交、差运算而又不破坏原来的集合,可以通过下面代码实现:Set union = new HashSet(s1);

union.addAll(s2);

Set intersection = new HashSet(s1);

intersection.retainAll(s2);

Set difference = new HashSet(s1);

difference.removeAll(s2);

下面的程序实现了两个集合的并、交、差运算:

程序SetDemo.java

import java.util.*;

public class SetDemo {

public static void main(String args[]) {

Set s1 = new HashSet();

Set s2 = new HashSet();

s1.add(new String("one"));

s1.add(new String("two"));

s1.add(new String("three"));

s2.add(new String("two"));

s2.add(new String("three"));

s2.add(new String("four"));

Set union = new HashSet(s1);

union.addAll(s2);

Set intersection = new HashSet(s1);

intersection.retainAll(s2);

Set difference = new HashSet(s1);

difference.removeAll(s2);

System.out.println(union);

System.out.println(intersection);

System.out.println(difference);

}

}

_____________________________________________________________________________▃程序输出结果为:

[one,two,foue,three]

[two,three]

[one]

3. SortedSet接口与TreeSet类

SortedSet接口对象是有序对象的集合,其中的元素排序规则按照元素的自然顺序排列。为了能够使元素排序,要求插入到SortedSet对象中的元素必须是相互可以比较的。关于对象的顺序在下节讨论。

SortedSet接口中定义了下面几个方法:

? E first() 返回有序集合中的第一个元素。

? E last() 返回有序集合中最后一个元素。

?SortedSet subSet(E fromElement, E toElement) 返回有序集合中的一个子有序集合,它的元素从fromElement开始到toElement结束(不包括最后元素)。

?SortedSet headSet(E toElement) 返回有序集合中小于指定元素toElement的一个子有序集合。

?SortedSet tailSet(E fromElement) 返回有序集合中大于等于fromElement元素的子有序集合。

?Comparator comparator() 返回与该有序集合相关的比较器,如果集合使用自然顺序则返回null。

TreeSet是SortedSet接口的实现类,它使用红黑树为存储元素排序,它基于元素的值对元素排序,它的操作要比HashSet慢。

TreeSet类的构造方法有:

?TreeSet() 创建一个空的树集合。

?TreeSet(Collection c) 用指定集合c中的元素创建一个新的树集合,集合中的元素是按照元素的自然顺序排序。

?TreeSet(Comparator c) 创建一个空的树集合,元素的排序规则按给定的c的规则排序。

?TreeSet(SortedSet s) 用SortedSet对象s中的元素创建一个树集合,排序规则与s 的排序规则相同。

下面的程序创建一个TreeSet对象,其中添加了四个字符串对象。从输出结果中我们可以看到,这些字符串是按照字母的顺序排列的。

程序TreeSetTest.java

import java.util.*;

public class TreeSetTest{

public static void main(String args[]){

Set ts = new TreeSet();

String[] s = new String[]{"one","two","three","four"};

for (int i=0;i

ts.add(s[i]);

System.out.println(ts);

}

}

_____________________________________________________________________________▃

程序输出结果为:

[four, one, three, two]

1.3 对象顺序

在上一小节中我们看到,在创建TreeSet类对象时如果没有指定比较器(Comparator)

对象,集合中的元素是按自然顺序排列的,如果指定了比较器对象,集合中的元素是根据比较器的规则排序。

所谓自然顺序(natural ordering)指的是集合中对象的类实现了Comparable接口,并实现了其中的compareTo()方法,对象则根据该方法排序。

如果希望集合中元素能够排序,必须使元素是可比较的,即要求元素所属的类必须实现Comparable接口。如果试图对没有实现Comparable接口的集合元素排序,将抛出ClassCastException运行时异常。

Java平台中有些类实现了Comparable接口,如基本数据类型包装类(Byte、Short、Integer、Long、Float、Double 、Character、Boolean),另外还有File类、String类、Date类、BigInteger 类、BigDecimal类等也实现了Comparable接口,这些类的对象直接可按自然顺序排序。

另一种排序方法是创建TreeSet对象时指定一个比较器对象,这样集合中的元素将按比较器的规则排序。

下面分别叙述这两种方法:

1. 实现Comparable接口

如果要对我们自己定义的类进行排序,则应该在定义类的时候实现https://www.360docs.net/doc/c416336447.html,parable 接口,并实现其中的compareTo()方法,该接口的定义如下:

public interface Comparable {

public int compareTo(T obj);

}

该接口中只声明了一个compareTo()方法,该方法用来实现调用对象与参数对象比较,返回值是一个整数。当调用对象小于、等于、大于参数对象时,该方法分别返回负整数、0和正整数。

下面的程序说明了如何通过实现Comparable接口对Student类的对象根据学号(id的值)进行排序。

程序Student.java

import java.util.*;

public class Student implements Comparable {

int id;

String name;

public Student(int id,String name){

this.id = id;

https://www.360docs.net/doc/c416336447.html, = name;

}

public int compareTo(Student s){

if(this.id

return -1;

else if (this.id>s.id)

return 1;

else

return 0;

}

public String toString(){

return "{"+this.id+","+https://www.360docs.net/doc/c416336447.html,+"}";

}

public static void main(String args[]){

Student[] stud=new Student[]{

new Student(1002,"Wang"),

new Student(1003,"Zhang"),

new Student(1001,"Zhou")};

Set ts = new TreeSet ();

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

ts.add(stud[i]);

System.out.println(ts);

}

}

_____________________________________________________________________________▃

程序运行结果为:

[{1001,Zhou}, {1002,Wang},{1003,Zhang}]

Student类实现了Comparable接口的compareTo()方法,它是根据学号(id的值)来比较两个Student对象的大小。当将Student对象存放到TreeSet中时就是按照compareTo()方法对Student对象排序的。

2. 比较器Comparator

如果一个类没有实现Comparable接口或实现了Comparable接口,我们又想改变比较规则,可以定义一个实现https://www.360docs.net/doc/c416336447.html,parator接口的类,然后为集合提供一个新的比较器。Comparator接口定义了2个方法,它的声明如下:

public interface Comparator {

int compare(T obj1, T obj2);

boolean equals(Object obj);

}

compare()方法用来比较它的两个参数。当第一个参数小于、等于、大于第二个参数时,该方法分别返回负整数、0、正整数。equals()方法用来比较两个Comparator对象是否相等。

字符串的默认比较规则是按字典顺序比较,假如按反顺序比较,我们可以通过下面的类来实现:

程序DescSort.java

import java.util.*;

public class DescSort implements Comparator{

public int compare(String s1, String s2){

if(https://www.360docs.net/doc/c416336447.html,pareTo(s2)>0)

return -1;

else if(https://www.360docs.net/doc/c416336447.html,pareTo(s2)<0)

return 1;

else return 0;

}

}

_____________________________________________________________________________▃

下面的程序就可以实现字符串的降序排序:

程序DescSortDemo.java

import java.util.*;

public class DescSortDemo{

public static void main(String args[]){

String[] s=new String []{"China",

"England","France","America","Russia",};

Set ts = new TreeSet< String > ();

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

ts.add(s[i]);

System.out.println(ts);

Comparator comp = new DescSort();

ts = new TreeSet< String > (comp);

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

ts.add(s[i]);

System.out.println(ts);

}

}

_____________________________________________________________________________▃

输出结果为:

[America, China, England, French, Russia]

[Russia, French, England, China, America]

输出的第一行是按字符串自然顺序的比较输出,第二行的输出使用了自定义的比较器,按与自然顺序相反的顺序输出。

1.4 List接口及实现类

List接口也是Collection接口的子接口,它实现一种顺序表的数据结构,有时也称为序列。存放在 List中的所有元素都有一个下标(下标从0开始),可以通过下标访问List中的元素。List中可以包含重复元素。List接口及其实现类的层次结构如图.3所示:

图.3 List接口及实现类的层次结构

Java平台提供了两个List类的通用实现类,ArrayList类和LinkedList类。另外,Java 早期版本的Vector类和Stack类被重新修改以适应新的集合框架。下面首先讨论List接口的操作,后面讨论这些实现类。

List接口除了继承Collection的方法外,还定义了一些自己的方法。使用这些方法可以实现定位访问、查找、链式迭代和范围查看。List接口的定义如下:

public interface List extends Collection {

// 定位访问

E get(int index);

E set(int index, E element);

boolean add(E element);

void add(int index, E element);

E remove(int index);

abstract boolean addAll(int index, Collection c);

// 查找

int indexOf(Object o);

int lastIndexOf(Object o);

// 迭代

ListIterator listIterator();

ListIterator listIterator(int index);

// 范围查看

List subList(int from, int to);

}

1. 集合操作

List接口从Collection接口继承的操作与Collection接口类似,但有的操作有些不同。例如,remove()方法总是从列表中删除指定的首次出现的元素;add()和addAll()方法总是将元素添加到列表的末尾,因此,下面的代码可以实现连接两个列表:

list1.addAll(list2);

如果不想破坏原来的列表,可以按如下代码实现:

List list3 = new ArrayList(list1);

list3.addAll(list2);

对于两个列表对象的比较,如果它们包含相同的元素并且顺序相同,则两个列表相等。

2. 定位访问和查找操作

List的基本的定位访问方法包括:get()、set()、add()和remove()。它们与Vector类的长名字的操作如elementAt()、setElementAt()、insertElementAt()和removeElementAt()的功能基本相同,只是set()和remove()方法返回被修改和删除的旧值,而Vector的setElementAt()和removeElementAt()返回void。

查找方法indexOf ()和lastIndexOf()与Vector的完全相同。addAll()方法可以将指定的集合插入到列表的指定位置中。

下面简单的方法可以交换列表中两个下标位置的元素:

public static void swap(List a, int i, int j) {

E tmp = a.get(i);

a.set(i, a.get(j));

a.set(j, tmp);

}

这是一个多态算法,它可以交换任何List中的元素而不管其实现类型。下面是另一个使用了上面的swap()方法的多态算法:

public static void shuffle(List list, Random rnd) {

for (int i = list.size(); i > 1; i--)

swap(list, i - 1, rnd.nextInt(i));

}

该算法包含在Java的Collections类中,它使用指定的随机数随机重排列表的元素。

3. 迭代器

List接口同样提供了iterator()方法返回一个Iterator对象。另外,List接口还提供了listIterator()方法返回ListIterator接口对象。该对象允许我们以两个方向遍历列表中元素,在迭代中修改元素以及获得元素的当前位置。ListIterator接口的声明如下:

public interface ListIterator extends Iterator {

boolean hasNext();

E next();

boolean hasPrevious();

E previous();

int nextIndex();

int previousIndex();

void remove();

void set(E o);

void add(E o);

}

该接口是Iterator的子接口。hasNext()、next()和remove()方法是从Iterator接口中继承的。hasPrevious()和previous()分别判断前面是否还有元素和返回前面的元素。set()和add()方法分别是修改当前元素和在当前位置插入一个元素。

4. ArrayList类和LinkedList类

ArrayList和LinkedList是List接口的两个常用的实现类。

(1)ArrayList是最常用的实现类,它是通过数组实现的集合对象。ArrayList类实际上实现了一个变长的对象数组,其元素可以动态地增加和删除。它的定位访问时间是常量时间。

ArrayList的构造方法如下

?ArrayList() 创建一个空的数组列表对象。

?ArrayList(Collection c) 用集合c中的元素创建一个数组列表对象。

?ArrayList(int initialCapacity) 创建一个空的数组列表对象,并指定初始容量。

下面的程序演示了ArrayList的使用:

程序ListDemo.java

import java.util.*;

public class ListDemo{

public static void main(String args[]){

Collection c=new ArrayList();

String weekday[]=new String[]{

"Sunday","Monday","Tuesday","Wednesday",

"Thursday","Friday","Saturday"};

for(int i=0;i

c.add(weekday[i]);

System.out.println(c);

String weekend[]=new String[]{"Saturday","Sunday"};

Collection c1=new ArrayList();

Collection c2=new ArrayList();

c1.add(weekend[0]);

c1.add(weekend[1]);

System.out.println(c1);

c.removeAll(c1);

c2=new ArrayList(c); //c2=c;

System.out.println(c);

System.out.println("c.containsAll(c1)="+c.containsAll(c1));

System.out.println(c2);

c.addAll(c1);

System.out.println(c);

System.out.println("c.containsAll(c1)="+c.containsAll(c1));

c.retainAll(c2);

System.out.println(c);

}

}

_____________________________________________________________________________▃程序输出结果为:

[Sunday, Monday, Tuesday, Wednesday, Thursday, Friday, Saturday]

[Saturday, Sunday]

[Monday, Tuesday, Wednesday, Thursday, Friday]

c.containsAll(c1)=false

[Monday, Tuesday, Wednesday, Thursday, Friday]

[Monday, Tuesday, Wednesday, Thursday, Friday, Saturday, Sunday]

c.containsAll(c1)=true

[Monday, Tuesday, Wednesday, Thursday, Friday]

(2)LinkedList

如果需要经常在List的头部添加元素,在List的内部删除元素,就应该考虑使用LinkedList。这些操作在LinkedList中是常量时间,在ArrayList中是线性时间,但定位访问是LinkedList线性时间而在ArrayList中是常量时间。

LinkedList的构造方法如下:

?LinkedList() 创建一个空的链表。

?LinkedList(Collection c) 用集合c中的元素创建一个链表。

创建ArrayList对象可以指定一个初始容量的参数,它指在ArrayList对象扩充之前存放元素的数量,LinkedList没有这样的参数。

LinkedList定义了7个可选的操作,一个是clone(),另外6个分别是addFirst()、getFirst()、removeFirst()、addLast()、getLast()和removeLast()。注意,LinkedList也实现了Queue 接口。

Vector类和Stack类

Vector类和Stack类是Java早期版本提供的两个集合类,分别实现向量和堆栈。

(1)Vector类

Vector类的构造方法有:

?public Vector() 创建一个空的向量对象,其内部数据数组的大小为10。

?public Vector(int initialCapacity) 创建一个空的向量对象,并指定初始容量大小。

?public Vector(int initialCapacity, int capacityIncrement) 创建一个空的向量对象,并指定初始容量大小和当向量满时增加的空间大小。

?public Vector(Collection c) 创建一个包含指定集合中元素的向量对象。

Vector类的常用方法有:

?public void addElement(E obj) 将指定的对象添加到向量的尾部,其大小加1。该方法与List接口的add(Object)方法的功能相同。

?public void insertElement(E obj, int index) 将指定的对象插入到向量中指定的位置。

向量中的每个元素都有一个下标,起始下标为0。使用该方法插入一个元素后,后

面的元素向后移动。index的值必须大于等于0,小于等于向量的大小。

?public void setElementAt(E obj, int index) 将指定下标位置的元素用指定的元素修改,原来的元素被丢弃。index的值必须大于等于0,小于等于向量的大小。

?public void removeElement(int index) 删除指定下标所在的元素,后面元素向前移动,向量的大小减1。

?public boolean removeElement(Object obj) 从向量中删除第一次出现的指定的元素对象,如果找到一个对象,则将其删除,后面元素向前移动,向量的大小减1。

?public void removeAllElements() 从向量中删除所有的元素,向量的大小置为0。

(2)Stack类

Stack类实现一种LIFO(last-in-frist-out)的对象堆栈。它的构造方法为:

?public Stack() 创建一个空的堆栈对象。

Stack类除了继承超类V ector中的方法外,还定义了堆栈的常用操作,如下所示:

?public E pop() 弹出堆栈顶端元素并返回弹出的对象。

?public E push(E item) 将参数item对象压入栈中并返回入栈对象。

?public boolean empty() 测试堆栈是否为空。

?public E peek() 返回栈顶元素,但并不将其删除。

?public int search(Object o) 返回指定对象o在栈中的位置,位置从1开始。

1.5 Queue接口及实现类

Queue接口也是Collection的子接口,它实现的是以FIFO(先进先出,first-in-first-out)的方式排列其元素,一般称为队列。

Queue接口有两个实现类:LinkedList和PriorityQueue,如图4所示。其中LinkedList 也是List接口的实现类,而PriorityQueue是优先队列。注意,优先队列中元素的顺序是根据元素的值排列的。不管使用什么顺序,队头总是在调用remove()或poll()方法时被最先删除。

图4 Queue接口及其实现类

Queue接口除了提供Collection的操作外,还提供了插入、删除和检查操作。Queue接口的定义如下:

public interface Queue extends Collection {

boolean add(E e) // 将指定的元素e插入到队列中

E element(); // 返回队列头元素,但不将其删除

E remove(); // 返回队列头元素,同时将其删除

boolean offer(E o); // 将指定的元素e插入到队列中

E peek(); // 返回队列头元素,但不将其删除

E poll(); // 返回队列头元素,同时将其删除

}

每个Queue的方法都有两种形式:一个是在操作失败时抛出异常,另一个是在操作失败时返回一个特定的值(根据操作的不同,可能返回null或false)。这些方法如表1所示:

表1 Queue接口的两类不同操作

一个Queue的实现类可能限制它所存放的元素的数量,这样的Queue称为受限(bounded)队列。在java.util.concurrent包中的有些队列是受限的,而java.util包中的队列不是。

Queue接口的add()方法是从Collection接口继承的,它向队列中插入一个元素。如果队列的容量限制遭到破坏,它将抛出IllegalStateExcepion异常。offer()方法与add()方法的区别

是在插入元素失败时返回false,它一般用在受限队列中。

element()和peek()方法返回队头元素但不删除。区别是如果队列为空element()方法抛出NoSuchElementException异常,而peek()方法返回false。

remove()和poll()方法都是删除并返回对头元素。它们的区别是当队列为空时remove()方法抛出NoSuchElementException异常,而poll()方法返回null。

队列的实现类一般不允许插入null元素,但LinkedList类是一个例外。由于历史的原因,它允许null元素。

下面的示例程序中,使用了队列实现一个记时器。事先从命令行指定一个整数,从指定的数到0事先存放的队列中,然后每隔1秒钟输出一个数。

程序CountDown.java

import java.util.*;

public class CountDown {

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

int time = Integer.parseInt(args[0]);

Queue queue = new LinkedList();

for (int i = time; i >= 0; i--)

queue.add(i);

while(!queue.isEmpty()) {

System.out.println(queue.remove());

Thread.sleep(1000);

}

}

}

_____________________________________________________________________________▃

PriorityQueue类是Queue接口的一个实现类,它实现一种优先级队列。它的元素的插入和删除并不遵循FIFO的原则,而是根据某种优先顺序插入元素和删除元素。这种优先顺序有对象的排序类似,可以通过Comparable接口和Comparator接口实现。

PriorityQueue类的常用构造方法有:

?public PriorityQueue() 创建一个空的优先队列。使用默认的初始容量(11),元素顺序为自然顺序。

?public PriorityQueue(int initialCapacity) 创建一个指定初始容量的空的优先队列,元素顺序为自然顺序。

?public PriorityQueue(Collection c) 创建一个包含指定集合c中的元素的优先队列。元素顺序与c的顺序相同或使用自然顺序。

?public PriorityQueue(int initialCapacity, Comparator comparator) 创建一个指定初始容量的空的优先队列,元素顺序为比较器comparator指定的顺序。

下面程序演示了PriorityQueue类的使用:

程序PQDemo.java

import java.util.*;

public class PQDemo {

static class PQSort implements Comparator{

public int compare(Integer one, Integer two){

return two - one ;

}

}

public static void main(String[]args){

int[] ia = {1,5,3,7,6,9,8};

PriorityQueue pq1 =

new PriorityQueue();

for(int x : ia)

pq1.offer(x); //将数组ia中的元素插入到优先队列中

for(int x : ia)

System.out.print(pq1.poll()+" ");

System.out.println();

PQSort pqs = new PQSort();

PriorityQueue pq2 =

new PriorityQueue(10,pqs);

for(int x : ia)

pq2.offer(x);

System.out.println("size = "+pq2.size());

System.out.println("peek = "+pq2.peek());

System.out.println("poll = "+pq2.poll());

System.out.println("size = "+pq2.size());

for(int x : ia)

System.out.print(pq2.poll()+" ");

}

}

_____________________________________________________________________________▃程序运行结构为:

1 3 5 6 7 8 9

size = 7

peek = 9

poll = 9

size = 6

8 7 6 5 3 1 null

从输出结果可以看到,对象是按某种优先顺序插入到队列中的。第一次插入使用对象的自然顺序,第二次插入使用了比较器对象,按与自然顺序相反的顺序插入。

从对peek()和poll()方法的调用结果可以看到,它们分别返回和删除了具有最高优先级的元素。最后输出的null表示队列已为空。

Map接口及实现类

Map是一个专门用来存储键/值对的对象。在Map中存储的关键字和值都必须是对象,并要求关键字是唯一的,而值可以有重复的。

Map接口常用的实现类有HashMap类、LinkedHashMap类、TreeMap类和Hashtable类,前三个类的行为和性能与前面讨论的Set实现类HashSet、LinkedHashSet及TreeSet类似。Hashtable类是Java早期版本提供的类,经过修改实现了Map接口。Map接口及实现类的层次关系如图5所示:

图5 Map接口及实现类的层次结构

1.1 Map接口

1. Map接口的定义

Map接口的定义如下:

public interface Map {

// 基本操作

V put(K key, V value);

V get(Object key);

V remove(Object key);

boolean containsKey(Object key);

boolean containsValue(Object value);

int size();

boolean isEmpty();

// 批量操作

void putAll(Map t);

void clear();

// 集合查看

public Set keySet();

public Collection values();

public Set> entrySet();

// 内部接口的定义

public interface Entry {

K getKey();

V getValue();

V setValue(V value);

}

}

2. Map接口的操作

(1)基本操作

Map接口的put()方法将一个键/值对存入Map对象中;get()方法根据给定的键,返回其值;containsKey()返回Map中是否包含指定的键;containsValue()返回Map中是否包含指定的值;size()和isEmpty()分别返回Map的大小和是否为空。

(2)批量操作

Map接口的批量操作有两个方法clear()和putAll()。clear()方法是从Map对象中清除所有的映射。putAll()方法与Collection接口的addAll()方法类似。

(3)集合视图

Map接口的集合视图操作可以从三个方面将Map作为Collection对待:

?public Set keySet()方法:它返回包含在Map中键的一个Set对象。

?public Collection values()方法:它返回包含在Map中值的一个Collection对象。

该Collection对象不是一个Set,因为在Map中可能多个键映射到一个相同的值上。

?public Set> entrySet()方法:它返回包含在Map中的键-值对的Set 对象。Map接口提供了一个名为Map.Entry的嵌套接口,它是该Set中的元素类型。

集合视图提供了在Map上迭代的唯一方法。下面的例子说明了在Map的键上迭代的方法,这里使用了for-each结构:

for (KeyType key : m.keySet())

System.out.println(key);

如果使用迭代器,可通过面方式实现:

for (Iterator i=m.keySet().iterator(); i.hasNext(); )

if (i.next().isBogus())

i.remove();

1.2 Map接口的实现类

Map接口的常用的实现类有HashMap、TreeMap和Hashtable类。

1. HashMap类与LinkedHashMap类

HashMap类的构造方法有:

?HashMap() 创建一个空的映射对象,使用缺省的装填因子(0.75)。

?HashMap(int initialCapacity) 用指定的初始容量和缺省的装填因子(0.75)创建一个映射对象。

?HashMap(int initialCapacity, float loadFactor) 用指定的初始容量和指定的装填因子创建一个映射对象。

?HashMap(Map t) 用指定的映射对象创建一个新的映射对象。

下面的程序从命令行输入一组单词,然后产生一个单词频率表,该表中记录每个单词与其出现的次数。

程序Frequency.java

import java.util.*;

public class Frequency {

public static void main(String args[]) {

Map m = new HashMap();

// 由命令行参数初始化单词频率表

for (String a : args) {

Integer freq = m.get(a);

m.put(a, (freq == null ? 1 : freq + 1));

}

System.out.println(m.size() + " distinct words:");

System.out.println(m);

}

}

_____________________________________________________________________________▃

使用下面的命令行运行该程序:

C:\>java Frequency if it is to be it is up to me to delegate

程序运行结果为:

8 distinct words:

{to=3, delegate=1, be=1, it=2, up=1, if=1, me=1, is=2}

LinkedHashMap是HashMap类的子类,它保持键的顺序与插入的顺序一致。它的构造方法与HashMap的构造方法类似。对程序Frequency.java,如果希望频率表按照单词输入的顺序输出,可以使用LinkedHashMap类创建映射对象。

2. TreeMap类

TreeMap类实现了SortedMap接口,SortedMap接口能保证各项按关键字升序排序。TreeMap类的构造方法如下:

?TreeMap() 创建根据键的自然顺序排序的空的映射。

?TreeMap(Comparator c) 根据给定的比较器创建一个空的映射。

?TreeMap(Map m) 用指定的映射创建一个新的映射,根据键的自然顺序排序。

?TreeMap(SortedMap m) 在指定的SortedMap对象创建新的TreeMap对象。

对程序Frequency.java的例子,假设希望频率表按字母顺序输出,仅将HashMap改为TreeMap即可。输出结果为:

{be=1, delegate=1, if=1, is=2, it=2, me=1, to=3, up=1}

这里,键的顺序是字母顺序输出的。

3. Hashtable类

Hashtable实现了一种哈希表,它是Java早期版本提供的一个存放键/值对的实现类,现在也属于集合框架。但哈希表对象是同步的,即是线程安全的。

任何非null对象都可以作为哈希表的关键字和值。但是要求作为关键字的对象必须实现hashCode()方法和equals()方法,以使对象的比较成为可能。

一个Hashtable实例有两个参数影响它的性能:一个是初始容量(initial capacity),另一个是装填因子(load factor)。

Hashtable的构造方法有:

?Hashtable() 使用默认的初始容量(11)和默认的装填因子(0.75)创建一个空的哈希表,

?Hashtable(int initialCapacity) 使用指定的初始容量和默认的装填因子(0.75)创建一个空的哈希表。

?Hashtable(int initialCapacity, float loadFactor) 使用指定的初始容量和指定的装填因子创建一个空的哈希表。

?Hashtable(Map t) 使用给定的Map对象创建一个哈希表。

Hashtable类的常用方法有:

?public V put(K key, V value) 在哈希表中建立指定的键和值的映射,键和值都不能为null。

?public V get(Object key) 返回哈希表中指定的键所映射的值。

?public V remove(Object key) 从哈希表中删除由键指定的映射值。

?public Enumeration keys() 返回键组成的一个Enumeration(枚举)对象。

?public Enumeration elements() 返回值组成的一个Enumeration(枚举)对象。

在返回的对象上使用Enumeration接口的方法可以顺序取出对象。

上面两个方法返回类型都是Enumeration接口类型的对象,该接口中定义了两个方法,如下所示:

?boolean hasMoreElements() 测试枚举对象中是否还含有元素,如果还含有元素返回true,否则返回false。

? E nextElement() 如果枚举对象中至少还有一个元素,它返回下一个元素。

下面的代码创建了一个包含数字的哈希表对象,使用数字名作为关键字:

Hashtable numbers = new Hashtable();

numbers.put("one", new Integer(1));

numbers.put("two", new Integer(2));

numbers.put("three", new Integer(3));

要检索其中的数字,可以使用下面代码:

Integer n = (Integer)numbers.get("two");

if (n != null) {

System.out.println("two = " + n);

}

Map对象与Hashtable对象的区别如下:

(1)Map提供了集合查看方法而不直接支持通过枚举对象(Enumeration)的迭代。集合查看大大地增强了接口的表达能力;

(2)Map允许通过键、值或键/值对迭代,而Hashtable不支持第三种方法;

(3)Map提供了安全的方法在迭代中删除元素,而Hashtable不支持该功能。

(4)Map修复了Hashtable的一个小缺陷。在Hashtable中有一个contains()方法,当Hashtable包含给定的值,该方法返回true。该方法可能引起混淆,因此Map接口将该方法改为containsValue(),这与另一个方法containsKey()实现了一致。

Arrays类和Collections类

在java.util包中提供了Arrays类和Collections类,这两个类提供了数组和集合对象的算法功能。这两个类提供了若干static方法实现有关操作。

1.1 Arrays类

Arrays类中定义了对数组操作的方法。常用的方法有:fill()方法用来将一个值填充到数组元素中;sort()方法用来对数组排序;binarySearch()用来在已排序的数组中查找指定元素;equals()方法用来比较两个数组是否相等。上述方法都有多个重载的方法,可用于所有的基本数据类型和Object类型。另外还提供了一个asList()方法,用来将数组转换为List对象。

1. 填充数组元素

调用Arrays类的fill()方法可以将一个值填充到数组的每个元素中,也可将一个值填充到数组连续的几个元素中。下面是向整型数组和对象数组中填充元素的方法:?public static void fill (int[] a, int val) 用指定的val值填充数组中的每个元素。

?public static void fill (int[] a, int fromIndex, int toIndex, int val) 用指定的val值填充数组中的下标从fromIndex开始到toIndex为止的每个元素。

?public static void fill (Object[] a, Object val) 用指定的val值填充对象数组中的每个元素。

?public static void fill (Object[] a, int fromIndex, int toIndex, Object val) 用指定的val 值填充对象数组中的下标从fromIndex开始到toIndex为止的每个元素。

下面的程序演示了fill()方法的使用:

程序FillTest.java

import java.util.*;

public class FillTest{

public static void main(String args[]){

int size = 6;

boolean[] a1 = new boolean[size];

byte [] a2 = new byte[size];

float [] a3 = new float[size];

String [] a4 = new String[size];

Arrays.fill (a1,true);

Arrays.fill (a2, (byte)11);

Arrays.fill (a3, (float)3.14);

Arrays.fill (a4, "Hello");

Arrays.fill (a4, 2, 4, "World");

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

System.out.print(a4[i]+" ");

}

}

_____________________________________________________________________________▃

该程序的输出结果为:

Hello Hello World World Hello Hello

2. 数组的排序

使用Arrays的sort()方法可以对数组元素排序。排序是稳定的(stable)排序,即相等的元素在排序结果中不会重新排列顺序。对于基本数据类型,按数据的升序排序。对于对象数组的排序要求数组元素的类必须实现Comparable接口,若要改变排序顺序,还可以指定一个比较器对象。对象数组的排序方法格式如下:

?public static void sort(Object[] a) 对数组a按自然顺序排序。

?public static void sort(Object[] a, int fromIndex, int toIndex) 对数组a中的元素从其始下标fromIndex到终止下标toIndex之间的元素排序。

?public static void sort(Object[] a, Comparator c) 使用比较器对象c对数组a排序。

注意不能对布尔型数组排序。

下面程序演示了对一个字符串数组的排序:

程序SortDemo.java

import java.util.*;

public class SortDemo{

public static void main(String args[]){

String[] s=new String []{"China", "England",

"France","America","Russia",};

for(int i=0;i

System.out.print(s[i]+" ");

System.out.println();

Arrays.sort(s); // 对数组s排序

for(int i=0;i

System.out.print(s[i]+" ");

System.out.println();

}

}

_____________________________________________________________________________▃

程序的输出结果为:

China England France America Russia

America China England France Russia

3. 数组元素的查找

对排序后的数组可以使用binarySearch()方法从中快速查找指定元素,该方法也有多个重载的方法,下面是对整型数组和对象数组的查找方法:

?public static int binarySearch (int[] a, int key)

?public static int binarySearch (Object[] a, Object key)

查找方法根据给定的键值,查找该值在数组中的位置,如果找到指定的值,则返回该值的下标值。如果查找的值不包含在数组中,方法的返回值为(-插入点-1)。插入点为指定的值在数组中应该插入的位置。

例如,下面代码输出结果为-3:

int[] a = new int[]{1,3,5,7};

Arrays.sort(a);

int i = Arrays.binarySearch(a,4);

System.out.println(i); // 输出-3

注意,使用binarySearch()方法前,数组必须已经排序。

4. 数组的比较

使用Arrays的equals()方法可以比较两个数组,被比较的两个数组要求数据类型相同且元素个数相等,比较的是对应元素是否相同。对于引用类型的数据,如果两个对象e1、e2值都为null或者e1.equals(e2),则认为e1与e2相等。

下面是布尔型数组和对象数组equals()方法的格式:

?public static boolean equals(boolean[] a, boolean[] b) 比较布尔型数组a与b是否相等。

?public static boolean equals(Object[] a, Object[] b) 比较对象数组a与b是否相等。

下面的程序给出了equals()方法的示例:

程序EqualsTest.java

import java.util.*;

public class EqualsTest {

public static void main(String[] args) {

int[] a1 = new int[10];

int[] a2 = new int[10];

Arrays.fill(a1, 47);

Arrays.fill(a2, 47);

System.out.println(Arrays.equals(a1, a2)); //输出true

System.out.println(a1.equals( a2)); //输出false

a2[3] = 11;

System.out.println(Arrays.equals(a1, a2)); //输出false

String[] s1 = new String[5];

Arrays.fill(s1, "Hi");

String[] s2 = {"Hi", "Hi", "Hi", "Hi", "Hi"};

System.out.println(Arrays.equals(s1, s2)); //输出true

}

}

_____________________________________________________________________________▃

5. 数组转换为List对象

Arrays类提供了一个asList()方法,它可以实现将数组转换成List对象的功能,该方法的定义如下:

public static List asList(T… a)

该方法提供了一个方便的从多个元素创建List对象的途径,例如:

程序AsListTest.java

import java.util.*;

public class AsListTest{

public static void main(String[]args){

List list = Arrays.asList(args);

System.out.println(list);

//list.add("five");

System.out.println(list);

《集合框架及泛型》上机实践内容

《集合框架及泛型》作业 一、根据课上讲解内容,完成演示示例和课堂练习 1、ArrayList获取并打印新闻标题 需求说明:按照以下实现的步骤,使用ArrayList获取和打印新闻标题,显示效果如下图所示: (1)创建多个各类新闻标题对象,包含ID、名称和创建者三个属性; (2)创建存储各类新闻标题的集合对象; (3)按照顺序依次添加各类新闻标题,使用add()方法; (4)获取新闻标题的总数,使用size()方法; (5)根据位置获取相应新闻标题、逐条打印每条新闻标题的名称,使用for 循环遍历。 2、ArrayList存储狗狗信息 需求说明:按照以下实现的步骤,使用ArrayList存储狗狗信息,使用ArrayList的方法对狗狗信息进行删除、读取和判断,显示效果如下图所示:(1)存储多条狗信息,获取狗总数,逐条打印出各条狗信息; (2)删除指定位置的狗,使用remove()方法; (3)判断集合中是否包含指定狗,使用contains()方法;

3、LinkedList添加和删除新闻标题 需求说明:在作业1的基础上,换用LinkedList存储新闻数据,并且使用LinkedList的getFirst()和getLast()方法获取第一条和最后一条数据,以及removeFirst()和removeLast()方法删除第一条和最后一条数据,输出效果如下图所示。 4、集合头尾位置删除和条件狗信息 需求说明:按照作业3的实现方式和所用到LinkedList的方法,实现狗狗信

息的更新并输出,输出效果如图所示。 5、使用Iterator和增强型for循环遍历Set 需求说明:按照以下实现的步骤,使用Iterator和增强型for循环遍历Set,输出效果如下图所示: (1)创建多个各类新闻标题对象,包含ID、名称和创建者三个属性; (2)创建存储各类新闻标题的集合对象; (3)按照顺序依次添加各类新闻标题; (4)获取新闻标题的总数; (5)使用iterator()获取Iterator对象; (6)使用Iterator遍历集合,使用hasNext()方法作为循环条件,判断是否存在另一个可访问的元素; (7)使用增强型for遍历集合;

java泛型详解

java泛型详解 泛型(Generic type 或者generics)是对 Java 语言的类型系统的一种扩展,以支持创建可以按类型进行参数化的类。可以把类型参数看作是使用参数化类型时指定的类型的一个占位符,就像方法的形式参数是运行时传递的值的占位符一样。 可以在集合框架(Collection framework)中看到泛型的动机。例如,Map类允许您向一个Map添加任意类的对象,即使最常见的情况是在给定映射(map)中保存某个特定类型(比如String)的对象。 因为Map.get()被定义为返回Object,所以一般必须将Map.get()的结果强制类型转换为期望的类型,如下面的代码所示: Map m = new HashMap(); m.put("key", "blarg"); String s = (String) m.get("key"); 要让程序通过编译,必须将get()的结果强制类型转换为String,并且希望结果真的是一个String。但是有可能某人已经在该映射中保存了不是String的东西,这样的话,上面的代码将会抛出ClassCastException。 理想情况下,您可能会得出这样一个观点,即m是一个Map,它将String键映射到String值。这可以让您消除代码中的强制类型转换,同时获得一个附加的类型检查层,该检查层可以防止有人将错误类型的键或值保存在集合中。这就是泛型所做的工作。 泛型的好处 Java 语言中引入泛型是一个较大的功能增强。不仅语言、类型系统和编译器有了较大的变化,以支持泛型,而且类库也进行了大翻修,所以许多重要的类,比如集合框架,都已经成为泛型化的了。这带来了很多好处: · 类型安全。泛型的主要目标是提高 Java 程序的类型安全。通过知道使用泛型定义的变量的类型限制,编译器可以在一个高得多的程度上验证类型假设。没有泛型,这些假设就只存在于程序员的头脑中(或者如果幸运的话,还存在于代码注释中)。 Java 程序中的一种流行技术是定义这样的集合,即它的元素或键是公共类型的,比如“Str ing列表”或者“String到String的映射”。通过在变量声明中捕获这一附加的类型信息,泛型允许编译器实施这些附加的类型约束。类型错误现在就可以在编译时被捕获了,而不是在运行时当作 ClassCastException展示出来。将类型检查从运行时挪到编译时有助于您更容易找到错误,并可提高程序的可靠性。

实验十 泛型与集合框架

实验十泛型与集合框架 1.实验目的 1、掌握LinkedList类和Collections类提供的用于排序和查找链表中 的数据的方法 2、掌握用散列映射来存储数据 3、掌握TreeSet类的使用 2.实验内容 1、根据附录里的源代码,按照注释要求,完成代码填空,使程序能够运行 得出结果。 1)实验1 按身高排序 2)实验2 英汉小字典 3)实验3 演出节目单 4)实验4输出args[]中的单词 2、设计编写程序完成以下任务。 1)仿照实验1编写TV类,要求通过实现Comparable接口规定该类的对象的大小关系,按price值得大小确定大小关系,即电视机按其价格确定之间的大小关系。 2)从控制台输入若干个单词(输入回车结束)放入集合中,将这些单词排序后(忽略大小写)打印出来。 知识点:List接口的实现类、String常用方法 3)请使用LinkedList来模拟一个队列(先进先出的特性): (1)拥有放入对象的方法void put(Object o) (2)取出对象的方法Object get() (3)判断队列当中是否为空的方法boolean isEmpty();并且,编写测试代码,验证你的队列是否正确。 知识点:List接口的实现类LinkedList常用方法 4)在一个列表中存储以下元素:apple,grape,banana,pear (1)返回集合中的最大的和最小的元素 (2)将集合进行排序,并将排序后的结果打印在控制台上 知识点:Collections类中的方法 3.实验步骤 略 4.评分标准 1.A——内容功能完善,编程风格好,人机接口界面好; 2.B——内容功能完善,编程风格良好,人机接口界面良好;

JAVA实验报告-集合框架与泛型机制

Java 语言程序设计 C 实验报告 集合框架及泛型机制 学生姓名 专业、班级 指导教师 成绩 计算机与信息工程学院 年月日

一、实验目的 学习课程相关章节知识,通过上机练习,掌握以下知识: 1.掌握 List 接口下 ArrayList 及 LinkedList 的使用方法。 2.掌握 Map 接口下 HashMap 及 HashTable的使用方法 3.掌握集合中泛型的使用 二、实验内容 利用集合完成象数据库那样存储数据,并且可以简单查询,利用 map 存储学生信息,字段如下: id ,name,age,实现步骤: (1)创建类,类图如下: (2)在 main 方法编写逻辑代码 (3)运行程序并测试结果 package https://www.360docs.net/doc/c416336447.html,; public class Student { private String name ; private int age ; private String id ;

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 getId() { return id; } public void setId(String id) { this. id=id; } public Student(String name ,int age , String id ) { super(); this. name =name ; this. age=age ; this. id=id; } public void sayHi() { System.out.println("name=" +this.getName()+"age=" + this .getAge()+" " + "id=" + this.getId()); } }

JAVA实验报告-集合框架及泛型机制

Java语言程序设计C 实验报告 集合框架及泛型机制 学生姓名 专业、班级 指导教师 成绩 计算机与信息工程学院 年月日 一、实验目的 学习课程相关章节知识,通过上机练习,掌握以下知识:

1.掌握List接口下ArrayList及LinkedList的使用方法。 2.掌握Map接口下HashMap 及HashTable的使用方法 3.掌握集合中泛型的使用 二、实验内容 利用集合完成象数据库那样存储数据,并且可以简单查询,利用map存储学生信息,字段如下: id ,name,age,实现步骤: (1)创建类,类图如下: (2)在main方法编写逻辑代码 (3)运行程序并测试结果 package com、cn; public class Student { private String name; private int age; private String id; 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 getId() { return id; } public void setId(String id) { this、id = id; } public Student(String name, int age, String id) { super(); this、name = name; this、age = age; this、id = id; } public void sayHi() { System、out、println("name="+this、getName()+"age="+this、getAge()+" "+"id="+this、getId()); } } //Databace类 package com、cn; import java、util、Collection; import java、util、HashMap; import java、util、Iterator; public class Databace { private Student a; public Databace() { super(); map=new HashMap(); } public Student getA() { return a; }

Java泛型详解

Java 泛型 1 什么是泛型 (2) 2 泛型类跟接口及泛型方法 (3) 2.1 泛型类跟接口及继承 (3) 2.1.1泛型类 (3) 2.1.2继承 (3) 2.1.3接口 (3) 2.2 泛型方法 (3) 2.2.1 方法 (3) 2.2.2 类型推断 (4) 3 泛型实现原理 (5) 4 泛型数组 (6) 5边界 (7) 6通配符 (8) 7 泛型的问题及建议 (9) 7.1问题 (9) 7.2 建议 (9)

1 什么是泛型 从jdk1.5开始,Java中开始支持泛型了。泛型是一个很有用的编程工具,给我们带来了极大的灵活性。在看了《java核心编程》之后,我小有收获,写出来与大家分享。 所谓泛型,我的感觉就是,不用考虑对象的具体类型,就可以对对象进行一定的操作,对任何对象都能进行同样的操作。这就是灵活性之所在。但是,正是因为没有考虑对象的具体类型,因此一般情况下不可以使用对象自带的接口函数,因为不同的对象所携带的接口函数不一样,你使用了对象A的接口函数,万一别人将一个对象B传给泛型,那么程序就会出现错误,这就是泛型的局限性。所以说,泛型的最佳用途,就是用于实现容器类,实现一个通用的容器。该容器可以存储对象,也可以取出对象,而不用考虑对象的具体类型。因此,在学习泛型的时候,一定要了解这一点,你不能指望泛型是万能的,要充分考虑到泛型的局限性。下面我们来探讨一下泛型的原理以及高级应用。首先给出一个泛型类: public class Pair { public Pair() { first = null; second = null; } public Pair(T first, T second) { this.first = first; this.second = second; } public T getFirst() { return first; } public T getSecond() { return second; } public void setFirst(T newValue) { first = newValue; } public void setSecond(T newValue) { second = newValue; } private T first; private T second; } 我们看到,上述Pair类是一个容器类(我会多次强调,泛型天生就是为了容器类的方便实现),容纳了2个数据,但这2个数据类型是不确定的,用泛型T来表示。关于泛型类如何使用,那是最基本的内容,在此就不讨论了。

实验6 泛型与集合框架_附答案

任务一:用LinkedList存放对象 1.利用面向对象的思想,创建以下类: ●Person类,包含Person的姓名和身份证号码,覆盖Object类的toString() 方法,显示“姓名:XXX 身份证号:XXX”。 ●Student类,继承Person类,包含学生的语文、数学、英文课的成绩,并覆盖 父类的toString()方法,显示“姓名:XXX 身份证号:XXX 语文:XXX 数学:XXX 英文:XXX”。 ●Teacher类,继承Person类,包含教师的工资。并覆盖父类的toString()方 法,显示“姓名:XXX 身份证号:XXX 工资:XXX”。 ●public class Person implements Comparable{ ●String name; ●String ID; ●Person(String s,String i){ ●name=s; ●ID=i; } ●public String toString() { ●String str="姓名:"+name+" 身份证号码:"+ID; ●return str; } ●public int compareTo(Object arg0) { ●Person p=(Person)arg0; ●return https://www.360docs.net/doc/c416336447.html,pareTo(p.ID); } } ●class Student extends Person { ●int Chinese; ●int Math; ●int English; ●Student(String n,String i,int c,int m,int e){ ●super(n,i); ●Chinese=c; ●Math=m; ●English=e; } ●public String toString() { ●String str; ●str=" 语文成绩:"+Chinese+" 数学成绩:"+Math+" 英语成绩: "+English; ●return super.toString()+str; ●} ●} ●class Teacher extends Person{ ●int salary; ●Teacher(String n,String i,int s){ ●super(n,i); ●salary=s; ●}

java泛型详解

Java 泛型详解 泛型是Java中一个非常重要的知识点,在Java集合类框架中泛型被广泛应用。本文我们将从零开始来看一下Java 泛型的设计,将会涉及到通配符处理,以及让人苦恼的类型擦除。 泛型基础 泛型类 我们首先定义一个简单的Box类: public class Box { private String object; public void set(String object) { this.object = object; } public String get() { return object; }}这是最常见的做法,这样做的一个坏处是Box里面现在只能装入String类型的元素,今后如果我们需要装入Integer等其他类型的元素,还必须要另外重写一个Box,代码得不到复用,使用泛型可以很好的解决这个问题。 public class Box { // T stands for 'Type' private T t; public void set(T t) { this.t = t; } public T get() { return t; }} 这样我们的Box类便可以得到复用,我们可以将T替换成任何我们想要的类型: Box integerBox = new Box();Box doubleBox = new

Box();Box stringBox = new Box(); 泛型方法 看完了泛型类,接下来我们来了解一下泛型方法。声明一个泛型方法很简单,只要在返回类型前面加上一个类似的形式就行了: public class Util { public static boolean compare(Pair p1, Pair p2) { return p1.getKey().equals(p2.getKey()) && p1.getValue().equals(p2.getValue()); }}public class Pair { private K key; private V value; public Pair(K key, V value) { this.key = key; this.value = value; } public void setKey(K key) { this.key = key; } public void setValue(V value) { this.value = value; } public K getKey() { return key; } public V getValue() { return value; }} 我们可以像下面这样去调用泛型方法: Pair p1 = new Pair(1, 'apple');Pair p2 = new Pair(2, 'pear');boolean same = https://www.360docs.net/doc/c416336447.html,pare(p1, p2); 或者在Java1.7/1.8利用type inference,让Java自动推导出相应的类型参数: Pair p1 = new Pair(1, 'apple');Pair p2 = new Pair(2, 'pear');boolean same = https://www.360docs.net/doc/c416336447.html,pare(p1, p2);

学号姓名--集合框架与泛型实验报告

浙江大学城市学院实验报告 课程名称面向对象程序设计 实验项目名称集合框架与泛型 学生姓名专业班级学号 一. 实验目的和要求 1. 了解Java集合框架的接口和实现类 2. 理解泛型类、泛型接口、泛型方法的特点 3. 掌握List接口及其实现类LinkedList、ArrayList 4. 了解Set接口及其实现类HashSet、TreeSet 5. 了解Map及其实现类HashMap、TreeMap 二. 实验内容 1. 分析Java集合框架的接口和实现类的组成 2. 分析泛型类、泛型接口、泛型方法的特点 3. 编程实现:设计学生管理类StudentManager(用List集合管理学生对象) 4. 选作-编程实现:设计学生管理类StudentManager(用Set集合管理学生对象) 5. 选作-编程实现:设计学生管理类StudentManager(用Map管理学生对象) 三. 实验结果与分析(可将程序运行结果截屏,也可分析运行结果) 1. 分析Java集合框架的接口和实现类的组成 请查阅书籍和Java帮助文档,说明Java集合框架的接口组成以及它们的继承关系,并针对每个接口给出具体的实现类。 答: 2. 分析泛型类、泛型接口、泛型方法的特点 请查阅书籍和Java帮助文档,举例说明泛型类、泛型接口、泛型方法的特点。 答: 3. 编程实现:设计学生管理类StudentManager(用List集合管理学生对象)。 StudentManager类的功能包括添加学生、查询学生、删除学生、统计学生成绩等。需要设计表示学生对象的Student类,并用LinkedList或ArrayList集合来管理可被数量的学生对象。另外还需要设计测试类Test来验证StudentManager的功能。 4. 编程实现:设计学生管理类StudentManager(用Set集合管理学生对象)。具体功能 要求同第3题,但是需要用Set的实现类(比如HashSet、TreeSet)管理学生对象。

泛型与集合框架

泛型与集合框架 1.实验目的 1、掌握LinkedList类和Collections类提供的用于排序和查找链表中 的数据的方法 2、掌握用散列映射来存储数据 3、掌握TreeSet类的使用 2.实验内容 1、根据附录里的源代码,完成代码填空,使程序能够运行得出结果。 1)实验1 按身高排序 2)实验2 英汉小字典 3)实验3 演出节目单 4)实验4输出args[]中的单词 2、设计编写程序完成以下任务。 1)仿照实验1编写TV类,要求通过实现Comparable接口规定该类的对象的大小关系,按price值得大小确定大小关系,即电视机按其价格确定之间的大小关系。 2)从控制台输入若干个单词(输入回车结束)放入集合中,将这些单词排序后(忽略大小写)打印出来。 知识点:List接口的实现类、String常用方法 3)请使用LinkedList来模拟一个队列(先进先出的特性): (1)拥有放入对象的方法void put(Object o) (2)取出对象的方法Object get() (3)判断队列当中是否为空的方法boolean isEmpty();并且,编写测试代码,验证你的队列是否正确。 知识点:List接口的实现类LinkedList常用方法 4)在一个列表中存储以下元素:apple,grape,banana,pear (1)返回集合中的最大的和最小的元素 (2)将集合进行排序,并将排序后的结果打印在控制台上 知识点:Collections类中的方法 3.实验步骤 略 4.评分标准 1.A——内容功能完善,编程风格好,人机接口界面好; 2.B——内容功能完善,编程风格良好,人机接口界面良好; 3.C——完成必做内容;

java集合框架(习题与答案)资料

java 集合框架(习题) 集合框架 Key Point * Collection 接口、Set 接口、List 接口基本操作 * List 接口及其实现类 * Set 接口及其实现类 * 迭代遍历 * Hash 算法与hashCode 方法 * Comparable 接口 * Map 接口及其实现类 * 遍历Map * 泛型 练习 1. 填空 Collection 接口的特点是元素是对象; List 接口的特点是元素有(有|无)顺序,可以(可以|不可以)重复; Set 接口的特点是元素无(有|无)顺序,不可以(可以|不可以)重复;Map 接口的特点是元素是键值对,其中值可以重复,键不可以重复。 2. (List)有如下代码 import java.util.*; public class TestList{ public static void main(String args[]){ List list = new ArrayList(); list.add(“Hello”); list.add(“World”); list.add(1, “Learn”); list.add(1, “Java”); printList(list); } public static void printList(List list){ for(Object obj:list){ String str=(String)obj; System.out.println(obj); } } } 要求: 1) 把//1 处的代码补充完整,要求输出list 中所有元素的内容 2) 写出程序执行的结果Hello java Learn World 3) 如果要把实现类由ArrayList 换为LinkedList,应该改哪里?ArrayList 和LinkedList 使用上有什么区别?实现上有什么区别?

实验13集合框架与泛型实验报告

实验13 集合框架与泛型 一、实验目的和要求 1. 了解Java集合框架的接口和实现类 2. 理解泛型类、泛型接口、泛型方法的特点 3. 掌握List接口及其实现类LinkedList、ArrayList 4. 了解Set接口及其实现类HashSet、TreeSet 5. 了解Map及其实现类HashMap、TreeMap 二、实验内容 1. 分析Java集合框架的接口和实现类的组成 2. 分析泛型类、泛型接口、泛型方法的特点 3. 编程实现:设计学生管理类StudentManager(用List集合管理学生对象) 4. 选作-编程实现:设计学生管理类StudentManager(用Set集合管理学生对象) 5. 选作-编程实现:设计学生管理类StudentManager(用Map管理学生对象) 三、实验步骤 1. 分析Java集合框架的接口和实现类的组成 请查阅书籍和Java帮助文档,说明Java集合框架的接口组成以及它们的继承关系,并针对每个接口给出具体的实现类。 答: 2. 分析泛型类、泛型接口、泛型方法的特点 请查阅书籍和Java帮助文档,举例说明泛型类、泛型接口、泛型方法的特点。 答: 3. 编程实现:设计学生管理类StudentManager(用List集合管理学生对象)。 StudentManager类的功能包括添加学生、查询学生、删除学生、统计学生成绩等。需要设计表示学生对象的Student类,并用LinkedList或ArrayList集合来管理可被数量的学生对象。另外还需要设计测试类Test来验证StudentManager的功能。 4. 编程实现:设计学生管理类StudentManager(用Set集合管理学生对象)。具体功能 要求同第3题,但是需要用Set的实现类(比如HashSet、TreeSet)管理学生对象。 5. 编程实现:设计学生管理类StudentManager(用Map管理学生对象)。具体功能要求

相关文档
最新文档