泛型1

ArrayList中的元素可以重复,ArrayList没有排序方法,要借助Collections中的sort()方法排序。

例如:

 1 import java.util.*;
 2 import java.io.*;
 3 
 4 public class Jukebox1{
 5     
 6     ArrayList<String> songList = new ArrayList<String>();
 7     
 8     public static void main(String[] args){
 9         new Jukebox1().go();
10     }
11     
12     public void go(){
13         getSongs();
14         System.out.println(songList);
15     }
16     
17     void getSongs(){
18         try{
19             File file = new File("SongList.txt");
20             BufferedReader reader = new BufferedReader(new FileReader(file));
21             String line = null;
22             while((line = reader.readLine()) != null){
23                 addSong(line);
24             }
25         }catch(Exception e){
26             e.printStackTrace();
27         }
28     }
29     
30     void addSong(String lineToParse){
31         String[] tokens = lineToParse.split("/");
32         songList.add(tokens[0]);
33     }
34 }
View Code

上面代码可以将SongList.txt文件中的元素按照歌名排序,并输出。

排序方法是:Collections.sort(songList);//借助Collections的sort()方法将songList排序

输出:System.out.println(songList);//String类中toString()方法重写,所以可以输出歌名。

将上述代码文件和SongList.txt文件放在同一个文件夹下,SongList.txt文件内容如下:

Communication/The Cardigans

Black Dog/Led Zeppelin

Dreams/Van Halen

Comfortably Numb/Pink Floyd

Beth/Kiss

倒退噜/黄克林

上面文件内容,/前面是歌名,/后面是歌手名。

ArrayList<Stirng> songList = new ArrayList<String>();//没有问题,可以借助Collections的sort()方法排序。

如果使用我们自己创建的类类型会怎样?

ArrayList<Song> songList = new ArrayList<Song>();

Song类定义如下:

 1 class Song {
 2     String title;//歌名
 3     String artist;//作者
 4     String rating;
 5     String bpm;
 6     
 7     Song(String t, String a, String r, String b){
 8         title = t;
 9         artist = a;
10         rating = r;
11         bpm = b;
12     }
13     
14     public String getTitle(){
15         return title;
16     }
17     
18     public String getArtist(){
19         return artist;
20     }
21     
22     public String getRating(){
23         return rating;
24     }
25     
26     public String getBpm(){
27         return bpm;
28     }
29     
30     public String toString(){
31         return title;
32     }
33 }
View Code

对ArrayList<Song> songList进行排序的代码如下:

 1 import java.util.*;
 2 import java.io.*;
 3 
 4 public class Jukebox3{
 5     
 6     ArrayList<Song> songList = new ArrayList<Song>();
 7     
 8     public static void main(String[] args){
 9         new Jukebox3().go();
10     }
11     
12     public void go(){
13         getSongs();
14         System.out.println(songList);
15         Collections.sort(songList);
16         System.out.println(songList);
17     }
18     
19     void getSongs(){
20         try{
21             File file = new File("SongList1.txt");
22             BufferedReader reader = new BufferedReader(new FileReader(file));
23             String line = null;
24             while((line = reader.readLine()) != null){
25                 addSong(line);
26             }
27         }catch(Exception e){
28             e.printStackTrace();
29         }
30     }
31     
32     void addSong(String lineToParse){
33         String[] tokens = lineToParse.split("/");
34         
35         Song nextSong = new Song(tokens[0], tokens[1], tokens[2], tokens[3]);
36         songList.add(nextSong);
37     }
38 }
View Code

SongList1.txt文件如下:

Communication/The Cardigans/5/80
Black Dog/Led Zeppelin/4/84
Dreams/Van Halen/6/120
Comfortably Numb/Pink Floyd/5/110
Beth/Kiss/4/100
倒退噜/黄克林/5/90

编译之后会报错:

ArrayList<String> 和 ArrayList<Song>有什么差异呢?

