Extending ArrayList with an abstract class in Java? - java

This is a problem I've been working on for a little while now and I've barely made any progress. I've been running into a lot of problems trying to use an abstract class when extending ArrayList.
My first step was to define three classes, Circle, Rectangle, and Triangle that are all concrete subclasses of an abstract class GeometricObject. The base class has abstract methods getArea() and getPerimeter() that are overridden in the subclasses by the specific getPerimeter() and getArea() formula for that particular object. This part is completed and is working as intended.
The next part is where I'm having trouble. I'm supposed to define a new class GeoemetricObjectList that extends ArrayList<GeometricObject>. This class should override the add(), remove(), and clear() methods. This class keeps a totalArea and totalPerimeter variable of the objects on the list.
Right now I've created a, quite frankly, messy if statement list in my GeometricObjectList add() method that I'd like to clean up. Here is my code for that class so far:
import java.util.ArrayList;
#SuppressWarnings("hiding")
public class GeometricObjectList<GeometricObject> extends ArrayList<GeometricObject>{
final static long serialVersionUID = 1L;
public double totalArea = 0;
public double totalPerimeter = 0;
public boolean add(GeometricObject element){
if(element instanceof Rectangle) {
totalArea += ((Rectangle)element).getArea();
totalPerimeter += ((Rectangle)element).getPerimeter();
}
if(element instanceof Circle) {
totalArea += ((Circle)element).getArea();
totalPerimeter += ((Circle)element).getArea();
}
if(element instanceof Triangle) {
totalArea += ((Triangle)element).getArea();
totalPerimeter +=((Triangle)element).getArea();
}
return super.add(element);
}
public boolean remove(GoemetricObject element) {
return super.remove(element);
}
public void clear() {
}
}
When I simply write totalArea += element.getArea() I get the error "The method getArea() is undefined for the type GeometricObject but in my GeometricObject class I have a public abstract getArea() that is overridden by the getArea() method in each concrete (Triangle, Circle, Rectangle) class.
My next issue is with the remove() method in GeometricObjectList. It looks like this:
public boolean remove(GeometricObject element) {
return super.remove(element);
}
I am getting the error "Name clash: The method remove(GeometricObject) of type GeometricObjectList<GeometricObject> has the same erasure as remove(Object) of type ArrayList but does not override it". I never received this error when creating the add() method.
Any help with this is REALLY greatly appreciated. If there's any more info you need ask for it and I'll have it up in a second!

You really had several different issues - including spelling and hiding,
// Make sure you have these methods in your GeometricObject.
// private static abstract class GeometricObject {
// public abstract double getArea();
// public abstract double getPerimiter();
// }
// Do not use that annotation. It was warning you!
public class GeometricObjectList extends
ArrayList<GeometricObject> {
final static long serialVersionUID = 1L;
public double totalArea = 0;
public double totalPerimeter = 0;
public boolean add(GeometricObject element) {
if (element != null && super.add(element)) {
totalArea += element.getArea(); // add area
totalPerimeter += element.getPerimiter(); // add perimeter
return true;
}
return false;
}
public boolean remove(GeometricObject element) { // Spelling!
if (element != null && super.remove(element)) {
totalArea -= element.getArea(); // subtract area
totalPerimeter -= element.getPerimiter(); // subtract perimeter
return true;
}
return false;
}
public void clear() {
super.clear();
}
}

Well, let's start with first things first.
This class declaration isn't doing what you believe it's doing:
public class GeometricObjectList<GeometricObject> extends ArrayList<GeometricObject>
Java is treating GeometricObject as a type parameter. If you want to bound the generic strictly to only instances of a GeometricObject, change that signature to this:
public class GeometricObjectList<T extends GeometricObject> extends ArrayList<T>
Then Java will identify the type parameter T to only be instances of GeometricObject and its children.
You could also eschew the need for the generic type argument altogether and have your ArrayList tightly bound to GeometricObject without a generic:
public class GeometricObjectList extends ArrayList<GeometricObject>
Next, the signature of add gets to change. Since T is already bound to be an instance of GeometricObject, we don't need to explicitly say that's what we're adding.
public boolean add(T element)
If you elected not to use T, then you would keep your signature the same.
In either case, the casts also become redundant and can go away.
Finally, your remove method isn't overriding the inherited remove - it needs to match the signature as well.
public boolean remove(Object element)

Related

How do I return a unsure type?

