Java - alternative to instanceof? - java

I have a Shape superclass and a NestedShape subclass. The NestedShape subclass has an ArrayList ('ShapesList') of Shapes that are nested within it. I need to implement a 'contains' method for NestedShape. This method, when given a Shape object, should check whether the shape exists in the NestedShape's ShapeList. My implementation at the moment is very simple: just call the ArrayList .contains() method on ShapesList.
However, the 'contains' method I need to implement also has to check that for any NestedShape in the ShapesList, that shape's ShapeList also doesn't contain the shape that is being searched for. The obvious way to me of doing this is to use instanceof to check if each Shape in the ShapeList is a NestedShape. Then, I guess I'd recursively call my 'contains' method on it if it was a NestedShape. However, I'm not sure if this is a good way of doing this - I've heard that the use of instanceof is frowned upon (also, I'm not sure if my idea of using recursion would even work).
Could anyone suggest a better way of solving this problem?
Thanks :)

Use polymorphism:
public class Shape {
public boolean contains(Shape shape) {
return false;
}
}
public class NestedShape extends Shape {
private List<Shape> subShapes = new ArrayList<Shape>();
#Override
public boolean contains(Shape shape) {
if (subShapes.contains(shape)) {
return true;
}
for (Shape subShape : subShapes) {
if (subShape.contains(shape)) {
return true;
}
}
return false;
}
}

Two ideas:
Don't let NestedShape extend Shape, but handle them seperately.
Let all Shapes be 'nested'. With single shapes returning always false for contains().

If
the performance of the contains() method is your concern and
NestedShape are immutable meaning the list of nested Shape instances once set will never change
then I would suggest a slightly different approach.
Instead of recursively iterating though all the NestedShapes you can add a Set inside the Shape class that will store the references to all the NestedShape instances for which it is possible to access this Shape instance.

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.

How do I correctly implement an interface with a method that has Object as an argument?

I'm writing a program our professor has given us as homework.
I have a class called Car, that has two private real members x and y, which are supposed to represent the coordinates of the car in the coordinate plane, and I wanted to implement an interface called MyInterface, in which I declared a method public boolean compare(Object t). It was stated it has to be Object t and not something else, so that I can implement the interface in multiple classes (part of the homework). Java is the programming language in question.
The part of the code that that is problematic looks like this:
public interface MyInterface {
public boolean compare(Object t);
}
public class Car implements MyInterface{
private double x, y;
#Override
public boolean compare(Car t) {
double curdist = Math.sqrt(this.x*this.x + this.y*this.y);
double givdist = Math.sqrt(t.x*t.x + t.y*t.y);
if(curdist < givdist) return true;
else return false;
}
}
My method compare needs to calculate the distances from the point (0,0) for the current car and the given car, and compare the two distances. If the current car's distance (curdist) is closer from the given car's distance (givdist) to (0,0), compare returns true, otherwise it returns false.
My question is, how do I correctly implement this method in the class Car?
I've tried a few things, but none of them seem to work out. Any help is appreciated, 'cause I am quite new to object-oriented programming. Thanks in advance.
If you must have Object as the parameter type for compare, then you must test the class of the parameter passed in to make sure it's a Car first.
Change the compare argument to Object in your Car class. Then the #Override annotation will determine that the method is properly overriding the instance method, and you won't get a compiler error. Use the instanceof operator to determine if t is a Car. You may decide to throw an IllegalArgumentException if it isn't a Car, or if it's null. Then you can cast it to a Car and continue with the logic of your method.
Even if you have to do have it take Object for your class, a better way to do this in general is with generics. Here, this would answer the question "What is this class comparable to?". If you've covered generics, then you may understand a class that is defined as MyInterface<T>. The compare method would take a parameter of type T. This allows you to implement the method in Car with a parameter of type Car, provided Car implements MyInterface<Car>. This is similar to the existing Comparable interface built-in to Java.

Overloading with Polymorphism

