Poobean
Poobean

Reputation: 27

How to distinguish between objects of the same class with different references?

Sorry if the title is poorly worded, I don't really know how to ask this. But I want to distinguish between instances of the same class, but referenced as different classes. Please consider following code:

class Shape {}

class Circle extends Shape {}

class Main {

public static void main(String[] args) {

    Circle myCircle = new Circle();
    Shape myOtherCircle = new Circle();

    System.out.print(myCircle.getClass() + ", ");
    System.out.println(myOtherCircle.getClass());

    System.out.print((myCircle instanceof Circle) + ", ");
    System.out.println(myOtherCircle instanceof Circle);

    System.out.print((myCircle instanceof Shape) + ", ");
    System.out.println(myOtherCircle instanceof Shape);

    System.out.print(Circle.class.isInstance(myCircle) + ", ");
    System.out.println(Circle.class.isInstance(myOtherCircle));

    System.out.print(Shape.class.isInstance(myCircle) + ", ");
    System.out.println(Shape.class.isInstance(myOtherCircle));
}

}

We can distinguish objects by the type of their instance by using the methods or operators shown above, but as shown, when trying to compare objects by the type of the reference there are no differences the code prints this:

class Circle, class Circle
true, true
true, true
true, true
true, true

How can I distinguish myCircle and myOtherCircle by the type reference. Thank you for reading, I appreciate all answers.

Upvotes: 0

Views: 501

Answers (4)

Ralf Kleberhoff
Ralf Kleberhoff

Reputation: 7290

In Java, a Circle instance is a Circle, no matter if you store a reference to it in a variable declared as e.g. Circle, Shape or Object.

So, anything you do with the instance found in a variable only depends on the instance's class, not on the variable's declared type. That applies to things like the instanceof operator, the getClass() method and so on.

There's one exception: if you have some overloaded methods like

String myType(Object x) { return "Object"; }
String myType(Shape x)  { return "Shape";  }
String myType(Circle x) { return "Circle"; }

then the compiler will decide which version to call, based on the type as it is known at compile-time. And if you pass a variable into a call of myType(), the type that the compiler assumes will be the variable's type, not knowing about the class of the instance that will later be referenced in the variable.

So then the following snippet might do what you want:

System.out.print(myType(myCircle) + ", ");
System.out.println(myType(myOtherCircle));

But, as for any given variable you statically know how you declared it, I don't see how such a construct might be useful.

Upvotes: 0

tucuxi
tucuxi

Reputation: 17945

In other words, you want to know, at runtime, the declared type of a reference to a variable (and not a class field - since you can use introspection to check out those, as shown by Conffusion's answer)

Why would you need to check it at runtime? In what case could it be useful to wait until then? The compiler knows much earlier -- at compile time, as it keeps track of the declared types of all identifiers. In your code, if you write

 Shape myOtherCircle = new Circle();
 // ...
 Circle c = myOtherCircle;  // compile-time error: invalid implicit cast

This warns you, at compile-time, that you are doing something fishy - as the compiler does not allow implicit (= non-explicit, that is, without an expliccit (Circle) cast) narrowing casts. For example: implicit casting from a Shape to a Circle: bad, because you could try to convert a Square-Shape to a Circle which would lead to run-time errors. From a Circle to a Shape, a broadening cast, no errors can occur.

So, my short answer would be:

you cannot do this at run-time because the compiler (and your IDE) already has this information at compile-time

On the other hand, with computers, almost everything is possible, although some are quite complicated. It is possible to detect such problems at runtime by using the JDK's built-in java compiler to (uh) compile and report on the declared types of variables in any piece of java code - but doing so is certainly not expected (most folks using it just want to compile and run code at runtime, rather than play with the AST), and requires a deep dive into internals. Asides from the JDK's own compiler, you can also use any of a large set of java compilers to do something similar (but beware possible incompatibilities with the standard one).

Upvotes: 0

Conffusion
Conffusion

Reputation: 4475

I don't think that is possible. The closest you can get is if these variables are fields of a class. Then you can access the type via the class definition:

class Main {
    Circle myMainCircle = new Circle();
    Shape myMainOtherCircle = new Circle();
        
    static class Shape {
    }
    
    static class Circle extends Shape {
    }
    
    public static void main(String[] args) throws Exception {            
        System.out.println(Main.class.getDeclaredField("myMainCircle").getGenericType());
        System.out.println(Main.class.getDeclaredField("myMainOtherCircle").getGenericType());
    }
}

output:

class Main$Circle
class Main$Shape

Upvotes: 2

matt
matt

Reputation: 12346

The problem I see is "When would you not know the reference type?" For example we could make two methods.

public int special(Circle a){
    return 1;
}

public int special(Shape a){
    return 2;
}

Then using your example.

System.out.println(special(myCircle) + ", " + special(myOtherCircle));

(This will print 1,2 because java will use the most specified method. myCircle is a Circle and a Shape, but the Circle is the most specified.)

For this to work though, we already know that one class is referenced as a Shape and the other a Circle.

Upvotes: 0

Related Questions