protected和protected[this]的区别

15

我有以下代码:

class Base{
    protected val alpha ="Alpha";
    protected def sayHello = "Hello";
}
class Derived extends Base{
        val base = new Base;
        def hello = println(this.alpha +" "+this.sayHello) ;
       // def hello = println(base.alpha +" "+base.sayHello) ; // don't compile
    }

    object MyObj extends App{
            val x=new Derived;
            x.hello;
        }

Base类中,如果我使用this标记protected,代码将按预期工作;如果我没有使用this标记protected,一切也都按预期工作。
在Scala中,protectedprotected[this]等效吗?如果是,为什么Scala会提供两者?如果不是,它们有什么区别?
2个回答

22

Scala中的protected及其衍生类protected[this]protected[pkg]有些令人不知所措,但我发现通过使用Javaprotected哲学可以轻松记住解决方案。

  1. 它们对子类可见(子类可以在同一包或其他包中)
  2. 它们对指定受保护成员的类所在包中的任何类都可见。

显然它们对类本身也是可见的。

但Scala对它们在子类中的可见性有一些限制。默认情况下,它们仅对子类可见。它们对声明类所在的包不可见。然而,在两种情况下它们在子类中是可见的。

如果受保护成员未经资格认证(普通受保护),则它在声明类的另一个实例以及this在类和子类中都可见,例如:

class Base{
    protected val alpha ="Alpha";
    protected def sayHello = "Hello";
}
class Derived extends Base{
        def hello = println((new Derived()).sayHello) ;
        def hello2 = println(this.sayHello);

}

如果受保护成员被限定为 this,则只能通过类和子类中的 this 访问它,不能被声明类或子类的其他实例访问,例如:

class Base{
    protected val alpha ="Alpha";
    protected[this] def sayHello = "Hello";
    def foo = Console println(new Base().sayHello) // won't compile
    def bar = Console println(this.sayHello)
}
class Derived extends Base{
        def hello = println(this.sayHello) ;
        //def hello2 = println((new Derived() .sayHello) // won't compile
}

由于Scala默认不支持对受保护成员进行包级别访问。但是,如果您想在包级别上使其可用,则需要明确指定包,例如protected[pkg]。现在,如果在pkg或以下声明的类中访问这些受保护成员,则可以在声明类/子类实例的情况下看到它们。

例如:

package com.test.alpha{
class Base{
    protected val alpha ="Alpha";
    protected[test] def sayHello = "Hello"; // if you remove [test] it won't compile
}

class Derived extends Base{
    val base = new Base
        def hello = println(base.sayHello) ;
}}

这是如何记住 Scala 的 protected 关键字。

2

区别在于使用 protected[this] 声明时,子类实例只能访问自己的字段(this.x),而使用 protected 声明时,子类可以访问所有实例中的字段(不仅限于 this):

class Base{
  protected val alpha ="Alpha";
  protected[this] def sayHello = "Hello";
}

class Derived extends Base{
  def hello = println(this.alpha +" "+this.sayHello) ;
  def hello2 = println(
   new Derived().alpha +" "
   +new Derived().sayHello) ; // error on "sayHello"
}

在这段代码中,您可以访问this.sayHello,但无法访问other.sayHelloprotected alpha没有这种限制。

你的意思是我可以在Derived中访问base.alpha吗? - optional
我按照你的要求尝试了,但结果相同,我正在使用Scala 2.11.7。 - optional
ProtectedDemo.scala:7: 错误:无法在Base类中访问alpha值 因为前缀类型Base不符合访问发生的Derived类, 所以不允许访问受保护的alpha值 def hello = println(base.alpha) ; - optional
1
是的,没错。作为带有[this]限定符的成员,只能通过this限定符来访问。如果我需要通过Base实例访问alpha,那么我就需要用protected[pkg_of_scbclass]来限定它,对吗? - optional

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接