泛型应用 - 卡拉 OK(三)
文章来源:《Head First Java》修炼感悟。
上文说到,正当老白为编译错误焦头烂额时,事情有了转机。老白在 API 中找到了答案,终于弄清楚了 v3.0 编译错误的原因。 为了以后不会忘记,特地在这里留下记录方便随时翻看。
一、原来是泛型惹的「祸」
为了保证集合中数据安全,Java 5.0 后续版本增加了泛型特性,防止不同类型数据被放到同一个集合中。
先来看看 API 中关于 ArrayList 的定义:
可以看到,ArrayList 类声明使用了 <E>
这种方式来表示泛型,意思就是在创建列表对象时把 E
换做实际类型。比如前面我们使用 new
创建的 Song 列表对象,其实原型应该是这样的:
public class ArrayList<Song> extends AbstractList<Song> implements List<Song>, ...
再看看 ArrayList 的 add()
方法定义:
ArrayList 的 add()
方法同样使用了泛型,所以创建 Song 类型的列表只允许添加 Song 类型对象。
二、泛型应该这样用
其实 Collections.sort()
方法多处使用了泛型,来看看定义:
可以看到,Collections 的泛型被直接声明在 sort()
方法中,与 ArrayList 声明在类中有些不同。 sort()
声明使用 <T extends ...>
这样的方式表示 T 类型必须是继承自指定对象,这样做的目的就是对传入的方法参数进行严格限制,进一步保证数据类型安全。
sort()
的参数为 List<T>,方法描述中明确指出 T 必须实现 Comparable 接口。 Comparable 接口只有一个方法,来看看定义:
方法说明:
对当前对象和指定对象进行排序比较。如果当前对象小于、等于或大于指定对象时,分别返回负整数、零或正整数。
也就是说,Song 需要实现 Comparable 接口才能进行对比操作。
三、Song 实现 Comparable 接口
我们再来看看 v3.0 代码,很明显问题就出在下面这段代码中:
public void go() {loadSongs();System.out.println(tracks);// 曲目排序Collections.sort(tracks);System.out.println(tracks);
}
tracks
是一个 ArrayList 对象,保存了所有 Song 类型元素,因为 Song 对象没能实现 Comparable 接口,不满足 Collections.sort()
的声明,自然也就不会存在 compareTo()
方法,所以必然会报错。解决方式也很简单,只要实现接口就可以了。
接下来老白再次修改 Song:
/*** 文件:Song.java** 描述:歌曲信息类,用于保存歌曲名称、歌手等信息,* 并且实现了 Comparable 接口用于按曲目排序。* 版本:v4.0*/
public class Song implements Comparable<Song> {// 定义歌曲信息String title;String artist;String rating;String bpm;// 默认构造方法public Song() {}// 构造器,新建对象时传入歌曲信息public Song(String t, String a, String r, String b) {title = t;artist = a;rating = r;bpm = b;}// 实现接口方法// 返回负值、0 或者正数,表示小于,等于或者大于public int compareTo(Song s) {return title.compareTo(s.getTitle());}// 返回歌曲名称public String getTitle() {return title;}// 返回歌手名称public String getArtist() {return artist;}// 返回歌曲等级public String getRating() {return rating;}// 返回歌曲节拍public String toString() {return title;}
}
还记得那次的编译错误吧,当初传入 String 可以通过编译,而传入 Song 就会报错。 那是因为 String 已经实现了 Comparable 接口:
所以排序的流程就是,Collections.sort()
调用 Song 类中的 compareTo()
方法,而 Song 类的 compareTo()
会自动调用 String 类的 compareTo()
方法,并返回一个整数来决定谁更靠前。
尝试再次编译:
OK,编译成功,并且正确排序。
迎接新挑战
解决了按歌名排序的问题后,老白兴致不减,开始思考另一个问题:若是按照歌手名称排序又该如何做? 老白决定趁热打铁,准备去做这件事情。
《 上一篇 泛型应用 - 卡拉 OK(二) |
---|