Java getClass and super classes - java

public boolean equals(Object o) {
if (this == o)
return true;
if ((o == null) || (this.getClass() != o.getClass()))
return false;
else {
AlunoTE umAluno = (AlunoTE) o;
return(this.nomeEmpresa.equals(umAluno.getNomeEmpresa()) && super.equals(umAluno);
}
}
Could anyone explain me how the fourth line ((this.getClass() != o.getClass())) works when the argument is a super class? Because the classes have different names. this.getClass will return a different name than o.getClass, right?

Check the following code snippet which answers your question. Object O can hold any object. o.getClass() will return the run time class of the object
public class Main {
void method(Object o) {
System.out.println(this.getClass() == o.getClass());
}
public static void main(String[] args) {
new Main().method(new Object()); // false
new Main().method(new Main()); // true
new Main().method(new String()); // false
new Main().method(new MainOne()); // false
}
}
class MainOne extends Main
{
}

So lets say there are two classes. Class A and Class B. Class A is a super class of class B. So this method would be in class B. "this.getClass()" refers to an object of class B while o.getClass()(The super class) will refer to class A. So Class B will not equal Class A. Meaning it will go into the if statement.

Suppose your super class is SHAPE and you have a class RECT that is a subclass of SHAPE.
If the this variable is for a RECT and the Object o is also a RECT,
then line 4 will return true because they are the same class (RECT).
The two objects will be equal as long as their types are the same at runtime.
However, if Object o is of type SQUARE, which also subclasses SHAPE,
(and could even subclass RECT).
then it will not be equal to the this pointer (RECT),
because their classes are different at runtime.
Now for why this kind of type checking is bad in the equals method (specifically for the use case of Hibernate entity classes).
If you use Hibernate and you are checking a newly created object whose class type is RECT against an object whose class type was RECT at the time it was cached in Hibernate, the class of the object in the cache will actually be a sub-class of type RECT, because Hibernate does byte-code manipulation and wraps the objects in a synthetic sub-class (RECT_$$javassist).
This means that your Hibernate cached objects that you expect to be equal will never be equal.
If the object is in a child collection, Hibernate will assume you wanted to delete the old object from the collection and create the new object in the collection instead of doing a (potential) update on an existing object in the collection.
We have legacy code that did this and could never figure out why (until now) it kept doing deletes and re-inserts on our collection.
For Hibernate entity objects you should use the instanceof operator to determine if two objects could be equal - and then cast Object o and continue the comparison operation with class SHAPE specific fields.
If your subclasses should not be considered equal, then you will have to implement equals() in each subclass to check for instanceof.
For other use cases, you will have to determine if there is a chance that someone (or some other library) could sub-class your Class (even through byte code manipulation) and whether any sub-classes should still be considered equal or not.
For instance, if you do any kind of mocking in your unit tests, a bad equals method may cause otherwise equal objects to be non-equal due to their classes not being equal.
Back to the OP's code. A better way to code the equals method would be:
public boolean equals(Object o) {
if (this == o)
return true;
if (!(o instanceof AlunoTE))
return false;
AlunoTE umAluno = (AlunoTE) o;
return(this.nomeEmpresa.equals(umAluno.getNomeEmpresa()) && super.equals(umAluno);
}
Because the instanceof operator always returns false for null, there is no need for a null check too.

Related

How to use an object that was called from a method in Java?

I'm trying to figure out what the syntax is for calling an object inside a method..
Pseudocode:
boolean check(Object someObject) {
return someObject == theOtherObject;
}
public static void main(String args[]) {
someClass one = new someClass();
someClass two = new someClass();
one.check(two);
}
So the check method is supposed to check whether the two objects are equal, but how would I specify the other object (theOtherObject should be one)?
Thanks in advance!
One word answer: this
boolean check(Object someObject) {
return someObject == this;
}
which will test object identity only. You should override equals and use that.
if (one.equals(two)) {
// ...
}
You can have the boolean check(Object o) method inside SomeClass and check
boolean check(Object o) {
this == (SomeClass) o;
}
This would work only if both reference variables are pointing to same object. Moreover the right way to check if two objects are meaningfully equal would be to use the inherited equals and hashCode method.
Override equals and hashCode method.
Why do I need to override the equals and hashCode methods in Java?
https://docs.oracle.com/javase/8/docs/api/java/lang/Object.html#equals-java.lang.Object-
So what you're asking for there is actually already a command in java.lang.Objects class to compare to objects.
one.equals(two)
the comparison this does is called a shallow comparison. So if that's what you're looking to do then this would work. For reference, the definitions of shallow comparison defined by geeksforgeeks.org is
Shallow comparison: The default implementation of equals method is defined in Java.lang.Object class which simply checks if two Object references (say x and y) refer to the same Object. i.e. It checks if x == y. Since Object class has no data members that define its state, it is also known as a shallow comparison.
if you're looking to do a more complicated comparison you're the best bet would be to actually override the equals command in the one class file
this article would be a good place to start to learn more about this topic.
https://www.geeksforgeeks.org/equals-hashcode-methods-java/

Inheritance and 'Instanceof' testing result

I'm studying 'instanceof' java, but I couldn't understand 'instanceof' clearly, I thought below answer would be true and false, but result is both true. Could you explain why this result happen? As I know, when A is child of B (Parent), and a instanceof B is 'false' but result is different with what I thought.
class Car{
String color;
int door;
}
class FireEngine extends Car{
void water(){
System.out.println("water");
}
}
public class Operator {
public static void main(String[] args) {
Car car = new FireEngine();
FireEngine fireCar = new FireEngine();
System.out.println(car instanceof FireEngine);
System.out.println(fireCar instanceof Car);
}
}
Declaration != Value
You declare car as an Car, but the Value is an FireEngine.
instanceof works based on values, not on the declarations of their variables!!!
Shortening may help to understand:
System.out.println(new FireEngine() instanceof FireEngine); // true
System.out.println(new FireEngine() instanceof Car); // true
The output of instanceof depends on the runtime type of the variable whose type you are testing. The compile time type of the variable doesn't matter (as long as it is possible that x instanceof Y will return true for some value of x, otherwise the expression won't pass compilation).
Both car and fireCar hold instances of FireEngine in your code. And since FireEngine is a kind of a Car, both car and fireCar are instanceof both Car and FireEngine, so your code prints true and true.
Implementation of the Instanceof operator. Returns a Boolean if the Object parameter (which can be an expression) is an instance of a class type.
Input 1: An object or Expression returning an object.
Input 2: A Class or an Expression returning a Class
Returns: A Boolean that is the result of testing the object against the Class.
For more information please go throught the javadocs # http://docs.oracle.com/cd/E13155_01/wlp/docs103/javadoc/com/bea/p13n/expression/operator/Instanceof.html
For more detailed explanation with examples please go through the following web page : http://mindprod.com/jgloss/instanceof.html
In Java there are two types of bindings: static (the reference type)
and dynamic (the object type).
In your case:
Car car = new FireEngine();
Car is the static type and FireEngine is dynamic type. It means, you are actually working with a FireEngine (the object type). You can imagine Car as a special pointer with a car shape pointing to the real object that is your awesome FireEngine. If you read 'instanceof' you can understand it, this method tell you if an object is an instance of a class, not the reference. So the compiler will see: FireEngine (car) instanceOf FireEngine? Of course, let's return a true!
You can have a look to this post also: What is the 'instanceof' operator used for?
The statement
As I know, when A is child of B (Parent),
and a instanceof B is 'false' but result is different with what I thought.
is not correct. instanceof does not check for the child, it tests for the parent.

Overriding the Object class' equal method

OK so so let's say you have two classes: ClassA and ClassB
ClassA extends Object and ClassB extends ClassA
ClassA has no argument constructor
ClassB has an integer variable x and a constructor with an integer argument that initializes x
ClassA doesn't override equals that it's inhering from Object
ClassB overrides equals so that two objects of ClassB are considered equal if the integer x has the same value in both objects.
//In Class B you have this method:
public boolean equals (Object obj) {
if (obj == null) {
return false;
}
if (obj.getClass() != this.getClass()) {
return false;
}
if (!super.equals(obj)) {
return false;
}
B b = (B) obj;
return this.x == b.x;
}
In the main if you were to run this code
B b1 = new B(1);
B b2 = new B(1);
System.out.println(b1.equals(b2));
I believe "false" would be printed but I'm trying to understand why. Maybe I'm not fully understanding the concept of overriding but I just figured since B should be overriding the Object.equals method so it can make sure the x fields are the same.
What appears to be "wrong" that I'm missing?
You should omit the
if (!super.equals(obj))
{
return false;
}
because that will use the default equals() method (which checks for object identity)
Your code is never going to get past the super.equals check, because (since Object.equals is comparing object references) any two different objects are always going to test false for equality. Object.equals is comparing references, the only time it returns true is if it is comparing a reference to itself.
Typically if you override equals it is because you want to compare the objects by value (like String or BigInteger), so there is no reason for referencing the super class's equals method (which compares by reference) in that case.

calling specific methods of generic types in ny equals() method

I am working on the equals() method for my sparse matrix class that I'm writing (part of a school project). I am constantly runnung into the issue that it won't let me use any methods or other members specific to my class, because that(the name I used for the parameter to equals) has to be of the generic type Object in order to override Objects's equals() method. Even beyond that, I need to be able to use some of the methods of my SparseMatrix's type parameter in order to really compare the equality, unless I can also figure ou. How can I write it to get around that obstacle?
I have a few ideas how I night do it, but none of them seem to work: I've triedcasting the parameter, I've tried overlading equals(), I've even tried some other stuff, but none of it seems to work.
This is what I have so far, but, as I said, I just can't get it to work.
public boolean equals(Object that) {
if (that instanceof SparseMatrix<?>) {
if (this.xSize != that.xSize ||
this.ySize != that.ySize)
return false;
/* make some more comparisons that depend on specific
* members of my matrix class, etc...*/
}
return false;
}
I have tried searching SO for this, and while I was able to find a few that seemed to be asking the same thing, I couldn't find any answers that actually explained how to do it.
When you have an object of a base class and you know which kind of subclass it is, you can convert it by downcasting it. Then you can call any methods specific to the subclass.
public boolean equals(Object o) {
if (o instanceof SparseMatrix<?>) {
SparseMatrix that = (SparseMatrix)o; // <-- downcast
if (this.xSize != that.xSize ||
this.ySize != that.ySize)
return false;
}
return false;
}
Should o not be an instance of SparseMatrix or a class which extends/implements SparseMatrix (you already checked that, but let's assume you didn't) you would get a ClassCastException.
public boolean equals(Object that) {
if (that !=null && that instanceof SparseMatrix<?>) {
SparseMatrix that = (SparshMatrix)o;
if (this.xSize != that.xSize ||
this.ySize != that.ySize)
return false;
}
return false;
}
Added Code to check for null value.
You need to have this method overrided in the class whose instances you want to compare.. And when you actually invoke equals on instances of that class, this overrided method will be invoked..
** Moved from comment: - Using instanceof you can only assure of what type your instance is, and not the parameterized type of that instance.. (You cannot findout whether you have ArrayList<String>, what you can find out is that it is ArrayList or ArrayList<?> to be precise) .. Reason for that is, generic type information is only available at compile time, and is erased through type erasure , so they are not available at runtime..

Why can't a "Class" variable be passed to instanceof?

Why doesn't this code compile?
public boolean isOf(Class clazz, Object obj){
if(obj instanceof clazz){
return true;
}else{
return false;
}
}
Why I can't pass a class variable to instanceof?
The instanceof operator works on reference types, like Integer, and not on objects, like new Integer(213). You probably want something like
clazz.isInstance(obj)
Side note: your code will be more concise if you write
public boolean isOf(Class clazz, Object obj){
return clazz.isInstance(obj)
}
Not really sure if you need a method anymore ,though.
instanceof can be used only with explicit class names (stated at compile time). In order to do a runtime check, you should do:
clazz.isInstance(obj)
This has a small advantage over clazz.isAssignableFrom(..) since it deals with the case obj == null better.
As others have mentioned, you cannot pass a class variable to instanceof because a class variable references an instance of an Object, while the right hand of instanceof has to be a type. That is, instanceof does not mean "y is an instance of Object x", it means "y is an instance of type X". In case you don't know the difference between an Object and a type, consider:
Object o = new Object();
Here, the type is Object, and o is a reference to the instance of the Object with that type. Thus:
if(o instanceof Object)
is valid but
if(o instanceof o)
is not because o on the right hand side is an Object, not a type.
More specific to your case, a class instance is not a type, it is an Object (which is created for you by the JVM). In your method, Class is a type, but clazz is an Object (well, a reference to an Object)
What you need is an way to compare an Object to a Class Object. It turns out that this is popular so this is provided to you as a method of the Class Object: isInstance().
Here is the Java Doc for isInstance, which explains this better:
public boolean isInstance(Object obj)
Determines if the specified Object is assignment-compatible with the
object represented by this Class. This method is the dynamic
equivalent of the Java language instanceof operator. The method
returns true if the specified Object argument is non-null and can be
cast to the reference type represented by this Class object without
raising a ClassCastException. It returns false otherwise.
Specifically, if this Class object represents a declared class, this
method returns true if the specified Object argument is an instance of
the represented class (or of any of its subclasses); it returns false
otherwise. If this Class object represents an array class, this method
returns true if the specified Object argument can be converted to an
object of the array class by an identity conversion or by a widening
reference conversion; it returns false otherwise. If this Class object
represents an interface, this method returns true if the class or any
superclass of the specified Object argument implements this interface;
it returns false otherwise. If this Class object represents a
primitive type, this method returns false.
Parameters: obj - the object to check
Returns: true if obj is an instance of this class
Since: JDK1.1
Firstly, instanceof requires that the operand on the right is an actual class (e.g. obj instanceof Object or obj instanceof Integer) and not a variable of type Class. Secondly, you have made a fairly common newbie mistake that you really should not do... the following pattern:
if ( conditional_expression ){
return true;
} else{
return false;
}
The above can be refactored into:
return conditional_expression;
You should always perform that refactoring, as it eliminates a redundant if...else statement. Similarly, the expression return conditional_expression ? true : false; is refactorable to the same result.

Categories

Resources