ArrayList中的元素可以重复,ArrayList没有排序方法,要借助Collections中的sort()方法排序。
例如:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
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 }
上面代码可以将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类定义如下:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
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 }
对ArrayList<Song> songList进行排序的代码如下:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
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 }
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:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
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 }
运行结果:
程序修改成功,我们再讲解一下运用泛型的方法:
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!