Java面向对象程序设计(IDEA版) 课件 第10章泛型与集合_第1页
Java面向对象程序设计(IDEA版) 课件 第10章泛型与集合_第2页
Java面向对象程序设计(IDEA版) 课件 第10章泛型与集合_第3页
Java面向对象程序设计(IDEA版) 课件 第10章泛型与集合_第4页
Java面向对象程序设计(IDEA版) 课件 第10章泛型与集合_第5页
已阅读5页,还剩108页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

面向对象程序设计第10章泛型与集合

1泛型23主要内容面向对象程序设计(Java语言描述微课版基于IntelliJIDEA)集合框架List接口及实现类45Set接口及实现类Queue接口及实现类6案例:用集合存储、遍历员工记录7Map接口及实现类89Collections类案例:用Map统计单词数量面向对象程序设计10.1泛型泛型是类和接口的一种扩展机制,主要实现参数化类型机制。使用泛型,程序员可以编写更安全的程序。概述泛型是Java5引进的新特征,泛型被广泛应用在Java集合API中,在Java集合框架中大多数的类和接口都是泛型类型。回顾一下,我们在8.5节中定义了一个整数栈类IntStack,该类使用Integer作为栈的元素,这就限制了该类只能对Integer元素操作。10.1.1泛型类如果要使这个栈类更具有通用性,我们可以使用Object作为栈的元素,因为Object类是所有类的超类,所以Object可以引用任何对象类型。然而,这种做法无法提供类型的安全性,在进行类型转换时可能发生类型不匹配异常。使用泛型就可以提高类型安全性,因为,它可以使类型转换自动地、隐式地进行。所谓泛型(generics)就是带一个或多个类型参数(typeparameter)的类或接口。对于上述讨论的对象栈,可以使用泛型定义。10.1.1泛型类为了简单,下面先定义一个泛型Node类表示节点,类型参数T表示节点中存放的数据值类型。具体代码如程序12.1所示。publicclassNode<E>{privateEdata;//泛型成员,T可以是任何引用类型publicNode(){}//默认构造方法publicNode(EdataItem){//带参数构造方法this.data=dataItem;}publicEget(){//访问方法定义returndata;}程序10-1Node.javapublicvoidset(EdataItem){//修改方法定义this.data=dataItem;}//显示类型名publicvoidshowType(){ System.out.println("T的类型是:"+data.getClass().getName());}}泛型类型的使用与方法调用类似,方法调用需向方法传递参数,使用泛型需传递一个类型参数,即用某个具体的类型替换T。例如,如果要在Node对象中存放Integer对象,就需要在创建Node对象时为其传递Integer类型参数。10.1.1泛型类要实例化泛型类对象,也使用new运算符,但在类名后面需加上要传递的具体类型。Node<Integer>

intNode=newNode<Integer>();一旦创建了intNode对象,就可以调用set()方法设置其中的Integer对象,如下代码所示。

publicstaticvoidmain(String[]args){Node<Integer>intNode=newNode<Integer>();intNode.set(Integer.valueOf(999));System.out.println(intNode.get());intNode.showType();}由于编译器能够从上下文中推断出泛型参数的类型,所以从JavaSE7开始,在创建泛型类型时可使用菱形语法(diamond),即仅用一对尖括号(<>),上述创建intNode的语句可以写成:Node<Integer>intNode=newNode<>();10.1.1泛型类按照约定,类型参数名使用单个大写字母表示。常用的类型参数名有:E表示元素,K表示键,N表示数字,T表示类型,V表示值等。需要注意,泛型可能具有多个类型参数,但在类或接口的声明中,每个参数名必须是唯一的。与类一样,接口也可以声明为泛型接口,即接口也可以带参数,例如,下面的Readable接口使用泛型类型作为其read()方法的参数:publicinterfaceReadble<T>{voidread(Tt);}10.1.2泛型接口类实现这个接口有三种方法。

(1)第一个是指定类中的泛型类型。下面的具体类说它只处理Book。这使得它可以用一个Book参数声明read()方法:publicclassIntelligentRobotimplementsReadable<Book>{publicvoidread(Bookb){}}10.1.2泛型接口(2)下一种方法是创建一个泛型类。下面的具体类允许调用者指定泛型的类型:publicclassIntelligentRobot<U>implementsReadable<U>{publicvoidread(Ut){}}在本例中,类型参数可以被命名为任何名称,包括T。我们在例子中使用了U,这样就不会混淆T指的是什么。10.1.2泛型接口(3)最后一种方法是不使用泛型。这是编写代码的老方法。它产生一个编译器警告Readable是一个原始类型,但它能够编译。这里的read()方法有一个Object参数,因为泛型类型没有定义:publicclassIntelligentRobotimplementsReadable{publicvoidread(Objecto){}}10.1.2泛型接口泛型接口也可带有多个类型参数。下面的Entry是泛型接口,带两个类型参数。10.1.2泛型接口publicinterfaceEntry<K,V>{publicKgetKey();publicVgetValue();}publicclassPair<K,V>implementsEntry<K,V>{privateKkey;privateVvalue;publicPair(Kkey,Vvalue){//构造方法this.key=key;this.value=value;}程序10-2Pair.javapublicvoidsetKey(Kkey){this.key=key;}publicKgetKey(){returnkey;}publicvoidsetValue(Vvalue){this.value=value;}publicVgetValue(){returnvalue;}}下面语句创建两个Pair类实例:Pair<String,Integer>p1=newPair<>("twenty-two",22);Pair<String,String>p2=newPair<>("china","Beijing");泛型方法(genericmethod)是带类型参数的方法。类的成员方法和构造方法都可以定义为泛型方法。泛型方法的定义与泛型类型的定义类似,但类型参数的作用域仅限于声明的方法和构造方法内。泛型方法可以定义为静态的和非静态的。10.1.3泛型方法下面的MathUtils类中定义两个static的泛型方法swap()和compare()。swap()方法用于交换任何数组中两个元素(数组元素类型不是基本类型),compare()方法用于比较两个泛型类Pair对象的参数K和V是否相等。特别注意,对于泛型方法必须在方法返回值前指定泛型,如<K,V>。publicclassMathUtils{publicstatic<T>voidswap(T[]array,inti,intj){Ttemp=array[i];array[i]=array[j];array[j]=temp;}publicstatic<K,V>booleancompare(Pair<K,V>p1,Pair<K,V>p2){returnp1.getKey().equals(p2.getKey())&&p1.getValue().equals(p2.getValue());}程序10-3MathUtils.javapublicstaticvoidmain(String[]args){Integer[]numbers={1,3,5,7};MathUtils.swap(numbers,0,3);for(Integern:numbers){System.out.println(n+"");//输出:7351}Pair<Integer,String>p1=newPair<>(1,"apple");Pair<Integer,String>p2=newPair<>(2,"orange");//调用泛型方法booleansame=MathUpare(p1,p2);System.out.println(same);//输出:false}泛型类型本身是一个Java类型,就像java.lang.String和java.time.LocalDate一样,为泛型类型传递不同的类型参数会产生不同的类型。例如,下面list1和list2就是不同的类型对象。

List<Object>list1=newArrayList<Object>();List<String>list2=newArrayList<String>();10.1.4通配符(?)的使用这里List和ArrayList是泛型接口和泛型类。尽管String是Object的子类,但List<String>与List<Object>却没有关系,List<String>并不是List<Object>的子类型。因此,把一个List<String>对象传递给一个需要List<Object>对象的方法,将会产生一个编译错误。请看下面代码。10.1.4通配符(?)的使用publicstaticvoidprintList(List<Object>list){for(Objectelement:list){System.out.println(element);}}该方法的功能是打印传递给它的列表的所有元素。如果传递给该方法一个List<String>对象,将发生编译错误。如果要使上述方法可打印任何类型的列表,可将其参数类型修改为List<?>,如下所示:publicstaticvoidprintList(List<?>list){for(Objectelement:list){System.out.println(element);}}这里,问号(?)就是通配符,它表示该方法可接受元素是任何类型的List对象。10.1.4通配符(?)的使用publicclassWildCardDemo{publicstaticvoidprintList(List<?>list){ for(Objectelement:list){ System.out.println(element); }}程序10-4WildCardDemo.javapublicstaticvoidmain(String[]args){ varmyList=newArrayList<String>(); myList.add("cat"); myList.add("dog"); myList.add("horse");printList(myList);}有时需要限制传递给类型参数的类型种类,例如,要求一个方法只接受Number类或其子类的实例,这就需要使用有界类型参数(boundedtypeparameter)。10.1.5有界类型参数有界类型分为上界和下界,上界用extends指定,下界用super指定。上界用extends指定,例如,List<?extendsNumber>,Number或Number的子类型下界用super指定,例如,List<?superInteger>,Integer或Integer的超类型publicstaticdoublegetAverage(List<?extendsNumber>numberList){ vartotal=0.0; for(varnumber:numberList){ total+=number.doubleValue(); } returntotal/numberList.size();}程序10-5BoundedTypeDemo.javapublicstaticvoidmain(String[]args){

varintegerList=newArrayList<Integer>(); integerList.add(3); integerList.add(30); integerList.add(300); System.out.println(getAverage(integerList));//输出:111.0

vardoubleList=newArrayList<Double>(); doubleList.add(5.5); doubleList.add(55.5); System.out.println(getAverage(doubleList));//输出:30.5当实例化泛型类型时,编译器使用一种叫类型擦除(typeerasure)的技术转换这些类型。在编译时,编译器将清除类和方法中所有与类型参数有关的信息。类型擦除可让使用泛型的Java应用程序与之前不使用泛型类型的Java类库和应用程序兼容。10.1.6类型擦除例如,Node<Integer>被转换成Node,它称为源类型(rawtype)。源类型是不带任何类型参数的泛型类或接口名。这说明在运行时找不到泛型类使用的是什么类型。下面的操作是不可能的。publicclassMyClass<E>{publicstaticvoidmyMethod(Objectitem){if(iteminstanceofE){//编译错误…}

Eitem2=newE();//编译错误E[]iArray=newE[10];//编译错误Eobj=(E)newObject();//非检查的造型警告}}面向对象程序设计10.2集合框架在编写面向对象的程序时,经常要用到一组类型相同的对象。可以使用数组来集中存放这些类型相同的对象,但数组一经定义便不能改变大小。因此,Java提供了一个集合框架(collectionsframework),该框架定义了一组接口和类,使处理对象组更容易。集合框架集合是指集中存放一组对象的一个对象。集合相当于一个容器。集合能够帮助Java程序员轻松地管理对象。Java集合框架由两种类型构成,一个是Collection,另一个是Map。Collection对象用于存放一组对象,Map对象用于存放一组“关键字/值”的对象。Collection<E>接口是所有集合类型的根接口,它继承了Iterable<E>接口,它有三个子接口:Set接口、List接口和Queue接口。Collection接口定义了集合操作的常用方法。可以简单分为以下几类:基本操作、批量操作、数组操作和流操作。集合框架实现基本操作的方法添加元素、删除指定元素、返回集合中元素的个数、返回集合的迭代器对象。1.基本操作booleanadd(Ee):向集合中添加元素e。booleanremove(Objecto):从集合中删除指定的元素o。booleancontains(Objecto):返回集合中是否包含指定的元素o。booleanisEmpty():返回集合是否为空,即不包含元素。intsize():返回集合中包含的元素个数。Iteratoriterator():返回包含所有元素的迭代器对象。下面的方法可实现集合的批量操作。booleanaddAll(Collection<?extendsE>c):将集合c中的所有元素添加到当前集合中。booleanremoveAll(Collection<?>c):从当前集合中删除c中的所有元素。defaultbooleanremoveIf(Predicate<?superE>filter)booleancontainsAll(Collection<?>c):返回当前集合是否包含c中的所有元素。booleanretainAll(Collection<?>c):在当前集合中只保留指定集合c中的的元素,其他元素删除。

voidclear():将集合清空。

2.批量操作下面方法可以将集合元素转换成数组元素。Object[]toArray():返回包含集合中所有元素的对象数组。

<T>T[]toArray(T[]a):返回包含集合中所有元素的数组,返回数组的元素类型是指定的数组类型。3.数组操作设c是一个Collection对象,下面的代码将c中的对象转换成一个新的Object数组,数组的长度与集合c中的元素个数相同。Object[]a=c.toArray();面向对象程序设计10.3List接口及实现类List接口是Collection的子接口,它实现一种线性表的数据结构。存放在

List中的所有元素都有一个下标(从0开始),可以通过下标访问List中的元素。List中可以包含重复元素。List接口的实现类包括ArrayList、LinkedList、Vector和Stack。概述北京上海广州bigCities012List接口除继承Collection的方法外,还定义了一些自己的方法。使用这些方法可以实现定位访问、查找、迭代和返回子线性表。List的常用方法如下。10.3.1List的操作booleanadd(Ee):向集合中添加元素e。voidadd(intindex,Eelement):将指定元素插入到指定下标处。Eget(intindex):返回指定下标处的元素。Eset(intindex,Eelement):修改指定下标处的元素。static

<E>

List<E>

of​(E...

elements):返回包含任意数量元素的不可修改列表。该方法还接受单个数组作为参数。结果列表的元素类型将是数组的元素类型,列表的大小等于数组的长度。Eremove(intindex):删除指定下标处的元素。intindexOf(Objecto):查找指定对象第一次出现的位置。intlastIndexOf(Objecto):查找指定对象最后一次出现的位置。List<E>subList(intfrom,intto):返回从from到to元素的一个子线性表。10.3.1List的操作下面代码使用List的of()方法创建一个不可修改的List对象,对不可修改的对象调用修改方法将抛出运行时异常。List<String>nameList=List.of("赵","钱","孙","李");System.out.println(nameList);//输出:[赵,钱,孙,李]//nameList.add("周");//nameList.set(1,"吴");//nameList.remove("李");System.out.println(nameList.indexOf("孙"));//输出:2产生运行时异常ArrayList类实际上实现了一个变长的对象数组,其元素可以动态地增加和删除。它的定位访问时间是常量时间。10.3.2ArrayList类ArrayList的构造方法如下:publicArrayList()publicArrayList(Collectionc)publicArrayList(intinitialCapacity)下列代码创建一个ArrayList对象并向其中插入几个元素,并使用ArrayList的有关方法对它操作。varcities=newArrayList<String>();cities.add("北京");cities.add("上海");cities.add("广州");System.out.println(cities.size());cities.add(1,"伦敦");cities.set(1,"纽约");System.out.println(cities.contains("北京"));System.out.println(cities);System.out.println(cities.indexOf("巴黎"));遍历集合中的元素有多种方法:用简单的for循环、用增强的for循环和用Iterator迭代器对象。10.3.3遍历集合元素1.使用for循环使用for循环可以遍历集合中的每个元素。for(vari=0;i<cities.size();i++){System.out.print(cities.get(i)+"");}2.使用增强的for循环使用增强的for循环不但可以遍历数组的每个元素,还可以遍历集合中的每个元素。下面的代码打印集合的每个元素:for(varcity:cities){System.out.println(city);}10.3.3遍历集合元素上述代码的含义是:依次将集合cities中的每个对象存储到city变量中,然后打印输出。如果只是简单输出每个元素,可以调用集合对象的forEach()方法,给它传递一个System.out:println方法引用。cities.forEach(System.out::println);10.3.3遍历集合元素3.使用迭代器迭代器是一个可以遍历集合中每个元素的对象。调用集合对象的iterator()方法可以得到Iterator对象,再调用Iterator对象的方法就可以遍历集合中的每个元素。Iterator接口定义了如下3个方法。booleanhasNext():返回迭代器中是否还有对象。Enext():返回迭代器中下一个对象。voidremove():删除迭代器中的当前对象。10.3.3遍历集合元素Iterator使用一个内部指针,开始它指向第一个元素的前面。如果在指针的后面还有元素,hasNext()方法返回true。调用next()方法,指针将移到下一个元素,并返回该元素。remove()方法将删除指针所指的元素。假设myList是ArrayList的一个对象,要访问myList中的每个元素,可以按下列方法实现:Iteratoriterator=myList.iterator();//得到迭代器对象while(iterator.hasNext()){System.out.println(iterator.next());}使用Iterator也可以用for循环访问集合元素。for(Iteratoriterator=myList.iterator();iterator.hasNext();){System.out.println(iterator.next());}4.双向迭代器List还提供了listIterator()方法返回ListIterator对象。它可以从前后两个方向遍历线性表中元素,在迭代中修改元素以及获得元素的当前位置。ListIterator是Iterator的子接口,它不但继承了Iterator接口中的方法,还定义了自己的方法。10.3.3遍历集合元素booleanhasPrevious():是否还有前一个元素。Eprevious():返回前一个元素。voidremove():删除当前元素。voidset(Eo):修改当前元素。List<String>myList=List.of("北京","上海","广州","深圳"); ListIterator<String>iterator=myList.listIterator();while(iterator.hasNext()){iterator.next();}//从后向前访问列表每个元素while(iterator.hasPrevious()){ System.out.print(iterator.previous()+"");}程序10-8IteratorDemo.javajava.util.Arrays类提供了一个asList()方法,它实现将数组转换成List对象的功能,该方法的定义如下。publicstatic<T>List<T>asList(T…a)该方法提供了一个方便的从多个元素创建List对象的途径,它的功能与Collection接口的toArray()方法相反。10.3.4数组转换为List对象String[]str={"one","two","three","four"};List<String>list=Arrays.asList(str);//将数组转换为列表System.out.println(list);面向对象程序设计10.4Set接口及实现类Set接口是Collection的子接口,Set接口对象类似于数学上的集合概念,其中不允许有重复的元素。Set接口没有定义新的方法,只包含从Collection接口继承的方法。Set接口的常用实现类有:HashSet类、TreeSet类和LinkedHashSet类。概述HashSet类用散列方法存储元素,具有最好的存取性能,但元素没有顺序。HashSet类的构造方法有:10.4.1HashSet类HashSet类的构造方法有:HashSet()初始容量是16,默认装填因子是0.75。HashSet(Collectionc)HashSet(intinitialCapacity)varwords=newHashSet<String>();words.add("one");words.add("two");words.add("three");words.add("one");for(varw:words){System.out.print(w+"");//输出:onetwothree}使用Set对象的批量操作方法,可以实现标准集合代数运算。假设s1和s2是Set对象,下面的操作可实现相关的集合运算。10.4.2用Set对象实现集合运算s1.addAll(s2):实现集合s1与s2的并运算。s1.retainAll(s2):实现集合s1与s2的交运算。s1.removeAll(s2):实现集合s1与s2的差运算。s1.containAll(s2):如果s2是s1的子集,该方法返回true。设集合中存放的元素类型为Integer。为了计算两个集合的并、交、差运算而又不破坏原来的集合,可以通过下面代码实现。vars1=Set.of(1,2,3);vars2=Set.of(2,3,4);varunion=newHashSet<Integer>(s1);union.addAll(s2);//[1,2,3,4]varintersection=newHashSet<Integer>(s1);intersection.retainAll(s2);//[2,3]vardifference=newHashSet<Integer>(s1);difference.removeAll(s2);//[1]TreeSet实现一种树集合,它使用红-黑树为元素排序,添加到TreeSet中的元素必须是可比较的,即元素的类必须实现Comparable<T>接口。它的操作要比HashSet慢。

TreeSet类的默认构造方法创建一个空的树集合,其他构造方法如下。10.4.3TreeSet类TreeSet(Collectionc)TreeSet(Comparatorc)varts=newTreeSet<String>();//TreeSet中的元素将自动排序vars=newString[]{"one","two","three","four"};for(vari=0;i<s.length;i++){ts.add(s[i]);}System.out.println(ts);//输出:[four,one,three,two]

从输出结果中可以看到,这些字符串是按照自然顺序排序的。程序10-9TreeSetDemo.java创建TreeSet类对象时如果没有指定比较器对象,集合中的元素按自然顺序排列。所谓自然顺序(naturalorder)是指集合对象实现了Comparable<T>接口的compareTo()方法,对象则根据该方法排序。如果试图对没有实现Comparable<T>接口的集合元素排序,将抛出ClassCastException异常。10.4.4对象顺序另一种排序方法是创建TreeSet对象时指定一个比较器对象,这样,元素将按比较器的规则排序。如果需要指定新的比较规则,可以定义一个类实现Comparator<T>接口,然后为集合提供一个新的比较器。字符串的默认比较规则是按字母顺序比较。假如按反顺序比较,可以定义一个类实现Comparator<T>接口,然后用该类对象作为比较器。下面的程序就可以实现字符串的降序排序:10.4.4对象顺序String[]s={"China","England","France","America","Russia",};varts=newTreeSet<String>();for(vari=0;i<s.length;i++){ts.add(s[i]);}System.out.println(ts);//按自然顺序输出程序10-10DescSortDemo.javats=newTreeSet<String>(

newComparator<String>(){

@Overridepublicintcompare(Stringa,Stringb){returnpareTo(a);}});

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

ts.add(s[i]);}System.out.println(ts);创建一个比较器对象面向对象程序设计10.5Queue接口及实现类Queue接口是Collection的子接口,它是以先进先出(First-In-First-Out,FIFO)的方式排列其元素,一般称为队列(queue)。Deque接口是Queue接口的子接口,它的对象实现双端队列,ArrayDeque和LinkedList是它的两个实现类。PriorityQueue实现的是一种优先队列,优先队列中元素的顺序是根据元素的值排列的。概述Queue接口除了提供Collection的操作外,还提供了插入、删除和检查操作。10.5.1Queue接口和Deque接口Deque接口实现双端队列,它支持从两端插入和删除元素,它同时实现了Stack和Queue的功能。Deque接口中定义的基本操作方法,如表12-1所示。Deque接口常用方法操作类型队首元素操作队尾元素操作插入元素addFirst(e)offerFirst(e)addLast(e)offerLast(e)返回元素getFirst()peekFirst()getLast()peekLast()删除元素removeFirst()pollFirstremoveLast()pollLast()Deque的常用实现类包括ArrayDeque类和LinkedList类,前者是可变数组的实现,后者是线性表的实现。LinkedList类比ArrayDeque类更灵活,它实现了线性表的所有操作,其中可以存储null元素,但ArrayDeque对象不能存储null。10.5.2ArrayDeque类和LinkedList类可以使用增强的for循环和迭代器访问Deque的元素。使用增强的for循环和迭代器访问Deque的元素。varqueue=newArrayDeque<String>();queue.add("s1");queue.add("s2");for(Stringstr:queue){System.out.print(str+"");//输出:s1s2}使用迭代器访问Deque元素代码如下:for(Iterator<String>iter=queue.iterator();iter.hasNext();){System.out.print(iter.next()+"");//输出:s1s2}可以使用LinkedList的无参数构造方法创建一个空的链表,也可以使用LinkedList(Collectionc)构造方法用集合c中的元素创建一个链表。LinkedList类的应用创建LinkedList对象不需要指定初始容量。LinkedList类除实现List接口中方法外,还定义了addFirst()、getFirst()、removeFirst()、addLast()、getLast()和removeLast()等方法。注意,LinkedList同时实现了List接口和Queue接口。下面程序使用LinkedList类实现一个10秒倒计时器。程序首先将10到1存储到队列中,然后从10到1每隔1秒钟输出一个数。inttime=10;varqueue=newLinkedList<Integer>();for(vari=time;i>0;i--){queue.add(i);//将10到1存储到队列中}while(!queue.isEmpty()){System.out.println(queue.remove());//从队列中删除一个元素try{Thread.sleep(1000);//当前线程睡眠1秒钟}catch(InterruptedExceptione){e.printStackTrace();}}程序10-12CountDown.java集合实现类的构造方法一般都接受一个Collection对象,这使得可以将Collection转换成不同类型的集合。下面是一些实现类的构造方法:10.5.3集合转换publicArrayList(Collectionc)publicHashSet(Collectionc)publicLinkedList(Collectionc)下面代码将一个Queue对象转换成一个List:Queue<String>queue=newLinkedList<>();queue.add("hello");queue.add("world");List<String>myList=newArrayList(queue);以下代码又可以将一个List对象转换成Set对象:Set<String>set=newHashSet(myList);10.5.3集合转换面向对象程序设计10.6案例:用集合存储、遍历员工记录设计一个员工记录类型Employee,该记录只用来存储数据,它包括员工号(id)、姓名(name)、出生日期(birthday)和工资(salary)等4个字段。程序创建多个员工记录并将其存储到集合中,员工号相同的记录视为同一个对象,不重复存储,遍历集合将员工信息按员工号升序输出到控制台。用集合存储、遍历员工记录(1)首先定义员工记录类型Employee。(2)创建HashSet集合对象,使用泛型限定只存储员工对象。(3)创建若干员工对象,把员工对象添加到集合。(4)遍历集合,输出员工信息到控制台。(5)修改员工类使其实现Comparable<Employee>接口,让对象拥有自然序。实现接口中的compareTo抽象方法,按员工号升序排序员工对象。(6)定义TreeSet集合,将HashSet集合中的员工对象添加到此TreeSet集合中,实现员工对象按员工号升序存储。设计思路publicrecordEmployee(intid,Stringname,LocalDatebirthday,doublesalary)implementsComparable<Employee>{@OverridepublicintcompareTo(Employeeemployee){ if(id()>employee.id()) return1; elseif(id()<employee.id()) return-1; else return0;} }程序10-13Employee.javavaremp1=newEmployee(105,"张三",LocalDate.of(1980,12,15),6000);varemp2=newEmployee(102,"李四",LocalDate.of(2002,8,28),4000);varemp3=newEmployee(108,"王五",LocalDate.of(2001,10,10),4800);

varemp4=newEmployee(102,"李四",LocalDate.of(2002,8,28),4000);Set<Employee>employeeSet=newHashSet<Employee>();employeeSet.add(emp1);employeeSet.add(emp2);employeeSet.add(emp3);employeeSet.add(emp4);程序10-14EmployeeSet.javaSystem.out.println("未排序的员工信息:");for(Employeeemp:employeeSet){System.out.println(emp);}Set<Employee>employeeTreeSet=newTreeSet<Employee>(employeeSet);System.out.println("按id号升序排序结果:");for(Employeeemp:employeeTreeSet){System.out.println(emp);

}面向对象程序设计10.7Map接口及实现类Map是用来存储“键/值”对的对象。在Map中存储的关键字和值都必须是对象,并要求关键字是唯一的,而值可以重复。Map接口常用的实现类有HashMap类、TreeMap类、Hashtable类和LinkedHashMap类。概述Map接口是所有映射的根接口。映射实际上是“键/值”对的集合,比如学号和姓名的对照表。学号是键,姓名是值。Map接口的操作可分为两类:基本操作和批量操作。10.7.1Map接口1.基本操作Map接口实现基本操作的方法包括添加“键/值”对、删除“键/值”、返回指定键的值对等。publicVput(Kkey,Vvalue):向映射对象中添加一个“键/值”对。publicVremove(Objectkey):从映射中删除指定键的“键/值”对。publicVget(Objectkey):返回指定键的值。10.7.1Map接口publicbooleancontainsKey(Objectkey):返回映射中是否包含指定的键。publicbooleancontainsValue(Objectvalue):返回映射中是否包含指定的值。defaultVreplace(Kkey,Vvalue):若指定的“键/值”对存在于映射中,用指定的“键/值”对替换之。defaultvoidforEach(BiConsumer<?superK,?superV):对映射中的每项执行一次动作,直到所有项处理完或发生异常。publicintsize():返回映射中包含的“键/值”对个数。publicbooleanisEmpty():返回映射是否为空。2.批量操作publicvoidputAll(Map<?extendsK,?extendsV>map):将参数map中的所有“键/值”对添加到映射中。publicvoidclear():删除映射中所有“键/值”对。publicSet<K>keySet():返回由键组成的Set对象。publicCollection<V>values():返回由值组成的Collection对象。publicSet<Map.Entry<K,V>>entrySet():返回包含Map.Entry<K,V>的一个Set对象。10.7.1Map接口3.不可改变的MapMap接口提供了下面几个方便的方法用于创建不可改变的Map对象。static

<K,​V>

Map<K,​V>

of​(K

k1,V

v1):返回包含单个映射的不可修改映射。static

<K,​V>

Map<K,​V>

of​(K

k1,V

v1,K

k2,V

v2):返回一个包含两个映射的不可修改映射。其中k1、k2是键,v1、v2是值。另外还定义了包含多个键值对的of()方法,最多可有10个键值对。10.7.1Map接口用上述方法创建的Map对象是不可改变的(unmodifiable),即不能添加、删除或更新键和值。Map<Integer,String>nums=Map.of(1,"one",2,"two",3,"three");for(Integerkey:nums.keySet()){ System.out.println(key+","+nums.get(key));}//nums.replace(1,"numberone");//nums.remove(2);//nums.put(4,"four");10.7.1Map接口HashMap类以散列方法存放“键/值”对,它的不带参数的构造方法创建一个空的映射对象,下面是带参数的构造方法。HashMap(intcapacity):用指定初始容量和默认装填因子创建一个映射对象。HashMap(Mapm):用指定的映射对象m创建一个新的映射对象。10.7.2HashMap类下面程序使用HashMap存放几个国家名称和首都名称对照表,国家名称作为键,首都名作为值,然后对其进行各种操作。String[]country={"中国","印度","澳大利亚",

"德国","古巴","希腊","日本"};String[]capital={"Beijing","NewDelhi","Canberra","Berlin","Havana","Athens","Tokyo"};Map<String,String>m=newTreeMap<>();

for(inti=0;i<country.length;i++){m.put(country[i],capital[i]);

}程序10-15MapDemo.javaSystem.out.println("共有"

+m.size()+"个国家:");System.out.println(m);System.out.println(m.get("中国"));//Beijingm.remove("日本");Set<String>coun=m.keySet();

for(Objectc:coun)System.out.print(c+"");TreeMap类实现了SortedMap接口,它保证Map中的“键/值”对按关键字升序排序。TreeMap类的构造方法如下。TreeMap():创建根据键的自然顺序排序的空的映射。TreeMap(Comparatorc):根据给定的比较器创建一个空的映射。

TreeMap(Mapm):用指定的映射m创建新的映射,根据键的自然顺序排序。10.7.3TreeMap类对程序12.15的例子,如果希望按国家名的顺序输出Map对象,仅将HashMap改为TreeMap即可。输出结果将为:{Australia=堪培拉,China=北京,Cuba=哈瓦那,Germany=柏林,Greece=雅典,India=新德里,Japan=东京}在Map对象键上迭代可以使用增强的for循环,也可以使用迭代器,如下所示。for(Stringkey:map.keySet()){System.out.println(key);}10.7.4在Map键和值上迭代如果使用迭代器,可通过下面方式实现:for(Iterator<String>it=map.keySet().iterator();it.hasNext();){if(it.next().equals("Japan")){it.remove();}}在值上迭代与在键上迭代类似。可以使用values()方法得到值的Collection对象,然后在其上迭代。for(Integervalue:map.values()){System.out.println(value);}10.7.4在Map键和值上迭代要迭代映射中的“键/值”对,可使用entrySet()方法返回Set<Map.Entry<K,V>>集合。Map.Entry是Map接口定义的一个内部接口,其中定义了3个抽象方法,分别为getKey()、getValue()和setValue()方法。Hashtable类是Java早期版本提供的一个存放“键/值”对的实现类,它实现了一种散列表,现在也属于集合框架。Hashtable类的方法都是同步的,因此它是线程安全的。10.7.5Hashtable类和Enumeration接口任何非null对象都可以作为散列表的关键字和值。但是要求作为关键字的对象必须实现hashCode()方法和equals()方法,以使对象的比较成为可能。下面代码创建一个包含数字的Hashtable对象,使用数字作为键,数字的英文名称作为值。varnumbers=newHashtable<Integer,String>();numbers.put(Integer.valueOf(1),"one");numbers.put(Integer.valueOf(2),"two");numbers.put(Integer.valueOf(3),"three");要检索其中的数字描述,可以使用下面代码:Strings=numbers.get(2);//返回键为2的值if(s!=null){System.out.println("2="+s);//输出:2=two}面向对象程序设计10.8Collections类java.util.Collections类是工具类,它提供了若干static方法实现集合对象的操作。这些操作大多对List操作,主要包括下面几个方面:排序、重排、查找、求极值以及常规操作等。Collections类对List对象的元素排序使用sort()方法,它有下面两种格式:static<T>voidsort(List<T>list)static<T>voidsort(List<T>list,Comparator<?superT>c)1.元素排序该方法实现对List的元素按升序或指定的比较器顺序排序。该方法使用优化的归并排序算法,因此排序是快速的和稳定的。在排序时如果没有提供Comparator<T>对象,则要求List中的对象必须实现Comparable<T>接口。下面代码对字符串List倒序排序。Listnames=Arrays.asList("peter","anna","mike","tom");Collections.sort(names,newComparator<String>(){

@Overridepublicintcompare(Stringa,Stringb){ returnpareTo(a); }});for(Stringname:names){System.out.print(name+"");//输出:tompetermikeanna}使用binarySearch()方法可以在已排序的List中查找指定的元素

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论