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

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.

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

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.

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

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.

Related

how to check if an instance of an abstract object belongs to a particular subclass

I am referencing this duplicate question here:
Check if a Class Object is subclass of another Class Object in Java
I have an abstract parent class named 'Figure' of which I have two subclasses, 'Circle' and 'Rectangle' both of which extend this abstract parent. I am trying to determine if a Figure object is of type Circle or type Rectangle.
My original code was:
public boolean isInstanceOfRectangle(Figure figure)
{
boolean isInstance = figure instanceof Rectangle;
System.out.println("instance of rectangle!");
return isInstance;
}
After studying the linked question above, I have rewritten my code as follows:
public boolean isRectangle()
{
boolean isInstance = Figure.class.isAssignableFrom(Rectangle);
System.out.println("instance of rectangle!");
return isInstance;
}
For some reason this does not work unless I include the following in my main class:
public Class<?> Rectangle;
public Class<?> Circle1;
I'm not sure the significance of including this in my class, if I do not, it seems to require that I include it as a parameter in my method. I am unable to correctly invoke and test this method because I am unsure what parameter to pass into the method when invoked. I'd like to write something like:
public void mouseReleased(MouseEvent e)
{
if ((isRectangle(shape1)))
addRectangle((Rectangle)shape1, e.getComponent().getForeground());
else if ((isCircle(shape1)))
addCircle((Circle) shape1, e.getComponent().getForeground());
}
where 'shape1' is a Figure object that was instantiated as either a circle or a rectangle. Because the parameter is of type Figure, I am unsure how to define the 'isRectangle' method to take a Figure object (the abstract parent) and determine specifically which subclass it is an instance of. Or preferrably to take no parameter and just do the work by using the Figure object to invoke the method. I am a bit confused how to proceed.
*Edit: upon user suggestions, I have rewritten the following which does NOT appear to work because in both cases the output is FALSE.
Figure circleObj = new Circle(Color.BLUE);
System.out.println(isInstanceOfRectangle(circleObj));
System.out.println(isInstanceOfCircle(circleObj));
public static boolean isInstanceOfRectangle(Figure figure)
{
boolean isInstance = figure instanceof Rectangle;
if (isInstance == true)
System.out.println("instance of rectangle!");
else
System.out.println("is NOT a rectangle");
return isInstance;
}
public static boolean isInstanceOfCircle(Figure figure)
{
boolean isInstance = figure instanceof Circle;
if (isInstance == true)
System.out.println("instance of circle!");
else
System.out.println("is NOT a circle");
return isInstance;
}
That will always return false since the Figure Class instance is not a subclass of the Rectangle Class instance :
boolean isInstance = Figure.class.isAssignableFrom(Rectangle.class);
You want to generally invoke isAssignableFrom() on the class of a variable which you don't know the runtime type.
It would make more sense :
Figure figure = ...;
boolean isInstance = Rectangle.class.isAssignableFrom(figure.getClass());
That allows to know whether the instance of the class of the figure variable IS a Rectangle.
Introducing a method to handle the requirement would make still more sense as it is dynamic and it also allows to handle different class compatibility checks :
public static boolean isInstanceOf(Figure figure, Class<?> clazz){
boolean isInstance = clazz.isAssignableFrom(figure.getClass());
return isInstance;
}
And you could so use it such as :
System.out.println(isInstanceOf(new Rectangle(), Rectangle.class));
System.out.println(isInstanceOf(new Circle(), Rectangle.class));
System.out.println(isInstanceOf(new Figure(), Rectangle.class));
That prints :
true
false
false
And of course all of these will outputtrue as a Figure, a Circle and a Rectangle are Figures :
System.out.println(isInstanceOf(new Rectangle(), Figure.class));
System.out.println(isInstanceOf(new Circle(), Figure.class));
System.out.println(isInstanceOf(new Figure(), Figure.class));
You can use the .getClas() method to find the subclass
Rectangle aRectangle = new Rectangle();
if (aRectangle.getClass == Rectangle.class){
// Do what you would do if it was a rectangle
System.out.println("you have a rectangle");
}
else{
// The figure is not a rectangle
System.out.println("the figure is not a rectangle");
}
I don’t see much reason to complicate your code with assignable. Your original code works. More than that, checking variable’s class is not a good practice, try to restructure your code. (Check polymorphism, Barbara Liskov principle and Interface segregation principle)
And for clarifying things: Figure is not an object since it’s abstract, it’s type. The type is what stands on the left side of variable declaration.
Your original implementation is correct and the simplest one until we get pattern matching in Java.
More detailed explaination:
instanceof operator can be used to check if an object is an instance of a particular class. This matches your intent.
You can achieve similar functionality with ClassA.isAssignableFrom(ClassB). Here, ClassA is superclass and ClassB is a subclass. Note that this function compares two classes (instances of Class<?>), not an instance against a class.
You can get the class from an instance using getClass method, and thus, the resulting code will look like:
Rectange.class.isAssignableFrom(figure.getClass())
Your proposed check
Figure.class.isAssignableFrom(Rectangle);
has multiple problems:
syntax error: you need a Class<?> instance on the right side, you could use class literal Rectangle.class, but this checks a trivial fact and is always true.
to fix this error, you defined a variable Class<?> Rectangle, but this variable does not have any relation with Rectangle class, unless explicitely initialized with class literal Rectangle.class
you dont use figure instance anywhere
I'm going to chime in here and point out a bug in these methods:
public static boolean isInstanceOfRectangle(Figure figure)
{
//boolean isInstance = figure instanceof Rectangle;
boolean isInstance = figure instanceof Rectangle;
if (isInstance == true)
System.out.println("instance of rectangle!");
else
System.out.println("is NOT a rectangle");
return isInstance;
}
public static boolean isInstanceOfCircle(Figure figure)
{
//boolean isInstance = figure instanceof Rectangle;
boolean isInstance = figure instanceof Rectangle;
if (isInstance == true)
System.out.println("instance of circle!");
else
System.out.println("is NOT a circle");
return isInstance;
}
In the second method, the behaviour you want is for it to check whether or not it is a circle. But instead, you check if it is a rectangle.
Instead of figure instanceof Rectangle you should be checking figure instanceof Circle
PS. it is acceptable to use instanceof. Anything else is overkill.

