Java: Доступ к локальным переменным из внутреннего класса? (PriorityQueue) - PullRequest
2 голосов
/ 17 ноября 2009

Я хочу использовать PriorityQueue для топологической сортировки на графике. Для краткости я хотел бы использовать анонимный внутренний класс для компаратора. Однако мне нужен доступ к графику g, чтобы определить степень узлов, на которые я смотрю. Это возможно?

    /**
 * topological sort 
 * @param g must be a dag
 */
public static Queue<String> topoSort(DirectedGraph<String, DefaultEdge> g) {
    Queue<String> result = new PriorityQueue<String>(g.vertexSet().size(), 
            new Comparator<String>() {

                DirectedGraph<String, DefaultEdge> g;

                @Override
                public int compare(String arg0, String arg1) {
                    if (g.inDegreeOf(arg0) < g.inDegreeOf(arg1)) {
                        return -1;
                    }
                    if (g.inDegreeOf(arg0) > g.inDegreeOf(arg1)) {
                        return 1;
                    }
                    return 0;
                }
    });

    result.addAll(g.vertexSet());

    return result;
}

ИСПРАВЛЕННЫЙ КОД

/**
 * topological sort 
 * @param g must be a dag
 */
public static Queue<String> topoSort(final DirectedGraph<String, DefaultEdge> g) {
    Queue<String> result = new PriorityQueue<String>(g.vertexSet().size(), 
            new Comparator<String>() {          
                @Override
                public int compare(String arg0, String arg1) {
                    if (g.inDegreeOf(arg0) < g.inDegreeOf(arg1)) {
                        return -1;
                    }
                    if (g.inDegreeOf(arg0) > g.inDegreeOf(arg1)) {
                        return 1;
                    }
                    return 0;
                }
    });

    result.addAll(g.vertexSet());

    return result;
}

Ответы [ 3 ]

11 голосов
/ 17 ноября 2009

Да, сделайте это окончательно:

public static Queue<String> topoSort(final DirectedGraph<String, DefaultEdge> g) {

См. Последнее слово о последнем ключевом слове :

Анонимные локальные классы

Вторая ситуация, связанная с финалом переменные на самом деле предписано семантика языка. В этой ситуации компилятор Java не позволит вам использовать переменная, если она не объявлена ​​окончательной. Эта ситуация возникает с замыканиями, также известный как анонимные локальные классы. Локальные классы могут ссылаться только на локальные переменные и параметры, которые объявлен окончательным.

public void doSomething(int i, int j)
{
  final int n = i + j; // must be declared final

  Comparator comp = new Comparator()
  {
    public int compare(Object left, Object right)
    {
      return n; // return copy of a local variable
    }
  };
} 

причина этого ограничения становится очевидным, если мы пролить свет о том, как реализованы локальные классы. Анонимный локальный класс может использовать локальный переменные, потому что компилятор автоматически дает классу поле частного экземпляра для хранения копии каждой локальной переменной использует класс. Компилятор также добавляет скрытые параметры для каждого конструктора инициализировать эти автоматически созданные частные поля. Таким образом, местный класс на самом деле не доступ к локальным переменные, но просто свой собственный их копии. Единственный способ, которым это может работать правильно, если местный переменные объявляются окончательными, так что они гарантированно не изменятся. С этой гарантией на месте, местный класс уверен, что его внутренние копии переменных точно отражать фактическое местное переменные.

2 голосов
/ 27 августа 2012

Если во внутреннем классе используется локальная переменная, компилятор генерирует поле экземпляра для внутреннего класса и копирует в него значение локальных переменных. Теперь, если локальная переменная изменится, тогда значение переменной instancs будет по-прежнему иметь старое значение. Таким образом, чтобы сделать значение локальных переменных таким же, как у поля экземпляра и не изменяемым, оно делается окончательным.

0 голосов
/ 18 ноября 2009

К вашему сведению, с коллекциями Google у вас также есть опция

  Ordering.natural().onResultOf(
      new Function<String, Integer>() {
        public Integer apply(String arg) {
          return g.inDegreeOf(arg);
        }
      });

Это не обязательно экономит вам много времени на печать, как вы можете видеть, если только вы не можете найти другие варианты использования этой функции, но это защищает вас от ошибок, которые очень часто проникают в ваши реализации ручного компаратора.

...