#java
#java
Вопрос:
Я пытаюсь создать реализацию коллекции карт, в которой хранится пара элементов ключа и значения. Ошибка возникает во время выполнения, когда я пытаюсь зарегистрировать пару ключ-значение и нажимаю на эту строку.
EntryNode<K, V> mapEntry = mapEntryList[mapSize];
У меня заканчиваются идеи о том, в чем может быть проблема, любая помощь приветствуется. Спасибо.
//Driver class to test output
public class Driver{
public static void main(String[] args) {
MyMap<String, String> mapInstance = new MyMap<String, String>();
myMap.register("Key1", "Value");
System.out.println(myMap.get("Key1"));
}
}
public class MyMap<K, V> implements MapInterface<K, V>{
private EntryNode<K, V>[] mapEntryList;
private int mapSize = 0;
public MyMap(){
}
public MyMap(int capacity){
this.mapEntryList = new EntryNode[mapSize];
}
//static
public class EntryNode<K, V>{
K keyElement;
V valueElement;
EntryNode<K, V> nextMapEntry;
public EntryNode(K keyElement, V valueElement, EntryNode<K, V> nextMapEntry) {
this.keyElement = keyElement;
this.valueElement = valueElement;
this.nextMapEntry = nextMapEntry;
}
public K getKey() {
return keyElement;
}
public V getValue() {
return valueElement;
}
public EntryNode<K, V> getNextMapEntry() {
return nextMapEntry;
}
public final V setNewValue(V newValueElement) {
V oldValueElement = valueElement;
valueElement = newValueElement;
return oldValueElement;
}
public String toString() {
return "{" keyElement ", " valueElement "}";
}
}
public int size() {
return mapSize;
}
public V get(K keyElement) {
EntryNode<K, V> mapEntry = mapEntryList[mapSize];
int count = mapSize;
boolean entryPresent = false;
EntryNode tempNode = firstEntry;
while (!entryPresent amp;amp; mapEntry != null) {
if (keyElement == mapEntry.keyElement) {
entryPresent = true;
return mapEntry.valueElement;
}
else {
mapEntry = mapEntry.nextMapEntry;
}
}
return null;
}
public void register(K newKeyElement, V newValueElement) {
EntryNode<K, V> newEntry = new EntryNode(newKeyElement, newValueElement, null);
EntryNode<K, V> mapEntry = mapEntryList[mapSize];
boolean entryPresent = false;
while (!entryPresent amp;amp; mapEntry != null) {
if (newKeyElement == mapEntry.keyElement) {
entryPresent = true;
break;
}
else {
if(mapEntry.nextMapEntry == null){
break;
}
mapEntry = mapEntry.nextMapEntry;
}
}
if(!entryPresent){
mapEntry.nextMapEntry = newEntry;
mapSize ;
}
}
public void remove(K removeKeyElement) {
EntryNode previousEntry = null;
EntryNode<K, V> mapEntry = mapEntryList[mapSize];
while (mapEntry != null) {
if (removeKeyElement == mapEntry.keyElement) {
mapEntry.keyElement = null;
mapEntry.valueElement = null;
previousEntry.nextMapEntry = mapEntry.nextMapEntry;
break;
}
else {
previousEntry = mapEntry;
mapEntry = mapEntry.nextMapEntry;
}
}
}
private int getEntriesSize() {
return mapEntryList.length;
}
public String toString() {
StringBuilder stringOutput = new StringBuilder();
for (EntryNode entry : mapEntryList) {
stringOutput.append("[");
while (entry != null) {
stringOutput.append(entry);
if (entry.nextMapEntry != null) {
stringOutput.append(", ");
}
entry = entry.nextMapEntry;
}
stringOutput.append("]");
}
return "{" stringOutput.toString() "}";
}
}
Комментарии:
1. Java!= Javascript!
2. Я удалил тег ‘javascript’.
3. Не могли бы вы показать ошибку, пожалуйста?
4. Какого рода ошибка возникает? Ошибка компилятора? Если да: пожалуйста, укажите сообщение об ошибке? Исключение / ошибка во время выполнения? Если да: пожалуйста, включите трассировку стека. В обоих случаях: пожалуйста, выделите строку кода, вызывающую ошибку / исключение.
5. Исключение в потоке «main» java.lang. Исключение NullPointerException
EntryNode<K, V> mapEntry = mapEntryList[mapSize];
Ответ №1:
Допустим, я создаю новую карту, а затем вызываю .get() для нее.
MyMap<Integer, String> m = new MyMap<>();
m.get(5);
Этот конструктор (без аргументов) означает, что mapEntryList
никогда не устанавливается, что означает, что по умолчанию он равен null. Таким образом, при get
вызове первое, что делает ваш get
метод, это разыменование mapEntryList
поля (разыменования foo[idx]
конструкции foo
). Разыменование нулевого значения означает: NullPointerException
выдается. Очевидно, что цель вашего кода — вернуть значение null, если ключа нет в карте, поэтому эта часть не работает.
В качестве альтернативы, я пойду с:
MyMap<Integer, String> m = new MyMap<>(10);
m.get(5);
На этот раз я вызываю второй конструктор. Этот конструктор принимает значение ‘capacity’, выбрасывает его в корзину и создает массив размером 0. Затем вызывается get, и ваш код выполняется:
mapEntry = mapEntryList[mapSize];
Это не может сработать; вы не можете получить что-либо из массива длиной 0. На самом деле, если вы напишете:
int[] a = new int[5];
a[5];
(например, вы создаете новый массив размером X, а затем запрашиваете элемент с индексом X), вы всегда получаете IndexOutOfBoundsException
: в java все массивы проиндексированы на 0. a[0]
является первым элементом и new int[1]
создает массив int размером 1, поэтому выполнение a[1]
(запрос второго элемента) для массива размером 1 невозможно (в нем есть только один элемент).
Есть около 50 других проблем с этим кодом, вам действительно нужно делать это по одному маленькому шагу за раз и отлаживать этот код: Вместо того, чтобы просто смотреть на весь этот код и думать: Э-э, это не работает — вам нужно его отладить:
Напишите некоторый код, затем запустите его. Когда вы ее запускаете, «мысленно запустите это»: возьмите ручку и бумагу, если нужно, пройдитесь по коду строка за строкой и выясните, что должна делать каждая строка, вручную. Затем проверьте, что, по вашему мнению, должно произойти, в сравнении с тем, что происходит на самом деле, либо с помощью отладчика, либо добавив кучу инструкций System.out, если необходимо. Там, где код делает что-то отличное от того, что вы думали? Вы обнаружили ошибку. Вероятно, первая в довольно большом их списке. Исправьте это и продолжайте, пока ошибки не исчезнут.
Комментарии:
1. Спасибо за отзыв. Означает ли это, что проблема возникает при вызове функции get, а не самой функции register? Как и в значениях внутри всей карты, все они равны нулю?
2. Прямо из вашего метода register: EntryNode<K, V> MapEntry = mapEntryList[mapSize]; — тот же код, поэтому у вас всегда будет сбой по тем же причинам. Ошибка возникает именно там, где указано в трассировке стека.