Stalk3r
Stalk3r

Reputation: 45

Calling a 'dynamic' Object of a HashMap

I just came to the problem where I want to call a function of an Object inside a HashMap. I already searched it up and found one thread but sadly I don't understand it.

So here's my code

public class Seat {

  //some attributes

  public int getNumber() {
     return number;
  }
  public boolean isReserved() {
     return status;
  }
}

public class Hall {

  private HashMap mySeats;

  public HashMap getMeinePlaetze() {
      return meinePlaetze;
  }
  public void createSeats() {
      for (int i = 1; i <= this.getnumberOfSeats(); i++) {
        this.getMySeats().put(i, new Seat(i, 1));
      }
   }
}
public class Main {
  Hall h1 = new Hall(...);

  h1.createSeats();

  h1.getMySeats().get(2).isReserved();  //How do I have to write this to work out? 
}

I hope my intend is reasonable. Feel free to correct me if my code sucks. I already apologize for it.

Thank you very much.

Upvotes: 0

Views: 187

Answers (3)

LowLevel
LowLevel

Reputation: 1095

Following my tip in the comments, I wouldn't use a Map to link a meaningful row or number to a map-key or an array-index.

So, actually I would do it this way (because you asked, what I mean with my tip):

Seat:

public class Seat {

    private final int row;
    private final int number;
    private boolean reserved = false;

    public Seat(int row, int number) {
        this.row = row;
        this.number = number;
    }

    public boolean reserve() {
        if (!reserved) {
            reserved = true;
            return reserved;
        }
        return !reserved;
    }

    public int getRow() {
        return row;
    }

    public int getNumber() {
        return number;
    }

    public boolean isReserved() {
        return reserved;
    }

    public boolean is(int row, int number) {
        return this.row == row && this.number == number;
    }

    @Override
    public int hashCode() {
        int hash = 7;
        hash = 23 * hash + this.row;
        hash = 23 * hash + this.number;
        return hash;
    }

    @Override
    public boolean equals(Object obj) {
        if (this == obj) {
            return true;
        }
        if (obj == null) {
            return false;
        }
        if (getClass() != obj.getClass()) {
            return false;
        }
        final Seat other = (Seat) obj;
        if (this.row != other.row) {
            return false;
        }
        return number == other.number;
    }
}

Hall:

public class Hall {

    public final Set<Seat> seats = new HashSet<>();

    public Set<Seat> getSeats() {
        return Collections.unmodifiableSet(seats);
    }

    public void createSeats(int lastRow, int seatsPerRow) { // This is an example; in case you have different count of seats per row, you better make an boolean addSeat(int row, int number) function; boolean to check if it has been added or if the seat already exists
        for (int row = 1; row <= lastRow; row++) {
            for (int number = 1; number <= seatsPerRow; number++) {
                seats.add(new Seat(row, number));
            }
        }
    }

    public Seat get(int row, int number) {
        for (Seat seat : seats) { // or you use seats.iterator; I personally hate Iterators; it is my subjective point of view.
            if (seat.is(row, number)) {
                return seat;
            }
        }
        return null;
    }

    public boolean reserve(int row, int number) {
        Seat seat = get(row, number);
        if (seat != null) {
            return seat.reserve();
        }
        return false;
    }
}

And my Test-drive:

public class TestDrive {

    public static void main(String[] args) {
        Hall hall = new Hall();
        int lastRow = 15;
        int seatsPerRow = 10;
        hall.createSeats(lastRow, seatsPerRow);

        boolean reserved = hall.reserve(5, 9);
        System.out.println("Seat(Row=5, Number=9) is reserved: " + (reserved == hall.get(5, 9).isReserved()));

        boolean reservedAgain = hall.reserve(5, 9);
        System.out.println("Seat(Row=5, Number=9) cannot be reserved again: " + (reservedAgain != hall.get(5, 9).isReserved()));
    }
}

Upvotes: 1

fps
fps

Reputation: 34470

Since version 5, Java has a feature called Generics. You'll find a lot about generics on the web, from articles, blog posts, etc to very good answers here on StackOverflow.

Generics allows Java to be a strongly typed language. This means that variables in Java can not only be declared to be of some type (i.e. HashMap), but also to be of some type along with one or more generic type parameters (i.e. HashMap<K, V>, where K represents the type parameter of the keys of the map and V represents the type parameter of the values of the map).

In your example, you are using a raw HashMap (raw types are types that allow for generic type parameters to be specified, however the developer has not specified them). Raw types are considered bad practice and are highly error-prone, as you are experiencing right now.

HashMap allows two generic type parameters (one for the keys and another one for the values). In your case, you are using Integer for the keys and Seat for the values. Put into simple words, you are mapping integers to seats, or you can also say that your map is a map of integers to seats.

So, inside you Hall class, you should define your map with its generic type parameters:

private Map<Integer, Seat> mySeats = new HashMap<>();

Then, this code:

h1.getMySeats().get(2)

will return an instance of type Seat, because your map already knows that all its values are of type Seat.

So your code:

h1.getMySeats().get(2).isReserved();

will compile fine and will work without any errors.

Please note that, apart from declaring the generic types of your map, I've also changed two additional things.

First, I've created an actual instance of HashMap by using its constructor:

mySeats = new HashMap<>()

If you don't create an instance of your type with new, there won't be any HashMap instance where to put your seats later, and you'll get a NullpointerException (try it!).

Secondly, I've changed the type of the variable from HashMap to Map. HashMap is a class, while Map is just an interface. The thing is that the HashMap class implements the Map interface, so, unless your code explicitly needs to access a method of HashMap that is not declared in the Map interface (which is almost never the case), you will be fine with the mySeats variable being of type Map<Integer, Seat> instead of HashMap<Integer, Seat>. This is called programming to the interface and is a best practice that you should embrace from the very beginning. It will save you a lot of headaches in the future.

Upvotes: 2

Valdrinium
Valdrinium

Reputation: 1416

h1.getMySeats().get(2).isReserved();

Please use an IDE like IntelliJ IDEA. It will tell you about mistakes like forgetting parentheses while typing.

Upvotes: 1

Related Questions