首页 > 解决方案 > 尽管已初始化 HashMap,但 HashMap.put 方法仍不起作用

问题描述

我们正在进行基于文本的冒险,您可以从 JSON 文件中读取布局。我正在阅读一个 JSON 文件以创建一个包含房间对象的 Layout 类。每个房间都有一张方向图,将方向名称(即南、东、西等)映射到方向对象。在布局类中,还有另一个映射将房间名称映射到房间对象。当我运行我的代码时,调试器告诉我我的 roomMap 和我的 directionMap 都是空的。因此,当我尝试调用 JUnit 测试以确保在访问地图时返回正确的值时,我得到了 NullPointerException。

import java.lang.reflect.Array;
import java.util.ArrayList;
import java.util.HashMap;

public class Room {

// instance variables
protected String name;
protected String description;
protected Item[] items;
protected Direction[] directions;

protected ArrayList<Direction> testList = new ArrayList<>();
protected HashMap<String, Direction> directionMap = new HashMap<>();

public Room(String name, String description, Direction[] directions, Item[] items) {
    this.name = name;
    this.description = description;
    this.items = items;
    this.directions = directions;
    for (Direction d : directions) {
        directionMap.put(d.directionName, d);
    }
}

}

这是我的方向课:

package com.example;

import com.sun.org.apache.xpath.internal.operations.Bool;

public class Direction {

// instance variables
protected String room;
protected String directionName;
protected boolean enabled;
protected String[] validKeyNames;


public Direction(String room, String directionName, String enabled, String[] validKeyNames) {
    this.room = room;
    this.directionName = directionName;
    this.enabled = Boolean.parseBoolean(enabled);
    this.validKeyNames = validKeyNames;
}


public static boolean compareDirections (Direction d1, Direction d2){
    boolean roomMatch = d1.room.equals(d2.room);

    boolean nameMatch = d1.directionName.equals(d2.directionName);

    boolean enabledMatch = d1.enabled == d2.enabled;

    boolean validKeyNamesMatch = true;

    if(d1.validKeyNames.length == d2.validKeyNames.length){
        for(int i = 0; i < d1.validKeyNames.length; i++){
            if(!d1.validKeyNames[i].equals(d2.validKeyNames[i])){
                validKeyNamesMatch = false;
            }
        }
    }

    return roomMatch && nameMatch && enabledMatch && validKeyNamesMatch;
}

}

这是我的播放器类:

public class Player {

protected Item[] items;
protected Room currentRoom;

public Player(Item[] items, Room startingRoom){
    this.items = items;
    this.currentRoom = startingRoom;
}

}

这是我的项目类:

public class Item {
protected String name;

public Item(String name){
    this.name = name;
}

public static boolean compareItems (Item i1, Item i2){
    return i1.name.equals(i2.name);
}

}

这是我的房间地图所在的布局类

