Java - Class.isInstance() always returns false - java

In my GameObject class I have the following method to check if the GameObject would be colliding with another object if it moved to the specified position:
public boolean collisionAt(Vector2d position, Class<? extends GameObject>... exclusions) {
if (getBounds() == null)
return false;
Rectangle newBounds = getBounds().clone();
newBounds.setPosition(position);
// Check collisions
for (GameObject object : new ArrayList<>(gameObjects)) {
if (object.getBounds() != null && newBounds.intersects(object.getBounds()) && object != this) {
boolean b = true;
for (Class<? extends GameObject> exclusion : exclusions) {
if (object.getClass().isInstance(exclusion))
b = false;
}
if (b)
return true;
}
}
return false;
}
I want to allow the program to define exclusions, for example if I don't want this method to return true if it collides with a Spell. But for some reason the Class.isInstance() line always returns false. I even tried this:
System.out.println(Spell.class.isInstance(Spell.class));
and the console outputs false! What's going on here?

The isInstance tests if the given object is an instance of the Class, not if the given Class is a subclass of the Class.
You have your invocation backwards. You need to test if the gameObject is an instance of one of the exclusion classes.
if (exclusion.isInstance(gameObject))

From official Javadocs
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.
You need to pass in the object of class rather than the class itself.
Example
SomeClass object = new SomeClass();
System.out.println(SomeClass.class.isInstance(object));

You need to pass in an instance of the class in question rather than a class literal. E.g.
Spell spell = new Spell();
System.out.println(Spell.class.isInstance(spell));

isInstance determines if the specified Object is assignment-compatible with the object represented by this Class. You're passing it a class when it expects an object.
The opposite should work:
Spell.class.isInstance(spell)

Related

Abstract class with equals method for all subclasses

I am trying to override the equals method in an abstract class. Is there a way that I can check if the parameter Object o is an instance of the class that has inherited the method and to then typecast o to same type as the class that has inherited the equals method?
This is what I have tried so far, but I am receiving the error variable of type java.lang.Object. Is there a reason that o is not being typecast? The getOperand()
method returns a compound type.
#Override
public boolean equals(Object o){
if (o.getClass() == this.getClass()){
this.getClass().cast(o);
return (o.getOperand().equals(this.getOperand()));
}
else {
return false;
}
}
You need to :
Assign the result of the cast to your class reference type so that the compiler is able to find the getOperand method since Object class doesn't have such a method.
Use the equals method to compare the operand values rather than using ==.
Use instanceof so that the solution supports mixed type equality. (Read Liskov Substitution Principle. Optional if you don't want to support mixed type equality)
Mark the equals method as final to prevent subclasses from overriding it inorder to support symmetry (if x.equals(y) then y.equals(x). Not required if not supporting mixed type equality)
public abstract class EqualsTest {
public final boolean equals(Object o) {//make equals final to maintain symmetry
if (o instanceof EqualsTest) {//use instanceof
EqualsTest e = (EqualsTest)o;//cast and assign to EqualTest reference
return e.getOperand().equals(this.getOperand());//use equals here
} else
return false;
}
}
}
With the above changes, sub-classes can inherit the equals method as is :
class EqualsTestSubClass extends EqualsTest {
//inherts the equals and getOperand methods.
}
class EqualsTestSubClass2 extends EqualsTestSubClass {
//inherts the equals and getOperand methods.
}
You can then check equality of an EqualsTestSubClass instance which is a direct subclass of EqualsTest and EqualsTestSubClass2 instance which is a subclass of EqualsTestSubClass instances as follows :
EqualsTest e1 = new EqualsTestSubClass();
EqualsTest e2 = new EqualsTestSubClass2();
System.out.println(e1.equals(e2));
Note : It is a better idea to directly compare the operand field in the equals method rather than using getOperand since getOperand is overridable.

Questions about the Class method "forName()"

