Java 8、等于、== 和 Lambda
Java 8, equals, == and Lambdas
(真题在最后)
世界,您好!
我在这里发生了一些令人不安的事情,我无法全神贯注...
像我一样懒惰,我讨厌一遍又一遍地重新实现愚蠢的 euqals() 方法;还有 hashCode() 方法,但仍然将 "equality" 集中在选定的成员变量上。
我还可以通过使用检查 class 个实例的默认接口或使用反射来减少实现,但我认为我已经使用了这个静态实用程序方法和一个 labmda:
public class Whosebug_TestEq {
static public interface JcLambda_pG1_pG1_rBool<T> {
boolean test(T p1, T p2);
}
static public <T> boolean equals_internal(final T pThisObject, final Object pOtherObject, final JcLambda_pG1_pG1_rBool<T> pEqualizer) {
if (pThisObject == null) return pOtherObject == null;
if (pOtherObject == null) return false;
final Class<? extends Object> thisClass = pThisObject.getClass();
if (!thisClass.isInstance(pOtherObject)) return false;
@SuppressWarnings("unchecked") final T other = (T) pOtherObject;
final boolean res = pEqualizer.test(pThisObject, other);
// System.out.println("Testing " + pThisObject + " vs " + other + " => " + res);
return res;
}
/*
* TEST DEFINES
*/
static private interface CNameable {
String getName();
}
static private class CA implements CNameable {
String name = "Bier";
@Override public String toString() {
return getClass().getSimpleName() + "." + name;
}
@Override public String getName() {
return name;
}
}
static private class CB implements CNameable {
String name = "Schnaps";
@Override public String toString() {
return getClass().getSimpleName() + "." + name;
}
@Override public String getName() {
return name;
}
}
@SuppressWarnings("synthetic-access") static private class CC extends CA {
@SuppressWarnings({ "hiding" }) String name = "Wein";
@Override public String toString() {
return getClass().getSimpleName() + "." + name;
}
@Override public String getName() {
return name;
}
}
@SuppressWarnings("synthetic-access") static private class CD extends CA {
@SuppressWarnings({ "hiding" }) String name = "Bier";
@Override public String toString() {
return getClass().getSimpleName() + "." + name;
}
@Override public String getName() {
return name;
}
}
/*
* TEST
*/
@SuppressWarnings("synthetic-access") public static void main(final String[] args) {
final CA a = new CA();
final CB b = new CB();
final CC c = new CC();
final CD d = new CD();
final JcLambda_pG1_pG1_rBool<CNameable> res = new JcLambda_pG1_pG1_rBool<CNameable>() {
@Override public boolean test(final CNameable pP1, final CNameable pP2) {
// return pP1.getName().equals(pP2.getName());
return pP1.getName() == pP2.getName();
}
};
System.out.println("\nExplicit eq");
System.out.println("a=a:" + equals_internal(a, a, (p1, p2) -> p1.getName().equals(p2.getName())));
System.out.println("a=b:" + equals_internal(a, b, (p1, p2) -> p1.getName().equals(p2.getName())));
System.out.println("a=c:" + equals_internal(a, c, (p1, p2) -> p1.getName().equals(p2.getName())));
System.out.println("a=d:" + equals_internal(a, d, (p1, p2) -> p1.getName().equals(p2.getName())));
System.out.println("\nExplicit ==");
System.out.println("a=a:" + equals_internal(a, a, (p1, p2) -> p1.getName() == p2.getName()));
System.out.println("a=b:" + equals_internal(a, b, (p1, p2) -> p1.getName() == p2.getName()));
System.out.println("a=c:" + equals_internal(a, c, (p1, p2) -> p1.getName() == p2.getName()));
System.out.println("a=d:" + equals_internal(a, d, (p1, p2) -> p1.getName() == p2.getName()));
System.out.println("\nImplicit");
System.out.println("a=a:" + equals_internal(a, a, res));
System.out.println("a=b:" + equals_internal(a, b, res));
System.out.println("a=c:" + equals_internal(a, c, res));
System.out.println("a=d:" + equals_internal(a, d, res));
System.out.println("\nExplicit eqName");
System.out.println("a=a:" + equals_internal(a, a, (p1, p2) -> p1.name.equals(p2.name)));
System.out.println("a=b:" + equals_internal(a, b, (p1, p2) -> p1.name.equals(p2.name)));
System.out.println("a=c:" + equals_internal(a, c, (p1, p2) -> p1.name.equals(p2.name)));
System.out.println("a=d:" + equals_internal(a, d, (p1, p2) -> p1.name.equals(p2.name)));
System.out.println("\nExplicit ==name");
System.out.println("a=a:" + equals_internal(a, a, (p1, p2) -> p1.name == p2.name));
System.out.println("a=b:" + equals_internal(a, b, (p1, p2) -> p1.name == p2.name));
System.out.println("a=c:" + equals_internal(a, c, (p1, p2) -> p1.name == p2.name));
System.out.println("a=d:" + equals_internal(a, d, (p1, p2) -> p1.name == p2.name));
}
}
输出:
Explicit eq
a=a:true
a=b:false
a=c:false
a=d:true
Explicit ==
a=a:true
a=b:false
a=c:false
a=d:true
Implicit
a=a:true
a=b:false
a=c:false
a=d:true
Explicit eqName
a=a:true
a=b:false
a=c:true
a=d:true
Explicit ==name
a=a:true
a=b:false
a=c:true
a=d:true
所以...我期待所有 5 个变体(eq
、==
、Implicit
、eqName
、==name
)给我回馈相同的结果(真、假、假、真)...
但是 eqName
和 ==name
没有。为什么他们 return a=c
作为 true
而不是 false
?
这与那里发生的名字阴影有关吗?因此,而不是访问 CC.name
比较 lambda 总是访问 CA.name
?
分析为什么下面的结果是true
equals_internal(a, c, (p1, p2) -> p1.name == p2.name)
你得看看equals_internal
的签名:
equals_internal(final T pThisObject, final Object pOtherObject, final JcLambda_pG1_pG1_rBool<T> pEqualizer)
所以在这种情况下,T
是 a
的类型,即 CA
。
因此你传递给静态方法的 JcLambda_pG1_pG1_rBool<T>
是一个 JcLambda_pG1_pG1_rBool<CA>
,这意味着 p1
和 p2
是 CA
类型,所以p1.name == p2.name
比较baseclassCA
的name
属性,由于String pool"Bier" == "Bier"
为真
出于同样的原因,equals_internal(a, c, (p1, p2) -> p1.name.equals(p2.name))
的结果是 true
(只是在这里您不必依赖字符串池为两个 [= 返回相同的 String
实例29=], 因为你使用的是 String.equals
).
前3种情况结果不同,因为你使用的是getName()
方法,在子class中被重写了,而returns是name
属性的子class.
总而言之,不同的行为是由这样一个事实造成的,即与方法不同,实例变量不能被覆盖。
只是为了让它更简单一点,考虑到这一点:
static class A {
public String name = "A";
}
static class B extends A {
public String name = "B";
}
public static void main(String[] args) {
B b = new B(); // line 57
System.out.println(b.name); // B
System.out.println(((A) b).name); // A
}
如果您调试并停在理论上的 line 57
- Eclipse 调试器会说您的 b
实例有两个名为 name
.
的字段
(真题在最后)
世界,您好! 我在这里发生了一些令人不安的事情,我无法全神贯注...
像我一样懒惰,我讨厌一遍又一遍地重新实现愚蠢的 euqals() 方法;还有 hashCode() 方法,但仍然将 "equality" 集中在选定的成员变量上。 我还可以通过使用检查 class 个实例的默认接口或使用反射来减少实现,但我认为我已经使用了这个静态实用程序方法和一个 labmda:
public class Whosebug_TestEq {
static public interface JcLambda_pG1_pG1_rBool<T> {
boolean test(T p1, T p2);
}
static public <T> boolean equals_internal(final T pThisObject, final Object pOtherObject, final JcLambda_pG1_pG1_rBool<T> pEqualizer) {
if (pThisObject == null) return pOtherObject == null;
if (pOtherObject == null) return false;
final Class<? extends Object> thisClass = pThisObject.getClass();
if (!thisClass.isInstance(pOtherObject)) return false;
@SuppressWarnings("unchecked") final T other = (T) pOtherObject;
final boolean res = pEqualizer.test(pThisObject, other);
// System.out.println("Testing " + pThisObject + " vs " + other + " => " + res);
return res;
}
/*
* TEST DEFINES
*/
static private interface CNameable {
String getName();
}
static private class CA implements CNameable {
String name = "Bier";
@Override public String toString() {
return getClass().getSimpleName() + "." + name;
}
@Override public String getName() {
return name;
}
}
static private class CB implements CNameable {
String name = "Schnaps";
@Override public String toString() {
return getClass().getSimpleName() + "." + name;
}
@Override public String getName() {
return name;
}
}
@SuppressWarnings("synthetic-access") static private class CC extends CA {
@SuppressWarnings({ "hiding" }) String name = "Wein";
@Override public String toString() {
return getClass().getSimpleName() + "." + name;
}
@Override public String getName() {
return name;
}
}
@SuppressWarnings("synthetic-access") static private class CD extends CA {
@SuppressWarnings({ "hiding" }) String name = "Bier";
@Override public String toString() {
return getClass().getSimpleName() + "." + name;
}
@Override public String getName() {
return name;
}
}
/*
* TEST
*/
@SuppressWarnings("synthetic-access") public static void main(final String[] args) {
final CA a = new CA();
final CB b = new CB();
final CC c = new CC();
final CD d = new CD();
final JcLambda_pG1_pG1_rBool<CNameable> res = new JcLambda_pG1_pG1_rBool<CNameable>() {
@Override public boolean test(final CNameable pP1, final CNameable pP2) {
// return pP1.getName().equals(pP2.getName());
return pP1.getName() == pP2.getName();
}
};
System.out.println("\nExplicit eq");
System.out.println("a=a:" + equals_internal(a, a, (p1, p2) -> p1.getName().equals(p2.getName())));
System.out.println("a=b:" + equals_internal(a, b, (p1, p2) -> p1.getName().equals(p2.getName())));
System.out.println("a=c:" + equals_internal(a, c, (p1, p2) -> p1.getName().equals(p2.getName())));
System.out.println("a=d:" + equals_internal(a, d, (p1, p2) -> p1.getName().equals(p2.getName())));
System.out.println("\nExplicit ==");
System.out.println("a=a:" + equals_internal(a, a, (p1, p2) -> p1.getName() == p2.getName()));
System.out.println("a=b:" + equals_internal(a, b, (p1, p2) -> p1.getName() == p2.getName()));
System.out.println("a=c:" + equals_internal(a, c, (p1, p2) -> p1.getName() == p2.getName()));
System.out.println("a=d:" + equals_internal(a, d, (p1, p2) -> p1.getName() == p2.getName()));
System.out.println("\nImplicit");
System.out.println("a=a:" + equals_internal(a, a, res));
System.out.println("a=b:" + equals_internal(a, b, res));
System.out.println("a=c:" + equals_internal(a, c, res));
System.out.println("a=d:" + equals_internal(a, d, res));
System.out.println("\nExplicit eqName");
System.out.println("a=a:" + equals_internal(a, a, (p1, p2) -> p1.name.equals(p2.name)));
System.out.println("a=b:" + equals_internal(a, b, (p1, p2) -> p1.name.equals(p2.name)));
System.out.println("a=c:" + equals_internal(a, c, (p1, p2) -> p1.name.equals(p2.name)));
System.out.println("a=d:" + equals_internal(a, d, (p1, p2) -> p1.name.equals(p2.name)));
System.out.println("\nExplicit ==name");
System.out.println("a=a:" + equals_internal(a, a, (p1, p2) -> p1.name == p2.name));
System.out.println("a=b:" + equals_internal(a, b, (p1, p2) -> p1.name == p2.name));
System.out.println("a=c:" + equals_internal(a, c, (p1, p2) -> p1.name == p2.name));
System.out.println("a=d:" + equals_internal(a, d, (p1, p2) -> p1.name == p2.name));
}
}
输出:
Explicit eq
a=a:true
a=b:false
a=c:false
a=d:true
Explicit ==
a=a:true
a=b:false
a=c:false
a=d:true
Implicit
a=a:true
a=b:false
a=c:false
a=d:true
Explicit eqName
a=a:true
a=b:false
a=c:true
a=d:true
Explicit ==name
a=a:true
a=b:false
a=c:true
a=d:true
所以...我期待所有 5 个变体(eq
、==
、Implicit
、eqName
、==name
)给我回馈相同的结果(真、假、假、真)...
但是 eqName
和 ==name
没有。为什么他们 return a=c
作为 true
而不是 false
?
这与那里发生的名字阴影有关吗?因此,而不是访问 CC.name
比较 lambda 总是访问 CA.name
?
分析为什么下面的结果是true
equals_internal(a, c, (p1, p2) -> p1.name == p2.name)
你得看看equals_internal
的签名:
equals_internal(final T pThisObject, final Object pOtherObject, final JcLambda_pG1_pG1_rBool<T> pEqualizer)
所以在这种情况下,T
是 a
的类型,即 CA
。
因此你传递给静态方法的 JcLambda_pG1_pG1_rBool<T>
是一个 JcLambda_pG1_pG1_rBool<CA>
,这意味着 p1
和 p2
是 CA
类型,所以p1.name == p2.name
比较baseclassCA
的name
属性,由于String pool"Bier" == "Bier"
为真
出于同样的原因,equals_internal(a, c, (p1, p2) -> p1.name.equals(p2.name))
的结果是 true
(只是在这里您不必依赖字符串池为两个 [= 返回相同的 String
实例29=], 因为你使用的是 String.equals
).
前3种情况结果不同,因为你使用的是getName()
方法,在子class中被重写了,而returns是name
属性的子class.
总而言之,不同的行为是由这样一个事实造成的,即与方法不同,实例变量不能被覆盖。
只是为了让它更简单一点,考虑到这一点:
static class A {
public String name = "A";
}
static class B extends A {
public String name = "B";
}
public static void main(String[] args) {
B b = new B(); // line 57
System.out.println(b.name); // B
System.out.println(((A) b).name); // A
}
如果您调试并停在理论上的 line 57
- Eclipse 调试器会说您的 b
实例有两个名为 name
.