我有一个有两个字符串字段的类。它们中的任何一个(但不是两个)都可以为空。
public class SimpleBluetoothDevice {
final String macAddress;
final String name;
public SimpleBluetoothDevice(String name, String macAddress) {
this.macAddress = macAddress;
this.name = name;
}
@Override
public boolean equals(Object o) {
if (o == this) {
return true;
}
if (!(o instanceof SimpleBluetoothDevice)) {
return false;
}
SimpleBluetoothDevice otherDevice = (SimpleBluetoothDevice) o;
if (name == null || otherDevice.name == null) {
return otherDevice.macAddress.equalsIgnoreCase(macAddress);
}
if (macAddress == null || otherDevice.macAddress == null) {
return otherDevice.name.equals(name);
}
return name.equals(otherDevice.name) || macAddress.equalsIgnoreCase(otherDevice.macAddress);
}
@Override
public int hashCode() {
int hash = 1;
hash = 31 * hash + ((name == null) ? 0 : name.hashCode());
hash = 31 * hash + ((macAddress == null) ? 0 : macAddress.toLowerCase(Locale.US).hashCode());
return hash;
} }
测试
public class Main {
private static final List<SimpleBluetoothDevice> DEVICE_LIST = new ArrayList<SimpleBluetoothDevice>();
private static final Set<SimpleBluetoothDevice> DEVICE_SET = new HashSet<SimpleBluetoothDevice>();
static {
DEVICE_LIST.add(new SimpleBluetoothDevice(null, "11-22-33-44-55-aa"));
DEVICE_LIST.add(new SimpleBluetoothDevice("iPad", "11-22-33-44-55-BB"));
DEVICE_SET.add(new SimpleBluetoothDevice(null, "11-22-33-44-55-aa"));
DEVICE_SET.add(new SimpleBluetoothDevice("iPad", "11-22-33-44-55-BB"));
}
/**
* @param args
*/
public static void main(String[] args) {
SimpleBluetoothDevice bluetoothDevice = new SimpleBluetoothDevice("Android", "11-22-33-44-55-AA");
System.out.println(DEVICE_LIST.contains(bluetoothDevice)); // TRUE
System.out.println(DEVICE_SET.contains(bluetoothDevice)); // FALSE
}
}
Set
确实包含bluetoothDevice
,但因错误实施false
而返回hashCode()
个值。
是否可以在此处实现hashCode
以使用基于散列的集合?如果它们的MAC地址或名称相等(或者MAC地址和名称分别相等),则两个设备将相等。
更新#1。
public class Main {
private static final List<SimpleBluetoothDevice> BLUETOOTH_DEVICES = new ArrayList<SimpleBluetoothDevice>();
static {
BLUETOOTH_DEVICES.add(new SimpleBluetoothDevice(null, "38:ec:e4:d7:ad:a2"));
BLUETOOTH_DEVICES.add(new SimpleBluetoothDevice("Nokia N9", "40:98:4E:48:1D:B0"));
BLUETOOTH_DEVICES.add(new SimpleBluetoothDevice("Galaxy S4", "08:FC:88:AD:4A:62"));
}
/**
* @param args
*/
public static void main(String[] args) {
SimpleBluetoothDevice one = new SimpleBluetoothDevice(null, "38:ec:e4:d7:ad:a2");
SimpleBluetoothDevice two = new SimpleBluetoothDevice("GT-I9003", "38:ec:e4:d7:ad:a2");
SimpleBluetoothDevice three = new SimpleBluetoothDevice("GT-I9003", "123");
System.out.println(one.equals(two));
System.out.println(two.equals(three));
System.out.println("Transitivity test. " + one.equals(three));
System.out.println("Contains test. " + BLUETOOTH_DEVICES.contains(one));
System.out.println("Contains test. " + BLUETOOTH_DEVICES.contains(two));
System.out.println("Contains test. " + BLUETOOTH_DEVICES.contains(three));
}
/**
* This class only contains two text fields: MAC address and name.
*
* @author Maxim Dmitriev
*
*/
private static final class SimpleBluetoothDevice {
final String macAddress;
final String name;
SimpleBluetoothDevice(String name, String macAddress) {
this.macAddress = macAddress;
this.name = name;
}
@Override
public String toString() {
return "Name: " + name + ", MAC address: " + macAddress;
}
@Override
public boolean equals(Object o) {
if (o == this) {
return true;
}
if (!(o instanceof SimpleBluetoothDevice)) {
return false;
}
SimpleBluetoothDevice otherDevice = (SimpleBluetoothDevice) o;
if (name == null) {
return macAddress.equalsIgnoreCase(otherDevice.macAddress);
} else if (macAddress == null) {
return name.equals(otherDevice.name);
} else {
return name.equals(otherDevice.name) || macAddress.equalsIgnoreCase(otherDevice.macAddress);
}
}
/**
* It is recommended to override {@link Object#hashCode()} in every class that overrides
* {@link Object#equals(Object)}. <br><br> But two instances of this class will be equal, if
* their MAC addresses (the
* case of the characters is ignored) or names are equal. Collections, such as
* {@link HashSet}, {@link HashMap}, cannot be used because the hash codes of logically
* equal instances are not the same.
*
*/
@Override
public int hashCode() {
return 1;
}
}
}
我修改了代码。因此,如果
,则认为两个对象相等更新#2。
没有equals
public class Main {
private static final Set<SimpleBluetoothDevice> BLUETOOTH_DEVICES = new HashSet<SimpleBluetoothDevice>();
static {
BLUETOOTH_DEVICES.add(new SimpleBluetoothDevice("G1", "38:ec:e4:d7:ad:a2"));
BLUETOOTH_DEVICES.add(new SimpleBluetoothDevice("Nokia N9", "40:98:4E:48:1D:B0"));
BLUETOOTH_DEVICES.add(new SimpleBluetoothDevice("Galaxy S4", "08:FC:88:AD:4A:62"));
}
/**
* @param args
*/
public static void main(String[] args) {
SimpleBluetoothDevice myDevice = new SimpleBluetoothDevice(null, "38:ec:e4:d7:ad:a2");
for (SimpleBluetoothDevice device : BLUETOOTH_DEVICES) {
if (myDevice.macAddress == null || device.macAddress == null) {
if (myDevice.name.equals(device.name)) {
System.out.println("Name");
break;
}
} else if (myDevice.name == null || device.name == null) {
if (myDevice.macAddress.equalsIgnoreCase(device.macAddress)) {
System.out.println("MAC");
break;
}
} else {
if (myDevice.macAddress.equalsIgnoreCase(device.macAddress) || myDevice.name.equals(device.name)) {
System.out.println("Either of them");
break;
}
}
}
}
/**
* This class only contains two text fields: MAC address and name.
*
* @author Maxim Dmitriev
*
*/
private static final class SimpleBluetoothDevice {
final String macAddress;
final String name;
/**
*
* @param name
* @param macAddress
*
* Throws an {@link IllegalArgumentException} if both parameters are null
*/
SimpleBluetoothDevice(String name, String macAddress) {
if (name == null && macAddress == null) {
throw new IllegalArgumentException("Both a name and a MAC address cannot be null");
}
this.name = name;
this.macAddress = macAddress;
}
}
}
答案 0 :(得分:3)
目前,您无法以符合contract of Object.equals
状态的方式实施equals
:
equals方法在非null对象引用上实现等价关系:
...
- 它是传递性的:对于任何非空引用值x,y和z,如果x.equals(y)返回true而y.equals(z)返回true,则x.equals(z)应返回true
考虑这三个对象:
x: Name=foo MacAddress=m1
y: Name=bar MacAddress=m1
z: Name=bar MacAddress=m2
现在x.equals(y)
将成立,y.equals(z)
将为真,这应该意味着x.equals(z)
是真的......但事实并非如此。
在你找到一种满足及物性契约的平等形式之前,没有必要担心hashCode
。如果不出意外,总是返回0的hashCode
实现始终是“正确的”(尽管在性能方面显然没有用)。当你的平等检查被打破时,这对你没什么帮助。
答案 1 :(得分:0)
许多集合的设计要求equals
实现等价关系,允许将对象划分为等价集(其中一些可能只包含一个项),这样集合中的每个对象都将比较相等,并且没有对象将比较等于另一组中的任何对象。然而,有时候进行“模糊”比较是有用的,这种比较不仅可以找到与给定对象在同一组中的对象,而且可以找到某种意义上“附近”的对象。单个查询不可能找到仅存储一次的项目,但如果冗余地存储项目或使用多个查询(不一定非常多),则可能实现模糊匹配。在您的情况下,例如,您可能能够定义您的equals操作,以便两个字段必须匹配,但是当向表中添加一个项(X,Y)时,其中两个值都不为null,添加(X,null)和( null,Y)。或者,您可以拥有一个将MAC地址映射到名称的表和另一个将名称映射到MAC地址的表;如果给出一种形式的ID而不是另一种形式,请使用适当的表格来获取另一种形式,然后将其作为一对进行查找。