what is dynamic method resolution

I am currently reading Herbert Schildt "Java the Complete Reference" and there he has used a term "Dynamic method resolution" and has provided a little explanation, but i am not getting the full import of it so asking for help in this forum.
while discussing 'interfaces', what he is saying is, dynamic method resolution helps in resolution of method name at run-time and it is achieved by declaring a interface variable and using it to refer to a class object. i.e
interface i = new object();
now what is so unique about it? you can use a class variable also to refer to the same object like:
class c = new object();
so, what is the use of interface here? and why introduce this new term "dynamic method resolution"??
Second he makes a point by saying: " when we use an interface variable to refer to instance of any class, and when you call a method through these interface variables, the method to be executed is looked up dynamically at run time allowing classes to be created later than the code which calls method on them. The calling code can dispatch through an interface without having to know anything about the callee".
Now, Anything dealing with objects has to be in run-time as objects are created at runtime, Now, I dont understand what he meant by "allowing classes to be created...on them".
Any help will be appreciated.
Here is a little example:
public interface Animal {
public String sound();
}
public class Cat implements Animal {
public String sound() { return "meow"; }
}
public class Dog implements Animal {
public String sound() { return "woof"; }
}
public class Test {
public static void main(String[] args) {
Animal a;
if (args.length > 0)
a = new Cat();
else {
a = new Dog();
}
System.out.println(a.sound()); // prints "MEOW" or "WOOF"
}
}
What is so unique about it? You can use a class variable also to refer to the same object
Yes. But you cannot use a single class variable to refer to an instance that can be an instance of any class that implements the interface.
In Test class, if I declared a to have type Dog or Cat there would be no way to get the code to compile. Without the ability to declare Animal a, I would need to have two distinct variables, and two separate print statements.
This is what dynamic method resolution (aka polymorphism) gives you.
To understand his second point:
public class Test2 {
public static void main(String[] args) {
Animal a = PetShop.buyPet(args);
System.out.println(a.sound()); // prints "MEOW" or "WOOF"
}
}
The Test2 class will work with my Cat and Dog class from above. It will also continue to work without recompilation if in 3 years time I implement a Goldfish class and modify my PetShop class to stock aquatic pets. And indeed, it is even possible to implement the PetShop class so that it doesn't need to be changed or recompiled to support other kinds of pets.
Now, these examples are clearly not practical. However, the Java features that they illustrate are useful in real Java applications. Indeed, a program as simple as a classic "hello world" program relies on dynamic method lookup.
dynamic method resolution means Single method which can be applied to solve multiple problems. Ex: Consider Shape is an interface and has method name draw.
you have Rectangle and Circle classes implements Shape Interface. So when you create instance of Rectangle object and call the draw method will draw the Rectangle shape.. In other case you can instantiate Circle instance and call draw method to draw Circle...
In interface you may assign child object in the parent container.
Ex: Shape p = new Rectangle();
in this case it will create the instance of Rectangle and assign it into Shape p..
but from the Shape p object you can call only the draw method... you can not call other methods in the Rectangle Object since its assigned to parent interface and parent has only draw method.

