【问题标题】:Calling super()调用 super()
【发布时间】:2010-04-13 20:14:00
【问题描述】:

在 Java 中什么时候调用 super()? 我在派生类的一些构造函数中看到了它,但是每个父类的构造函数不是自动调用的吗?为什么需要使用 super?

【问题讨论】:

    标签: java


    【解决方案1】:

    如果你提供这样的类:

    public class Foo
    {
    }
    

    或者这个:

    public class Foo()
    {
        public Foo()
        {
        }
    }
    

    编译器会为此生成代码:

    public class Foo()
    {
        public Foo()
        {
            super();
        }
    }
    

    所以,严格来说,对“super()”的调用总是存在的。

    在实践中,你应该只在有你想传递给父构造函数的参数的地方调用“super(...)”。

    调用“super()”(不带参数)并没有错,但人们会嘲笑你:-)

    【讨论】:

    • 不应该Foo 扩展另一个类吗?否则对 super 的调用毫无意义......
    • Foo 隐式扩展 java.lang.Object。对 super 的调用必须存在,这就是编译器将其放入的原因。
    • @Camilo Diaz,对 super 的调用是调用 java.lang.Object 上的构造函数
    • 有时值得显式调用 super 以引起对基类构造函数的注意,如果它做了一些时髦的事情。
    • 正如我在下面提到的,在其中包含 super() 确实为您的调试器提供了一些可以锁定的东西,如果正如 Tom 所说,基类的构造函数做了一些时髦的事情,这可能很重要。跨度>
    【解决方案2】:

    需要在这种情况下使用super()

    public class Base {
       public Base(int foo) {
       }
    }
    
    public class Subclass extends Base {
       public Subclass() {
          super(15);
       }
    }
    

    这是一个非常人为的示例,但您需要调用super() 的唯一情况是您从不提供默认无参数构造函数的类继承。在这种情况下,您需要从子类的构造函数中显式调用super(),并传入满足基类构造函数所需的任何参数。此外,对super() 的调用必须是继承类构造函数的第一行

    【讨论】:

    • 最后一句话很重要。
    【解决方案3】:

    不需要调用 super()。

    来自Accessing Superclass Members

    使用 super(),调用超类的无参数构造函数。使用 super(parameter list),调用具有匹配参数列表的超类构造函数。

    注意:如果构造函数没有显式调用超类构造函数,Java 编译器会自动插入对超类的无参数构造函数的调用。如果超类没有无参数构造函数,则会出现编译时错误。 Object 确实有这样的构造函数,所以如果 Object 是唯一的超类,则没有问题。

    【讨论】:

    • 感谢关于自动调用 Object 构造函数的说明。
    【解决方案4】:

    如前所述,如果你的构造函数没有显式调用 super() 有或没有一些参数,java 将自动调用超类的默认构造函数。

    然而,显式调用 super() 就是这样——显式的。如果您知道超类的构造函数做了一些重要的事情,那么对于维护您的代码的人来说,这是一个有用的提醒,即首先调用 super() (并且可能有副作用)。这甚至可能是在调试时放置断点的有用位置。

    【讨论】:

    • 我从来没有想过这个;当我在其他人的代码中看到对super 的显式调用时,我只是认为他们“非常努力”以确保使用超类的特殊行为(他们并没有意识到它无论如何都会发生)。我想你可以采取你的方法,也可以争辩说,一旦你看到一个类扩展了另一个类,你就应该查看父类,看看那里定义了什么行为。
    【解决方案5】:

    如果在构造函数中调用 super 失败,那么编译器会在构造函数主体的第一行添加一个无参数的 super 调用作为父构造函数。

    和之前发布的代码一样

    public class Foo
    {
    }
    

    public class Foo
    {
      public Foo()
      {
      }
    }
    

    编译器将生成符合 Java 规则的代码。所有的对象都是 java.lang.Object 的子类,所以编译器会像写的一样编译它

    // All classes extend Object.  This is Java, after all.
    public class Foo extends java.lang.Object
    {
      public Foo()
      {
        // When constructing Foo, we must call the Object() constructor or risk
        // some parts of Foo being undefined, like getClass() or toString().
        super()
      }
    }
    

    但是如果超类没有匹配参数的构造函数,那么你必须调用适当的不匹配的超类构造函数。

    public class LightBlue extends java.awt.Color
    {
      public LightBlue()
      {
        // There is no Color() constructor, we must specify the suitable super class
        // constructor.  We chose Color(int red, int green, int blue).
        super(172, 216, 230);
      }
    }
    

    其他时候,也许有一个构造函数与子类构造函数的签名相匹配,但出于某种原因,您不希望将参数直接传递给超类构造函数。

    public class HSVColor extends Color
    {
      public HSVColor(int hue, int saturation, int value)
      {
        super(...code converting HSV to Red...,
              ...code converting HSV to Green...,
              ...code converting HSV to Blue);
      }
    }
    

    如果您忽略显式指定超类构造函数,则编译器会添加默认的无参数超类构造函数。但是,如果该构造函数不存在,那么编译器将不会编译该类,因为不清楚哪个暴露的构造函数是正确调用的。

    这是一种风格考虑,但您可以决定始终包含 super() 调用。如果您选择这样做,那将是因为您想提醒读者基类对象必须作为子类对象的一部分构建,并且您想让特定的超类构造函数显式化。传统上,总是包含 super() 调用是很奇怪的,因为传统上代码只有在与“默认”行为不同时才会被输入。

    【讨论】:

      【解决方案6】:

      当你有一个扩展另一个类的类并且父类没有默认构造函数时,你必须在 Son 的构造函数中使用 super() 来调用父类中的构造函数,并使用如下适当的参数:

      class A
      {   
          int a; 
          A(int value) 
          {
            this.a=value; 
            System.out.println("A Constructor " + a ); 
          }
      }
      
      class B extends A
      { 
          int b;
          B()
          {
            super(5);
            this.b=10; 
            System.out.println("B Constructor " + b); 
          } 
      
      }
      

      如果你想使用“this”调用类中的另一个构造函数,你必须知道你不能将“super”与“this”一起使用。

      【讨论】:

        【解决方案7】:

        我想提供一些迄今为止尚未提及的信息。如果在构造函数中调用this(...),则不能调用super(...); 这还包括Java 自动插入对super(); 的无参数调用

        以下示例说明了这一点,包括解释性 cmets:

        public class B extends A {
            private int x;
        
            public B() {
                // Java doesn't call super(); here, because 
                // of the call to this(...); below.
                // You can't call super(...) here either,
                // for the same reason.
        
                this(42);  // Calls public B(int x) below.
            }
        
            public B(int x) {
                // Java does call super(); here.
                // You can call super(...) here, if you want/need to.
                // The net result of calling new B() above is that
                // super(...) for class A only gets called once.
        
                this.x = x;
            }
        }
        

        【讨论】:

          【解决方案8】:

          当没有调用其他类/超类构造函数时,super() 是隐式的。

          【讨论】:

            【解决方案9】:

            如果你想调用超类的非默认构造函数,或者如果超类没有默认构造函数,你可以使用参数调用 super()。编译器只能插入默认的、无参数的 super() 构造函数。

            【讨论】:

              【解决方案10】:

              因为超类的构造函数不会被自动调用。 例如,可能有多个构造函数,其中一些带有附加参数。所以你并不总是有一个“空”的 super() 语句,而是这样的:

              public class DerivedClass extends SomeOtherClass
              {
                 private String anotherParameter;
                 public DerivedClass(int parameterA, String parameterB, String anotherParameter)
                 {
                   super(parameterA, parameterB);
                   this.anotherParameter = anotherParameter;
                 }
              }
              

              编辑:我显然忘了说(或者我选择的词根本不好,但我不是母语人士,对此感到抱歉)如果超类不接受任何参数,对 super() 的调用将由 java/编译器为您完成。 (现在我重新阅读了我的答案,我可以看到听起来你真的必须调用 super()。)

              【讨论】:

              • 鉴于示例的上下文,您给出的“未自动调用”是有道理的,但是是的,本来可以更好的措辞(我给了你 +1 而不是 -1 正弦我明白你在说什么)
              【解决方案11】:

              虽然super() 对编译器没有任何功能(超类默认构造函数会自动调用),但它确实对我有很大帮助。它对我说:“不要删除空的构造函数。它的存在是有原因的”。

              一个完美的例子是您创建 Spring 托管 bean 或 JPA 实体并创建了参数化构造函数。

              @Entity
              public class Portfolio {
              
                  ...
              
                  public Portfolio() {
                      super(); // This says to me: DON'T DELETE!
                  }
              
                  /**
                  *  Because there is now a parameterised constructor (me), 
                  *  the default constructor no longer exists. This means
                  *  that for this example, you need an empty constructor in place (above) 
                  **/
                  public Portfolio(String name) {
                      this.name = name;
                  }
              }
              

              【讨论】:

                【解决方案12】:

                当我们想从父类继承一些参数时调用Super。这不是强制性的,因为编译器总是调用默认构造函数。如果你想继承一个有一些参数的构造函数,那么你需要调用super。所以你可以使用它。

                【讨论】:

                  猜你喜欢
                  • 2012-06-12
                  • 1970-01-01
                  • 1970-01-01
                  • 2012-08-08
                  • 2015-04-02
                  • 2019-04-11
                  • 1970-01-01
                  • 2019-02-05
                  • 2016-08-19
                  相关资源
                  最近更新 更多