Create a new object of a subclass with a String

My friend and I are working on a game. There is an abstract item class and some specific items:

abstract class Item{
  PVector Start;
  PVector End;
  float Progress;
  
  boolean delete;
  
  boolean flammable;
  int BurnNumbers;
  
  Item(float Speed, PVector Pos) {
    Start = Pos;
    End = Pos;
    Progress = 0f;
    
    delete = false;
    
    flammable = false;
    BurnNumbers = 0;
  }
}
class Iron extends Item{
  Iron(PVector Pos) {
    super(1f, Pos);
  }
  Iron() {super(1f, new PVector());}
}
class Gold extends Item{
  Gold(PVector Pos) {
    super(1f, Pos);
  }
  Gold() {super(1f, new PVector());}
}
class Copper extends Item{
  Copper(PVector Pos) {
    super(1f, Pos);
  }
  Copper() {super(1f, new PVector());}
}
class Coal extends Item{
  Coal(PVector Pos) {
    super(1f, Pos);
    flammable = true;
    BurnNumbers = 5;
  }
  Coal() {super(1f, new PVector());}
}

We save the items in JSONObjects as a string. To reload a game, we have to make new item objects out of the strings.
I know you can do something like this with Class.forname(String), but I haven’t been able to use it. That’s why we’ve solved it this way up until now:

Item getItem(String Name) {
  switch(Name) {
    case "Iron": return new Iron();
    case "Gold": return new Gold();
    case "Copper": return new Copper();
    case "Coal": return new Coal();
    default: println("Item \""+Name+"\" does not exist or it has to be updated in getItem()."); return null;
  }
}

Anyone know how to write the getItem() function without a switch?

I recently saw a similar problem here

The problems and solutions are described in the link above. If you adapt it to your code, it becomes

interface IMenuRunnable {
}

abstract class Item implements IMenuRunnable {
  PVector Start;
  PVector End;
  float Progress;

  boolean delete;

  boolean flammable;
  int BurnNumbers;

  Item(float Speed, PVector Pos) {
    Start = Pos;
    End = Pos;
    Progress = 0f;

    delete = false;

    flammable = false;
    BurnNumbers = 0;
  }
}
class Iron extends Item {
  Iron(PVector Pos) {
    super(1f, Pos);
  }
  Iron() {
    super(1f, new PVector());
  }
}
class Gold extends Item {
  Gold(PVector Pos) {
    super(1f, Pos);
  }
  Gold() {
    super(1f, new PVector());
  }
}
class Copper extends Item {
  Copper(PVector Pos) {
    super(1f, Pos);
  }
  Copper() {
    super(1f, new PVector());
  }
}
class Coal extends Item {
  Coal(PVector Pos) {
    super(1f, Pos);
    flammable = true;
    BurnNumbers = 5;
  }
  Coal() {
    super(1f, new PVector());
  }
}

final String THISPROC = this.getClass().getCanonicalName();

Item getItem(String Name) {
  Item item = null;
  try {
    Class<?> sketchClass = Class.forName(THISPROC);
    Class<?> c = Class.forName(THISPROC + "$" + Name);
    java.lang.reflect.Constructor constructor = c.getDeclaredConstructor(sketchClass);
    item = (Item)constructor.newInstance(this);
  } 
  catch (ClassNotFoundException e) {
    println(e);
  } 
  catch (Exception e) {
    println(e);
  }
  return item;
}

void setup() {
  println(new Iron());
  println(getItem("Iron"));
  println(new Coal());
  println(getItem("Coal"));
}

However I’m not sure if I recommend to do so :slight_smile: Your switch statement looks a bit wordy or repetitive, but it’s a good way to keep track of what is going on.

3 Likes

Thanks. I had to replace the getCanonicalName() with getName(), but now it works perfectly.