I need to figure out whenever two given interface implementation are the same. My naive approach was to test equality of their classes roughly by:
first.getClass().equals(second.getClass())
. It works until my code encountered (de)serialized lambda expressions. Which seem to change their Class
instance during deserialization. Following example illustrates the case:
public interface SerializableSupplier<T> extends Serializable{
T get();
}
private static final SerializableSupplier<Integer> FINAL_SUPPLIER = () -> 8;
public static void main(String args[]) throws IOException, ClassNotFoundException {
ByteArrayOutputStream outStr = new ByteArrayOutputStream();
ObjectOutputStream oss = new ObjectOutputStream(outStr);
oss.writeObject(FINAL_SUPPLIER);
oss.flush();
oss.close();
ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream(outStr.toByteArray()));
SerializableSupplier<Integer> supplierDeserialized = (SerializableSupplier<Integer>) ois.readObject();
System.out.println(FINAL_SUPPLIER.getClass());
System.out.println(supplierDeserialized.getClass());
System.out.println(FINAL_SUPPLIER.getClass().equals(supplierDeserialized.getClass()));
}
Which prints:
class cz.plastique.examples.LambdaChangingClass$$Lambda$1/295530567
class cz.plastique.examples.LambdaChangingClass$$Lambda$4/1854731462
false
The behavior is different when anonymous implementation is used:
private static final SerializableSupplier<Integer> ANONYMOUS_FINAL_SUPPLIER =
new SerializableSupplier<Integer>() {
@Override
public Integer get() {
return 8;
}
};
Which prints:
class cz.plastique.examples.LambdaChangingClass$1
class cz.plastique.examples.LambdaChangingClass$1
true
I'm puzzled by this. Why is the lambda changing it's class? And how else a'm able to recognized whenever two given interface implementations are the same even after serialization?
I suppose this has something to do with runtime lambda object construction. But I do not see how and why it is happening?