0

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.

Poobean
  • 27
  • 4
  • hashCode and equals override them in circle. – sango Sep 30 '20 at 06:05
  • and shape as well – sango Sep 30 '20 at 06:11
  • Well, `myCircle != myOtherCircle`, I don't know how much more "distinguished" you can get than that. – Kevin Anderson Sep 30 '20 at 06:16
  • Ignoring the typos in your code, `isInstance()`, `getClass()` and `instanceof` will all distinguish between `myCircle` and `myOtherCircle`. So, please show us your complete code. There must be some problem or misunderstanding outside the snippet you posted. – Ralf Kleberhoff Sep 30 '20 at 07:00
  • Sorry about typos, I edited the question and have some more code to demonstrate what I am asking. – Poobean Sep 30 '20 at 08:49
  • The class doesn't change. Consider this. `Circle a = new Circle();` and `Shape b = a;` So you want to find a difference between a and b? What is the context though. You already know that a is referenced as a circle and b is referenced as a shape. – matt Sep 30 '20 at 08:51

4 Answers4

2

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
Conffusion
  • 4,092
  • 2
  • 13
  • 19
0

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.

matt
  • 8,598
  • 3
  • 19
  • 30
0

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).

tucuxi
  • 15,614
  • 2
  • 36
  • 70
0

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.

Ralf Kleberhoff
  • 5,711
  • 1
  • 8
  • 6