【问题标题】:Difference between super keyword vs class name to call method from super class超级关键字与类名与从超级类调用方法之间的区别
【发布时间】:2016-10-03 08:10:27
【问题描述】:

请原谅我的问题,因为我试图搜索使用 super 关键字与类名从超类调用方法之间的区别,但无法找到答案。 我的问题是我正在尝试将 Java 作为一门学习课程来学习,并且正在使用链接中的一个示例:http://www.javatpoint.com/super-keyword using Example # 3,这是我编写的代码:

我创建了一个名为 Vehicle 的超类

public class Vehicle {
    Vehicle() {
        System.out.println("Vehicle constructor created");
    }

    public void speed() {
        int a = 20;
        System.out.println(a);
    }

}

然后使用以下代码创建了一个名为 Bike 的子类:

public class Bike extends Vehicle {
    int speed;

    Bike(int speed1) {
        this.speed = speed1;
        System.out.println(speed1);
        super.speed();

    }

    public static void main(String args[]) {
        Bike b = new Bike(10);

    }

}

在 Bike 构造函数下的子类中,我使用 super.speed() 从 super (Vehicle) 类调用 speed 方法。现在,如果我将此行更改为 Vehicle.speed() 我会收到一条错误消息,指出我需要将我的速度方法设为静态。

我不想让我的方法是静态的,想知道它们之间的区别。

干杯,

【问题讨论】:

  • 我认为原因是如果您使用 class.method 名称,它是以静态方式访问该方法。但我不是 100% 确定这一点。所以只是评论:)
  • 如果您将其更改为 this.speed(),恕我直言,它应该可以工作 :)

标签: java methods constructor super


【解决方案1】:

直接使用类名调用方法,就是要调用一个静态方法,它与类的任何对象无关,只与自身的类相关。 这就是为什么编译器会告诉你方法必须是静态的。

至于您的问题,当您创建子类(本例中为自行车类)的对象时,始终会创建其父类的对象,并在此基础上创建特定的子对象。

就像,每当您创建 Bike 时,总是会创建一个支持 Vehicle,在此基础上创建 Bike。否则Bike 不会是Vehicle

因此,通过super 调用方法意味着,您是在告诉编译器在用作创建此Bike 类的基(父)类上调用此方法,我从中调用此方法.

当您通过类名调用方法时,您是在告诉编译器调用与任何 Vehicle 对象/实例无关的 Vehicle 类的此方法(并且显然与任何子对象(例如Bike 对象或实例)

【讨论】:

    【解决方案2】:

    非静态方法只能在对象的特定实例上调用。这就是为什么调用Vehicle.speed() 仅在speed 方法是静态的情况下才有效。之所以可以调用super.speed(),是因为在构造函数中,你已经构造了vehicle对象,基本上是在调用你正在构造的对象上的方法。

    对于上面的例子,我会说调用super.speed() 是最好的方法。

    此外,由于您没有覆盖 speed 方法的超级实现,因此您可以轻松调用 this.speed()speed()。这种方法意味着,如果您曾经决定 Bike 需要 speed 方法中的不同功能,则将调用您的特定实现而不是默认实现。

    【讨论】:

      【解决方案3】:

      这两个构造不等价。

      当调用Vehicle.speed() 时,编译器会在名为Vehicle 的类中寻找名为speed()静态 方法。静态方法不属于该类的任何实例。您不能在静态方法中使用任何实例变量。您还没有在Vehicle 类中定义名为speed() 的静态方法,因此没有Vehicle.speed() 这样的东西。因此,您会收到编译错误。

      当调用super.speed() 时,您不会像前一种情况那样寻找静态 方法:使用super 语法时要调用的实际方法是instance 方法(在您的情况下名为 speed())。即super.speed()是在当前对象的超类中定义的实例方法(不像this.speed()是在当前对象的实际类中定义的名为speed()的实例方法)。换句话说,它将调用类Vehicle中定义的方法speed(),但this参数将是当前对象b所引用的参数。

      【讨论】:

        【解决方案4】:

        您需要实例来调用实例(非静态)方法。

        super 是父类的实例。简单地说类名不是一个实例(它是整个类的静态上下文)。

        [super 是父类的实例?]

        Jon skeet said 没有“父实例”之类的东西,但我怀疑实例这个词。

        先初始化super的变量,然后轮到child来决定是否共享同一个变量/方法(即return this.i;在这种方法中会返回super.i,而不是this.i,当被child调用时)或者覆盖它。

        import java.util.Random;
        class Love {
        
            int i = 1;
            int hole() {
                return this.i;
            }
        }
        
        class Main extends Love {
        
            void wrapper() {
                System.out.println(super.i); //1
                System.out.println(this.i); //2
                super.i = new Random().nextInt(50) + 2; //to avoid compiler pre-optimizing hard coded return value in hole(), so we set again.
                System.out.println(super.i); //23
                i = 3; //2nd attempt override
                this.i = 3; //3rd attempt override
                System.out.println(hole()); //23, super "instance" keep its own version of this.i
            }
        
            int i = 2; //1st attempt oveeride
            public static void main(String[] args) {
                new Main().wrapper();
            }
        
        }
        

        所以很明显,当子覆盖时,​​super仍然保留自己的版本,所以恕我直言,super可以大致像父实例一样对待,只是与普通实例的区别在于它是一个使用限制的关键字(例如super.super.i是不允许的,直接打印超不允许)。另一个区别是变量值将在每个实例中同步,因为孩子可能会如上所述共享它。

        你可以尝试在静态方法中打印super.variable_name,它会输出super is a non-static variable

        $ javac Bike.java 
        Bike.java:132: error: non-static variable super cannot be referenced from a static context
                System.out.println(super.dummy); 
                                   ^
        Bike.java:132: error: cannot find symbol
                System.out.println(super.dummy); 
                                        ^
          symbol: variable dummy
        2 errors
        $ 
        

        因此,在您的示例中,作为 非静态 变量可以访问 非静态 方法 speed() 是有意义的。

        【讨论】:

          【解决方案5】:

          如果你想直接使用类名的方法,那么你必须将方法指定为静态

          public static void speed() {
              int a = 20;
              System.out.println(a);
          }
          

          您可以像这样在您的子类中创建 Vehicle 类的对象并访问 speed 方法

          Bike(int speed1) {
              this.speed = speed1;
              System.out.println(speed1);
              Vehicle vehicle = new Vehicle();
              vehicle.speed();
          }
          

          【讨论】:

            【解决方案6】:

            hi super 是一个关键字,用于访问子类中的超类方法。 这个 super 关键字主要在方法被覆盖时使用。

            例子

            class A    
            {       
                method m()        
            }
            
            class B extends A     
            {       
               method m()        
            
               method m1()   
               {        
                   super.m()          
               }        
            }
            
            class C
            {
               public static void main(String args[])   
               {   
                    B b = new B(); 
            
                    b.m()  // calls method m() in class B
                    b.m1()  // calls method m() in class A because method m is pointing to  super class method 
                 }   
            }
            

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 2011-08-17
              • 1970-01-01
              • 2016-06-21
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2016-09-21
              • 2015-10-07
              相关资源
              最近更新 更多