How do I let the user insert a String and check for classes with the same "name"?
Imagine I have a method marked as public A[] getB(String bString) and two classes, A and B, where B extends A.
In this method I want to search through an existing A[] for objects that are upcast from being from the class B and return an A[] with said objects.
I searched through the internet and found out that the class Class has the method forName(), but I don't really understand how to use it. For example, I do this:
Class<?> cl = Class.forName(bString);
Where bString is a String that contains B, B being another class.
My questions are:
What exactly is the object "cl" now?
How could I now check if objects are of the same class as it?
What exactly is the object "cl" now?
cl is an instance of Class class.
How could I now check if objects are of the same class as it?
you have 2 object o1 and o2 you can use getClass()
o1 != null && o2 != null && o1.getClass().equals(o2.getClass())
The method Class.forName(String) returns a Class object for the corresponding class, if known. To quote from its documentation:
Returns the Class object associated with the class or interface with the given string name.
An example would be:
Class threadClass = Class.forName("java.lang.Thread");
Note that the name of the class needs to be fully qualified, not just Thread but java.lang.Thread.
The object you are getting is, as said, a representation of the corresponding class. You can use it to dynamically create instances, check methods, and so on. Here is its documentation and here is an example:
Class<?> threadClass = Class.forName("java.lang.Thread");
// Dynamically create a thread, unchecked cast
Thread thread = (Thread) threadClass.newInstance();
You can check whether two objects are of the same class by using the getClass (documentation) method which every object has:
if (first.getClass().equals(second.getClass()) {
// Same
} else {
// Different
}
However note that this comparison is strict. It would throw false if you compare Integer and Number although Integer extends Number. If you want a less strict variant you may use the instanceof operator:
if (first instanceof second) {
// Is type of
} else {
// Not type of
}
are you sure you wouldn't rather use isInstance?
You could change your method to take a Class instead of a String, since that's what you're really using, a Class.
public A[] getB(Class type){
// I'm assuming you have an array of all As somewhere, called Aarray here
List<A> BList = new ArrayList<>();
for(int i = 0; i < Aarray.length; i++){
if(type.isInstance(Aarray[i])){
BList.add(Aarray[i]);
}
}
return BList.toArray();
}

Java equals() method - how does 'semantics of equals in subclasses' determine the use of getClass and instanceof

I'm a beginner in Java programming. Currently I'm reading about Inheritance and the equals method at this page.
I understand the explanations until this point:
Compare the classes of this and otherObject. If the semantics of
equals can change in subclasses, use the getClass test:
if (getClass() != otherObject.getClass()) return false;
If the same semantics holds for all subclasses, you can use an instanceof test:
if (!(otherObject instanceof ClassName)) return false;
I don't understand what 'semantics of equals' mean. Can someone share scenarios where we use getClass() and instanceof please?
Thank you for reading.
Simply put, getClass() returns the immediate class of the object. for example,
class A { }
class B extends A { }
if we create two objects from A and B,
A objA = new A();
B objB = new B();
now we can check how getClass work
System.out.println(objA.getClass()); //Prints "class A"
System.out.println(objB.getClass()); //Prints "class B"
So,
objA.getClass() == objB.getClass()
returns false. But
System.out.println(objB instanceof A); //Prints true
This is because instanceof returns true even if a superclass is given of the provided object.
So, when you design your equals() method, if you want to check the given object(otherObject) is instantiated from the same immediate Class, use the
if (getClass() != otherObject.getClass()) return false;
If it is okay that the given object(otherObject) is made even from a subclass of a Class (ClassName) you provide, use
if (!(otherObject instanceof ClassName)) return false;
Simply, "semantics of equals" means "The purpose you expect from equals() method". So you can use the appropriate method according to your need.
changing semantics of equals
It means that may be the equals method can be overwritten in subclasses, in such scenarios use getClass to check whether objects belong to same class.
In general, getClass vs instance of
We use getClass when we need to know the class of a particular object. Consider cases when there is linear chain of Inheritance as follows:
MainClass -> SubClassLevel1 -> SubClassLevel2
and initialize as
MainClass mc = new SubClassLevel2();
Here to know that which class in the hierarchy is the class of our object.
Now, instance of method is used in the cases where you have to merely check that whether x is an instance of class Y or not. It returns boolean.
Hope this answers your query :)

How can I return objects of different type from a single function?