从API说明文件找到java.util.Collections下的sort():

                                                                                                 图1

看不懂了吧?别急,作为初学者,我也看不懂,慢慢来。 这里还有一个:

                                                                                                 图2

我们定义一个ArrayList如下:

ArrayList<String> songList = new ArrayList<String>();

ArrayList前后尖括号中的内容要一样,这就相当于告诉编译器,SongList这个ArrayList中能存储String类类型。就是这么简单。

图1:一步一步看

<T extends Comparable<? super T>>

T extends Comparable 表明T必须Comparable,这个字很重要。

<? super T> 代表Comparable的类型参数必须是T或T的父类型。

void sort(List<T> list)

List<T>:仅能传入Comparable的参数化类型的list

                                                                           图3

图3查看String说明,String并没有extends(继承)Comparable,只是implements(实现)Comparable。

所以上面的字很重要,以泛型的观点来说,extend代表extend或implement。

因此String类implement(实现)Comparable,就相当于泛型中extend(继承)Comparable。

于是乎,我们就想到,我们的Song类没有extend也没有implement过Comparable。所以编译器翻脸不认人,ArrayList<Song> songList就不能使用Collections.sort()

下面,我们想办法,怎么让Collections.sort()认可我们的Song类,查看Comparable:

                                                                            图4

Comparable<T>原来是接口,再看它中的方法:

                                                                             图5

只有comareTo()一个方法,这就好办,让我们的Song类implement(实现)Comparable:

 1 class Song implements Comparable<Song>{
 2     String title;
 3     String artist;
 4     String rating;
 5     String bpm;
 6     
 7     //比较两个title大小
 8     public int compareTo(Song s){
 9         return title.compareTo(s.getTitle());
10     }
11     
12     Song(String t, String a, String r, String b){
13         title = t;
14         artist = a;
15         rating = r;
16         bpm = b;
17     }
18     
19     public String getTitle(){
20         return title;
21     }
22     
23     public String getArtist(){
24         return artist;
25     }
26     
27     public String getRating(){
28         return rating;
29     }
30     
31     public String getBpm(){
32         return bpm;
33     }
34     
35     public String toString(){
36         return title;
37     }
38 }
View Code

运行结果:

 

程序修改成功,我们再讲解一下运用泛型的方法:

1.使用定义在类声明的类型参数,简单来说就是,把泛型定义在class上:

public class ArrayList<E> extends AbstractList<E> ...{//这个是图2中的内容,可以查看API,里面有一个add()方法

    public bolean add(E o)

}

这表明,在ArrayList<String> songList = new ArrayList<String>();//这里已经把上面的E替换成了String类类型。

songList.add(a);//这里的a必须是String类类型,即声明String a;,否则编译器会报错。

2.使用为定义在类声明的类型参数,换句话说,除了上面定义在类上的泛型以外,其他的都是。比如:

定义在方法上的泛型:

public <T extends Animal> void takeThing(ArrayList<T> list)//如果类本身没有使用泛型参数,我们可以在返回类型之前指定泛型

<T extends Animal>,我们的老朋友又和我们见面了,只要是extend或implement过的T都可以。

如果Animal是类,Animal,和extend它的子类(Dog,Cat...),甚至如果Animal是接口,那么implement它的类都可以。

 

在泛型中什么时候用E,什么时候用T?

这个问题的回答是甲鱼的臀部-——龟腚(规定)。习惯的用法除了与集合有关的用E(表示element元素),其余都用T,就这么简单。

 

说完了。

有个问题,public <T extends Animal> void takeThing(ArrayList<T> list) 和 public void takeThing(ArrayList<Animal> list)有什么区别?

第一个就不说了,第二个代表只有传入ArrayList<Animal>的变量是合法的,传入ArrayList<Dog>的变量是非法的。

OVER!

 

posted @ 2017-07-14 15:51  lanshanxiao  阅读(271)  评论(0)    收藏  举报