Functions You always need to Override
We always can override non-final methods in parent class. However, we also need to pay attention to the general contracts of those methods. Otherwise, they will not work correctly. In this article, I would share how I learn about the way to override specific functions correctly with effective-java-3rd.
It is not necessary to override the equals method each time in child class. But if we really need overriding
equals() to solve our problems, our
equals() need to obey following contracts:
x.equals(x) = true
x.equals(y) iff y.equals(x)
if x.equals(y) && y.equals(z) => x.equals(z)
x.equals(y)should always has a same result
- For any x not null,
x.equals(null) = false
The problematic cases always happen when we try to use equals between different class.
I override the
equals() of a; however, I don’t override the
equals() of b. Then, this violate the symmetric. To solve this kind of problem, how about checking the instance of object which is the parameter of
equals()? Take a look at the e.g.-2.
This is an very interesting example because this would have a problem of stackoverflow. First, I would describe the difference between
getClass. Here I would assume that a is the parent class of b. The result of
(a instance of b) is false and
(b instanceof a) is true while the result of
(a.getClass != b.getClass()). The reason is that
getClass() would return the most cloest level of class name. But, if
b are the same level child classes, the problem of stackoverflow would happen.
a.equals(b) will try to call
b.equals(a) will call back to
a.equals(b) again… then it becomes an infinite call loop!
Here I would summarize four important points to overriding
==to check object type first. It can return true directly if we get true on this check, because
==would compare the memory addresses of two objects.
instanceofto check object type
- Cast of object to correct type
- check all properties match
The properties in the point four are those significant field in class such like some variable or arrays. If the fields are basic type which are not float or double, we can use
== to check equality.
If the fields are object, we should recursively call equals on properties of the object.
If the fields are float or double type, we should call
Then here comes a sample
At the end,
URL.equals() might violates the consistency requirement of equals. When connected to the Internet, the
equals() method follows the steps decribed in java API; when disconnected, it performs a string compare on the two URLS . In addition, you should also remember to override
hashCode() method after you override the
I would only describe an interesting problem in this section:
Why the result of
map.get(new Phone(123)) not
str? The answer is simple: two key are put into the different hash buckets because two keys have different hashcode! The solution is override hashCode() method with matching significant fields.
Here comes the contract we should obey while overriding
x.clone() != x
x.clone().getClass() == x.getClass()
x.clone().equals(x) == true
Always overriding clone() with super.clone()!! In addition, immutable object shoud not provide
Here we should make sure we return a precise object type instead of
public Object clone(). This way can help client not need to cast again in client side. But, if object with mutable references, deep copies are required:
However, if there are more mutable reference inside the mutable reference, we would need deeper copies:
However, there are much better ways to clone a object, the ways are called Copy Constructor and Copy Factory.
e.g. Copy Constructor
e.g. Copy Factory
I was confused about the use of result.elements = elements.clone(); in example. The elements is the private property of class. Why can we access to the private property of other instance? The answer is the private modifier does not mean that only the same instance can access to the field, but only objects of the same class can access to it!! I think this is very important fact each developers should understand.
Here is the class exercise of
Someone would implement
return new IntSet(new ArrayList<Integer>(els));. However, it is wrong way. I assume
IntChild is a subclass extending to
IntChild doesn’t override the
clone() method and I try to call
IntChild.clone(), it would call
IntSet.clone() and return the wrong type of object.