I have a parent Class named 'Shape' and write a method in it
I want any class extends from it can call the bigger method for other use.
simple logic like this:
public abstract Class Shape{
public int size;
public Shape() {}
public Class<? extends Shape> bigger() {
this.size += 1;
return this; // ← Here,How can I return it with unsure type?
}
}
but how can I return a unsure type in here ?
thanks for any ideas!
====
and if I have a class Square extends Shape;
and I want use it like this:
Square S = new Square().bigger();
And it will return a Shape Class, not a Square Class.
but I don't wanna use: (Square) new Square.bigger();
I hope it can automatic recognize what Class a using this method
And return the correct type.
You can override bigger() method which returns Square (not Shape).
It is regal.
public abstract class Shape {
public int size;
public Shape() {}
public Shape bigger() {
this.size += 1;
return this; // ← Here,How can I return it with unsure type?
}
}
public class Square extends Shape {
#Override
public Square bigger() { // returns Square, not Shape
return this;
}
}
You don't return a Class here, just a Shape. Something like,
public abstract class Shape { // <- class
public int size;
public Shape() {
}
public Shape bigger() { // <-- a Shape. By definition of a sub-class because
this.size += 1; // <-- "this" class is abstract
return this;
}
}
im not sure what is the "unsure" type, but in java we have the Generic type which is Java can return any class regardless what they are.
for example
public interface dbDao<T>{
public T t; //this is generic class, all class can use this method
}
i hope you understand what im trying to say.
In Java, when you override a method you can actually be more specific than the interface requires. For example, the interface requires bigger returns a Shape, but a Square class that extends from Shape could return a Square since a Square is a Shape. This means if you assign it to a Square variable, there is no need to cast when you call bigger.
public abstract class Shape { // class not Class
public int size;
public Shape bigger() {
this.size += 1;
return this;
}
}
public class Square extends Shape {
#Override
public Square bigger() {
this.size += 1;
return this;
}
}
That's one way of doing it, which in this case is a little frustrating because it repeats the code. Another way of doing this, that would work in C# as well, is to use a generic with a restriction that the generic type implement itself. This is called the Curiously Recurring Template Pattern https://en.wikipedia.org/wiki/Curiously_recurring_template_pattern
public abstract class Shape <S extends Shape>{
public int size;
public S bigger() {
this.size += 1;
return this;
}
}
public class Square extends Shape<Square>{
}

How would I call an interface method in main?

