How should this instanceof condition look like? - java

I have a list of nodes. This nodes are a data class I defined by myself. Each node has a data field of the type Object. Now I want to find the node in a list of nodes that has the parameter object in the data field. I wrote this method, because I wanted to first compare if the two objects (the parameter and the object in the data field) are of the same type:
public Node getnNodeByData(Object obj) {
for (Node node : nodes) {
if (node.getData() instanceof obj.getClass()) {
}
}
}
Unfortunately this condition does not work:
Incompatible operand types boolean and Class<capture#1-of ? extends Graph>
I don't really know why this is a problem. How can I make this working?

No, you need to use Class.isInstance(Object). The instanceof keyword does not expect an object of type Class, but only the name of the class directly -- but Class.isInstance is basically analogous.

No, that is not possible like that. You should use isAssignableFrom() or isInstance(). The difference between the two methods is that isInstance(null) will return false and isAssignableFrom(null) will give true.
[object] instanceof [class]
should be translated to this:
[class].class.isAssignableFrom(object.getClass());
Example:
Integer i = 4;
boolean b = i instanceof Number;
boolean k = Number.class.isAssignableFrom(i.getClass());
b and k are equivalent.

Related

SPRING Function to validate object not accepting type of data

I'm triying to make a function to validate if an object is inside a List of objects, but I have a problem, because I'm using a class to define the properties of the awaiting object, so in the IDE seems to give some help to solve the issue, but I don't want to do like that, my idea, is to make a function global, to validate any type of list, so this is my code, sorry if are not good, but is a try.
*The list and the object have the same class.
objExist(statusClaim, statusClaimRP) /*<=== Is just the function on my code for reference */
private Boolean objExist(List<Object> arreglo, Object objeto) throws JSONException {
Integer valida = 0;
for(Integer i = 0; i < arreglo.size(); i++) {
if(arreglo.get(i) == objeto) {
valida++;
}
}
if(valida > 0) {
return false;
} else {
return true;
}
}
The method objExist(List'<'Object'>', Object) in the type ClaimService is not applicable for the arguments (List'<'StatusClaimDTO'>', StatusClaimDTO).
As I understood you want to make sure that certain list contains certain object?
If so you can use list.contains(objectToFind) or streams:
listOfSomeObjects.stream().anyMatch(obj -> obj.equals(objectToFind);
Alternatevely, for learning purposes, you can simply iterate over you list in for loop and wrap it into generic method:
private <T> boolean listContainsElement(List<T> list, T elementToFind) {
for (T element: list) {
if (element.equals(elementToFind)) {
return true;
}
}
return false;
}
But it's not practical.
Note: == compares references, not objects themselves, which means if obj1 == obj2 that both variable point to the same instance of the object, if this is what you want then ok. But ussually objects are compared with equals method which you can override and use your own logic, otherwise it has default implementation that basically acts like == operator.

How can I change between classes?

This is what I wrote.
public class Test {
public static void main(String[] args) {
Object a1 = new A();
Object a2 = new Object();
System.out.println(a1.toString());
System.out.println((a1 == a2) + " " + (a1.equals(a2)));
}
}
class A {
int x;
public boolean equals(Object obj) {
A _obj = (A) obj;
return x == _obj.x;
}
public String toString() {
return "A's x is " + x;
}
}
How can I make 'false true' on the console? Except revising the main method. Revise only A method.
I tried to make change the Object a2 to an a2. How Can I change that in the A class?
The reason you're getting the error class java.lang.Object cannot be cast to class A is because the object you're comparing it to is not an instance of class A, so trying to cast the object as such will fail.
When implementing the .equals method, you should always perform these three checks first to ensure the safety of the object before you try comparing its properties:
if (obj == this) return true; If the two objects are the exact same object, meaning that they are the same instance, not just two objects with the same properties, immediately return true because there is no need to check the properties.
if (obj == null) return false; This prevents a NullPointerException by trying to access a property of a null object (such as when in your code you do return x == _obj.x)
if (!(obj instanceof A)) return false; If the object is not an instance of your class, the typecast will fail (as it did in your code) and this protects against that by returning false before trying to cast.
Finally, if the code reaches this point you can cast and compare the objects as you had done in your code:
A _obj = (A) obj;
return this.x == _obj.x;
Keep in mind that if the properties you are comparing are not primitives, you should use .equals on them
First of all, what do you mean by "making false true" exactly? I assume you want your code to run, but could you give us a bit more context of what you are trying to do?
The reason your code fails is that you are trying to cast your instance of an Object (a2) onto a reference of type A when you pass it into the equals method. But since a2 is actually a pure instance of Object and not of A, this cast fails. Even though Object is the baseclass for everything in Java, including your self defined A, you are casting in the wrong direction. An Object does not hold an attribute x so casting this way would be unsafe. Java's typechecking mechanism catches this and throws an error when you try to cast.
Have a look at a document explaining inheritance and casting to get the basics of this. E.g., this one.

arraylist.contains() method returns false [duplicate]

Say I create one object and add it to my ArrayList. If I then create another object with exactly the same constructor input, will the contains() method evaluate the two objects to be the same? Assume the constructor doesn't do anything funny with the input, and the variables stored in both objects are identical.
ArrayList<Thing> basket = new ArrayList<Thing>();
Thing thing = new Thing(100);
basket.add(thing);
Thing another = new Thing(100);
basket.contains(another); // true or false?
class Thing {
public int value;
public Thing (int x) {
value = x;
}
equals (Thing x) {
if (x.value == value) return true;
return false;
}
}
Is this how the class should be implemented to have contains() return true?
ArrayList implements the List Interface.
If you look at the Javadoc for List at the contains method you will see that it uses the equals() method to evaluate if two objects are the same.
I think that right implementations should be
public class Thing
{
public int value;
public Thing (int x)
{
this.value = x;
}
#Override
public boolean equals(Object object)
{
boolean sameSame = false;
if (object != null && object instanceof Thing)
{
sameSame = this.value == ((Thing) object).value;
}
return sameSame;
}
}
The ArrayList uses the equals method implemented in the class (your case Thing class) to do the equals comparison.
Generally you should also override hashCode() each time you override equals(), even if just for the performance boost. HashCode() decides which 'bucket' your object gets sorted into when doing a comparison, so any two objects which equal() evaluates to true should return the same hashCode value(). I cannot remember the default behavior of hashCode() (if it returns 0 then your code should work but slowly, but if it returns the address then your code will fail). I do remember a bunch of times when my code failed because I forgot to override hashCode() though. :)
It uses the equals method on the objects. So unless Thing overrides equals and uses the variables stored in the objects for comparison, it will not return true on the contains() method.
class Thing {
public int value;
public Thing (int x) {
value = x;
}
equals (Thing x) {
if (x.value == value) return true;
return false;
}
}
You must write:
class Thing {
public int value;
public Thing (int x) {
value = x;
}
public boolean equals (Object o) {
Thing x = (Thing) o;
if (x.value == value) return true;
return false;
}
}
Now it works ;)
Just wanted to note that the following implementation is wrong when value is not a primitive type:
public class Thing
{
public Object value;
public Thing (Object x)
{
this.value = x;
}
#Override
public boolean equals(Object object)
{
boolean sameSame = false;
if (object != null && object instanceof Thing)
{
sameSame = this.value == ((Thing) object).value;
}
return sameSame;
}
}
In that case I propose the following:
public class Thing {
public Object value;
public Thing (Object x) {
value = x;
}
#Override
public boolean equals(Object object) {
if (object != null && object instanceof Thing) {
Thing thing = (Thing) object;
if (value == null) {
return (thing.value == null);
}
else {
return value.equals(thing.value);
}
}
return false;
}
}
Other posters have addressed the question about how contains() works.
An equally important aspect of your question is how to properly implement equals(). And the answer to this is really dependent on what constitutes object equality for this particular class. In the example you provided, if you have two different objects that both have x=5, are they equal? It really depends on what you are trying to do.
If you are only interested in object equality, then the default implementation of .equals() (the one provided by Object) uses identity only (i.e. this == other). If that's what you want, then just don't implement equals() on your class (let it inherit from Object). The code you wrote, while kind of correct if you are going for identity, would never appear in a real class b/c it provides no benefit over using the default Object.equals() implementation.
If you are just getting started with this stuff, I strongly recommend the Effective Java book by Joshua Bloch. It's a great read, and covers this sort of thing (plus how to correctly implement equals() when you are trying to do more than identity based comparisons)
Shortcut from JavaDoc:
boolean contains(Object o)
Returns true if this list contains the specified element. More formally,
returns true if and only if this list contains at least one element e such
that (o==null ? e==null : o.equals(e))
record overrides equals
You said:
another object with exactly the same constructor input
… and …
Assume the constructor doesn't do anything funny with the input, and the variables stored in both objects are identical.
As other Answers explain, you must override the Object#equals method for List#contains to work.
In Java 16+, the record feature automatically overrides that method for you.
A record is a brief way to write a class whose main purpose is to communicate data transparently and immutably. By default, you simply declare the member fields. The compiler implicitly creates the constructor, getters, equals & hashCode, and toString.
The logic of equals by default is to compare each and every member field of one object to the counterpart in another object of the same class. Likewise, the default implementations of hashCode and toString methods also consider each and every member field.
record Thing( int amount ) {} ;
That’s it, that is all the code you need for a fully-functioning read-only class with none of the usual boilerplate code.
Example usage.
Thing x = new Thing( 100 ) ;
Thing y = new Thing( 100 ) ;
boolean parity = x.equals( y ) ;
When run.
parity = true
Back to your List#contains question.
Thing x = new Thing( 100 );
List < Thing > things =
List.of(
new Thing( 100 ) ,
new Thing( 200 ) ,
new Thing( 300 )
);
boolean foundX = things.contains( x );
When run.
foundX = true
Bonus feature: A record can be declared locally, within a method. Or like a conventional class you can declare a record as a nested class, or as a separate class.

