通过示例了解 Java 枚举方法实现
Understanding Java Enum Methods Implementation through an Example
所以,我现在正在和几个人一起为学校做一个项目,其中一个人提交了一些我真的很难理解的代码。该项目的基础是创建一个包含歌曲、专辑和播放列表的音乐库。特别是这些播放列表 arraylists
的歌曲需要不同的排序方式,因此他实现了排序比较器。他使用枚举来做到这一点,我从仅实例的角度理解枚举来表示项目。喜欢
public enum Suit {
SPADES, CLUBS, HEARTS, DIAMONDS
}
代表一张牌的不同花色。我还了解到您可以在枚举旁边声明方法,他看起来就是这么做的。这里是属性声明区和构造函数:
public class Playlist implements Comparator<Song>{
private TotalTime aTotalTime;
private String aName;
private ArrayList<Song> playList;
private Comparator<Song> aComparator;
private enum Method{
SortByTitle(new Comparator<Song> () {
@Override
public int compare(Song o1, Song o2) {
// TODO Auto-generated method stub
return o2.getTitle().compareTo(o1.getTitle());
}
}),
SortByArtist(new Comparator<Song>() {
@Override
public int compare(Song o1, Song o2) {
// TODO Auto-generated method stub
return o2.getExpectedTags().getArtist().compareTo(o1.getExpectedTags().getArtist());
}
}),
SortByLength(new Comparator<Song>() {
@Override
public int compare(Song o1, Song o2) {
// TODO Auto-generated method stub
return o2.getTotalSeconds()-o1.getTotalSeconds();
}
});
private Comparator<Song> comparator;
Method(Comparator<Song> pComparator){
comparator = pComparator;
}
public Comparator<Song> getComparator(){
return this.comparator;
}
}
// constructor that initializes the the playlist.
public Playlist(String pName,Method aMethod) {
aName = new String(pName);
playList = new ArrayList<Song>();
this.aComparator = aMethod.getComparator();
}
}
我可以模糊地理解这里发生的事情:我们从调用 aMethod.getComparator()
的构造函数开始,aMethod
是枚举实例,然后是 aMethod.getComparator()
return 是 this.comparator
对象,它本身在上面三行中声明为 private Comparator<Song> comparator
。从我的角度来看,看起来它每次都会 return 私有 comparator
对象,而不是实际更改 Comparable
接口的排序方法。任何解析所有这些的帮助将不胜感激。
您的分析是正确的。这 class 似乎很奇怪。突出的几点:
- 为什么播放列表是歌曲的比较器?允许使用方法对播放列表进行排序而不是传递构造可能更有意义。
- 提供的方法对播放列表中歌曲的顺序没有影响。
- 方法枚举可能不应该是私有的。
可能值得重新审视项目中组件的范围。
- 什么是播放列表?如果歌曲顺序改变了,是否是不同的播放列表?
- 是否应该由播放列表来决定如何播放播放列表中的歌曲?
只看枚举定义。
枚举定义定义了 3 个实际枚举:SortByTitle
、SortByLength
和 SortByArtist
- 这些是您对该枚举的 SPADE, HEARTS, DIAMONDS, CLUBS;
。对于每个值,它们都使用 non-zero-length 构造函数进行初始化,传递的对象是比较器的自定义实现,但暂时忘记所有这些。
枚举值的枚举(呵呵)到此结束。为什么?因为分号.
但是枚举定义还没有结束;然后我们得到 private Comparator<Song> comparator;
.
请注意,每个单独的枚举值都有该字段的副本。枚举的每个值本身就是该枚举所代表的 'class' 的一个实例。这里的关键点是该字段包含 SortByArtist
、SortByLength
等不同的比较器
因此,Method.SortByArtist.getComparator();
returns Method
'class' 实例的那个字段的值(枚举基本上是 classes,高度有限的构造;每个值只有一个实例,所以这里有 3 个实例)。这与 SortByLength
实例的该字段的值不同。
其余只是匿名内classes.
这是有效的java,我想应该很明显了吧?
class StringByLengthComparator implements Comparator<String> {
public int compare(String a, String b) {
return a.length() - b.length();
}
}
...
Comparator<String> c = new StringByLengthComparator();
但是我们可以用 java 中更少的字符来写,使用概念 'anonymous inner classes'。当您创建 class 然后打算只使用此定义一次,然后再也不会使用它时,这会起作用。假设此 'Comparator c = ...;' 行是整个代码库中唯一您要按名称提及 StringByLengthComparator
的地方。那么:
Comparator<String> c = new Conmparator<String>() {
public int compare(String a, String b) {
return a.length() - b.length();
}
};
看起来很古怪,但这意味着 完全一样的东西。一个区别是这个 class,它仍然存在,没有命名为 StringByLengthComparator
,但它有一个随机名称,您不必担心并且永远不会使用。不过没关系 - 毕竟,这是我们唯一会用到这个东西的地方。
Java lambdas.
请注意,您可以使用 lambda 语法使此 更短:
Comparator<String> c = (a, b) -> a.length() - b.length();
仍然意味着同样的事情(好吧,你得到的对象不再存在,只有当你做了非常愚蠢的事情时才有意义,比如依赖它的对象标识哈希码,或者锁定比较器本身,这些都是所有疯狂的事情都要做。所以如果你不做任何疯狂的事情,那就是一回事。
这就是代码的作用。这与首先定义 3 个 class 没有什么不同,每个实现 Comparable<Song>
,然后将 new SongsByLengthComparer()
作为表达式作为第一个参数传递。
所以,我现在正在和几个人一起为学校做一个项目,其中一个人提交了一些我真的很难理解的代码。该项目的基础是创建一个包含歌曲、专辑和播放列表的音乐库。特别是这些播放列表 arraylists
的歌曲需要不同的排序方式,因此他实现了排序比较器。他使用枚举来做到这一点,我从仅实例的角度理解枚举来表示项目。喜欢
public enum Suit {
SPADES, CLUBS, HEARTS, DIAMONDS
}
代表一张牌的不同花色。我还了解到您可以在枚举旁边声明方法,他看起来就是这么做的。这里是属性声明区和构造函数:
public class Playlist implements Comparator<Song>{
private TotalTime aTotalTime;
private String aName;
private ArrayList<Song> playList;
private Comparator<Song> aComparator;
private enum Method{
SortByTitle(new Comparator<Song> () {
@Override
public int compare(Song o1, Song o2) {
// TODO Auto-generated method stub
return o2.getTitle().compareTo(o1.getTitle());
}
}),
SortByArtist(new Comparator<Song>() {
@Override
public int compare(Song o1, Song o2) {
// TODO Auto-generated method stub
return o2.getExpectedTags().getArtist().compareTo(o1.getExpectedTags().getArtist());
}
}),
SortByLength(new Comparator<Song>() {
@Override
public int compare(Song o1, Song o2) {
// TODO Auto-generated method stub
return o2.getTotalSeconds()-o1.getTotalSeconds();
}
});
private Comparator<Song> comparator;
Method(Comparator<Song> pComparator){
comparator = pComparator;
}
public Comparator<Song> getComparator(){
return this.comparator;
}
}
// constructor that initializes the the playlist.
public Playlist(String pName,Method aMethod) {
aName = new String(pName);
playList = new ArrayList<Song>();
this.aComparator = aMethod.getComparator();
}
}
我可以模糊地理解这里发生的事情:我们从调用 aMethod.getComparator()
的构造函数开始,aMethod
是枚举实例,然后是 aMethod.getComparator()
return 是 this.comparator
对象,它本身在上面三行中声明为 private Comparator<Song> comparator
。从我的角度来看,看起来它每次都会 return 私有 comparator
对象,而不是实际更改 Comparable
接口的排序方法。任何解析所有这些的帮助将不胜感激。
您的分析是正确的。这 class 似乎很奇怪。突出的几点:
- 为什么播放列表是歌曲的比较器?允许使用方法对播放列表进行排序而不是传递构造可能更有意义。
- 提供的方法对播放列表中歌曲的顺序没有影响。
- 方法枚举可能不应该是私有的。
可能值得重新审视项目中组件的范围。
- 什么是播放列表?如果歌曲顺序改变了,是否是不同的播放列表?
- 是否应该由播放列表来决定如何播放播放列表中的歌曲?
只看枚举定义。
枚举定义定义了 3 个实际枚举:SortByTitle
、SortByLength
和 SortByArtist
- 这些是您对该枚举的 SPADE, HEARTS, DIAMONDS, CLUBS;
。对于每个值,它们都使用 non-zero-length 构造函数进行初始化,传递的对象是比较器的自定义实现,但暂时忘记所有这些。
枚举值的枚举(呵呵)到此结束。为什么?因为分号.
但是枚举定义还没有结束;然后我们得到 private Comparator<Song> comparator;
.
请注意,每个单独的枚举值都有该字段的副本。枚举的每个值本身就是该枚举所代表的 'class' 的一个实例。这里的关键点是该字段包含 SortByArtist
、SortByLength
等不同的比较器
因此,Method.SortByArtist.getComparator();
returns Method
'class' 实例的那个字段的值(枚举基本上是 classes,高度有限的构造;每个值只有一个实例,所以这里有 3 个实例)。这与 SortByLength
实例的该字段的值不同。
其余只是匿名内classes.
这是有效的java,我想应该很明显了吧?
class StringByLengthComparator implements Comparator<String> {
public int compare(String a, String b) {
return a.length() - b.length();
}
}
...
Comparator<String> c = new StringByLengthComparator();
但是我们可以用 java 中更少的字符来写,使用概念 'anonymous inner classes'。当您创建 class 然后打算只使用此定义一次,然后再也不会使用它时,这会起作用。假设此 'Comparator c = ...;' 行是整个代码库中唯一您要按名称提及 StringByLengthComparator
的地方。那么:
Comparator<String> c = new Conmparator<String>() {
public int compare(String a, String b) {
return a.length() - b.length();
}
};
看起来很古怪,但这意味着 完全一样的东西。一个区别是这个 class,它仍然存在,没有命名为 StringByLengthComparator
,但它有一个随机名称,您不必担心并且永远不会使用。不过没关系 - 毕竟,这是我们唯一会用到这个东西的地方。
Java lambdas.
请注意,您可以使用 lambda 语法使此 更短:
Comparator<String> c = (a, b) -> a.length() - b.length();
仍然意味着同样的事情(好吧,你得到的对象不再存在,只有当你做了非常愚蠢的事情时才有意义,比如依赖它的对象标识哈希码,或者锁定比较器本身,这些都是所有疯狂的事情都要做。所以如果你不做任何疯狂的事情,那就是一回事。
这就是代码的作用。这与首先定义 3 个 class 没有什么不同,每个实现 Comparable<Song>
,然后将 new SongsByLengthComparer()
作为表达式作为第一个参数传递。