📜  Scala中的方法覆盖

📅  最后修改于: 2022-05-13 01:55:07.623000             🧑  作者: Mango

Scala中的方法覆盖

Scala 中的方法覆盖与Java中的方法覆盖相同,但在 Scala 中,覆盖特性在此处进一步阐述,方法以及varval都可以被覆盖。如果子类的方法名与父类中定义的方法名相同,则称为方法覆盖,即由声明的超类继承的子类使用覆盖关键字。

方法覆盖流程图

让我们看一下重写方法的流程图,以便明确地对其进行可视化。

在这里,在上图中, School是超类,其中定义了一个名为NumberOfStudents()的方法,并且该方法被子类(即类 1、类 2、类 3)覆盖。所以,所有子类都具有与超类中定义的相同的命名方法。

何时应用方法覆盖?

当子类希望为父类中定义的方法赋予特定实现时,该子类将覆盖父类中定义的方法。当我们希望重构超类中定义的方法时,我们可以应用方法覆盖。
让我们看一个与上面提到的方法覆盖图相关的示例。

例子 :

// Scala program of method overriding
  
// Creating a super class
class School
{ 
  
    // Method defined
    def NumberOfStudents()=
    { 
        0 // Utilized for returning an Integer
    } 
} 
  
// Creating a subclass 
class class_1 extends School
{
      
    // Using Override keyword
    override def NumberOfStudents()=
    { 
        30
    } 
} 
  
// Creating a subclass 
class class_2 extends School
{ 
  
    // Using override keyword 
    override def NumberOfStudents()=
    { 
        32
    } 
} 
  
// Creating a subclass
class class_3 extends School
{ 
      
    // Using override keyword
    override def NumberOfStudents()=
    { 
        29
    } 
} 
  
// Creating object 
object GfG
{ 
  
    // Main method
    def main(args:Array[String])
    { 
          
        // Creating instances of all
        // the sub-classes
        var x=new class_1() 
        var y=new class_2() 
        var z=new class_3()
          
        // Displays number of students in class_1
        println("Number of students in class 1 : " + 
                                x.NumberOfStudents()) 
          
        // Displays number of students in class_2
        println("Number of students in class 2 : " + 
                                y.NumberOfStudents())
          
        // Displays number of students in class_3
        println("Number of students in class 3 : " +
                                z.NumberOfStudents()) 
          
    } 
} 
输出:
Number of students in class 1 : 30
Number of students in class 2 : 32
Number of students in class 3 : 29

在上面的例子中,我们有一个名为School的类,它定义了一个 NumberOfStudents() 方法,我们有三个类,即 class_1、class_2 和 class_3,它们继承自超类School ,这些子类覆盖了超类中定义的方法-班级。

例子 :

// Scala program of method overriding
  
// Creating a super class
class Shapes
{ 
  
    // Method defined with parameters
    def Area(l:Double, b:Double, r:Double)=
    { 
      
        0.0 // Utilized for returning double
    } 
} 
  
// Creating a subclass 
class Rectangle extends Shapes
{
      
    // Overriding method to find
    // area of the rectangle 
    override def Area(l:Double, b:Double, r:Double)=
    { 
      
        (l * b)
    } 
} 
  
// Creating a subclass 
class Circle extends Shapes
{ 
  
    // Overriding method to find
    // area of the circle
    override def Area(l:Double, b:Double, r:Double)=
    { 
          
        ((3.14)* r * r)
    } 
} 
  
// Creating object 
object GfG
{ 
  
    // Main method
    def main(args:Array[String])
    { 
          
        // Creating instances of all
        // the sub-classes
        var rectangle = new Rectangle() 
        var circle = new Circle() 
          
        // Displays area of the rectangle
        println(rectangle.Area(3, 11, 4)) 
          
        // Displays area of the circle
        println(circle.Area(1, 7, 10)) 
          
    } 
} 
输出:
33.0
314.0

