0

So I have a class Spaceship with some private variables, one of which have a LinkedHashMap of another Class and an Integer like this

private LinkedHashMap<Resource, Integer> cargo;

Resource is an Abstract class that has several types of Resources (like ResourceBlue, ResourceRed, etc...)

Can I do a LinkedHashMap with an abstract class and if so, how would I go about to do it?

This is what I have so far:

Constructor:

public SpaceShip() {

    this.cargoHold = 0;
    this.upgradeLevel = 0;
    this.drone = null;
    this.artifact = 0;
    this.crewMembers = new ArrayList<String>() {
        {
            add("Captain");
            add("Navigation");
            add("Landing");
            add("Shields");
            add("Cargo");
        }
    };
    this.cargo = new LinkedHashMap<Resource, Integer>(){
        {
            cargo.putIfAbsent(new ResourceAzul(), 0);
            cargo.putIfAbsent(new ResourcePreto(), 0);
            cargo.putIfAbsent(new ResourceVerde(), 0);
            cargo.putIfAbsent(new ResourceVermelho(), 0);
        }
    };

}

When I run this in my main (as a test):

SpaceShip ss = new SpaceShip();
System.out.println(ss);

This is just giving me a NullPointerException at the first "putIfAbsent" in the constructor.

3 Answers3

2

What you're doing with that shorthand is actually rather complex. You're creating an anonymous subclass of LinkedHashMap containing a non-static block. That non-static block, similar to a constructor, will be run during the objects instantiation. Because your object hasn't yet been instantiated, your "cargo" variable will not exist. In a non-static block, similarly to a constructor, you can use the "this" keyword.

this.cargo = new LinkedHashMap<Resource, Integer>(){
    {
        this.put(new ResourceAzul(), 0);
        this.put(new ResourcePreto(), 0);
        this.put(new ResourceVerde(), 0);
        this.put(new ResourceVermelho(), 0);
    }
};

Also, because your cargo LinkedHashMap is just being created, it will be empty. So you can simplify "putIfAbsent" to just "put".

Jeremy
  • 98
  • 7
1

You can't put objects into cargo until you complete the initialization statement. The putIfAbsent() calls should come after:

 this.cargo = new LinkedHashMap<Resource, Integer>();
 cargo.putIfAbsent(new ResourceAzul(), 0);
 cargo.putIfAbsent(new ResourcePreto(), 0);
 cargo.putIfAbsent(new ResourceVerde(), 0);
 cargo.putIfAbsent(new ResourceVermelho(), 0);

You have multiple questions in your actual questions. To answer the question of how to print the contents of the LinkedHashMap, you can print it normally to System.out.println(this.cargo) , but you will need to @Override the toString() method for each of your Resource objects. Otherwise, calling toString() on them will, by default, just print the class name and memory reference.

pczeus
  • 7,709
  • 4
  • 36
  • 51
  • Humm it works, but is it specific to HashMaps? I did it with the crewMembers (which is an ArrayList) and it seems to work fine. –  Apr 30 '20 at 01:36
  • You can check the API for LinkedHashMap. https://docs.oracle.com/javase/8/docs/api/java/util/LinkedHashMap.html . If you look, you will see it does have a constructor that accepts another Map, but you don't have one yet, so that is not an option. – pczeus Apr 30 '20 at 01:37
  • Apparently I can use it that way, I just need to do the changes jhon said, but thanks anyway! –  Apr 30 '20 at 01:40
  • @FDinis with crewMembers, you just wrote `add`, which is implicitly `this.add`; if you had written `crewMembers.add` you would have had the same problem. – David Conrad Apr 30 '20 at 02:33
0

If you want to use this style of initialization don't write cargo. in front of all the putIfAbsent() calls. cargo is still null at this point.

this.cargo = new LinkedHashMap<Resource, Integer>(){
    {
        putIfAbsent(new ResourceAzul(), 0);
        putIfAbsent(new ResourcePreto(), 0);
        putIfAbsent(new ResourceVerde(), 0);
        putIfAbsent(new ResourceVermelho(), 0);
    }
};

This matches how you just wrote add() rather than crewMembers.add() above.

Also, seeing as this is a brand new map it'd be simpler to just call put(). You know the map is starting out empty, no need for putIfAbsent().

this.cargo = new LinkedHashMap<Resource, Integer>(){
    {
        put(new ResourceAzul(), 0);
        put(new ResourcePreto(), 0);
        put(new ResourceVerde(), 0);
        put(new ResourceVermelho(), 0);
    }
};
John Kugelman
  • 349,597
  • 67
  • 533
  • 578