【问题标题】:Can a class have no constructor?一个类可以没有构造函数吗?
【发布时间】:2012-11-26 06:12:09
【问题描述】:

这是一段代码作为示例,剩下的只是方法(迷宫类在底部)。所以当它被实例化时,使用

Maze labyrinth = new Maze();

System.out.println (labyrinth);

这将打印出网格数组。 这是合法的吗?我认为所有类都需要构造函数它如何打印出二维网格数组?

迷宫类:

public class Maze
{
    private final int TRIED = 3;
    private final int PATH = 7;
    private int[][] grid = { {1,1,1,0,1,1,0,0,0,1,1,1,1},
                             {1,0,1,1,1,0,1,1,1,1,0,0,1},
                             {0,0,0,0,1,0,1,0,1,0,1,0,0},
                             {1,1,1,0,1,1,1,0,1,0,1,1,1},
                             {1,0,1,0,0,0,0,1,1,1,0,0,1},
                             {1,0,1,1,1,1,1,1,0,1,1,1,1},
                             {1,0,0,0,0,0,0,0,0,0,0,0,0},
                             {1,1,1,1,1,1,1,1,1,1,1,1,1} };

    public String toString ()
    {
        String result = "\n";
        for (int row = 0; row < grid.length; row++)
        {
            for (int column=0; column < grid[row].length; column++)
            result += grid[row][column] + "";
            result += "\n";
        }
        return result;
    }

}

【问题讨论】:

标签: java


【解决方案1】:

不需要显式定义构造函数;但是,所有的类都必须有一个构造函数,如果你不提供任何构造函数,将会生成一个默认的空构造函数:

public Maze() {
}

Default Constructor

【讨论】:

  • System.out.println(迷宫)如何;那么打印出网格数组呢?
  • toString() 在实际类中是否被自定义打印逻辑覆盖(在您没有向我们展示的其中一种方法中)?我刚刚将你的类复制到一个新的Java项目中,当我打印出来时,我得到了Maze@50c8d62f,正如预期的那样;因为默认情况下自定义类没有以有意义的方式打印出其内容的方法。
  • System.out.println 只是调用了新创建的Maze 对象的toString() 方法。
  • 那么任何有 tostring 方法的类,如果我尝试通过引用变量打印出来,它会自动调用 tostring 方法?
  • @fvu 本身调用 toString
【解决方案2】:

如果不显式编写构造函数,编译器会默认生成一个无参数的构造函数。

public Maze(){

}    

如果不显式编写构造函数,编译器会默认生成一个无参数的构造函数。

public Maze(){

}    

编译器会包含以上内容。

例如检查这个类的字节码:

public class ABC {

}

字节码:

public class sorting/ABC {

  // compiled from: ABC.java

  // access flags 0x1
  public <init>()V         //Default no-args constructor included by the compiler
   L0
    LINENUMBER 7 L0
    ALOAD 0
    INVOKESPECIAL java/lang/Object.<init>()V
    RETURN
   L1
    LOCALVARIABLE this Lsorting/ABC; L0 L1 0
    MAXSTACK = 1
    MAXLOCALS = 1
}

【讨论】:

  • @Aaron 没有什么是先进的。检查您编写的代码的字节码是一个很好的做法。我建议下载字节码大纲作为 Eclipse 插件。 :)
  • 我没有透露您的知识,但我不知道这些语句在字节码中的含义。只是还没有达到那个水平,我还是个初学者:)。不过感谢您的帮助,我非常感谢。
【解决方案3】:

更准确地说,编译器会自动为没有构造函数的类提供一个no-args构造函数,这个构造函数调用no-args构造函数在超类中,如果超类没有no-args构造函数,那就是错误,如果有,那很好。

如果你的类没有显式的超类,那么它有一个隐式 超类 (Object),确实 有一个 no-args 构造函数。

【讨论】:

    【解决方案4】:

    这个问题的典型答案是“如果你不声明构造函数,就会创建一个默认构造函数”。这是通常正确,但不是总是。一个类可能没有构造函数。

    (这里要画的一个重要区别是 JVM does not require all class files to have a constructor;但是,Java 中定义的任何类 does have a default constructor if a constructor is not explicitly declared。这个答案提出了一个奇怪的问题,其中创建了前者的示例来自 Java 代码)。

    考虑以下代码,来自this question

    public class Outer
    {
        private class Inner {}
    
        void someMethod()
        {
            Inner inObj = this.new Inner();
        }
    }
    

    如果你用 OpenJDK 编译,你会发现 3 个类文件:

    Outer.class
    Outer$Inner.class
    Outer$1.class
    

    Outer$1 是其中最不寻常的:它实际上什么都没有,甚至没有构造函数:

    Compiled from "Outer.java"
    class Outer$1 {
    }
    

    InnerOuter 类具有生成的构造函数:

    Compiled from "Outer.java"
    class Outer {
      Outer();        <------------- Generated Constructor
        Code:
           0: aload_0
           1: invokespecial #1                  // Method java/lang/Object."<init>":()V
           4: return
    
      void someMethod();
        Code:
           0: new           #2                  // class Outer$Inner
           3: dup
           4: aload_0
           5: aconst_null
           6: invokespecial #3                  // Method Outer$Inner."<init>":(LOuter;LOuter$1;)V
           9: astore_1
          10: return
    }
    Compiled from "Outer.java"
    class Outer$Inner {
      final Outer this$0;
    
      Outer$Inner(Outer, Outer$1);        <------------- Generated Constructor
        Code:
           0: aload_0
           1: aload_1
           2: invokespecial #1                  // Method "<init>":(LOuter;)V
           5: return
    }
    

    【讨论】:

    • 有趣。你知道为什么编译器会生成Outer$1 以及最近的编译器是否仍然这样做?我没有看到编译器从提供的源代码生成此类的理由。它看起来像是 Outer$Inner 的构造函数的某种标记。
    【解决方案5】:

    如果不指定构造函数,编译器会生成一个默认的构造函数。

    但是,任何在声明时未初始化的成员变量都将为空。

    换句话说,如果您不为 grid 分配值(就像您在示例中所做的那样),它将为空。

    您的示例运行良好,因为您碰巧在声明时立即为 grid 分配了一个值。

    【讨论】:

      【解决方案6】:

      Java 实际上并不需要在类描述中显式构造函数。如果不包含构造函数,Java 编译器将创建一个带空参数的默认构造函数。

      【讨论】:

      • above 已经给出了相同的答案。再次添加相同的答案没有意义。
      【解决方案7】:

      如果您的意思是您不希望任何人直接创建您的类的实例,我认为您可以创建一个构造函数,将其访问修饰符设置为私有,并且您只能通过具有访问权限的公共静态方法创建此类的实例到这个私有构造函数

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2017-11-07
        • 2011-04-08
        • 2010-09-20
        • 2013-07-05
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多