原文: https://beginnersbook.com/2014/07/super-keyword-in-java-with-example/

super关键字指的是直接父类的对象。在学习super关键字之前,您必须具备 Java 中继承的知识,以便您能够理解本指南中给出的示例。

使用super关键字

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

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

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

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

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

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

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

  1. //Parent class or Superclass or base class
  2. class Superclass
  3. {
  4. int num = 100;
  5. }
  6. //Child class or subclass or derived class
  7. class Subclass extends Superclass
  8. {
  9. /* The same variable num is declared in the Subclass
  10. * which is already present in the Superclass
  11. */
  12. int num = 110;
  13. void printNumber(){
  14. System.out.println(num);
  15. }
  16. public static void main(String args[]){
  17. Subclass obj= new Subclass();
  18. obj.printNumber();
  19. }
  20. }

输出:

  1. 110

访问父类的num变量:

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

  1. super.variable_name

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

  1. class Superclass
  2. {
  3. int num = 100;
  4. }
  5. class Subclass extends Superclass
  6. {
  7. int num = 110;
  8. void printNumber(){
  9. /* Note that instead of writing num we are
  10. * writing super.num in the print statement
  11. * this refers to the num variable of Superclass
  12. */
  13. System.out.println(super.num);
  14. }
  15. public static void main(String args[]){
  16. Subclass obj= new Subclass();
  17. obj.printNumber();
  18. }
  19. }

输出:

  1. 100

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

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

当我们创建子类的对象时,new关键字调用子类的构造函数,它隐式调用父类的构造函数。因此,当我们创建子类的对象时执行的顺序是:首先执行父类构造函数,然后执行子类构造函数。这是因为编译器本身添加了super()(这会调用父类的无参数构造函数)作为子类构造函数中的第一个语句。

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

  1. class Parentclass
  2. {
  3. Parentclass(){
  4. System.out.println("Constructor of parent class");
  5. }
  6. }
  7. class Subclass extends Parentclass
  8. {
  9. Subclass(){
  10. /* Compile implicitly adds super() here as the
  11. * first statement of this constructor.
  12. */
  13. System.out.println("Constructor of child class");
  14. }
  15. Subclass(int num){
  16. /* Even though it is a parameterized constructor.
  17. * The compiler still adds the no-arg super() here
  18. */
  19. System.out.println("arg constructor of child class");
  20. }
  21. void display(){
  22. System.out.println("Hello!");
  23. }
  24. public static void main(String args[]){
  25. /* Creating object using default constructor. This
  26. * will invoke child class constructor, which will
  27. * invoke parent class constructor
  28. */
  29. Subclass obj= new Subclass();
  30. //Calling sub class method
  31. obj.display();
  32. /* Creating second object using arg constructor
  33. * it will invoke arg constructor of child class which will
  34. * invoke no-arg constructor of parent class automatically
  35. */
  36. Subclass obj2= new Subclass(10);
  37. obj2.display();
  38. }
  39. }

输出:

  1. Constructor of parent class
  2. Constructor of child class
  3. Hello!
  4. Constructor of parent class
  5. arg constructor of child class
  6. Hello!

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

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

但是当我们在父类中有一个带有参数的构造函数时,我们可以使用参数化的超类,如super(100);从子类的构造函数中调用父类的参数化构造函数

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

  1. class Parentclass
  2. {
  3. //no-arg constructor
  4. Parentclass(){
  5. System.out.println("no-arg constructor of parent class");
  6. }
  7. //arg or parameterized constructor
  8. Parentclass(String str){
  9. System.out.println("parameterized constructor of parent class");
  10. }
  11. }
  12. class Subclass extends Parentclass
  13. {
  14. Subclass(){
  15. /* super() must be added to the first statement of constructor
  16. * otherwise you will get a compilation error. Another important
  17. * point to note is that when we explicitly use super in constructor
  18. * the compiler doesn't invoke the parent constructor automatically.
  19. */
  20. super("Hahaha");
  21. System.out.println("Constructor of child class");
  22. }
  23. void display(){
  24. System.out.println("Hello");
  25. }
  26. public static void main(String args[]){
  27. Subclass obj= new Subclass();
  28. obj.display();
  29. }
  30. }

输出:

  1. parameterized constructor of parent class
  2. Constructor of child class
  3. Hello

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

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

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

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

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

  1. class Parentclass
  2. {
  3. //Overridden method
  4. void display(){
  5. System.out.println("Parent class method");
  6. }
  7. }
  8. class Subclass extends Parentclass
  9. {
  10. //Overriding method
  11. void display(){
  12. System.out.println("Child class method");
  13. }
  14. void printMsg(){
  15. //This would call Overriding method
  16. display();
  17. //This would call Overridden method
  18. super.display();
  19. }
  20. public static void main(String args[]){
  21. Subclass obj= new Subclass();
  22. obj.printMsg();
  23. }
  24. }

输出:

  1. Child class method
  2. Parent class method

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

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

  1. class Parentclass
  2. {
  3. void display(){
  4. System.out.println("Parent class method");
  5. }
  6. }
  7. class Subclass extends Parentclass
  8. {
  9. void printMsg(){
  10. /* This would call method of parent class,
  11. * no need to use super keyword because no other
  12. * method with the same name is present in this class
  13. */
  14. display();
  15. }
  16. public static void main(String args[]){
  17. Subclass obj= new Subclass();
  18. obj.printMsg();
  19. }
  20. }

输出:

  1. Parent class method