I need to return objects of different classes in a single method using the keyword Object as the return type
public class ObjectFactory {
public static Object assignObject(String type) {
if(type.equalsIgnoreCase("abc")){
return new abcClass();
} else if(type.equalsIgnoreCase("def")) {
return new defClass();
} else if(type.equalsIgnoreCase("ghi")) {
return new ghiClass();
}
return null;
}
}
and in another class I am trying to get the objects as
public class xyz{
public void get(){
Object obj=(abcClass)ObjectFactory.assignObject("abc");
}
}
How can I access the methods in abcClass using the obj object??
Your current code will throw an exception if assignObject returns an instance that is not an abcClass, so you can change the type of obj to absClass :
public void get(){
abcClass obj=(abcClass)ObjectFactory.assignObject("abc");
}
I would suggest as one of the commentators on your initial post did. That is, refactor this to use an interface.
Your classes AbcClass, DefClass, and GhiClass, could all implement an interface, lets call it Letters. You can then define a class called LettersFactory, with the method createLetters. At this point, I'd also recommend changing your hard coded string identifiers into an enumeration. For instance:
public enum LetterTypes { ABC, DEF, GHI }
You're factory method can then accept this enumeration, and you have no fears of getting invalid values. The factory method can also return the type Letters (the interface) and you have a more specific version of Object (which is good).
Finally, if you need to determine these types on the fly, you can have a method defined in Letters (forcing all children to implement it) called getType() which returns the LetterTypes enumeration for the class that is implemented.
You could also use the instanceof operator to determine which class you have.
Cheers,
Frank
You can use this as a refrence :-
public Object varyingReturnType(String testString ){
if(testString == null)
return 1;
else return testString ;
}
Object o1 = varyingReturnType("Lets Check String");
if( o1 instanceof String) //return true
String now = (String) o1;
Object o2 = varyingReturnType(null);
if( o2 instanceof Integer) //return true
int i = (Integer)o2;
So similarly you can use your own conditions along with the instanceof operator and can cast it to get the actual object type from Object type.

java why should equals method input parameter be Object

I'm going through a book on data structures. Currently I'm on graphs, and the below code is for the vertex part of the graph.
class Vertex<E>{
//bunch of methods
public boolean equals(Object o){
//some code
}
}
When I try to implement this equals method my compiler complains about not checking the type of the parameter and just allowing any object to be sent it. It also does seem a bit strange to me why that parameter shouldn't be a Vertex instead of an Object. Is there a reason why the author does this or is this some mistake or antiquated example?
#Override
public boolean equals(Object obj)
{
if (!(obj instanceof Vertex)) return false;
else return // blah blah
}
equals(Object) is the method defined in the root - Object. If you don't match the signature exactly, Object's version will be called when someone checks if two objects are equal. Not what you want.
You've probably seen other methods (like Comparator) where you can use the exact time. That's because those APIs were generic-ified with Java 5. Equals can't be because it is valid to call equals with two separate types. It should return false, but it is valid.
equals is a method inherited from Object, is defined to be flexible enough so that you can take any object and test if it is equal to any other object (as it rightfully should be able to do), so how could it be any other way?
Edit 1
Comment from jhlu87:
so is it not good form to write an equals method that has an input parameter of vertex?
You are welcome to create your own overload to any method, including equals, but doing so without changing the name could risk confusing many who would assume that your equals is the one that inherits from Object. If it were my code and I wanted a more specific equals method, I'd name it slightly different from just "equals" just to avoid confusion.
If your method doesn't take an argument of type Object, it isn't overriding the default version of equals but rather overloading it. When this happens, both versions exist and Java decides which one to use based on the variable type (not the actual object type) of the argument. Thus, this program:
public class Thing {
private int x;
public Thing(int x) {
this.x = x;
}
public boolean equals(Thing that) {
return this.x == that.x;
}
public static void main(String[] args) {
Thing a = new Thing(1);
Thing b = new Thing(1);
Object c = new Thing(1);
System.out.println(a.equals(b));
System.out.println(a.equals(c));
}
}
confusingly prints true for the first comparison (because b is of type Thing) and false for the second (because c is of type Object, even though it happens to contain a Thing).
It's because this method existed before generics, so for backward compatabitity it has to stay this way.
The standard workaround to impose type is:
return obj instanceof MyClass && <some condition>;
It is because the author is overriding equals. Equals is specified in java.lang.Object and is something that all classes inherrits from.
See the javadoc for java.lang.Object

Categories