在上面的例子中, Area是超类的一个方法,它将被子类中定义的方法覆盖。在这里,我们使用相同的方法名称(即Area )来查找区域,但对于不同的形状,我们可以说这种方法覆盖可以应用于相同类型的操作,但适用于不同的类别,值得注意的是方法必须具有与超类中定义的相同数据类型和相同数量的参数,否则编译器将抛出错误。虽然当方法被覆盖时,定义的方法中的参数顺序可以在子类中更改。

方法覆盖规则

对于方法覆盖,我们需要遵循一些限制,如下所示:

  • 对于方法覆盖,关键规则之一是被覆盖的类需要使用修饰符override或 override 注释。
  • 辅助构造函数不能立即调用超类构造函数。他们几乎不能调用主构造函数,而主构造函数反过来会调用超类构造函数。
  • 在 Method Overriding 中,我们将无法使用 def 或 val 覆盖 var,否则会引发错误。
  • 在这里,我们将无法通过子类中的 var 或 def 覆盖超类中的val ,如果超类中的 var 是抽象的,那么我们可以在子类中覆盖它。
  • 如果一个字段被声明为var那么它可以覆盖在超类中定义的defvar只能覆盖超类中的 getter 或 setter 组合。

笔记:

  1. 辅助构造函数的定义类似于使用defthis关键字的方法,其中this是构造函数的名称。
  2. Primary Constructors从类定义的开头开始,延伸到类的整个主体。

现在让我们看一些例子。

例子 :

// Scala program of method 
// Overriding
  
// Creating a class
class Animal
{
      
    // Defining a method
    def number()
    { 
        println("We have two animals")
  
    } 
} 
  
// Extending the class Animal
class Dog extends Animal
{
  
    // using override keyword
    override def number()
    { 
          
        // Displays output
        println("We have two dogs") 
  
    } 
} 
  
// Creating object 
object GfG
{ 
  
    // Main method
    def main(args:Array[String])
    { 
          
        // Creating object of the subclass
        // Dog
        var x = new Dog() 
              
        // Calling overridden method
        x.number() 
              
    } 
} 
输出:
We have two dogs

在这里,我们使用关键字override覆盖了方法。在上面的示例中,超类Animal有一个名为number的方法,该方法在子类Dog中被覆盖。因此,可以通过创建子类的对象来调用被覆盖的方法。

例子 :

// Scala program of method 
// overriding
  
// Creating super-class
class Students(var rank:Int, var name:String)
{
      
    // overriding a method 'toString()'
    override def toString():String =
    {
        " The rank of "+name+" is : "+rank
    }
}
  
// Creating a subclass of Students
class newStudents(rank:Int, name:String)
        extends Students(rank, name){
}
  
// Inheriting main method of 
// the trait 'App' 
object GfG extends App
{
      
    // Creating object of the super-class
    val students = new Students(1, "Geeta Sharma")
      
    // Displays output
    println(students)
      
    // Creating object of the subclass
    val newstudents = new newStudents(3, "Priti Singh")
      
    // Displays output
    println(newstudents)
  
}
输出:
The rank of Geeta Sharma is : 1
The rank of Priti Singh is : 3

在这里,超类的构造函数,即Students ,是从子类的主构造函数,即newStudents中调用的,因此,超类的构造函数是使用关键字extends调用的。
注意: AnyRef类中定义了一个 toString() 方法,并且我们知道每个类都是AnyRef类的子类,因此使用关键字override覆盖了 toString() 方法。

覆盖与重载
  • 在 Scala 中,方法重载为我们提供了一个属性,该属性允许我们定义同名的方法,但它们具有不同的参数或数据类型,而方法重载允许我们在同名和相同参数的子类中重新定义超类的方法体或数据类型以改变方法的性能。
  • 在 Scala 中,方法覆盖使用override修饰符来覆盖超类中定义的方法,而方法重载不需要任何关键字或修饰符,我们只需要更改使用的参数的顺序或参数的数量方法重载的方法或参数的数据类型。
为什么我们需要方法覆盖?

为了以不同的方式重新定义单个方法,我们可以进行方法覆盖,这有助于我们使用相同的方法名称执行不同的操作。就像,在上图中有一个超类School ,它有一个名为NumberOfStudents()的方法,它被子类覆盖以执行不同的操作。