请原谅我的问题,因为我试图搜索使用超级关键字与类名来从超类调用方法但无法找到答案之间的区别。 我的问题是我正在尝试将Java作为一门学习课程学习,并使用链接中的示例:http://www.javatpoint.com/super-keyword使用示例#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(),则会收到一条错误消息,指出我需要将我的速度方法设置为静态。
我不想让我的方法成为静态的,并想知道它们之间的区别。
干杯,
答案 0 :(得分:2)
非静态方法只能在对象的特定实例上调用。这就是为什么只有Vehicle.speed()
方法是静态的,才能调用speed
。你可以调用super.speed()
的原因是因为在构造函数中,你已经构造了车辆对象,并且基本上是在你正在构造的对象上调用方法。
对于上面的例子,我会说调用super.speed()
是最好的方法。
此外,由于您没有覆盖speed
方法的超级实现,因此您可以轻松调用this.speed()
或speed()
。这种方法意味着如果您确定Bike
需要speed
方法中的不同功能,那么将调用您的特定实现而不是默认实现。
答案 1 :(得分:2)
直接使用类名调用方法意味着您要调用静态方法,该方法与类的任何对象无关,而与自身的类无关。 这就是编译器告诉您该方法必须是静态的原因。
至于你的问题,当你创建一个子类的对象(在这个例子中是Bike类)时,总是创建它的父对象,在其基础上创建特定的子对象。
就像,当您创建Bike
时,始终会创建一个支持Vehicle
,基于该支持创建Bike
。否则,Bike
将不是Vehicle
。
所以通过super
调用方法意味着,你告诉编译器在用作基类(父)的类上调用这个方法来创建这个Bike
类,我从这个类开始我叫这个方法。
当你按类名调用方法时,你告诉编译器调用Vehicle
类的这个方法,它与任何Vehicle
对象/实例无关(显然不相关)对任何孩子(例如Bike
对象或实例)
答案 2 :(得分:1)
这两种结构不相同。
调用Vehicle.speed()
时,编译器正在名为speed()
的类中查找名为Vehicle
的静态方法。静态方法不属于该类的任何实例。您不能在静态方法中使用任何实例变量。您尚未在speed()
课程中定义名为Vehicle
的静态方法,因此没有Vehicle.speed()
这样的内容。因此,您会收到编译错误。
调用super.speed()
时,您不会像上一种情况那样寻找静态方法:使用{{1时将要调用的实际方法语法是在当前对象的超类中定义的实例方法(在您的情况下命名为super
)。也就是说,speed()
是在当前对象的超类中定义的实例方法(与super.speed()
不同,this.speed()
是在当前对象的实际类中定义的名为speed()
的实例方法。换句话说,它将调用类speed()
中定义的方法Vehicle
,但this
参数将是b
引用的参数,当前对象
答案 3 :(得分:1)
您需要实例来调用实例(非静态)方法。
super 是父类的实例。简单地说,类名不是一个实例(它是整个类的静态上下文)。
[超级是父类' s实例?]
Jon skeet said 没有"父实例" 这样的东西,但我怀疑实例的用语。
首先初始化超级变量,然后轮换子进行判断是否共享相同的变量/方法(即return this.i;
在这种方法中将返回super.i,而不是this.i,当孩子打电话时)或覆盖它。
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.i不允许,直接打印超级不允许)。另一个区别是变量值将在每个实例中同步,因为如上所述,孩子可能会共享它。
你可以尝试在静态方法中打印super.variable_name,它会输出 super是一个非静态变量:
$ 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
$
因此,它非常有意义,因为非静态变量可以在您的示例中访问非静态方法速度()。
答案 4 :(得分:0)
如果要直接使用类名称方法,则必须将方法指定为静态
my %HoH;
while ( <DATA> ) {
next unless s/^(.*?):\s*//;
my $who = $1;
for my $field ( split ) {
my ($key, $value) = split /=/, $field;
$HoH{$who}{$key} = $value;
}
}
print Dumper \%HoH;
__DATA__
flintstones: husband=fred pal=barney wife=wilma pet=dino
或
您可以在子类中创建类Vehicle的对象和访问速度方法,如此
public static void speed() {
int a = 20;
System.out.println(a);
}
答案 5 :(得分:0)
hi 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
}
}