关于继承:无法在scala中覆盖子类的方法

Unable to override a method from child class in scala

我在自学斯卡拉。我试图实现继承,却偶然发现了一个小问题。有人能帮我吗?

问题:

  • 在下面的代码中,为什么我不能为对象p6、p7和p8设置x的值。
  • 为什么我无法覆盖我的孩子类中的def setx?
  • 1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    object classes {
        def main (args: Array[String]) {
            //create objects for class Point
            val p1 = new Point
            println("P1 created using no argument constructor:"+p1.toString())

            val p2 = new Point
            p2.setX(1)
            println("P2 created using setter methods:"+p2.toString())

            val p3 = new Point(2)
            println("P3 created using single argument constructor:"+p3.toString())

            val p4 = new Point(3,1)
            //demonstrating how to use objects within println statement
            println(s"P4 is created using default constructor and its x value is ${p4.getX} its y value is ${p4.getY} and its id is ${p4.id}")

            val p5 = new ThreeD
            println("P5 is created using no argument constructor of 3D class:"+p5.toString)

            val p6 = new ThreeD(2)
            println("P6 is created using single argument constructor of 3D class:"+p6.toString)

            val p7 = new ThreeD(2,3)
            println("P7 is created using two argument constructor of 3D class:"+p7.toString)

            val p8 = new ThreeD(2,3,4)
            p8.setX(5) // has no effect.. why??
            println("P8 is created using default constructor of 3D class:"+p8.toString)
        }

        //The class name works as a class constructor which can take a number of parameters.
        class Point (var x: Int, var y: Int) {
            //demonstrating how to protect the values
            this.setX(x)

            /*
            Scala does not have static methods or static variables.
            However we can mimic its behavior.

            Outside the scope of the class, create a companion object for the class
            Companion objects has same name as that of the class and holds the static members and functions.
            */


            val id = Point.getId

            //lets define getters and setters
            def getX() : Int = x
            def getY() : Int = y

            def setX(x: Int) {
                this.x = x
            }

            //this is how we override a function
            //here we implement our custom toString() method
            override def toString() : String = {
                return"(%d, %d) and id is %d".format(this.x, this.y, this.id)
            }

            //lets define other constructors

            //to define a constructor, we create a method called"this"
            //constructor with no arguments
            def this () {
                this(0,0)
            }

            //constructor with 1 value
            def this (x: Int) {
                this(0,0)
                this.setX(x)
            }


        }

        object Point {
            //static member
            private var id = 0

            //static method
            private def getId () : Int = { id += 1; id}
        }

        //Inheritance
        class ThreeD (x: Int, y: Int, z: Int) extends Point (x, y) {
            def this(x: Int, y: Int) {
                this(0,y,0)
                this.setX(x)
            }

            def this(x: Int) {
                this(0,0,0)
                this.setX(x)
            }

            def this() {
                this(0,0,0)
            }

            //to override parent class's setX method
            override def setX(x: Int) {
                super.setX(x)
            }

            override def toString() : String = {
                return"(%d, %d, %d) and id is %d".format(this.x, this.y, this.z, this.id)
            }
        }
    }


    class ThreeD (x: Int, y: Int, z: Int) extends Point (x, y)。不声明具有三个成员的类。xyz不是threed类的成员,它们只是构造函数参数。(如果你想让他们成为会员的话,你必须声明他们是(val x: Int, val y: Int, val z: Int)……或者更确切地说,在这种情况下,(override var x: Int, override var y: Int, val z: Int)…但不要这样做-见下文)。

    因为在scala中,类构造函数几乎是类的整个主体,所以有时很难区分这两者的区别:您可以在类主体内的任何地方引用构造函数参数,就像它们是成员一样。

    只有当成员是可变的(一般来说不是好事,你不想把可变成员作为政策问题)时,它才变得重要。在这里:

    1
    2
    3
    override def toString() : String = {
      return"(%d, %d, %d) and id is %d".format(this.x, this.y, this.z, this.id)
    }

    xyz指的是构造函数参数,不是Point的重写成员。p8.setX调用确实改变了p8的成员x的值,但它不是p8.toString打印的-它打印的是构造函数参数的值,即2

    从这里拿走:

  • 避免使用可变成员。你很少需要在斯卡拉。如果你认为你需要它…再想一想。

  • 不要给构造函数参数赋予与它们初始化的成员相同的名称,特别是如果您计划在类体中访问它们的话。如果你这样做了,就把它们声明为override val x,而不仅仅是x