Java - Инициализировать хэш-карту HashMaps

Я новичок в java и занимаюсь созданием упрощенного классификатора NaiveBayes. Я еще новичок в создании экземпляра объекта и задаюсь вопросом, что делать, чтобы инициализировать HashMap из HashMaps. При вставке новых наблюдений в классификатор я могу создать новый HashMap для невидимого имени функции в данном классе, но мне нужно инициализировать?

import java.util.HashMap;

public class NaiveBayes {

    private HashMap<String, Integer> class_counts;
    private HashMap<String, HashMap<String, Integer>> class_feature_counts;

    public NaiveBayes() {
        class_counts = new HashMap<String, Integer>();
        // do I need to initialize class_feature_counts?
    }

    public void insert() {
        // todo
        // I think I can create new hashmaps on the fly here for class_feature_counts
    }

    public String classify() {
        // stub 
        return "";
    }

    // Naive Scoring:
    // p( c | f_1, ... f_n) =~ p(c) * p(f_1|c) ... * p(f_n|c)
    private double get_score(String category, HashMap features) {
       // stub
       return 0.0;
    }

    public static void main(String[] args) {
        NaiveBayes bayes = new NaiveBayes();
       // todo
     }
}

Обратите внимание, что этот вопрос не относится к классификаторам Naive Bayes, просто подумал, что я предоставил бы какой-то контекст.

Ответ 1

Да, вам нужно инициализировать его.

class_feature_counts = new HashMap<String, HashMap<String, Integer>>();

Если вы хотите добавить значение в class_feature_counts, вам также необходимо создать его экземпляр:

HashMap<String, Integer> val = new HashMap<String, Integer>();
// Do what you want to do with val
class_feature_counts.put("myKey", val);

Ответ 2

Рекурсивные общие структуры данных, такие как карты карт, а не прямая плохая идея, часто указывают на то, что вы могли бы реорганизовать, - внутренняя карта часто может быть объектом первого порядка (который содержит карту), а не просто карта. Вам все равно придется инициализировать эти внутренние объекты, но часто это намного более чистый и понятный способ разработки.

Например, если у вас есть Map<A,Map<B,C>>, вы часто действительно сохраняете карту A to Thing, но способ, которым Thing хранится, является совпадением с картой. Вы будете часто находить его более чистым и легче скрыть тот факт, что Thing - это карта, и вместо этого сохраните отображение Map<A,Thing>, где вещь определяется как:

public class Thing {
    // Map is guaranteed to be initialized if a Thing exists
    private Map<B,C> data = new Map<B,C>();

    // operations on data, like get and put
    // now can have sanity checks you couldn't enforce when the map was public
}

Также обратите внимание на утилиты Guava Mulitmap/Multiset, они очень полезны для таких случаев, в частности, они делают внутренний объект инициализация автоматически. Обратите внимание на ваш случай, примерно в любое время, когда вы реализуете Map<E, Integer>, вам действительно нужен набор Guava Multiset. Чище и понятнее.

Ответ 3

Вы должны создать объект перед его использованием через ссылочную переменную. Неважно, насколько сложным является этот объект. Вы не обязаны инициализировать его в конструкторе, хотя это наиболее распространенный случай. В зависимости от ваших потребностей вы можете использовать вместо этого "ленивую инициализацию".

Ответ 4

  • Не указывайте свои переменные с помощью HashMap. Это слишком ограничивает.
  • Да, вам нужно инициализировать class_feature_counts. Вы будете добавлять в него записи, поэтому это должна быть действительная карта. Фактически, инициализируйте как при объявлении, так и не в конструкторе, так как для каждого из них есть только один способ. Я надеюсь, что вы используете Java 7; это проще.

    private Map < String, Integer > classCounts = new HashMap < > ();

    private Map < String, Map < String, Integer → classFeatureCounts = new HashMap < > ();

Компилятор выведет типы из < > . Кроме того, я изменил имена переменных на стандартный стиль Java-верблюда. Связаны ли classCounts и classFeatureCounts?