Compiler interpretation of overriding vs overloading

Forgive me if this question is primarily opinion based, but I have the feeling that it is not and there is a good reason for the choice. So, here's an example. Sorry, it's really long, but super simple:
Interface:
public interface Shape
{
double area ();
}
Implementing class 1:
import static java.lang.Math.PI;
public class Circle implements Shape
{
private double radius;
public Circle(double radius)
{
this.radius = radius;
}
public double area()
{
return PI*radius*radius;
}
}
Implementing class 2:
public class Square implements Shape
{
private double size;
public Square(double sideLength)
{
size = sideLength;
}
public double area()
{
return size*size;
}
}
Driver:
Shape[] shapes = new Shape[]{new Circle (5.3), new Square (2.4)};
System.out.println(shapes[0].area()); //prints 88.247...
System.out.println(shapes[1].area()); //prints 5.76
This works since .area() is overridden by Circle and Square. Now, here's where my question truly begins. Let's say that the driver has these methods:
public static void whatIs(Shape s)
{
System.out.println("Shape");
}
public static void whatIs(Circle s)
{
System.out.println("Circle");
}
public static void whatIs(Square s)
{
System.out.println("Square");
}
If we call:
whatIs(shapes[0]); //prints "Shape"
whatIs(shapes[1]); //prints "Shape"
This happens because Java interprets the objects as Shapes and not Circle and Square. Of course we can get the desired results through:
if (shapes[0] instanceof Circle)
{
whatIs((Circle) shapes[0]); //prints "Circle"
}
if (shapes[1] instanceof Square)
{
whatIs((Square) shapes[1]); //prints "Square"
}
Now that we have a background my question is:
What reasons contributed to the compiler/language design such that whatIs(shapes[0]); will print "Shape?" As in, why can the Java compiler accurately distinguish between overridden methods for related objects, but not overloaded methods? More specifically, if the only methods that the driver has access to are:
public static void whatIs(Circle s)
{
System.out.println("Circle");
}
public static void whatIs(Square s)
{
System.out.println("Square");
}
and we attempt to call,
whatIs(shapes[0]);
whatIs(shapes[1]);
we will get two errors (one for Square and one for Circle) indicating that:
method Driver.whatIs(Square) is not applicable
actual argument Shape cannot be converted to Square by method invocation conversion
So, again, now that we've gotten to the nitty-gritty, why can Java not handle a situation like this? As in, is this done due to efficiency concerns, is it just not possible due to the some design decisions, is this a bad practice for some reason, etc?
Why can the Java compiler accurately distinguish between overridden methods for related objects, but not overloaded methods?
It can't.
It checks strictly by the type it can see & guarantee. If your code is shapes[0].area() it will check that Shape has an area method and will compile it to "call area() on that object". The concrete Object that exists at runtime is now guaranteed to have that method. Which version from which class is actually used is dynamically resolved at runtime.
Calling overloaded methods works the same. Compiler sees a Shape and compiles that into "call whatis() in the basic Shape version". If you wanted to change that (and even allow having no basic Shape version) you would need to be able to determine the type at compile time.
But it is AFAIK impossible to create a compiler that can determine the type that an object will have at runtime at that point. Think for example:
final Shape[] shapes = new Shape[] { new Circle(5.3), new Square(2.4) };
new Thread() {
public void run() {
shapes[0] = new Square(1.5);
}
}.start();
whatIs(shapes[0]);
You must execute that code to find out.
The compiler could auto generate code like
if (shapes[0] instanceof Circle)
{
whatIs((Circle) shapes[0]); //prints "Circle"
}
for you to achieve dynamic method invocation at runtime but it does not. I don't know the reason but it would be neat to have sometimes. Although instanceof is often a sign for bad class design - you should not look from the outside for differences, let the class behave differently so the outside does not need to know.
Java, with object-oriented features, supports polymorphism, so calling area will call the area method of the specific instance, whatever it is. This is determined at runtime.
However, this polymorphism is not supported with overloaded methods. The Java Language Specification, Section 8.4.9 covers this:
When a method is invoked (§15.12), the number of actual arguments (and
any explicit type arguments) and the compile-time types of the
arguments are used, at compile time, to determine the signature of the
method that will be invoked (§15.12.2). If the method that is to be
invoked is an instance method, the actual method to be invoked will be
determined at run time, using dynamic method lookup (§15.12.4).
That is, with overloaded methods, the method is chosen at compile time, using the compile time types of the variables, not at runtime like with polymorphism.
The dispatch to one of the whatIsmethods is decided by the compiler at compile time. The call to one of the areamethods is decided at runtime, based on the actual class of the object that is referenced.
Q: Why can the Java compiler accurately distinguish between overridden methods for related objects, but not overloaded methods ... why can Java not handle a situation like this?
A: You've got the question backwards.
Java ALLOWS you to distinguish between "overloading" and "overriding".
It doesn't try to second-guess what you mean, it gives you a choice to use one or the other.
Well, as a stupid answer, you could get the whatIs function to work fine THIS way (without any type checking)
class Shape{
public abstract String whatIs();
}
class Square{
public String whatIs(){ return "Square"; }
}
class Circle{
public String whatIs(){ return "Circle"; }
}
And then call them like this
Shape square = new Square();
Shape circle = new Circle();
System.out.println(square.whatIs()) //prints 'square'
System.out.println(circle.whatIs()) //prints 'circle
Not at all the answer to the question you asked... But I couldn't resist.