Compare object type

I don't know how to perform type checking on newEntry, I want to make sure that it is of type MyTable (without creating an object of MyTable).
public static boolean add(String table, Object newEntry)
{
boolean result;
if (table.equals("MyTable") && newEntry.getClass() == MyTable.getClass())
{
...
}
}
My problem is:
newEntry.getClass() == MyTable.getClass().
Note: MyTable is a class name, not an object.
Basically what you want is:
isAssignableFrom
Take a look at: http://www.ralfebert.de/blog/java/isassignablefrom/
So, in your case, you want:
MyTable.class.isAssignableFrom(newEntry.getClass())
Use instanceof operator .. Refer to the JLS for more documentation
Check this famous answer What is the difference between instanceof and Class.isAssignableFrom(...)?
instanceof is your friend:
if (table.equals("MyTable") && newEntry instanceof MyTable)
It is actually a shorthand for the isAssignableFrom method, but it's much easier to type :)
Compare with instanceof.
if (newEntry instanceof MyTable) {
// do something
}
In this example, the condition is true if newEntry is an instance of MyTable, or if newEntry is an instance of a superclass of MyTable.
Change your statement to this to make it work properly:
if (table.equals("MyTable") && newEntry instanceof MyTable)
You could also use isAssignableFrom() to compare them. The reason you might want to do this is because with instanceof, you have to know the class you are comparing before you compile your program. With isAssignableFrom(), you can change the class you are comparing to during run-time.
if (table.equals("MyTable") && MyTable.class.isAssignableFrom(newEntry.getClass()))
You can use MyTable.class to retrieve the class name.

