直接初始化类成员与在方法中执行它有啥区别?

Posted

技术标签:

【中文标题】直接初始化类成员与在方法中执行它有啥区别?【英文标题】:What is the difference between direct initialization of class member vs doing it within a method?直接初始化类成员与在方法中执行它有什么区别? 【发布时间】:2015-11-09 07:41:17 【问题描述】:

我已经完成了一项 Google Foobar 任务,并且很好奇为什么 2 个看似等效的实现以不同的方式工作。当第二个解决方案通过所有测试用例时,第一个给我带来“测试 2 失败”。我知道他们两个都没有遵循最佳 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));
     

【问题讨论】:

【参考方案1】:

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

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

    // ...

【讨论】:

你说得对,我需要在 answer() 函数中清除我的容器。然而,一个测试用例本身只调用一次 answer() 函数。可能是一个接一个的测试用例很多,都在同一个main()方法中。【参考方案2】:

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

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

对于所有引用类型 (§4.3),默认值为 null

第二种情况下的对象被分配null,直到你初始化它们,你在topologicalSort每个调用中这样做。所以每次调用该方法时,都会创建一个new对象。

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

【讨论】:

我理解你写的内容,但问题是每个测试用例只调用一次 topologicalSort 函数。另外,我仍然不明白为什么在这种特殊情况下结果可能会有所不同。 @ruvinbsu 这取决于测试,也许其他测试会假设以前测试的结果,出于某种原因.. 有趣的假设,你可能是对的。虽然,谷歌没有警告我们这似乎有点奇怪。无论如何,非常感谢。

以上是关于直接初始化类成员与在方法中执行它有啥区别?的主要内容,如果未能解决你的问题,请参考以下文章

请问java构造函数如何初始化成员变量的啊?

类成员变量初始赋值有啥意义么?

Delphi 中公共和已发布的类成员有啥区别?

成员变量(实例变量)&局部变量&静态变量(类变量)的区别

Eclipse 对象弹出方法和成员变量设置

c++里面的protect和public、private有啥区别?