I'm designing a physics simulator with 3 types of things that can collide.
The most basic [abstract] class is called Item which contains information on mass, position & speed.
There are 3 other types: Circle, Boundary & Photon which extend the Item class and have their own properties.
I have a List<Item> called system which contains various Circles, Boundaries etc and I go through this list to check for collisions by using a method: system.get(i).collide(system.get(j)); and this edits the velocities etc.
My problem is, Eclipse wants me to have a method in each of the Circle, Boundary... classes called collide(Item itemName) but by doing this the compiler wouldn't be able to treat each type of item differently.
I currently have different methods in the Circle, Boundary... classes like:
collide(Circle c){..}
collide(Boundary b){..}
collide(Photon p){..}
But the compiler wants a general collide(Item i) method.
How can I satisfy the compiler but still treat collisions with different types differently using inheritance the way I have?
You should Override collide(Item i) for each of subclasses. You could check the type of item in each implementation, for instance, in your Photon class :
#Override
public void collide(Item item) {
if (item instanceof Photon) {
// implement collision of this with (Photon) item
} else if ... {
// I wonder how collision of Photon with Circle would look like :)
}
}
This is quite similar approach to Overriding Object's equals method for new types.
You can still use collide(Item i)
But if you want the method to act differently for each super class you can do this:
public void collide(Item i) {
if(i instanceof Circle) {
//do something for a circle
} else if(i instanceof Photon) {
//do something for a photon
} else if(i instanceof Boundary) {
//do something for a boundary
}
}
You can simply keep collide(Item b){..} or Something like collide(<? extends Item> b){..}. You can introduce generics concept here if you are going to pass subtypes also.
This will give more info about it. http://www.thejavageek.com/tag/generics/

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.

type T parameters in generic method arguments

Suppose the following classes are defined:
class Shape { }
class Circle extends Shape { }
class Rectangle extends Shape { } // 1
You can write a generic method to draw different shapes:
public static <T extends Shape> void draw(T shape) { } // 2
The Java compiler replaces T with Shape:
public static void draw(Shape shape) { } // 3
My Question is, if we define directly // 3 in our class then we still be able to pass Shape, Circle and Rectangle reference to method at //3. Then why do we need to write // 2 generic method with type parameter <T extends Shape> which is untimately going to be same as //3 ?
You can refer this link with same example : http://docs.oracle.com/javase/tutorial/java/generics/genMethods.html
You may or may not need it. You need it if your method has to deal with other objects of the type T that must match the type of T extends Shape exactly, for example:
public static <T extends Shape> void drawWithShadow(T shape, Class<T> shapeClass) {
// The shadow must be the same shape as what's passed in
T shadow = shapeClass.newInstance();
// Set the shadow's properties to from the shape...
shadow.draw(); // First, draw the shadow
shape.draw(); // Now draw the shape on top of it
}
Above, passing Shape would not be enough, because we wouldn't be able to make the shadow of the exactly same type.
In case when there is no such requirement, a simple Shape would be sufficient.
In this particular case, you don't need a generic method.
But you can do more in a generic method than call a dynamically linked method on its arguments.
For example, you might have a generic method that accepts and returns a collection of T elements. Parameterizing it by type allows you to use it on multiple collection types.
Other examples where generic methods are useful are in this Java tutorial.
In your example, //3 is indeed the same as //2. But in other usecases, generic type may be useful:
you want to return value from the method, of the same type as the argument
you have 2 or more parameters and want to set restriction that they must be of the same type
The difference is that the kind of polymorphism you are using.
In the generic case you are using parametric polymorphism while in the second one you are using polymorphism by subtype. Actually you first case uses both kind of polymorphism.
Now, they could be similar in some aspects but they are not the same. A practical example:
List<Shape> shapes;
List<T extends Shape> specificShapes;
You can see that in the first case, not having a type parameter, I can't manage a list of a specific subtype of Shape, I can only manage an eterogeneous list of shapes but I'm unable to force any specific one on it. So I don't have any compile time juice that forbids me from adding a Triangle and a Rectangle to the shapes.
class ShapeDecorator {
private Shape shape;
..
Shape get() { return shape; }
}
class ShapeDecorator<T extends Shape> {
private T shape;
T get() { return shape; }
}
Here is another example, in this case you could write a generic decorator which is able to return a type T without the need of any cast. This can be useful in many situations in which having the common ancestor as subtype is not enough.
The main interest is that you can restrict the usage of your method to a specific type of shape in different part of the code.
At some point you may want to parametrize it to draw only Rectangle and in another place only Circle and this will be checked at compile time even if, at runtime, you will pass something of type Shape

Categories

Resources