I have a homework to write a test for the following method in other to show that the Object and its duplicate ,which has been created using this method, are equal.
/**
* Creates a new object that is a duplicate of this instance of
* Parameter.
* <p>
* The duplication is a "deep copy" in that all values contained in the
* Parameter are themselves duplicated.
*
* #return The new duplicate Parameter object.
*/
public Parameter copy( )
{
Parameter result = new Parameter( );
result.setName( getName( ) );
for ( int index = 0; index < getNumberOfValues( ); index++ )
{
result.addValue( getValue( index ).copy( ) );
}
return result;
}
I wrote different methods, but each time the result shows that they are not equal. One of my tests:
#Test
public void testCopy() {
Parameter param = new Parameter();
Value val1 = new Value();
//val1.setName("Hi!");
//param.addValue(val1);
Parameter param2 = param.copy();
Parameter expected = param;
Parameter actual = param2;
assertEquals(param, param2);
}
But it seems that this method doesn't create and exact duplicate of param.
Would you please guide me?
And this is the copy method for value:
/**
* Creates a new Value object that is a duplicate of this instance.
*
* #return The new duplicate Value object.
*/
public Value copy( )
{
Value newValue = new Value( );
newValue.setName( getName( ) );
return newValue;
}
Your Parameter class needs an equals method(). Without this java runs equality based on reference(the default behavior of Object.equals() ), hence your observation.
Your equals method may look like:
public boolean equals(Object o)
{
Parameter p = (Parameter)o;
return this.getName().equals(p.getNames) && this.getNumberOfValues() == p.getNumberOfValues() &&B this.values().equals(p.values());
}
The equals method for the class Object (described here) states clearly that the references need to the refer to the same object in order to return true. In your case, the copy method correctly creates a new Parameter and afterwards a new Value in order to create the copy object. Hence, the existing equals() method will always return false.
In order to correctly test, you need to do what the comments stated, that is, create a new equals() method that will override the existing one in the Object class, both in the Parameter and in the Value classes. Your method should test whether the content (the name, in each object) of each object is the same, or any other semantic that you will deem fit according to your application.
Related
Can Javers compare two sets to identify the changes happened in the objects in the new set for each corresponding object in the old set?
Does the implementation rely on the equals method of the value object class? I implemented equals method for my value object, but it still seems to treat them as different objects.
If it is not using the equals method, can we do that? Because, Java Set itself relies on the equals method to make sure no duplicates exist in the set.
Please suggest.
In the below test case, I'm using sysCode and localId as a combined identifier for the object, not including the goldenId.
But the diff (output below the class) is not recognizing that equal objects and showing the diff as all the objects in the old set as removed and the objects in the new se as added, which doesn't seem to add any value.
Here is my test case:
Javers javers = JaversBuilder.javers().build();
SetConMap oldMap = new SetConMap();
Set<Contact> oldSysCons = new HashSet<>();
oldMap.setSysCons(oldSysCons);
oldSysCons.add(new Contact().sysCode("AL").localId("123").goldenId("ABC"));
oldSysCons.add(new Contact().sysCode("AL").localId("456").goldenId("ABC"));
SetConMap newMap = new SetConMap();
Set<Contact> newSysCons = new HashSet<>();
newMap.setSysCons(newSysCons);
newSysCons.add(new Contact().sysCode("AL").localId("123").goldenId("DEF"));
newSysCons.add(new Contact().sysCode("AL").localId("456").goldenId("DEF"));
newSysCons.add(new Contact().sysCode("AL").localId("789").goldenId("DEF"));
Diff diff = javers.compare(oldMap, newMap);
System.out.println(diff);
private static class Contact {
private String sysCode;
private String localId;
private String goldenId;
//getters, setters.
#Override
public int hashCode() {
return super.hashCode();
}
#Override
public boolean equals(Object obj) {
return obj != null && (obj instanceof Contact) && Objects.equals(sysCode, ((Contact) obj).getSysCode())
&& Objects.equals(localId, ((Contact) obj).getLocalId());
}
}
Diff:
* new object: org.ishafoundation.cdi.web.rest.GoldenContactResource$SetConMap/#sysCons/c76fadcd55d4dbf6d8cbe49310b1ab26
* new object: org.ishafoundation.cdi.web.rest.GoldenContactResource$SetConMap/#sysCons/96b23b34a0f42a5105491350db5c46f1
* new object: org.ishafoundation.cdi.web.rest.GoldenContactResource$SetConMap/#sysCons/a9c7f46bbe5f0e46b5751f3f5c5d8542
* object removed: org.ishafoundation.cdi.web.rest.GoldenContactResource$SetConMap/#sysCons/a53e4ba1b22c4f290a80daf40adf5d81
* object removed: org.ishafoundation.cdi.web.rest.GoldenContactResource$SetConMap/#sysCons/782edf187b8add9bab004ca06f7b6c7c
* changes on org.ishafoundation.cdi.web.rest.GoldenContactResource$SetConMap/ :
- 'sysCons' collection changes :
. 'org.ishafoundation.cdi.web.rest.GoldenContactResource$SetConMap/#sysCons/782edf187b8add9bab004ca06f7b6c7c' removed
. 'org.ishafoundation.cdi.web.rest.GoldenContactResource$SetConMap/#sysCons/a53e4ba1b22c4f290a80daf40adf5d81' removed
. 'org.ishafoundation.cdi.web.rest.GoldenContactResource$SetConMap/#sysCons/a9c7f46bbe5f0e46b5751f3f5c5d8542' added
. 'org.ishafoundation.cdi.web.rest.GoldenContactResource$SetConMap/#sysCons/c76fadcd55d4dbf6d8cbe49310b1ab26' added
. 'org.ishafoundation.cdi.web.rest.GoldenContactResource$SetConMap/#sysCons/96b23b34a0f42a5105491350db5c46f1' added
The Contact class is considered as a Value Object by Javers: in this case, it performs a property by property comparison (see here).
To get more detailed comparison results, you may transform the Contact class into an Entity using the #Id annotation on one of its properties.
Another solution may be to write a custom comparator here (but I never tried it).
Imagine an Optional.ofNullable check assigning to a String:
String result = Optional.ofNullable(class1)
.map(Class1::getClass2)
.map(Class2::getResult);
Where getResult returns a String.
While I know this doesn't compile, I can fix it by either adding toString() or .orElse(""); to sort that.
As it stands, the error is:
Bad return type in method reference, cannot convert java.lang.String
to U
I understand adding orElse("") as that will assign result to an empty String.
But what's the benefit of adding toString() if something is null along the way? Or is that just to purely get it to compile?
The return type of map is Optional <U>, so to get a real value you should call for orElse with the return type of T.
This is the toString implementation if the Optional:
#Override
public String toString() {
return value != null
? String.format("Optional[%s]", value)
: "Optional.empty";
}
So, calling toString you'll never get the real value, but a value wrapped to Optional, while orElse will return you the default provided value.
Let's see the difference:
Integer i = 4;
String s = Optional.ofNullable(i)
.map(Objects::toString)
.toString();
System.out.println(s);
Output:
Optional[4]
With null:
Integer i = null;
String s = Optional.ofNullable(i)
.map(Objects::toString)
.toString();
System.out.println(s);
Output:
Optional.empty
While using orElse:
Integer i = null;
String s = Optional.ofNullable(i)
.map(Objects::toString)
.orElse("None");
System.out.println(s);
Output:
None
So you can see that there are different purposes of these methods.
And the answer to your comment:
"Is there a way to call get() and also call orElse() in the same chain?"
Integer i = 10;
String s = Optional.ofNullable(i)
.map(Objects::toString)
.orElse("None");
System.out.println(s);
Output:
10
You don't need to call get explicitly, the value will be fetched if not null;
/**
* If a value is present, returns the value, otherwise returns
* {#code other}.
*
* #param other the value to be returned, if no value is present.
* May be {#code null}.
* #return the value, if present, otherwise {#code other}
*/
public T orElse(T other) {
return value != null ? value : other;
}
I understand adding orElse("") as that will assign result to an empty
String.
It doesn't sound like you do understand it to me because that's not a good description of what's happening. Optional.orElse does the following: if the optional contains a value, return that value. If it doesn't contain a value, return whatever argument you've given it.
It's semantically equivalent to the following:
if (optional.ifPresent())
{
return optional.get();
}
else
{
return theArgument;
}
Calling toString, while it will satisfy the compiler, is not what you want to do. You are converting the Optional object itself to a String, not getting the String from inside! While your string will be included, this is only because of how the JDK developers have decided to implement toString. They could equally have not provided an implementation, leaving you with just the default behaviour.
Calling toString on an Optional should basically never be relied upon outside of logging. It's essentially just debugging information. If you do this, then information about the Optional wrapper will be printed as well, which is almost certainly not what you want.
System.out.println(Optional.empty()); // Optional.empty
System.out.println(Optional.of("foo")); // Optional[foo]
If you want result to be null if something along the way returns null then do orElse(null)
String result = Optional.ofNullable(class1)
.map(Class1::getClass2)
.map(Class2::getResult).orElse(null);
When called this.getClass().getFields() to return an array of Field objects, would it return the same objects in subsequent calls?
In case someone wondering why this is asked, I am trying to put the Field objects as key and their current value as value in a HashMap to be retrieved later on while changes can be made to the field values, the old values are kept for comparison.
There is no guarantee that you will get the same objects from different calls and the chances are that you won't. One thing you can do is check the source code for the Class class.
In my installation of jdk1.8.0_131 has the following as the code for getFields()
public Field[] getFields() throws SecurityException {
checkMemberAccess(Member.PUBLIC, Reflection.getCallerClass(), true);
return copyFields(privateGetPublicFields(null));
}
Now you can follow that further, but I'm thinking that this makes a copy of some internal data.
This doesn't mean that the values wont work as keys in a HashMap however, because the HashMap will use the .equals() and .hashCode() methods to determine if two keys are the same, and not the equals operator '=='.
So here is some clunky code to investigate this:
public static void main(String... none) throws Exception {
Field[] fields1 = Point.class.getFields();
Field[] fields2 = Point.class.getFields();
for (int i = 0; i < fields1.length; ++i) {
compare(fields1[i], fields2[i]);
}
}
static void compare(Field field1, Field field2) {
System.out.format("Field %s\n", field1.getName());
System.out.format("field1 == field2 -> %s\n", field1 == field2);
System.out.format("field1.equals(field2) -> %s\n", field1.equals(field2));
System.out.format("field1.hashCode() == field2.hashCode() -> %s\n", field1.hashCode() == field2.hashCode());
System.out.println();
}
Which for me has the output:
Field x
field1 == field2 -> false
field1.equals(field2) -> true
field1.hashCode()==field2.hashCode() -> true
Field y
field1 == field2 -> false
field1.equals(field2) -> true
field1.hashCode() == field2.hashCode() -> true
So it looks like you may be ok to use the Field instances as keys. Furthermore if you look at the documentation for .equals() on Field it reads:
/**
* Compares this {#code Field} against the specified object. Returns
* true if the objects are the same. Two {#code Field} objects are the same if
* they were declared by the same class and have the same name
* and type.
*/
There is similar documentation for .hashCode() so you'll probably be ok using the field as a key.
This question already has answers here:
when to use toString() method
(9 answers)
Closed 6 years ago.
I've been learning Java currently and am confused about a certain piece of code. I come from a C, Python background, so I'm more learning the syntax and small niches of Java.
Below I have 2 classes. My Main class and a class that contains a method to return the decorated input string of the class.
I'm confused as to why calling myObject automatically calls the "toString()" method which returns the message? Shouldn't I need to define the method I want to call on the object? Why can you do this in Java?
I thought it was because the class is called "OtherClass" and the method inside OtherClass is called "OtherClass" but when I test this hypothesis out with another class, calling the object returns the object and it's address location.
Any help would be great. Thanks!
public class HelloWorld
{
public static void main(String[] args)
{
int i = 0;
OtherClass myObject = new OtherClass("Hello World!");
// This calls method toString()
System.out.print(myObject);
// This calls method toString()
System.out.print(myObject.toString());
}
}
public class OtherClass
{
private String message;
private boolean answer = false;
public OtherClass(String input)
{
message = "Why, " + input + " Isn't this something?\n";
}
public String toString()
{
return message;
}
}
public void print(Object obj)
Prints an object. The string produced by the String.valueOf(Object) method is translated into bytes according to the platform's default character encoding, and these bytes are written in exactly the manner of the write(int) method.
public static String valueOf(Object obj)
Returns the string representation of the Object argument.
public static String valueOf(Object obj) {
return (obj == null) ? "null" : obj.toString();
}
And as #Andreas said in the comments, toString() prints the hashcode if this method isn't overridden by the subclass:
public String toString() {
return getClass().getName() + "#" + Integer.toHexString(hashCode());
}
"I thought it was because the class is called "OtherClass" and the method inside OtherClass is called "OtherClass" but when I test this hypothesis out with another class, calling the object returns the object and it's address location."
In fact, the method which holds the same name as the class(OtherClass for example) is the constructor method, which will be called automatically when you initialize the class.
In this case, when you run OtherClass myObject = new OtherClass("Hello World!");, the constructor method
public OtherClass(String input)
{
message = "Why, " + input + " Isn't this something?\n";
}
is called and set message value.
And when it comes to System.out.print(myObject);, myObject.toString()will be called and return String message.
So the key point here is to override toString() method in your class, you may print whatever message you want by modifying toString()method, if this method is not override, it will return something associate with hashcode. (Just try and enjoy~)
in Java there is a class that called Object, any other classes that you define
inherit from that , it has a method named 'toString'
/**
* Returns a string representation of the object. In general, the
* {#code toString} method returns a string that
* "textually represents" this object. The result should
* be a concise but informative representation that is easy for a
* person to read.
* It is recommended that all subclasses override this method.
*
* The {#code toString} method for class {#code Object}
* returns a string consisting of the name of the class of which the
* object is an instance, the at-sign character `{#code #}', and
* the unsigned hexadecimal representation of the hash code of the
* object. In other words, this method returns a string equal to the
* value of:
*
*
* getClass().getName() + '#' + Integer.toHexString(hashCode())
*
*
* #return a string representation of the object.
*/
So you can simply run your main method in debug mode and set a break point
in toString of Object
System.out.println(new Object());
If you want to represent any object as a string, toString() method comes into existence.
If you print any object, java compiler internally invokes the toString() method on the object. So overriding the toString() method, returns the desired output, it can be the state of an object etc. depends on your implementation.
Java was designed to easily print objects as strings.
System.out is a PrintStream (see https://docs.oracle.com/javase/8/docs/api/java/io/PrintStream.html#print-java.lang.Object-)
When you pass an object to the method print (or println), you're actually calling
String.valueOf(Object) (see https://docs.oracle.com/javase/8/docs/api/java/lang/String.html#valueOf-java.lang.Object-)
Which in turn will do the following
"if the argument is null, then a string equal to "null"; otherwise,
the value of obj.toString() is returned."
If your object has an explicit toString() implementation, this method will be called, otherwise the interpreter will try to find an object in the hierarchy that implements it.
This is a build in feature in java. You dont need to write .toString() to print information about the Object.
You can use this feature everywhere, even with java operators:
System.out.print(myObject1 + myObject2);
is the same like:
System.out.print(myObject1.toString() + myObject2.toString());
toString() is a method in java.lang.Object, so every object contains this method. The default implementation displays the hashcode. You can override it with your own implementation.
I have a problem when retrieving values from a hashmap. The hashmap is declared as follows:
HashMap<TRpair,A> aTable = new HashMap<TRpair,A>();
I then put 112 values into the map as follows:
aTable.put(new TRpair(new T(<value>),new Integer(<value>)),new Ai());
where Ai is any one of 4 subclasses that extend A.
I then proceed to check what values are in the map, as follows:
int i = 0;
for (Map.Entry<TRpair,A> entry : aTable.entrySet()) {
System.out.println(entry.getKey().toString() + " " + entry.getValue().toString());
System.out.println(entry.getKey().equals(new TRpair(new T("!"),new Integer(10))));
i++;
}
i holds the value 112 at the end, as one would expect and the equality test prints true for exactly one entry, as expected.
However, when I do
System.out.println(aTable.get(new TRpair(new T("!"), new Integer(10))));
null is output, despite the above code snippet confirming that there is indeed one entry in the map with exactly this key.
If it helps, the class TRpair is declared as follows:
public class TRpair {
private final T t;
private final Integer r;
protected TRpair(Integer r1, T t1) {
terminal = t1;
row = r1;
}
protected TRpair(T t1, Integer r1) {
t = t1;
r = r1;
}
#Override
public boolean equals(Object o) {
TRpair p = (TRpair)o;
return (p.t.equals(t)) && (p.r.equals(r));
}
#Override
public String toString() {
StringBuilder sbldr = new StringBuilder();
sbldr.append("(");
sbldr.append(t.toString());
sbldr.append(",");
sbldr.append(r.toString());
sbldr.append(")");
return sbldr.toString();
}
}
the equals() and toString() methods in each of the Ai (extending A) and in the T class are overridden similarly and appear to behave as expected.
Why is the value output from the hashmap aTable null, when previously it has been confirmed that the value for the corresponding key is indeed in the map?
With many thanks,
Froskoy.
The keys/elements for a Hash collection but override hashCode() if euqals is overridden.
You could use.
public int hashCode() {
return t.hashCode() * 31 ^ r.hashCode();
}
BTW: It appears from your code that Integer r cannot be null in which case using int r makes more sense.
From Object.equals()
Note that it is generally necessary to override the hashCode method whenever this method is overridden, so as to maintain the general contract for the hashCode method, which states that equal objects must have equal hash codes.
IIRC hashmap looks up by hashCode() and not by equality, and since you did not implemented hashcode you use default implementation which is consistent with object pointer equality -
you need to implement proper hashcode function which takes into account "T" parameter as well as integer (or not)
It is good practice that hashCode() and equals() are consistent, but not structly necessary if you know what you are doing.