java线程有几种状态复写compare方法,怎么知道返回正值还是负值?怎知道括号中两Object对象谁大谁小?

博客分类:
在使用java8之前,我们在处理一些包含有单个方法的接口时,一般是通过实现具体类或者匿名类的方式来处理的。这种方式能实现所期望的功能,而且也是传统的一切皆对象思想的体现。从实现的细节来看,却显得比较繁琐。在引入了lambda表达式这种新特性之后,我们有了一种更加简练的方式来实现对应的功能特性,当然,也带来了一种函数式编程思想上的转变。
我们先来看一个简单的示例,假定我们首先定义如下的类:
public class Apple {
private Integer weight = 0;
private String color = "";
public Apple(Integer weight, String color) {
this.weight =
this.color =
public Integer getWeight() {
public void setWeight(Integer weight) {
this.weight =
public String getColor() {
public void setColor(String color) {
this.color =
public String toString() {
return "Apple{" +
"color='" + color + '\'' +
", weight=" + weight +
这仅仅是一个普通的实体类。然后我们有一组这样的对象,在实现中需要针对这些Apple对象的weight属性进行排序。这是一个非常简单的问题,一种最传统的方式无非就是实现一个Comparator&Apple&的接口,再将该实现的对象作为参数传递到原来的sort方法中去。其详细的实现如下:
AppleComparator:
import java.util.C
public class AppleComparator implements Comparator&Apple& {
public int compare(Apple a1, Apple a2) {
return a1.getWeight().compareTo(a2.getWeight());
主函数代码如下:
import java.util.*;
public class Sorting {
public static void main(String[] args) {
List&Apple& inventory = new ArrayList&&();
inventory.addAll(Arrays.asList(new Apple(80, "green"),
new Apple(155, "green"), new Apple(120, "red")));
inventory.sort(new AppleComparator());
System.out.println(inventory);
这样,我们就实现了一个基于自定义对象进行排序的功能。它能够实现排序的要点是inventory.sort方法里需要接收的参数是Comparator类型的对象。而这个类型的对象必须要实现compare方法。从功能实现的角度来说,我们的方法需要传递的参数类型和实际传递的都是对象,也正好符合一切皆对象的这个说法。
当然,这种实现方式显得比较繁琐,因为我们这里仅仅是需要实现一个简单的接口,这里却需要定义一个类,专门实现它。而且真正能够在排序里起作用的就是compare这个方法。只有根据它才能知道怎么排序。可是在这里没办法,必须针对这个需要的方法行为包装成一个对象传递过去。
当然,我们还想到一种稍微简单一点的方法,就是使用匿名类,这种实现的方式如下:
import java.util.*;
public class Sorting {
public static void main(String[] args) {
List&Apple& inventory = new ArrayList&&();
inventory.addAll(Arrays.asList(new Apple(80, "green"),
new Apple(155, "green"), new Apple(120, "red")));
inventory.sort(new Comparator&Apple&() {
public int compare(Apple a1, Apple a2) {
return a1.getWeight().compareTo(a2.getWeight());
System.out.println(inventory);
这种方式实现的代码要稍微简洁一点,但还是显得比较冗长。如同前面我们讨论中提到,对这个接口建模最关键的就是它的这个compare方法。至于其传递方式,由于要求面向对象设计的要求,必须将该方法包装在一个对象里。那么,有没有更加简洁的方式来解决这个问题呢?
lambda表达式
在详细讨论lambda表达式之前,我们先看看用这种方式来解决上述问题有多简单。我们实现排序比较的代码如下:
inventory.sort((Apple a1, Apple a2) -& a1.getWeight().compareTo(a2.getWeight()));
我们甚至可以将类型信息给省略掉:
inventory.sort((a1, a2) -& a1.getWeight().compareTo(a2.getWeight()));
甚至更简单的情况下可以用如下代码来描述:
inventory.sort(comparing(Apple::getWeight));
在上述代码里,我们没有新建什么对象,而是采用一种类似于方法传递的方式来实现排序的目的。这里,我们使用的就是lambda表达式。在函数式编程语言的概念里,这里相当于将一个函数作为参数传递到另外一个对象方法里。笼统的来说,在java8里新加入的特性是的我们可以将一个函数作为参数来传递了。
那么,该怎么来理解lambda表达式呢?一个lambda表达式可以视为一个匿名方法,但是它可以像普通的对象参数那样被传递。它没有具体定义的名字,但是可以有一组参数,函数体以及返回类型。它甚至可以包含有被抛出的异常列表。我们针对它的每个具体特征来讨论。
匿名(Anonymous)
像在前面的代码里,我们传递给inventory.sort方法的是一段代码。这段代码没有方法声明。
(a1, a2) -& a1.getWeight().compareTo(a2.getWeight())
函数式(Function)
在上述传递的函数里,这个函数的定义和使用和我们通常使用的方法不一样。它并不是专门定义在某个类里面。但是它却有我们在普通类里定义的方法具有的特性。比如函数参数列表,返回值以及抛出的异常列表。
可传递性(Passed around)
从往常的理解来看,一个函数的定义是放在某个类里面的。但是这里它却表现的像一个类一样。实际上我们甚至可以将它赋值给一个变量。比如上述示例里的代码可以声明如下:
Comparator&Apple& comparator = (a1, a2) -& a1.getWeight().compareTo(a2.getWeight());
inventory.sort(comparator);
从代码的表面上看起来,我们可以用一个lambda表达式来替换一个对应的接口。关于这方面的详情将在后面讨论。
lambda表达式语法
从前面示例我们可以看到一个lambda表达式的样式基本如下:
它不需要定义名字,所以首先是包含有输入的函数参数列表,一般用一个括号来包含,比如:()
然后是一个箭头符号,后面包含具体的函数语句,可以有一句或者多句。比如: a.length - b.length。
所以上述示例的解析结构如下图:
基于上述的描述,我们可以定义很多类似的lambda表达式,它们对应的函数签名如下:
(String s) -& s.length
输入参数为String类型,返回结果为int类型的函数。它的函数签名样式为: (String)
(Apple a) -& a.getWeight() & 150
输入参数为Apple类型,返回结果为boolean类型的函数,函数签名样式为:(Apple) -& boolean
在需要返回结果的函数签名里,如果函数语句只有一句的话,该语句执行的结果将作为函数结果返回。
(int i, int j) -& {
System.out.println(i);
System.out.println(j);
System.out.println("Result printed");
输入参数为int, int,返回结果为void,即没有返回任何结果。函数签名样式为:(int, int) -& void
(String a, String b) -& {
System.out.println(a);
return a +
该示例代码的输入参数为(String, String),返回结果为String。但是因为函数中有多条语句,所以需要添加一个return语句在最后作为返回的结果。
看了上述简单的介绍后,估计我们心里还是有很多的疑问。比如说,为什么上述的代码可以对等的替换一个接口呢?难道说它和一个接口是等价的?那么它是不是可以替换所有类型的接口呢?另外一个就是,我们前面写的lambda表达式里,对于传入的参数甚至连类型都没有声明,它是怎么知道我们的参数类型的呢?
函数式接口(Functional interfaces)
在前面的示例代码里,我们看到,可以将一个lambda表达式用在一个接口所使用的地方。在java8里,lambda表达式可以传递和识别的类型是函数式接口。那么函数式接口是什么呢?
在java里,我们经常可以看到不少只包含有一个方法定义的接口,比如Runnable, Callable, Comparator等。而这种仅仅包含有一个接口方法的接口就可以称其为函数式接口。需要特别注意的一点就是,这里指的方法是接口里定义的抽象方法。由于java8里引入了默认方法(default method),在接口里也可以定义默认方法的实现。但是这些方法并不算抽象方法。关于默认方法我们会在后续的文章里讨论。
另外,如果某个接口定义了一个抽象方法的同时继承了一个包含其他抽象方法的接口,那么该接口就不是函数式接口。实际上,如果我们去查看目前那些常见的java类库里的函数式接口,它们都有一个如下的声明修饰: @FunctionalInterface。比如Comparator接口和Runnable接口:
@FunctionalInterface
public interface Comparator&T& {
int compare(T o1, T o2);
// details ignored.
@FunctionalInterface
public interface Runnable {
* When an object implementing interface &code&Runnable&/code& is used
* to create a thread, starting the thread causes the object's
* &code&run&/code& method to be called in that separately executing
* The general contract of the method &code&run&/code& is that it may
* take any action whatsoever.
java.lang.Thread#run()
public abstract void run();
在这里@FunctionalInterface相当于函数式接口的声明,类似于我们继承类里实现某个方法使用的@Override声明。它表示该接口是函数式接口,方便在编译的时候进行检查。
这样,我们可以发现,每个函数对象对应一个函数式接口的实例。所有传递单个方法接口的地方就可以用lambda表达式来替换了。
除此之外,Java SE 8中增加了一个新的包:java.util.function,它里面包含了常用的函数式接口,例如:
Predicate&T&——接收T对象并返回boolean
Consumer&T&——接收T对象,不返回值
Function&T, R&——接收T对象,返回R对象
Supplier&T&——提供T对象(例如工厂),不接收值
UnaryOperator&T&——接收T对象,返回T对象
BinaryOperator&T&——接收两个T对象,返回T对象
目标类型(Target typing)
在前面的讨论中我们发现,其实一个lambda表达式就是一个对应的函数式接口对象。但是,一个lambda表达式它本身并没有包含它到底实现哪个函数式接口的信息。我们怎么知道我们定义的某个lambda表达式可以用到某个函数式接口呢?实际上,对于lambda表达式的类型是通过它的应用上下文来推导出来的。这个过程我们称之为类型推导(type inference)。那么,在上下文中我们期望获得到的类型则称之为目标类型。该怎么来理解上述的内容呢?
例如,下面代码中的lambda表达式类型是ActionListener:
ActionListener l = (ActionEvent e) -& ui.dazzle(e.getModifiers());
但是同样的lambda表达式在不同的上下文中可以有不同的类型:
Callable&String& c = () -& "done";
PrivilegedAction&String& a = () -& "done";
第一个lambda表达式() -& "done"是Callable的实例,而第二个lambda表达式则是PrivilegedAction的实例。
下面,我们来结合前面的示例代码做一个详细的类型检查分析:
首先,我们这部分应用lambda表达式的代码如下:
inventory.sort((Apple a1, Apple a2) -& a1.getWeight().compareTo(a2.getWeight()));
1. 我们首先检查inventory.sort方法的签名,它的详细签名如下:void sort(Comparator&? super E& c)。
2. 那么它期待的参数类型是Comparator&Apple&.
3. 我们来看Comparator接口,它是一个函数式接口,并有定义的抽象方法compare。
4. 这个compare方法的详细签名如下:int compare(Apple o1, Apple o2),这表示这个方法期待两个类型为Apple的输入参数,并返回一个整型的结果。
5. 比对lambda表达式的函数签名类型,它也是两个输入类型为Apple,并且输出为int类型。
这样,lambda表达式的目标类型和我们的类型匹配了。
总结起来,当且仅当下面所有条件均满足时,lambda表达式才可以被赋给目标类型T:
T是一个函数式接口
lambda表达式的参数和T的方法参数在数量和类型上一一对应
lambda表达式的返回值和T的方法返回值相兼容(Compatible)
lambda表达式内所抛出的异常和T的方法throws类型相兼容
由于目标类型(函数式接口)已经“知道”lambda表达式的形式参数(Formal parameter)类型,所以我们没有必要把已知类型再重复一遍。也就是说,lambda表达式的参数类型可以从目标类型中得出:
Comparator&Apple& comp = (a1, a2) -& a1.getWeight().compareTo(a2.getWeight());
在上面的例子里,编译器可以推导出a1和a2的类型是Apple。所以它就在lambda表达式里省略了a1, a2的类型声明。这样可以使得我们的代码更加简练。
方法引用(Method references)
我们定义一些lambda表达式并传递给一些函数,这种方式可以使得我们实现的代码很简练。但是在有的情况下,我们已经有一些方法实现同样的功能了,那么我们能不能想办法重用这些原有的功能而不至于自己去重复实现呢?
像我们前面代码示例里使用的如下代码:
inventory.sort(comparing(Apple::getWeight));
这里就是引用了一个方法。将它作为一个参数传递给comparing方法。这里的Apple::getWeight可以看做lambda表达式p -& p.getWeight()的一个简写形式。其中Apple::getWeight就是一个对Apple类中实现方法getWeight的引用。所以,我们可以将方法引用当做lambda表达式的语法糖。
方法引用有很多种,它们的语法如下:
静态方法引用:ClassName::methodName
实例上的实例方法引用:instanceReference::methodName
超类上的实例方法引用:super::methodName
类型上的实例方法引用:ClassName::methodName
构造方法引用:Class::new
数组构造方法引用:TypeName[]::new
对于静态方法引用,我们需要在类名和方法名之间加入::分隔符,例如Integer::sum。
对于具体对象上的实例方法引用,我们则需要在对象名和方法名之间加入分隔符:
Set&String& knownNames = ...
Predicate&String& isKnown = knownNames::
针对上述的讨论,我们先来看个示例。假设我们需要对一组String进行排序,并忽略大小写。那么我们可以采用lambda表达式写成如下:
List&String& str = Arrays.asList("a","b","A","B");
str.sort((s1, s2) -& s1.compareToIgnoreCase(s2));
按照我们这里方法引用的定义,我们可以进一步将代码简化成如下:
List&String& str = Arrays.asList("a","b","A","B");
str.sort(String::compareToIgnoreCase);
实际上对于方法引用的类型检查和lambda表达式的类型检查过程基本上一致,我们也可以用前面类型检查的步骤来验证方法引用。
和静态方法引用类似,构造方法也可以通过new关键字被直接引用:
SocketImplFactory factory = MySocketImpl::
而对于包含有参数的函数,比如我们有一个构造函数Apple(Integer weight),我们可以采用这种方式来构造:
Function&Integer, Apple& c2 = Apple::
Apple a2 = c2.apply(100);
数组的构造方法引用的语法则比较特殊,为了便于理解,我们可以假想存在一个接收int参数的数组构造方法。参考下面的代码:
IntFunction&int[]& arrayMaker = int[]::
int[] array = arrayMaker.apply(10) // 创建数组 int[10]
背后的故事
如果我们感到好奇的话,会想更深入一步了解一下。为什么在java8里可以将方法或者说函数当一个参数传递给一个别的方法。这种行为使得方法的传递就像我们将普通对象当参数传递一样。
如果我们将前面用到的示例代码给反编译之后进行比较,将会发现如下一些有趣的地方:
面向对象式实现:
74: aload_1
// class AppleComparator
79: invokespecial #12
// Method AppleComparator."&init&":()V
82: invokeinterface #13,
// InterfaceMethod java/util/List.sort:(Ljava/util/C)V
87: getstatic
// Field java/lang/System.out:Ljava/io/PrintS
90: aload_1
91: invokevirtual #15
// Method java/io/PrintStream.println:(Ljava/lang/O)V
94: return
lambda表达式实现:
74: aload_1
75: invokedynamic #11,
// InvokeDynamic #0:apply:()Ljava/util/function/F
80: invokestatic
// InterfaceMethod java/util/Comparator.comparing:(Ljava/util/function/F)Ljava/util/C
83: invokeinterface #13,
// InterfaceMethod java/util/List.sort:(Ljava/util/C)V
88: getstatic
// Field java/lang/System.out:Ljava/io/PrintS
91: aload_1
92: invokevirtual #15
// Method java/io/PrintStream.println:(Ljava/lang/O)V
95: return
这里省略了大部分的反编译后的代码。我们会发现它们大部分都非常相似,除了在基于lambda表达式实现里有一个invokedynamic的指令。而java8这里之所以能够实现将方法当做参数传递的特性就是基于这个invokedynamic指令。由于篇幅的限制,关于invokedynamic指令的详细讨论会放在后面的文章里。
Java8里引入了函数式编程的特性,这里每个定义的lambda表达式通过和传递的目标对象进行类型检查比较来寻找到一个匹配的结果。这样一个表达式就和一个函数式接口实现了对应的代换关系。通常我们也可以通过方法引用来重用一些已有的方法,这种方法引用的语法相当于是对lambda表达式的进一步增强,它使得我们的实现更加简练。同样,它的类型检查和lambda表达式是一样的。
http://www.drdobbs.com/jvm/lambda-expressions-in-java-8/
http://www.drdobbs.com/jvm/lambdas-and-streams-in-java-8-libraries/
http://cr.openjdk.java.net/~briangoetz/lambda/lambda-state-final.html
http://cr.openjdk.java.net/~briangoetz/lambda/lambda-libraries-final.html
http://cr.openjdk.java.net/~briangoetz/lambda/lambda-translation.html
http://blog.headius.com/2008/09/first-taste-of-invokedynamic.html
http://www.infoq.com/cn/articles/jdk-dynamically-typed-language
http://www.javaworld.com/article/2860079/scripting-jvm-languages/invokedynamic-101.html
下载次数: 5
浏览: 1150036 次
来自: 北京
inventory.sort(Comparator.compa ...
&div class=&quote_title ...
讲的很详细,感谢
(window.slotbydup=window.slotbydup || []).push({
id: '4773203',
container: s,
size: '200,200',
display: 'inlay-fix'温馨提示!由于新浪微博认证机制调整,您的新浪微博帐号绑定已过期,请重新绑定!&&|&&
本科在读IT女
LOFTER精选
网易考拉推荐
用微信&&“扫一扫”
将文章分享到朋友圈。
用易信&&“扫一扫”
将文章分享到朋友圈。
&以下是利用Comparable接口实现:(缺点,只能使一个类拥有一种排序方法)利用Comparator接口实现的更加完善的多种排序方法见:例:按PIG的名字的升序将猪猪们排列【关sort()方法的描述:public static &T extends Comparable&? super T&& void sort(List&T& list)将指定的序列按自然顺序升序排序,List中所有元素必须实现Comparable接口,元素两两之间必须相互可比较,否则会抛出异常ClassCastException】先看一看该程序的main函数:&由于System.out.println(anObject)执行时都会调用toString()而toString()是定义在Object类中的一般而言,不人为在类中覆盖toString()方法,默认的toString(anObject)范围的字符串是这样的:所以为了让System.out.println(anObject)输出正确的pig的名字,我们要人为覆盖toString()方法以下是Pig类的代码:&&在之前对于sort()方法的描述和上面的代码中我们可以看到,被sort的对象的类必须implements Comparable&T&并且实现接口内的int compareTo()方法int compareTo(T o)方法的实现:关于int compareTo(T o)的说明是这样的【返回一个负值,0,正值,来表示这个object小于,等于,或大于括号中指定的object】public int compareTo(Pig pig){ return name.compareTo(pig.getName()); //name比括号中的那个pig的name‘大’则返回1,一样就返回0,‘小于’则返回-1& //相当于给系统一个排序的规则进行排序 //这样写是顺着系统的逻辑的,是升序 //降序怎么写,且看后文}关于class Pig implements Comparable&T&:T基本要跟class一样,因为都是猪跟猪比,人跟人比,鸡翅膀不能跟鸡屁股比以下是程序的输出结果(升序):&降序怎么写:只要把compareTo()内部的人return 换一换:(换言之 本pig比你小才返回1(原来是本pig比你大返回1))降序的输出结果:&程序的代码下载:&
阅读(218)|
用微信&&“扫一扫”
将文章分享到朋友圈。
用易信&&“扫一扫”
将文章分享到朋友圈。
历史上的今天
loftPermalink:'',
id:'fks_',
blogTitle:'Java.util.Collections.sort(List l) 排序 [implements Comparable]',
blogAbstract:'
{if x.moveFrom=='wap'}
{elseif x.moveFrom=='iphone'}
{elseif x.moveFrom=='android'}
{elseif x.moveFrom=='mobile'}
${a.selfIntro|escape}{if great260}${suplement}{/if}
{list a as x}
推荐过这篇日志的人:
{list a as x}
{if !!b&&b.length>0}
他们还推荐了:
{list b as y}
转载记录:
{list d as x}
{list a as x}
{list a as x}
{list a as x}
{list a as x}
{if x_index>4}{break}{/if}
${fn2(x.publishTime,'yyyy-MM-dd HH:mm:ss')}
{list a as x}
{if !!(blogDetail.preBlogPermalink)}
{if !!(blogDetail.nextBlogPermalink)}
{list a as x}
{if defined('newslist')&&newslist.length>0}
{list newslist as x}
{if x_index>7}{break}{/if}
{list a as x}
{var first_option =}
{list x.voteDetailList as voteToOption}
{if voteToOption==1}
{if first_option==false},{/if}&&“${b[voteToOption_index]}”&&
{if (x.role!="-1") },“我是${c[x.role]}”&&{/if}
&&&&&&&&${fn1(x.voteTime)}
{if x.userName==''}{/if}
网易公司版权所有&&
{list x.l as y}
{if defined('wl')}
{list wl as x}{/list}java compare 降序/升序怎么确定_百度知道
java compare 降序/升序怎么确定
private class ComparatorList implements Comparator {
public int compare(Object arg0, Object arg1) {
ErpAccountCheckDetail cd1 = (ErpAccountCheckDetail)arg0;
ErpAccountCheckDetail cd2 = (ErpAccountCheckDeta...
答题抽奖
首次认真答题后
即可获得3次抽奖机会,100%中奖。
我印象中如果不重写compareTo方法那返回值都是-1吧......我一般都是实现Comparable接口,重写CompareTo方法就可以了。至于降序升序,可以这样比较:假如A的值大于B,你返回1。这样调用Collections.sort()方法就是升序假如A的值大于B,你返回-1。这样调用Collections.sort()方法就是降序一般比较的都是对象中一个具体的数值。不知道你的类的构造,不好给例子
cd1.getCheckDate().compareTo(cd2.getCheckDate())返回值不是一会1,一会-1吗,到底什么时候升序什么时候降序呢
怎么会?你用System.out.println(cd1.getCheckDate().compareTo(cd2.getCheckDate()))打印出结果看的吗?
结果每次不一样
cd1.getCheckDate()返回什么类型的值?Date还是String?
采纳率:60%
String 是字符串,它的比较用compareTo方法,它从第一位开始比较,如果遇到不同的字符,则马上返回这两个字符的ascii值差值..返回值是int类型
先举个例子1 2 5 3 6 9 7从大家的认知来看,上面的数字从小到大为1 2 3 5& 6 7 9&但是如果是一对的字符串或者对象呢?那么就需要Comparator来自定义字符串或对象的比较方法,来排序了。如aa& bb cc& cc& ab如果你在Comparator中自定义c是大于b&& b是大于a的 那么降序排序就是aa ab bb cc cc&对于&public int compare(Object arg0, Object arg1)的理解如果放回1& 说明arg0 & arg1& 如 2& 1如果放回0& 说明arg0&= arg1& 如&cc& cc如果放回-1 说明arg0&& arg1& 如&6& 7&所以如果你希望1 2 5 3 6 9 7 的排序变成 离5最接近的先输出那么如下代码(降序)&public&int&compare(Object&arg0,&Object&arg1)&{&&&&&&&&&&&&Integer&cd1&=&(Integer)arg0;&&&&&&&&&&&&Integer&cd2&=&(Integer)arg1;&&&&&&&&&&&&if&(Math.abs(5-cd1)-Math.abs(5-cd2)&0)&&&&&&&&&&&&&&&&return&1;&&&&&&&&&&&&if&(Math.abs(5-cd1)-Math.abs(5-cd2)==0)&&&&&&&&&&&&&&&&return&0;&&&&&&&&&&&&if&(Math.abs(5-cd1)-Math.abs(5-cd2)&0)&&&&&&&&&&&&&&&&return&-1;&}
参数o1&o2&升序参数o2&o1&降序public&int&compare(String&o1,&String&o2)&{&&&&//升序&&&&return&o1.compareTo(o2);&}public&int&compare(String&o1,&String&o2)&{&&&&//降序&&&&return&o2.compareTo(o1);&}
1条折叠回答
为您推荐:
其他类似问题
java的相关知识
换一换
回答问题,赢新手礼包
个人、企业类
违法有害信息,请在下方选择后提交
色情、暴力
我们会通过消息、邮箱等方式尽快将举报结果通知您。java复写compare方法,怎么知道返回正值还是负值?怎知道括号中两Object对象谁大谁小?_百度知道
java复写compare方法,怎么知道返回正值还是负值?怎知道括号中两Object对象谁大谁小?
答题抽奖
首次认真答题后
即可获得3次抽奖机会,100%中奖。
首先必须将两个object分别转型为你需要比较的对象具体类型(比如(User)element1)再根据具体类型里面的某个属性进行比较(吧如user.age)
采纳率:56%
这是用String类的comparTo方法
为您推荐:
其他类似问题
换一换
回答问题,赢新手礼包
个人、企业类
违法有害信息,请在下方选择后提交
色情、暴力
我们会通过消息、邮箱等方式尽快将举报结果通知您。

我要回帖

更多关于 java返回上一级 的文章

 

随机推荐