因此,显然,我需要基于某些字段值在我的对象中实现equals和hashCode方法。
例如:
1.尝试使用JavaScript。由于JavaScript没有这些方法而无法工作。请参见样例1和样例2。
2.扩展java.lang.Object。样例3。部分工作正常,方法正在被调用。但是
-如何插入具有参数的构造函数?
-如何从this:[object Object]转换为其他:jdk.nashorn.javaadapters.java.lang.Object@0或反之亦然?
3.在Java中实现我的自定义类并在JavaScript中进行扩展。样例4。它可以工作。但是如果必须使用Java,那么我需要Nashorn吗?
var PriorityQueue = java.util.PriorityQueue;
var HashMap = java.util.HashMap;
var Integer = java.lang.Integer;
// Sample 1
// Doesn't work, equals and hashCode are not being invoked
function Vertex1(from, cost) {
this.from = from;
this.cost = cost;
this.equals = function(other) { return this.from == other.from; }
this.hashCode = function() { return Integer.hashCode(this.from); }
}
var hm = new HashMap();
hm.put(new Vertex1(1, 10), 10);
hm.put(new Vertex1(1, 20), 21);
// Prints size is 2, but I'd like to see 1
print("HashMap size: " + hm.size());
// Prints false
print("HashMap1 contains: " + hm.containsKey(new Vertex1(1, 20)));
// ------------------------------------------------------------------
// Sample 2
// Doesn't work, equals and hashCode are not being invoked
function Vertex1(from, cost) {
this.from = from;
this.cost = cost;
}
Vertex1.prototype = {
equals : function(other) { return this.from == other.from; },
hashCode : function() { return Integer.hashCode(this.from); },
}
var hm = new HashMap();
hm.put(new Vertex1(1, 10), 10);
hm.put(new Vertex1(1, 20), 21);
// Prints size is 2, but I'd like to see 1
print("HashMap size: " + hm.size());
// Prints false
print("HashMap1 contains: " + hm.containsKey(new Vertex1(1, 20)));
// ------------------------------------------------------------------
// Sample 3
// Works partially, Methods are being invoked. But
// 1. How to plugin construstor with parameters?
// 2. How to do the cast from this:[object Object] to other:jdk.nashorn.javaadapters.java.lang.Object@0, or vice versa
var JObject = Java.type("java.lang.Object");
var Vertex2 = Java.extend(JObject, {
from : 0,
equals : function(other) { return this.from.equals(other.from); },
hashCode : function() { return Integer.hashCode(this.from); },
});
var hm = new HashMap();
// How to implement constructor for new Vertex2(10, 10)?
hm.put(new Vertex2(), 10);
hm.put(new Vertex2(), 21);
// Prints size is 2, because hashCode is the same and equals returns false
print("HashMap size: " + hm.size());
// Prints false, because equals returns false
print("HashMap1 contains: " + hm.containsKey(new Vertex2()));
// ------------------------------------------------------------------
// Sample 4
// com.arsenyko.MyObject is implemented in Java, Works, but Nashorn is ambiguous then!!!
var MyObject = Java.type("com.arsenyko.MyObject");
var Vertex2 = Java.extend(MyObject, {});
var hm = new HashMap();
hm.put(new Vertex2(1, 10), 10);
hm.put(new Vertex2(1, 20), 21);
print("HashMap size: " + hm.size());
print("HashMap1 contains: " + hm.containsKey(new Vertex2(1, 10)));
编辑1
@Tomasz,谢谢。我看到了所有提到的链接。但是似乎存在一些未经记录的内容。几乎放弃了Nashorn。我得出了以下部分解决方案,方法被调用,构造函数被使用,但如何在equals
方法中将other.from
转换为原始对象的from
字段(这段代码为每个Vertex
实例产生不同的类):
//load("nashorn:mozilla_compat.js");
var PriorityQueue = java.util.PriorityQueue;
var HashMap = java.util.HashMap;
var Integer = java.lang.Integer;
function Vertex1(from, cost) {
this.from = from;
this.cost = cost;
this.equals = function(other) {
var value1 = this.from;
// How to get other.from here???
var value2 = other.from;
print('value1=' + value1 + ' value2=' + value2);
print(other);
var eq = value1.equals(value2);
print('equals is ' + eq);
return eq;
}
this.hashCode = function() {
var hashCode = Integer.hashCode(this.from);
print('hashCode is ' + hashCode);
return hashCode;
}
var JObject = Java.type("java.lang.Object");
// return Java.extend(JObject, this); // doesn't work
// return this; // doesn't work
// return new JavaAdapter(java.lang.Object, this); // Works! with load("nashorn:mozilla_compat.js");
var Type = Java.extend.apply(Java, [JObject]);
return new Type(this);
}
var hm = new HashMap();
hm.put(new Vertex1(1, 10), 10);
hm.put(new Vertex1(1, 20), 21);
// Prints size is 2, but I'd like to see 1
print("HashMap size: " + hm.size());
// Prints false
print("HashMap contains: " + hm.containsKey(new Vertex1(1, 20)));
编辑2
感谢Tomasz指出,使用具有类特定实现对象的Java.extend()函数的每个调用都会产生一个新的Java适配器类。因此,我们需要一个Object Extender并使用该类型实例化对象,正如他在示例中所展示的那样。我稍微修改了它,以便使用相同的Object Extender生成具有相同类的实例,无论是使用工厂还是直接构造函数。
var HashMap = java.util.HashMap;
var JInteger = java.lang.Integer;
var JObject = Java.extend(java.lang.Object);
var createVertex = (function() {
var
_equals = function(other) {
print(this + ' vs ' + other);
return this._from === other.from;
};
_hashCode = function() {
var hashCode = JInteger.hashCode(this._from);
print(hashCode);
return hashCode;
};
return function(from, cost) {
return new JObject() {
_from : from,
_cost : cost,
equals : _equals,
hashCode : _hashCode,
}
}
})();
var JSVertex = function(from, cost) {
return new JObject() {
_from : from,
_cost : cost,
equals : function(other) {
print(this + ' vs ' + other);
return this._from === other._from;
},
hashCode : function() {
var hashCode = JInteger.hashCode(this._from);
print(hashCode);
return hashCode;
}
}
}
var v1 = JSVertex(1, 10);
var v2 = JSVertex(1, 20);
//var v1 = createVertex(1, 10);
//var v2 = createVertex(1, 20);
var v3 = createVertex(1, 20);
print(v1.class === v2.class); // returns true
print(v2.class === v3.class); // returns true
var hm = new HashMap();
hm.put(v1, 10);
hm.put(v2, 21);
print("HashMap size: " + hm.size()); // Prints 2, but I'd like to see 1
print("HashMap contains: " + hm.containsKey(v3)); // Prints false
然而,还存在一个问题:
equals
的参数类型是 jdk.nashorn.javaadapters.java.lang.Object
,换句话说,equals
中的other
和this
是不同的类型。 有没有办法将对象传递给equals
并强制转换或获取_from
值?
解决方案
请参见Tomasz的答案中的解决方案。
干得好,Tomasz!谢谢。
PS:非常遗憾,在Nashorn中没有简洁明了的方法来实现equals
和hashCode
。 这对原型设计很有用。只需比较一下:
import groovy.transform.EqualsAndHashCode
@EqualsAndHashCode(excludes="cost")
class Vertex {
int from, cost
}
JSVertex
是一个返回new JObject() { ...
的函数,那么在调用它时不需要调用new
- 只需调用var v1 = JSVertex(1, 10);
;2. 在你的createVertex
中,如果你没有在匿名函数调用中隐藏任何“私有”变量(这是我之前示例中的情况),则不需要使用匿名函数来返回实际函数。 - Tomasz Gawelvar
看起来很奇怪。在_equals
的定义后面应该是逗号而不是分号吗? - David Conrad