class 成员的直接初始化与在方法中进行初始化有什么区别?

What is the difference between direct initialization of class member vs doing it within a method?

我完成了一项 Google Foobar 任务,并且很好奇为什么 2 个看似相同的实现以不同的方式工作。当第二个解决方案通过所有测试用例时,第一个给我带来 "Test 2 failed"。我知道他们都没有遵循最佳 OOP 实践,但我很感兴趣第一个实现的确切问题是什么。

1.

public class Answer {
    static Map<Character, LinkedList<Character>> g = new HashMap<Character, LinkedList<Character>>();
    static Set<Character> visited = new HashSet<Character>();
    static ArrayList<Character> ans = new ArrayList<Character>();

    public static void dfs(char v) {
        visited.add(v);
        //some standard code for DFS
        ans.add(v);
    }

    public static String topologicalSort() {

        for (Character element : g.keySet()) {
            if (!visited.contains(element))
                dfs(element);
        }

        //some code to prepare the output
    }

    public static void builGraph(String[] words) {

        //some code to build adjacency list and then use it through g reference 
    }

    public static String answer(String[] words) {

        if (words.length == 1) {
            //some code
        }

        builGraph(words);

        return topologicalSort();
    }

    public static void main(String[] args) {
        //some code
        System.out.println(answer(words));
    } 
}

2.

public class Answer {
    static Map<Character, LinkedList<Character>> g;
    static Set<Character> visited;
    static ArrayList<Character> ans;

    public static void dfs(char v) {
        visited.add(v);
        //some standard code for DFS
        ans.add(v);
    }

    public static String topologicalSort() {
        visited = new HashSet<Character>();
        ans = new ArrayList<Character>();

        for (Character element : g.keySet()) {
            if (!visited.contains(element))
                dfs(element);
        }

        //some code to prepare the output
    }

    public static void builGraph(String[] words) {

        g = new HashMap<Character, LinkedList<Character>>();

        //some code to build adjacency list and then use it through g reference 
    }

    public static String answer(String[] words) {

        if (words.length == 1) {
            //some code
        }

        builGraph(words);

        return topologicalSort();
    }

    public static void main(String[] args) {
        //some code
        System.out.println(answer(words));
    } 
}

我不知道测试在检查什么,所以我不知道为什么会失败。但是,很容易分辨出这两种实现之间的区别。

在Java中(引用4.12.5. Initial Values of Variables):

For all reference types (§4.3), the default value is null.

第二种情况下的对象被分配 null,直到您初始化它们,并且您在 每个 调用 topologicalSort 时执行此操作。所以每次调用该方法时,都会创建一个new对象。

在第一个实现中,您只初始化它们一次 - 当 class 创建时。这应该足以让您更深入地研究问题并更好地理解第一次实施中测试失败的原因。

在第一个实现中,您在哪里清除容器(Map、Set、ArrayList)? 一个测试用例可能多次调用 answer() ,所以 我会将 answer() 方法从第一个实现更改为:

public static String answer(String[] words) {
    this.g.clear();
    this.visited.clear();
    this.ans.clear();

    // ...
}