我遇到了以下问题。我想在Nashornjava.util.HashMap
脚本中使用and ,我需要使用特定的自定义对象作为HashMap 中的键,并且还用于检查 Map 中是否有键(另一种选择是检查对象是否在Collection.contains(对象 o))。java.util.PriorityQueue
HashMap.containsKey()
所以,很明显,我需要根据一些字段值在我的对象中实现 equals 和 hashCode。
例如:
尝试使用 JavaScript。由于 JavaScript 没有这些方法,因此不起作用。请参阅样本 1和样本 2
扩展 java.lang.Object。样品 3。部分工作,正在调用方法。但
- 如何使用参数插入构造函数?
- 如何从 this:[object Object] 转换为 other:jdk.nashorn.javaadapters.java.lang.Object@0,反之亦然?
用 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。来到以下部分解决方案,正在调用方法,正在使用构造函数,但是如何other.from
在equals
方法中进行强制转换以访问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
theother
和this
insideequals
是不同的类型。有没有办法从传递给的对象中转换或获取_from
equals
值?
解决方案
在 Tomasz 的回答中查看问题的解决方案。
伟大的工作托马斯!谢谢。
PS:很遗憾在 Nashornequals
中没有简洁直接的实现方式。hashCode
这对原型设计很有用。只需将其与此进行比较:)
import groovy.transform.EqualsAndHashCode
@EqualsAndHashCode(excludes="cost")
class Vertex {
int from, cost
}