1

My goal is this: Be able to save an array of objects (in this case; Animal) to disc. Then I would like to be able to load them. I have used JSON to do this, but left it out in this snippet for clarity. I would like to be able to make many more classes of Animal that will have many more fields (see Unicorn Class below).

The class of the object cannot be known in advance. How can I get addAnimal to work using a String input?

AnimalWrangler aw;

void setup()
{
  aw = new AnimalWrangler();

  aw.addAnimal("cat");
  aw.addAnimal("horse");
  aw.addAnimal("unicorn");
  aw.addAnimal("unknown");
}

class AnimalWrangler
{

  ArrayList<Animal> animals;

  AnimalWrangler()
  {
    animals = new ArrayList<Animal>();
  }

  void addAnimal(String type)
  {
    //makes an animal according to type        

    ///if type does not exist then throw

    //add to animals array 

  }
}



class Animal
{
  String type;

  Animal()
  {
  }
}

class Cat extends Animal
{
  Animal animal;
  Cat()
  {
    animal = new Animal();
    type = "cat";
  }
}

class Horse extends Animal
{
  Animal animal;
  Horse()
  {
    animal = new Animal();
    type = "horse";
  }
}

class Unicorn extends Animal
{
  Animal animal;
  float magic_level;
  /////classes can have any number of attributes

  Unicorn()
  {
    animal = new Animal();
    type = "unicorn";
  }
}
3
  • Your problem really looks like a NoSQL database with document approach... Commented Jan 4, 2017 at 13:15
  • Your Animal subclasses probably shouldn't have an Animal animal field... Commented Jan 4, 2017 at 13:25
  • @king_nak yes! this is just an artefact of an earlier (incorrect) approach and should be ignored. Commented Jan 4, 2017 at 13:33

2 Answers 2

1

The typical way is to create a registry of string-to-class mappings:

static Map<String, Class<? extends Animal>> registry;

Then populate the map with the types:

static {
            registry = new HashMap<>();
            registry.put("cat", Cat.class);
        }

Then, for AnimalWrangler.addAnimal("cat"); add to addAnimal method:

animals.add(registry.get("cat").newInstance());

Ought to solve it, so long as each class has a default constructor.

Sign up to request clarification or add additional context in comments.

3 Comments

So when I save the animals I build the registry and save it to disc as well?
to save it to disc you would use serialization. Make the top parent class implement Serializable then write each instance to a separate file. To read back: `registry.get("cat").cast(objectReadFromDeserialization); See how to ser/deser here javatpoint.com/serialization-in-java
This is a much less verbose solution, however there is some performance loss using reflection to generate a new Instance
0

Probably you're looking for a switch statement that does this for you, something like:

switch (type)
{
    type.equals("cat"): // Note hardcoding isn't the best idea and doesn't account for case sensitivity
        animals.add(new Cat());
        break;
    type.equals("horse"):
        animals.add(new Horse());
        break;
    // Add other animals in a similar fashion.
    default:
        throw new exception();
        break;
    }
}

2 Comments

Is there an alternative to hardcoding? If I was a lazy programmer, how could I avoid writing out a new switch every time I make a new class?
@jackoverflow The hardcoding you can solve with an enum, something like stackoverflow.com/questions/6667243/…. I wouldn't know how to avoid adding new animals to the switch.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.