# java 中的`super`关键字

> 原文： [https://beginnersbook.com/2014/07/super-keyword-in-java-with-example/](https://beginnersbook.com/2014/07/super-keyword-in-java-with-example/)

`super`关键字指的是直接父类的对象。在学习`super`关键字之前，您必须具备 Java 中[继承](https://beginnersbook.com/2013/03/inheritance-in-java/)的知识，以便您能够理解本指南中给出的示例。

## 使用`super`关键字

1）当父类和子类都具有相同名称的成员时访问父类的数据成员

2）显式调用父类的无参和参数化构造函数

3）访问父类的方法当子类重写该方法时的类。

**现在让我们借助示例**详细讨论它们：

### 1）如何使用`super`关键字访问父类的变量

当子类中的变量已存在于父类中时，为了访问父类的变量，您需要使用`super`关键字。

让我们举一个例子来理解这一点：在下面的程序中，我们在子类中声明了一个数据成员`num`，父类中已经存在同名的成员。如果不使用`super`关键字，则无法访问父类的`num`变量。 。

```java
//Parent class or Superclass or base class
class Superclass
{
   int num = 100;
}
//Child class or subclass or derived class
class Subclass extends Superclass
{
   /* The same variable num is declared in the Subclass
    * which is already present in the Superclass
    */
    int num = 110;
    void printNumber(){
	System.out.println(num);
    }
    public static void main(String args[]){
	Subclass obj= new Subclass();
	obj.printNumber();	
    }
}
```

输出：

```
110
```

**访问父类的`num`变量：**

通过调用这样的变量，如果类（父类和子类）具有相同的变量，我们可以访问父类的变量。

```java
super.variable_name
```

让我们采用我们在上面看到的相同示例，这次在`print`语句中我们传递`super.num`而不是`num`。

```java
class Superclass
{
   int num = 100;
}
class Subclass extends Superclass
{
   int num = 110;
   void printNumber(){
	/* Note that instead of writing num we are
	 * writing super.num in the print statement
	 * this refers to the num variable of Superclass
	 */
	System.out.println(super.num);
   }
   public static void main(String args[]){
	Subclass obj= new Subclass();
	obj.printNumber();	
   }
}
```

输出：

```
100
```

正如您通过使用`super.num`所看到的，我们访问了父类的`num`变量。

### 2）使用`super`关键字来调用父类的构造函数

当我们创建子类的对象时，`new`关键字调用子类的[构造函数](https://beginnersbook.com/2013/03/constructors-in-java/)，它隐式调用父类的构造函数。因此，当我们创建子类的对象时执行的顺序是：首先执行父类构造函数，然后执行子类构造函数。这是因为编译器本身添加了`super()`（这会调用父类的无参数构造函数）作为子类构造函数中的第一个语句。

让我们看一个例子来理解我上面解释的内容：

```java
class Parentclass
{
   Parentclass(){
	System.out.println("Constructor of parent class");
   }
}
class Subclass extends Parentclass
{
   Subclass(){
	/* Compile implicitly adds super() here as the
	 *  first statement of this constructor.
	 */
	System.out.println("Constructor of child class");
   }
   Subclass(int num){
	/* Even though it is a parameterized constructor.
	 * The compiler still adds the no-arg super() here
	 */
	System.out.println("arg constructor of child class");
   }
   void display(){
	System.out.println("Hello!");
   }
   public static void main(String args[]){
	/* Creating object using default constructor. This 
	 * will invoke child class constructor, which will 
	 * invoke parent class constructor
	 */
	Subclass obj= new Subclass();
	//Calling sub class method 
	obj.display();
	/* Creating second object using arg constructor
	 * it will invoke arg constructor of child class which will
	 * invoke no-arg constructor of parent class automatically 
	 */
	Subclass obj2= new Subclass(10);
	obj2.display();
   }
}

```

**输出：**

```java
Constructor of parent class
Constructor of child class
Hello!
Constructor of parent class
arg constructor of child class
Hello!

```

#### 参数化的`super()`调用来调用父类的参数化构造函数

我们可以在子类的构造函数中显式调用`super()`，但它没有任何意义，因为它会是多余的。这就像明确地做一些其他方式隐含的事情。

但是当我们在父类中有一个带有参数的构造函数时，我们可以使用参数化的超类，如`super(100);`从子类的构造函数中调用父类的[参数化构造函数](https://beginnersbook.com/2014/01/parameterized-constructor-in-java-example/)。

让我们看一个例子来理解这个：

```java
class Parentclass
{
   //no-arg constructor
   Parentclass(){
	System.out.println("no-arg constructor of parent class");
   }
   //arg or parameterized constructor
   Parentclass(String str){
	System.out.println("parameterized constructor of parent class");
   }
}
class Subclass extends Parentclass
{
   Subclass(){
       /* super() must be added to the first statement of constructor 
	* otherwise you will get a compilation error. Another important 
	* point to note is that when we explicitly use super in constructor
	* the compiler doesn't invoke the parent constructor automatically.
	*/
	super("Hahaha");
	System.out.println("Constructor of child class");

   }
   void display(){
	System.out.println("Hello");
   }
   public static void main(String args[]){		
	Subclass obj= new Subclass();
	obj.display();	 
   }
}

```

**输出：**

```java
parameterized constructor of parent class
Constructor of child class
Hello
```

在这个例子中有几点需要注意：

1）`super()`（或参数化的`super`必须是构造函数中的第一个语句，否则你将得到编译错误：“构造函数调用必须是构造函数中的第一个语句”

2）当我们在构造函数中明确地放置`super`时，java 编译器没有调用父类的默认无参构造函数。

### 3）如何在方法覆盖的情况下使用`super`关键字

当子类声明父类中已存在的相同方法时，这称为[方法覆盖](https://beginnersbook.com/2014/01/method-overriding-in-java-with-example/)。我们将在本系列的下一个教程中学习方法覆盖。现在您只需要记住这一点：当子类重写父类的方法时，从子类对象调用该方法总是调用该方法的子类版本。但是通过使用这样的`super`关键字：`super.method_name`可以调用父类的方法（被覆盖的方法）。在方法覆盖的情况下，使用这些术语：重写方法：父类的方法重写方法：子类的方法让我们举一个例子来理解这个概念：

```java
class Parentclass
{
   //Overridden method
   void display(){
	System.out.println("Parent class method");
   }
}
class Subclass extends Parentclass
{
   //Overriding method
   void display(){
	System.out.println("Child class method");
   }
   void printMsg(){
	//This would call Overriding method
	display();
	//This would call Overridden method
	super.display();
   }
   public static void main(String args[]){		
	Subclass obj= new Subclass();
	obj.printMsg(); 
   }
}
```

**输出：**

```java
Child class method
Parent class method
```

#### 如果子类没有覆盖任何方法怎么办：不需要`super`

当子类没有覆盖父类方法时，我们不需要使用`super`关键字来调用父类方法。这是因为在这种情况下我们只有每个方法的一个版本，子类可以访问父类方法，所以我们可以直接调用父类的方法而不使用`super`。

```java
class Parentclass
{
   void display(){
	System.out.println("Parent class method");
   }
}
class Subclass extends Parentclass
{
   void printMsg(){
	/* This would call method of parent class,
	 * no need to use super keyword because no other
	 * method with the same name is present in this class
	 */
	display();
   } 
   public static void main(String args[]){

	Subclass obj= new Subclass();
        obj.printMsg(); 
   }
}

```

**输出：**

```java
Parent class method
```