public class Layout {

// instance variables
protected String startingRoom;
protected String endingRoom;
protected Room[] rooms;
protected Player player;

protected HashMap<String, Room> roomMap = new HashMap<>();


public Layout(String startingRoom, String endingRoom, Room[] rooms, Player player) {
    this.startingRoom = startingRoom;
    this.endingRoom = endingRoom;
    this.rooms = rooms;
    this.player = player;

    for (Room room : rooms) {
        roomMap.put(room.name, room);
    }
}

这是 JSON 阅读器类:

public class JsonReader {

public static String getJsonFromUrl (String link) throws IOException {
    try{
        URL url = new URL(link);
    } catch(MalformedURLException e){
        System.out.println("That is not a valid link");
        System.exit(0);
    }
    URL url = new URL(link);
    // Connect to the URL using java's native library
    URLConnection request = url.openConnection();
    request.connect();

    // Convert to a JSON object to print data
    JsonParser jp = new JsonParser(); //from gson
    JsonElement root = jp.parse(new InputStreamReader((InputStream) request.getContent())); //Convert the input stream to a json element
    JsonObject rootobj = root.getAsJsonObject(); //May be an array, may be an object.
    return rootobj.toString();
}

}

我已经测试了 Gson 解析器,并且知道 JSON 文件中的所有值都被正确序列化,这就是为什么我对键值对没有放在哈希图中感到困惑的原因。

这是我的 JUnit 测试

import com.google.gson.Gson;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;

import java.io.IOException;

import static org.junit.Assert.*;

public class AdventureTest {


Adventure adventure;

@Before
public void setup() {
    adventure = new Adventure("https://drive.google.com/uc?export=download&id=1qmmrC3jZ3zrmdvrL8ukM5r4pB4BYhfyd");
}

@Test
public void getJsonFromUrlTest() throws IOException {
    assertEquals(
            "{\"startingRoom\":\"SDRPCommons\",\"endingRoom\":\"HopkinsRoom345\",\"rooms\":[{\"name\":\"SDRPCommons\",\"description\":\"You are in the Ikenberry Dining Hall. There is good food, good people, and good study areas\",\"directions\":[{\"directionName\":\"North\",\"room\":\"DiningHall\",\"enabled\":\"false\",\"validKeyNames\":[\"I-card\"]},{\"directionName\":\"Northwest\",\"room\":\"UpstairsArea\",\"enabled\":\"true\",\"validKeyNames\":[]},{\"directionName\":\"West\",\"room\":\"OutsideAreaOfSixPack\",\"enabled\":\"false\",\"validKeyNames\":[\"backpack\",\"depression\"]}],\"items\":[{\"name\":\"I-card\"},{\"name\":\"Chair\"},{\"name\":\"Fork\"}]},{\"name\":\"DiningHall\",\"description\":\"The best eats on campus, other than PAR/FAR, Chomps, and basically anything on Green Street.\",\"directions\":[{\"directionName\":\"South\",\"room\":\"SDRPCommons\",\"enabled\":\"true\",\"validKeyNames\":[\"depression\"]}],\"items\":[{\"name\":\"sweatshirt\"},{\"name\":\"key\"}]},{\"name\":\"UpstairsArea\",\"description\":\"You are upstairs. Near you is Caffeinator but it's closed. So there is nothing to do but to go back to your room and grind...\",\"directions\":[{\"directionName\":\"Southeast\",\"room\":\"SDRPCommons\",\"enabled\":\"true\",\"validKeyNames\":[]}],\"items\":[{\"name\":\"depression\"},{\"name\":\"backpack\"}]},{\"name\":\"OutsideAreaOfSixPack\",\"description\":\"It's a beautiful day and everyone is out and about. Kinda makes you want to sit in your room in the dark, right?\",\"directions\":[{\"directionName\":\"North\",\"room\":\"HopkinsRoom345\",\"enabled\":\"false\",\"validKeyNames\":[\"depression\",\"backpack\"]}],\"items\":[{\"name\":\"depression\"},{\"name\":\"backpack\"}]},{\"name\":\"HopkinsRoom345\",\"description\":\"This is your room. Go inside and grind your cs 126 hw, idiot.\",\"directions\":[{\"directionName\":\"South\",\"room\":\"OutsideAreaOfSixPack\",\"enabled\":\"false\",\"validKeyNames\":[\"key\",\"depression\"]}],\"items\":[{\"name\":\"bed\"}]}]}",
            JsonReader.getJsonFromUrl("https://drive.google.com/uc?export=download&id=1qmmrC3jZ3zrmdvrL8ukM5r4pB4BYhfyd")
    );
}

@Test
public void loadJsonIntoLayout() throws IOException {
    String json = JsonReader.getJsonFromUrl("https://drive.google.com/uc?export=download&id=1qmmrC3jZ3zrmdvrL8ukM5r4pB4BYhfyd");
    Gson gson = new Gson();
    Layout layout = gson.fromJson(json, Layout.class);
    if (layout != null) {
        assertEquals("SDRPCommons", layout.startingRoom);

        //  System.out.println(layout.roomMap.get(layout.startingRoom));
        Room r = adventure.roomMap.get("DiningHall");
        Direction d = adventure.directionMap.get("south");
        String s = d.directionName;
        assertEquals("south", layout.roomMap.get("DiningHall").directionMap.get("south"));
    }
}

}

这是冒险课:

import com.google.gson.Gson;
import java.io.*;
import java.lang.reflect.Array;
import java.net.*;
import java.util.*;

import static sun.plugin.javascript.navig.JSType.Element;

public class Adventure {

protected Layout layout;
protected HashMap<String, Room> roomMap = new HashMap<>();
protected HashMap<String, Direction> directionMap = new HashMap<>();
//    private Player player;
private static String jsonUrl;
// link for easy access: https://drive.google.com/uc?export=download&id=1qmmrC3jZ3zrmdvrL8ukM5r4pB4BYhfyd
protected Room currentRoom;

protected final List<String> ACTION_VERBS = Arrays.asList("go");
protected final List<String> EXIT_VERBS = Arrays.asList("exit", "quit");
protected final List<String> ITEM_VERBS = Arrays.asList("pickup", "use");


public Adventure(String url) {
    this.jsonUrl = url;
    this.layout = getLayoutFromJson(jsonUrl);
    String startingRoom = layout.getStartingRoom();
    for (Room r : layout.rooms) {
        for (Direction d : r.directions) {
            r.directionMap.put(d.directionName, d);
        }
        layout.roomMap.put(r.name, r);
    }
    this.currentRoom = roomMap.get(startingRoom);
}

public Layout getLayoutFromJson(String url) {
    try {
        String json = JsonReader.getJsonFromUrl(url);
        Gson gson = new Gson();
        Layout layout = gson.fromJson(json, Layout.class);
        return layout;
    } catch (Exception e) {
        return null;
    }
}

}

标签: javajunithashmap

解决方案


Gson 不会自动调用非默认构造函数。它要么调用无参数构造函数,要么“自动”无中生有地创建一个实例,然后通过反射填充其字段。阅读Gson 是否必须使用默认的无参数构造函数?

这意味着您的roomMap/directionMap人口代码不会被调用,因为该代码位于非默认构造函数中。


推荐阅读