How to see if an object is an array without using reflection?

How can I see in Java if an Object is an array without using reflection?
And how can I iterate through all items without using reflection?
I use Google GWT so I am not allowed to use reflection :(
I would love to implement the following methods without using refelection:
private boolean isArray(final Object obj) {
//??..
}
private String toString(final Object arrayObject) {
//??..
}
BTW: neither do I want to use JavaScript such that I can use it in non-GWT environments.
You can use Class.isArray()
public static boolean isArray(Object obj)
{
return obj!=null && obj.getClass().isArray();
}
This works for both object and primitive type arrays.
For toString take a look at Arrays.toString. You'll have to check the array type and call the appropriate toString method.
You can use instanceof.
JLS 15.20.2 Type Comparison Operator instanceof
RelationalExpression:
RelationalExpression instanceof ReferenceType
At run time, the result of the instanceof operator is true if the value of the RelationalExpression is not null and the reference could be cast to the ReferenceType without raising a ClassCastException. Otherwise the result is false.
That means you can do something like this:
Object o = new int[] { 1,2 };
System.out.println(o instanceof int[]); // prints "true"
You'd have to check if the object is an instanceof boolean[], byte[], short[], char[], int[], long[], float[], double[], or Object[], if you want to detect all array types.
Also, an int[][] is an instanceof Object[], so depending on how you want to handle nested arrays, it can get complicated.
For the toString, java.util.Arrays has a toString(int[]) and other overloads you can use. It also has deepToString(Object[]) for nested arrays.
public String toString(Object arr) {
if (arr instanceof int[]) {
return Arrays.toString((int[]) arr);
} else //...
}
It's going to be very repetitive (but even java.util.Arrays is very repetitive), but that's the way it is in Java with arrays.
See also
Managing highly repetitive code and documentation in Java
Java Arrays.equals() returns false for two dimensional arrays.
One can access each element of an array separately using the following code:
Object o=...;
if ( o.getClass().isArray() ) {
for(int i=0; i<Array.getLength(o); i++){
System.out.println(Array.get(o, i));
}
}
Notice that it is unnecessary to know what kind of underlying array it is, as this will work for any array.
There is no subtyping relationship between arrays of primitive type, or between an array of a primitive type and array of a reference type. See JLS 4.10.3.
Therefore, the following is incorrect as a test to see if obj is an array of any kind:
// INCORRECT!
public boolean isArray(final Object obj) {
return obj instanceof Object[];
}
Specifically, it doesn't work if obj is 1-D array of primitives. (It does work for primitive arrays with higher dimensions though, because all array types are subtypes of Object. But it is moot in this case.)
I use Google GWT so I am not allowed to use reflection :(
The best solution (to the isArray array part of the question) depends on what counts as "using reflection".
In GWT, calling obj.getClass().isArray() does not count as using reflection1, so that is the best solution.
Otherwise, the best way of figuring out whether an object has an array type is to use a sequence of instanceof expressions.
public boolean isArray(final Object obj) {
return obj instanceof Object[] || obj instanceof boolean[] ||
obj instanceof byte[] || obj instanceof short[] ||
obj instanceof char[] || obj instanceof int[] ||
obj instanceof long[] || obj instanceof float[] ||
obj instanceof double[];
}
You could also try messing around with the name of the object's class as follows, but the call to obj.getClass() is bordering on reflection.
public boolean isArray(final Object obj) {
return obj.getClass().toString().charAt(0) == '[';
}
1 - More precisely, the Class.isArray method is listed as supported by GWT in this page.
You can create a utility class to check if the class represents any Collection, Map or Array
public static boolean isCollection(Class<?> rawPropertyType) {
return Collection.class.isAssignableFrom(rawPropertyType) ||
Map.class.isAssignableFrom(rawPropertyType) ||
rawPropertyType.isArray();
}
Simply obj instanceof Object[] (tested on JShell).

Categories

Resources