I do not understand 'this' being used with a superclass

I have two classes and an interface shown below.
Quick summary: Interface Winterface, Class Big, Class Little that extends Big and implements Winterface.
public interface Winterface {}
public class Big {
public int hello = 88;
public Big() {}
public void theMethod() {
System.out.println ("Big was here: " + (this instanceof Winterface) + ", " + this.hello);
}
}
public class Little extends Big implements Winterface{
private boolean hello = true;
public Little(){}
public void theMethod() {
super.theMethod();
System.out.println("Little was here: " + hello);
}
public static void main(String [] args) {
Little l = new Little();
l.theMethod();
}
}
When I execute the main in Little, I get the following output
Big was here: true, 88
Little was here: true
my question is, how can
1) (this instanceof Winterface) return true but
2) this.hello be 88?
If this.hello = 88, then this = Big, which isn't an instance of Winterface.
I do not understand how this is possible, thanks in advance
EDIT: THANKS everyone I understand now that 'this' refers to little, which is a Big and implements Winterface. Since the method is being called as super.theMethod(), the variable 'hello' available is the one in Big even though 'this' refers to little.
this can only be one class. However this.hello is the field accessible to that class.
As this can only be one class it is a Little which has a parent Big and implements Winterface When you call a method in its parent which can only see hello that is what it sees.
i.e. Java supports polymorphism for methods but not fields.
l is Little but Little is a Big and also implements the behavior of Winterface.
The super is a call to the parent class so the hello member of the parent class (i.e. Big) is used.
You are not doing this.hello but super.theMethod() that uses the parent's class member variable hello.
UPDATE:
The super.theMethod() invokes the corresponding method in the parent class. In the parent class you access the fields of the parent (which also belong to the derived class since Little is also a Big). So the this.hello at that point is accessing the part of the code that is of the parent class.
You can imagine the memory print of Little as follows:
++++++++
+ Big +
--------
+Little+
++++++++
So Little has all the members variables of the parent i.e. Big and when the code runs inside super.theMethod() it is running inside the "code area" of Big.
As Peter states in his answer, polymorhism is not supported for methods and I hope that this overly simplistic description helps understand this
This is because the this instanceof ... check does not use the static (i.e., compile-time) type (which is Big), but the object's (this') dynamic run-time type (i.e., this.getClass()), which is Little in your example. If it would use the static type, the operator would be pretty pointless, since we would have:
Object obj = "foo";
if (obj instanceof Object) { /* always entered */ }
/* but */ if (obj instanceof String) { /* never entered */ }
statically, at compile-time. The purpose of the instanceof operator is to enable run-time type testing, for example:
Object obj = /* whatever */;
if (obj instanceof String) {
String str = (String)obj; // Cast cannot fail
...
} else if (obj instanceof Long) {
Long val = (Long)obj; // Cast cannot fail
...
}
Note, that this technique should only be used sparingly.
Your variable is an instance of Big and of Little. It's a direct instance of Little, but since Little inherits from Big the instanceof operator will return true for Big too.
Little l = new Little();
System.out.println(l instanceof Little); // true, l is an instance Little
System.out.println(l instanceof Big); // true, l is an instance of Little which inherits from Big
Your other misunderstanding (I'm assuming) is how the 'method lookup' works. When you call theMethod the it picks Little's implementation of that method. When you call super.theMethod though, you've explicitly said "call Big's version of this method", and then inside that method it's using Big's hello variable rather than Little's hello variable.
What is happening here is that when you are defining your variable hello in Little you are not overwriting the variable hello that is inside Big you are defining a new variable hello within Little that is hiding the variable hello within Big. Thus within the scope of Big, hello will refer to the integer value of 88 and within the scope of Little, hello will refer to true. These are different variables both contained within your object, the only difference is the scope by which you refer to them.
Like others here have said, instanceof is an operator that compares the runtime type of your object (what is returned by this.getClass()). When in Big even though the scope of the variables within your object will refer to Big, this is still of runtime type Little which is why it is an instance of Winterface.

Why cast after an instanceOf?

In the example below (from my coursepack), we want to give to the Square instance c1 the reference of some other object p1, but only if those 2 are of compatible types.
if (p1 instanceof Square) {c1 = (Square) p1;}
What I don't understand here is that we first check that p1 is indeed a Square, and then we still cast it. If it's a Square, why cast?
I suspect the answer lies in the distinction between apparent and actual types, but I'm confused nonetheless...
Edit:
How would the compiler deal with:
if (p1 instanceof Square) {c1 = p1;}
Edit2:
Is the issue that instanceof checks for the actual type rather than the apparent type? And then that the cast changes the apparent type?
Old code will not work correctly
The implied cast feature is justified after all but we have trouble to implement this FR to java because of backward-compatibility.
See this:
public class A {
public static void draw(Square s){...} // with implied cast
public static void draw(Object o){...} // without implied cast
public static void main(String[] args) {
final Object foo = new Square();
if (foo instanceof Square) {
draw(foo);
}
}
}
The current JDK would compile the usage of the second declared method.
If we implement this FR in java, it would compile to use the first method!
🔴 JDK 14
We finally implemented this feature in JDK 14. As you might have noticed you can declare a new variable within the instanceof-linkage. This new variable has been defined by the value of a automatically downcast to the specified type.
if (any instanceof String s) {
System.out.println(s);
}
Keep in mind, you could always assign an instance of Square to a type higher up the inheritance chain. You may then want to cast the less specific type to the more specific type, in which case you need to be sure that your cast is valid:
Object p1 = new Square();
Square c1;
if(p1 instanceof Square)
c1 = (Square) p1;
The compiler does not infer that since you are in the block, you have done a successful check for the type of the object. An explicit cast is still required to tell the compiler that you wish to reference the object as a different type.
if (p1 instanceof Square) {
// if we are in here, we (programmer) know it's an instance of Square
// Here, we explicitly tell the compiler that p1 is a Square
c1 = (Square) p1;
}
In C# you can do the check and the cast in 1 call:
c1 = p1 as Square;
This will cast p1 to a Square, and if the cast fails, c1 will be set to null.
Just to provide an update on this, Java 14 now provides pattern matching for instanceof, this allows you to check and cast in one fell swoop.
This (old way):
void outputValue(Object obj) {
if (obj instanceof String) { // Compare
String aString = (String) obj; // New variable & explicit casting
System.out.println(aString.toUpperCase()); // Access member
}
}
Can be simplified to this:
void outputValue(Object obj) {
if (obj instanceof String aString) { // Compare and cast (if true)
System.out.println(aString.toUpperCase()); // Access member
}
}
There's a difference between measuring if some object will fit in a box, and actually putting it in the box. instanceof is the former, and casting is the latter.
Because this particular syntactic sugar is not yet added to the language. I think it was proposed for Java 7, but it doesn't seem to have entered project coin
E.g. If you hand over p1 as of type Object, the compiler wouldn't know that it is in fact an instance of Square, so that Methods etc. wouldn't be accessible. The if simply checks for a certain type to return true/false, but that doesn't change the type of the variable p1.
The test is done to prevent from ClassCastExceptions at runtime:
Square c1 = null;
if (p1 instanceof Square) {
c1 = (Square) p1;
} else {
// we have a p1 that is not a subclass of Square
}
If you're absolutly positive that p1 is a Square, then you don't have to test. But leave this to private methods...
The variable p1 has whatever type it started with - let's say Shape. p1 is a Shape, and only a Shape, no matter that its current contents happen to be a Square. You can call - let's say - side() on a Square, but not on a Shape. So long as you are identifying the entity in question via the variable p1, whose type is Shape, you can't call side() on it, because of the type of the variable. The way Java's type system works, if you can call p1.side() when you happen to know it's a Square, you can always call p1.side(). But p1 can hold not just Square Shapes, but also (say) Circle Shapes, and it would be an error to call p1.side() when p1 held a Circle. So you need another variable to represent the Shape which you happen to know is a Square, a variable whose type is Square. That's why the cast is necessary.
Not to be obnoxious, but you have to tell the compiler what you want to do because the alternative would be for it to guess what you're trying to do. Sure, you might think, "If I'm checking the type of an object, OBVIOUSLY that must mean that I want to cast it to that type." But who says? Maybe that's what you're up to and maybe it isn't.
Sure, in a simple case like
if (x instanceof Integer)
{
Integer ix=(Integer) x;
...
My intent is pretty obvious. Or is it? Maybe what I really want is:
if (x instanceof Integer || x instanceof Double)
{
Number n=(Number) x;
... work with n ...
Or what if I wrote:
if (x instanceof Integer || x instanceof String)
What would you expect the compiler to do next? What type should it assume for x?
RE the comments that instanceof is obsolete or otherwise a bad idea: It can certainly be mis-used. I recently worked on a program where the original author created six classes that all turned out to be pages and pages long, but identical to each other, and the only apparent reason for having them was so he could say "x instanceof classA" versus "x instanceof classB", etc. That is, he used the class as a type flag. It would have been better to just have one class and add an enum for the various types. But there are also plenty of very good uses. Perhaps the most obvious is something like:
public MyClass
{
int foo;
String bar;
public boolean equals(Object othat)
{
if (!(othat instanceof MyClass))
return false;
MyClass that=(MyClass) othat;
return this.foo==that.foo && this.bar.equals(that.bar);
}
... etc ...
}
How would you do that without using instanceof? You could make the parameter be of type MyClass instead of Object. But then there's be no way to even call it with a generic Object, which could be highly desirable in many cases. Indeed, maybe I want a collection to include, say, both Strings and Integers, and I want comparisons of unlike types to simply return false.
As Leroy mentioned, Java 14 introduces pattern matching for instanceof. So, you can combine both instanceof check and typecast altogether in a single expression:
if (p1 instanceof Square) {
c1 = (Square) p1;
}
can be rewritten as
if (p1 instanceof Square c1) {
// use c1
}
This feature is finalized in Java 16 (JEP 394). For the below versions, refer this link to enable this preview feature from IDEs such as IntelliJ, Eclipse, and STS.
If c1 is declared as a type of Square then casting is required. If it is a declared as an Object then casting is not needed.

Categories

Resources