3

I have a base class called Geometry from which there exists a subclass Sphere:

public class Geometry 
{
 String shape_name;
 String material;

 public Geometry()
 {
     System.out.println("New geometric object created.");
 }
}

and a subclass:

public class Sphere extends Geometry
{
 Vector3d center;
 double radius;

 public Sphere(Vector3d coords, double radius, String sphere_name, String material)
 {
  this.center = coords;
  this.radius = radius;
  super.shape_name = sphere_name;
  super.material = material;
 }
}

I have an ArrayList that contains all Geometry objects and I want to iterate over it to check whether the data from a text file is read in correctly. Here is my iterator method so far:

public static void check()
 {
  Iterator<Geometry> e = objects.iterator();
  while (e.hasNext())
  {
   Geometry g = (Geometry) e.next();
   if (g instanceof Sphere)
   {
    System.out.println(g.shape_name);
    System.out.println(g.material);
   }
  }
 }

How do I access and print out the Sphere's radius and center fields? Thanks in advance :)

jmj
  • 237,923
  • 42
  • 401
  • 438
user283188
  • 287
  • 3
  • 11
  • 19
  • 3
    This is very similar to http://stackoverflow.com/questions/2701182/call-a-method-of-subclass-in-java. Does that answer your question? – Rafe Kettler Dec 22 '10 at 18:23
  • The need of the base class to know about the subclass data is pointing out that your abstraction might not be correct. You should take a step back and ask yourself what check is doing and if it needs to be on the base, child or possibly a method of a utility class external to your object model. – dhable Dec 22 '10 at 18:28
  • 1
    also, you don't need 'super.' everywhere in subclasses, since they inherit the fields. – gtrak Dec 22 '10 at 18:31

4 Answers4

11

If you want to access properties of a subclass, you're going to have to cast to the subclass.

if (g instanceof Sphere)
{
    Sphere s = (Sphere) g;
    System.out.println(s.radius);
    ....
}

This isn't the most OO way to do things, though: once you have more subclasses of Geometry you're going to need to start casting to each of those types, which quickly becomes a big mess. If you want to print the properties of an object, you should have a method on your Geometry object called print() or something along those lines, that will print each of the properties in the object. Something like this:


class Geometry {
   ...
   public void print() {
      System.out.println(shape_name);
      System.out.println(material);
   }
}

class Shape extends Geometry {
   ...
   public void print() {
      System.out.println(radius);
      System.out.println(center);
      super.print();
   }
}

This way, you don't need to do the casting and you can just call g.print() inside your while loop.

rwat
  • 833
  • 5
  • 10
1

You have to cast (specifically, downcast):

((Sphere) g).radius
Michael Brewer-Davis
  • 14,018
  • 5
  • 37
  • 49
1

I agree with rwhat, but instead of implementing your own print() function, it might benefit you (and be more Object Oriented) to avoid the downcasts by overriding the toString() function.

public class Geometry 
{
 String shape_name;
 String material;

 public Geometry()
 {
     System.out.println("New geometric object created.");
 }

 public String toString() {
      StringBuilder result = new StringBuilder();
      result.append("Shape name: " + shape_name + "\t");
      result.append("Material: " + material + "\t");
      return result.toString();
 }
 public static void check (Geometry[] gList) {
     for (Geometry g: gList) {
         System.out.println(g.toString());
     }
 }

Note the check() doesn't care whether g is a Sphere or a Cube. This will help minimize the calls to instanceof. Over in Sphere...

public class Sphere extends Geometry
 {
  Vector3d center;
  double radius;

  public Sphere(Vector3d coords, double radius, String sphere_name, String material)
  {
   this.center = coords;
   this.radius = radius;
   shape_name = sphere_name;
   super.material = material;
  }
  public String toString() {
      StringBuilder result = new StringBuilder();
      result.append("Radius: " + radius + "\t");
      result.append("Center: " + center.toString() + "\t");
      result.append(super.toString());
      return result.toString();
  }
 }

Any new shape (e.g., Cone) would benefit by having the toString() function, but lacking it would just print out Geometry's version.

rajah9
  • 11,645
  • 5
  • 44
  • 57
0

use instanceof and Cast to the desired subclass. You might want to make those fields public or the standard idiom of private fields with getters and setters too.

gtrak
  • 5,598
  • 4
  • 32
  • 41