ArrayList with different object-types

Hello! it is possible to put in an arraylist different types of objects, right?

e.g.

ArrayList al;

al.add (new Circle(0,0,10)); al.add (new Rect(0,0,10,10));

How can I figure out which class is stored when I iterate through that array?

for (int i=0; i<al.size(); i++) CLASS? obj = (CLASS?) ai.get(i);

Answers

  • edited April 2014

    How can I figure out which class is stored when I iterate through that array?

    If we don't define which object type is gonna be stored in some Collection, such as an ArrayList,
    for each reading, using get() method for example, the returning type is Object!
    So an extra (cast) operator is necessary to force the real data-type outta it! :-<

    Problem is, if we happen to cast the wrong type, we'd get ClassCastException!
    To mend that, we gotta use relational operator instanceof in order to make sure our type guess is indeed right! :-SS

    There are other inventive ways as well. For example, if we're gonna store 2 diff. types only, like Circle & Rect,
    we can decide that the former goes to even indices and the latter to odd indices.
    Thus we're certain about which (cast) to use for each reading! :-B

    However IMHO, stick to 1 object type Collection as much as possible: :(|)

    final ArrayList<Circle> circles = new ArrayList();
    final ArrayList<Rect> rects = new ArrayList();
    
  • Hello!

    Hope this helps:

    ArrayList<Shape> shapes = new ArrayList<Shape>();
    
    void setup() {
      shapes.add(new Rect());
      shapes.add(new Circle());
    
      for(Shape s : shapes) {
        if(s instanceof Rect) {
          println("type is rect");
        } 
        else if (s instanceof Circle) {
          println("type is circle");
    
        }
      }
    }
    
    
    class Rect extends Shape {
    }
    
    class Circle extends Shape {
    }
    
    class Shape {
    }
    
  • This is also possible:

    ArrayList<Object> shapes = new ArrayList<Object>();
    
    void setup() {
      shapes.add(new Rect());
      shapes.add(new Circle());
    
      for(Object s : shapes) {
        if(s instanceof Rect) {
          println("type is rect");
        } 
        else if (s instanceof Circle) {
          println("type is circle");
    
        }
      }
    }
    
    
    class Rect   {
    }
    
    class Circle   {
    }
    
  • very helpfully! thank's a lot!!

  • edited April 2014

    ArrayList<Object> shapes = new ArrayList<Object>();

    <Object> is completely redundant! Since w/o specifying the generics, it's assumed to be an <Object> already: ;)

    final ArrayList shapes = new ArrayList();

  • good to know! ;-)

  • This might be a little bit picky (especially for Processing)... but I find that if you have to use instanceOf, then you're probably doing something wrong. It's better to use OOP principles - in this case, abstraction:

    ArrayList<Shape> shapes = new ArrayList<Shape>();
    
    void setup() {
      shapes.add(new Rect());
      shapes.add(new Circle());
    
      for(Shape s : shapes) {
        //We don't need to cast because display() is defined in Shape...
        s.display();
        //If done properly, abstraction should remove the need to check for the object's type
      }
    }
    
    class Rect implements Shape {
      //Implement display()
      void display() {
        //Draw a rectangle
      }
    }
    
    class Circle implements Shape {
      //Implement display();
      void display() {
        //Draw circle
      }
    }
    
    interface Shape {
      //Let's abstract display()
      void display();
    }
    

    Abstraction is your friend. I find a way to use it all the time (maybe even too much...). There are interfaces, abstract classes, anonymous classes... it's just something to think about.

  • I am not so far familiar in java as in c++. but if abstraction works in java then that's the right way! thank's a lot!

  • edited September 2015

    @calsign : I just try to implement your interface, but I fail....

    [Edited]

    troubles in line 35 and 36 (I don't know where to place the vars x,y etc. in the class / interface). Or do I have to use a setter method for x and y?

    Can you explain or correct my mcve?

    Thank you!

    Best, Chrisir ;-)

    // mcve for interface with different classes
    
    // the nodes 
    ArrayList<Node> nodes = new ArrayList();
    
    // --------------------------------------------
    // Core functions 
    
    void setup() {
      size(900, 800);
    
      // add new EllipseClass/RectClass with random color 
      color randomColor = color(random(0, 255), random(0, 255), random(0, 255));
    
      nodes.add ( new EllipseClass(44, 44, 
      randomColor));
      nodes.add ( new EllipseClass(111, 111, 
      randomColor));
      nodes.add ( new RectClass(211, 211, 
      randomColor));
    } // func 
    
    void draw() {
      // clear screen 
      background(255);
    
      // for-loop
      for (int i = 0; i < nodes.size (); i++) { 
        Node someClass  = nodes.get(i);
        someClass.display();
      } // for 
    
      if (frameCount>10&&frameCount<12) {     
        Node someClass  = nodes.get(1);
        someClass.x += 22; // change position 
        someClass.y += 33;
      } // else
    } // func 
    
    // ==============================================
    // interface and classes
    
    class RectClass implements Node {  
    
      // pos
      float x=0;
      float y=0;
    
      // color 
      color RectClassColor=0; 
    
    
      // constr 
      RectClass(float tempX, float tempY, 
      color tempRectClassColor) {
        x = tempX;
        y = tempY;
    
        RectClassColor = tempRectClassColor;
        //
      } // constr
      //
      void display() {
        fill(RectClassColor);
        rect (x, y, 16, 16);
      }
      //
    } // class
    
    class EllipseClass implements Node {  
    
      // pos
      float x=0;
      float y=0;
    
      // color 
      color RectClassColor=0; 
    
    
      // constr 
      EllipseClass(float tempX, float tempY, 
      color tempRectClassColor) {
        x = tempX;
        y = tempY;
    
        RectClassColor = tempRectClassColor;
        //
      } // constr
      //
      void display() {
        fill(RectClassColor);
        ellipse (x, y, 15, 15);
      }
      //
    } // class
    
    
    interface Node {
    
      //Let's abstract
    
      //Let's abstract display()
      void display();
    }
    //
    
  • You have an ArrayList of Node objects. The only thing about Node objects the compiler is aware of is that it has the display() method implemented. In this situation you would be better off with straight inheritance.

  • It would work with getters and setters, or casting I think...

    See this: http://forum.processing.org/two/discussion/12310/accessing-member-fields-using-interfaces

  • edited September 2015

    It's part of another bigger project and I thought for a great diversity of classes, interface would be better (because all classes can be very different from each other)

  • Maybe an incrementBy(float amount){}, decrementBy(float amount){} methods in the Interface.

  • yeah, or just

    void setXY(float x_, float y_) {
        x=x_;
        y=y_;
    }
    
  • or increment, you are right............

  • it works now

    thank you!

    Chrisir ;-)

    // mcve for interface with different classes
    
    // the nodes 
    ArrayList<Node> nodes = new ArrayList();
    
    // --------------------------------------------
    // Core functions 
    
    void setup() {
      size(900, 800);
    
      // add new EllipseClass/RectClass with random color 
      color randomColor = color(random(0, 255), random(0, 255), random(0, 255));
    
      nodes.add ( new EllipseClass(44, 44, 
      randomColor));
      nodes.add ( new EllipseClass(111, 111, 
      randomColor));
      nodes.add ( new RectClass(211, 211, 
      randomColor));
    } // func 
    
    void draw() {
      // clear screen 
      background(255);
    
      // for-loop
      for (int i = 0; i < nodes.size (); i++) { 
        Node someClass  = nodes.get(i);
        someClass.display();
      } // for 
    
      if (frameCount>60&&frameCount<64) {     
        Node someClass  = nodes.get(1);
        someClass.incrementXY(22, 0); // change position 
        someClass.incrementXY(33, 0);
      } // else
    } // func 
    
    // ==============================================
    // interface and classes
    
    class RectClass implements Node {  
    
      // pos
      float x=0;
      float y=0;
    
      // color 
      color RectClassColor=0; 
    
    
      // constr 
      RectClass(float tempX, float tempY, 
      color tempRectClassColor) {
        x = tempX;
        y = tempY;
    
        RectClassColor = tempRectClassColor;
        //
      } // constr
      //
      void display() {
        fill(RectClassColor);
        rect (x, y, 16, 16);
      }
    
      void setXY(float x_, float y_) {
        x=x_;
        y=y_;
      }
    
      void incrementXY(float x_, float y_) {
        x+=x_;
        y+=y_;
      }
      //
    } // class
    
    // -------------------------
    
    class EllipseClass implements Node {  
    
      // pos
      float x=0;
      float y=0;
    
      // color 
      color RectClassColor=0; 
    
    
      // constr 
      EllipseClass(float tempX, float tempY, 
      color tempRectClassColor) {
        x = tempX;
        y = tempY;
    
        RectClassColor = tempRectClassColor;
        //
      } // constr
      //
      void display() {
        fill(RectClassColor);
        ellipse (x, y, 15, 15);
      }
    
      void setXY(float x_, float y_) {
        x=x_;
        y=y_;
      }
    
      void incrementXY(float x_, float y_) {
        x+=x_;
        y+=y_;
      }
      //
    } // class
    
    
    interface Node {
    
      // Let's abstract
    
      // Let's abstract display()
      void display();
      void incrementXY(float x_, float y_);
    }
    //
    
  • edited January 2016

    .

Sign In or Register to comment.