I have an abstract method that is implemented on a class, but when I try to call this method from main, it doesn't show up on my methods list. All other methods show, except for the one coming from the interface. What did I do wrong?
public interface Printable {
public void print();
}
Implements Printable.
#Override
public void print() {
for(int i = 0; i < getLength(); i++){
for(int j = 0; j < getLength(); j++){
System.out.println("o");
}
System.out.println();
}
}
Call in main, printable method not available.
if(shapes[i] instanceof Printable) {
shapes[i]
}
Although you checked whether the shape is printable here:
if(shapes[i] instanceof Printable){
the compiler does not know that you did. It still thinks that shapes is an array of Shape, which does not implement Printable. You have to tell the compiler "I have indeed checked that shape[i] is printable, so print it!"
How to tell it that then?
Cast!
if(shapes[i] instanceof Printable){
((Printable)shape[i]).print();
}
You might have used this (type)value syntax before. It forcefully converts the value into the type. You probably have used it to convert a float value to int. It's the same thing here!
Your class, that implements printable, must declare "implements Printable", it's not enough just to have the right method
Also this:
if(shapes[i] instanceof Printable){
shapes[i]
}
Does not call print
If your base array type is of a class that doesn't implement Printable, you can change it to use what Philipp wrote
class Base {}
class Shape extends Base implements Printable {
void print()...
}
Base[] shapes = ....;
if(shapes[i] instanceof Printable) {
Printable.class.cast(shapes[i]).print()
}
Or
class Shape implements Printable {
void print()...
}
Shape[] shapes = ....;
Shapes[i].print(); // no instanceof or cast necessary

Java: Interface

I have been reading about interface in java. Overall I understood the concept except one problem. In http://goo.gl/l5r69 (docs.oracle), in the note it is written that we can type cast an interface and a class implementing it. That is
public interface Relatable {
public int isLargerThan (Relatable other) ;
}
public class RectanglePlus implements Relatable {
public int width = 0;
public int height = 0;
public Point origin;
// four constructors
// ...
// a method for computing the area of the rectangle
public int getArea() {
return width * height;
}
// a method required to implement the Relatable interface
public int isLargerThan(Relatable other) {
RectanglePlus otherRect = (RectanglePlus) other;
if (this.getArea() < otherRect.getArea()) {
return -1;
} else if (this.getArea () > otherRect.getArea()) {
return 1;
} else {
return 0;
}
}
}
How can otherRect (which is a interface) be casted to a RectanglePlus. The confusion is, RectanglePlus is a class having variables, which are not present in the otherRect which is an interface
I have to admit that the example in the java doc you showed is simply bad and confusing.
It's bad because it contains an unsafe cast down the hierarchy.
It is always safe to cast up (from implementing class to interface/superclass), but casting down should be avoided when possible.
Ideally, the Relatable interface should also contain getArea() method:
public interface Relatable {
public int isLargerThan(Relatable other);
public int getArea();
}
Now you don't need the ugly cast, simply:
public int isLargerThan(Relatable other) {
if (this.getArea() < other.getArea()) {
return -1;
} else if (this.getArea () > other.getArea()) {
return 1;
} else {
return 0;
}
}
is enough. I also think that isLargerThan(Relatable other) is a bad name (larger in terms of what?). It should probably be something like hasBiggerArea(Relatable other) so that it explains what we are actually comparing (only "larger" is rather vogue).
Your interface is pretty similar to Comparable, (Are you sure Comparable isn't what your looking for?) so maybe you should add a generic to it:
public interface Relatable<T extends Relatable> {
public int isLargerThan(T t);
}
And then your class will start as:
public class RectanglePlus implements Relatable<RectanglePlus> {...
So your RectanglePlus instance will be compared with other RectanglesPlus elements only.
If this does not suit what you need, then you have to choose what will happen when you are comparing two different classes:
public class RectanglePlus implements Relatable {
public int width = 0;
public int height = 0;
public Point origin;
public int getArea() {
return width * height;
}
public int isLargerThan(Relatable other) {
if (!(other instanceof RectanglePlus)) {
return 1; // I'm bigger than any other class!
}
RectanglePlus otherRect =(RectanglePlus)other;
return this.getArea() - otherRect.getArea();
}
}
Or, a third option, you can add another method to your interface to obtain the measureable, realatable value of an object. Then you could add a default implementation to isLargerThan, if you are using Java 8:
public interface Relatable<T extends Relatable> {
public default int isLargerThan(T t) {
return this.getRelatableValue - t.getRelatableValue();
}
public int getRelatableValue();
}
In the method declaration public int isLargerThan(Relatable other){...} the parameter other is declared to be a reference to an object whose class implements the interface Relatable.
In the method body, the expression (RectanglePlus)other means to check that the object is of class RectanglePlus or a subclass of that (and throw a ClassCastException if it isn't). Now, a RectanglePlus is Relatable, but the inverse isn't necessarily true; the cast here ensures that other will either be RectanglePlus; if it's not further instructions will not be executed because an exception will have been thrown.
We can type cast any object(of class C) stored in a variable of type T1 (interface or class) into a variable of type T2 if T2 is a super class or super interface of class C or T2==C otherwise a ClassCastException will be thrown.
So in your case if an object obj of class Foo implements Relatable is passed to isLargerThan method then it will throw ClassCastException, because obj's class Foo is not a super class of RectanglePlus.
One aspect that hasn't been touched on in other answers is the fact that the example in the Oracle docs has a clear problem: if Relatable is only meant to be analogous to Comparable, then there needs to be a specialization for shapes in order to avoid the cast in the isLargerThan method. Perhaps, for example, an interface called RelatableShape, which itself extends Relatable, and provides for the getArea() method. Then, you could have Circle, Hexagon, Rectangle, etc. classes that implement RelatableShape (the interface with isLargerThan and getArea), and the isLargerThan() method would not need to cast its argument to a particular concrete class (since the parameter could be guaranteed to implement RelatableShape, and getArea() would always be available).
Thus, though the Oracle documentation is showing something that is valid Java, it's also showing something that's necessary because of a bad design. Keep that in mind. Casting is almost never necessary in real code.
It's rather simple your mehtod
public int isLargerThan(Relatable other)
just asks for an argument that implements Relatable. It could be an object of any class that implements Relatable. As long as there is something like
public class SomeName implements Relatable { /* Implementation */ }
in the class, you can treat objects of that class as Relatable.
But that does not mean that these objects are not of their own type. If you have the following classes
public class Square implements Relatable {
public int isLargerThan(Relatable other) {
// Implementation
}
// Square specific implementation
}
and
public class Rectangle implements Relatable {
public int isLargerThan(Relatable other) {
// implmentation
}
// Rectangle specific implemenation
}
you can call the interface methods like this:
/* ... */
public static int check(Relatable a, Relatable b) {
return a.isLargerThan(b);
}
/* ... */
Square s = new Square();
Rectangle r = new Rectangle();
System.out.println("Check: " + check(s, r));
ATTENTION:
Because several different classes can implement Relatable you have to check the type of the argument to isLargerThan, otherwise you run into type cast exceptions.
Maybe you can specify something like this in Relatable
public int getSize();
Than you could write your isLargeThan method like this:
public int isLargerThan(Relatable other) {
if (this.getSize() < other.getSize())
return -1;
else if (this.getSize() > other.getSize())
return 1;
else
return 0;
}
Then there would be no need for a type cast.

Casting INSIDE the Generic classes in java

I know that we can skip casting by adding using the Generics in java as follows. (When we are using it outside of the Generic class.)
But if we are doing some logics on the type object (T item) inside the generic class (Container<T>) we should check the instance of and specially cast isn't it? So we can use it to skip casting out side the generic classes.
Please check the commented code in the public void setItem(T item) method.
I want to know whether my understanding is correct or am I missing something
Client.java
public class Client {
public static void main(String[] args) {
// String container
Container<String> stringContainer = new Container<String>();
stringContainer.setItem("Test");
//stringContainer.setItem(new StringBuffer("")); // compilation error, type safety checking
System.out.println(stringContainer.getItem().toUpperCase()); // No need to cast
// Integer container
Container<Integer> integerContainer = new Container<Integer>();
integerContainer.setItem(123);
//integerContainer.setItem("123"); // compilation error, type safety checking
System.out.println(integerContainer.getItem().intValue()); // No need to cast
}
}
Container class
class Container<T> {
private T item;
public T getItem(){
return item;
}
public void setItem(T item){
/* If I' doing some thing on item then I have to check the instance of and cast isn't it?
if(item instanceof String){
System.out.println("setItem().((String)item).toUpperCase() : " + ((String) item).toUpperCase());
}
*/
this.item = item;
}
}
Reference : http://nandirx.wordpress.com/category/java-2/generics-java/
As others have said, you shouldn't ever downcast a generic type as it defeats the purpose of generics.
You should use bound generics instead. A bound generics allows you to require a generic be of a specific type. This allows you to access values in the specific type without needing to cast.
This doesn't make sense with the String class as String is marked final and so cannot be extended, but for the future, try something like this.
public interface Shape{
double getArea();
}
public class Rectangle implements Shape{
double width;
double height;
public double getArea(){ return width*height;}
}
//this collection can hold Shape, or any type implementing shape.
public class MyShapeCollection<T extends Shape>{
List<T> shapes;
public double getAreaSum(){
double areaSum = 0;
for(Shape s : shapes){
areaSum += s.getArea();
}
return areaSum;
}
}
public static void main(String[] args){
MyShapeCollection<Rectangle> rectangles = new MyShapeCollection<Rectangle>();
//bad code monkey. String does not implement Shape!
//this line won't compile. including it for demonstration purposes.
MyShapeCollection<String> willNotCompile = new MyShapeCollection<String>();
}
If your collection will only hold strings, you don't need generics.
Yes, your understanding is correct.
Adding type specific code here, however, defeats the purpose of generics.
A better solution would be the following.
Client.java
public class Client {
public static void main(String[] args) {
// String container
Container<String> stringContainer = new StringContainer();
stringContainer.setItem("Test");
//stringContainer.setItem(new StringBuffer("")); // compilation error, type safety checking
System.out.println(stringContainer.getItem().toUpperCase()); // No need to cast
}
}
Container.java
class Container<T> {
private T item;
public T getItem(){
return item;
}
public void setItem(T item){
this.item = item;
}
}
StringContainer.java
class StringContainer extends Container<String> {
#Override
public void setItem(String item){
System.out.println( item.toUpperCase() );
super.setItem( item );
}
}
Right, or you could overload the setItem() method for different types of parameters, but that's actually even worse.
Yes, for your case casting is necessary. Because you are using string functions specifically.
But its like you are not using generic feature.
If you wanna to print item, then you can override toString() method of each item, and you can directly put item object in sysout(). By doing so, there will be no casting needed and all code get generic for all items.
What you say here.

Java: Superclass constructor needs preparation

I have a following superclass:
class FloatVector {
private List<Float> components;
public FloatVector(List<Float> comps)
{
components = comps;
}
public int getComponentCount(){
return components.size();
}
public float getComponent(int ind){
return components.get(ind);
}
//other methods
}
and I want to extend it to, for example, a 2D vector:
public class FloatVector2D extends FloatVector {
FloatVector2D(float x,float y)
{
List<Float> comps = new ArrayList<>();
comps.add(x);
comps.add(y);
super(comps);
}
}
but the IDE claims, that the superclass constructor must be the first call. There must be a way to implement the required behaviour.
super must be the first call in a constructor (if super is called).
You can simply replace your FloatVector2D constructor body with:
super(Arrays.asList(new Float[]{x,y}));
(and add the necessary imports)
Put super(comps); as first line in your FloatVector2D constructor.
Source: http://docs.oracle.com/javase/tutorial/java/IandI/super.html
"Invocation of a superclass constructor must be the first line in the subclass constructor."

Categories