scala教程之:可见性规则

前端之家收集整理的这篇文章主要介绍了scala教程之:可见性规则前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。


和java很类似,scala也有自己的可见性规则,不同的是scala只有private和protected关键字,没有public关键字,同时scala还提供了更加细粒度的访问控制如protected[scope]和private[scope]。

public

scala中默认的访问权限就是public,这意味着在scala中没有可见性关键字的声明体,他的访问权限就是public,是具有公有可见性的。这与Java不同,Java 语言中默认的“公有”可见性只对包可见(即包内私有)。

我们看一个例子:

  1. package scopeA {
  2. class PublicClass1 {
  3. val publicField = 1
  4. class Nested {
  5. val nestedField = 1
  6. }
  7. val nested = new Nested
  8. }
  9. class PublicClass2 extends PublicClass1 {
  10. val field2 = publicField + 1
  11. val nField2 = new Nested().nestedField
  12. }
  13. }
  14. package scopeB {
  15. class PublicClass1B extends scopeA.PublicClass1
  16. class UsingClass(val publicClass: scopeA.PublicClass1) {
  17. def method = "UsingClass:" +
  18. " field: " + publicClass.publicField +
  19. " nested field: " + publicClass.nested.nestedField
  20. }
  21. }

我们可以看到PublicClass1和它的内部类Nested的字段是公有可以访问的。

Protected

所有使用protected 关键字声明的成员只对该定义类型可见,包括
相同类型的其他实例以及所有的继承类型。

我们看一个例子:

  1. package scopeA {
  2. class ProtectedClass1(protected val protectedField1: Int) {
  3. protected val protectedField2 = 1
  4. def equalFields(other: ProtectedClass1) =
  5. (protectedField1 == other.protectedField1) &&
  6. (protectedField2 == other.protectedField2) &&
  7. (nested == other.nested)
  8. class Nested {
  9. protected val nestedField = 1
  10. }
  11. protected val nested = new Nested
  12. }
  13. class ProtectedClass2 extends ProtectedClass1(1) {
  14. val field1 = protectedField1
  15. val field2 = protectedField2
  16. val nField = new Nested().nestedField // ERROR
  17. }
  18. class ProtectedClass3 {
  19. val protectedClass1 = new ProtectedClass1(1)
  20. val protectedField1 = protectedClass1.protectedField1 // ERROR
  21. val protectedField2 = protectedClass1.protectedField2 // ERROR
  22. val protectedNField = protectedClass1.nested.nestedField // ERROR
  23. }
  24. protected class ProtectedClass4
  25. class ProtectedClass5 extends ProtectedClass4
  26. protected class ProtectedClass6 extends ProtectedClass4
  27. }
  28. package scopeB {
  29. class ProtectedClass4B extends scopeA.ProtectedClass4 // ERROR
  30. }

由于ProtectedClass2 继承了Protected1 类,因此ProtectedClass2 能访问ProtectedClass1中定义的受保护成员。不过,ProtectedClass2 无法访问protectedClass1.nested 对象中受保护的nestedField 成员。同时,ProtectedClass3 类也无法访问它使用的ProtectedClass1实例中的受保护成员。

最后,由于ProtectedClass4 被声明为protected 类,其对scopeB 包内的对象不可见。

private

私有(private)可见性将实现细节完全隐藏起来,即便是继承类的实现者也无法访问这些细节。声明中包含了private 关键字的所有成员都只对定义该成员的类型可见,该类型的其他实例也能访问这些成员。

注意,虽然private的继承者无法访问成员,但是包含该字段的类型的其他实例也可以访问这些成员。

举个例子:

  1. package scopeA {
  2. class PrivateClass1(private val privateField1: Int) {
  3. private val privateField2 = 1
  4. def equalFields(other: PrivateClass1) =
  5. (privateField1 == other.privateField1) &&
  6. (privateField2 == other.privateField2) &&
  7. (nested == other.nested)
  8. class Nested {
  9. private val nestedField = 1
  10. }
  11. private val nested = new Nested
  12. }
  13. class PrivateClass2 extends PrivateClass1(1) {
  14. val field1 = privateField1 // ERROR
  15. val field2 = privateField2 // ERROR
  16. val nField = new Nested().nestedField // ERROR
  17. }
  18. class PrivateClass3 {
  19. val privateClass1 = new PrivateClass1(1)
  20. val privateField1 = privateClass1.privateField1 // ERROR
  21. val privateField2 = privateClass1.privateField2 // ERROR
  22. val privateNField = privateClass1.nested.nestedField // ERROR
  23. }
  24. private class PrivateClass4
  25. class PrivateClass5 extends PrivateClass4 // ERROR
  26. protected class PrivateClass6 extends PrivateClass4 // ERROR
  27. private class PrivateClass7 extends PrivateClass4
  28. }
  29. package scopeB {
  30. class PrivateClass4B extends scopeA.PrivateClass4 // ERROR
  31. }

其他的都很好解释, 请注意,equalFields 方法可以访问其他实例中定义的私有成员

scoped private 和 scoped protected

除了普通的public,private和protected这三种可见性外,scala还提供了范围内的可见性: scoped private 和 scoped protected。 scala的范围有this,package和具体的某个类型。

简单点讲范围内的可见性就是在范围内保持该可见性的特性。

我们可以比较一下上面我们在讲private和proteced可见性的时候,两者在范围内(class,package)的表现是一样的,是可以替换的,只有在继承方面有差异。

我们先看一下继承的差异性:

  1. package scopeA {
  2. class Class1 {
  3. private[scopeA] val scopeA_privateField = 1
  4. protected[scopeA] val scopeA_protectedField = 2
  5. private[Class1] val class1_privateField = 3
  6. protected[Class1] val class1_protectedField = 4
  7. private[this] val this_privateField = 5
  8. protected[this] val this_protectedField = 6
  9. }
  10. class Class2 extends Class1 {
  11. val field1 = scopeA_privateField
  12. val field2 = scopeA_protectedField
  13. val field3 = class1_privateField // ERROR
  14. val field4 = class1_protectedField
  15. val field5 = this_privateField // ERROR
  16. val field6 = this_protectedField
  17. }
  18. }
  19. package scopeB {
  20. class Class2B extends scopeA.Class1 {
  21. val field1 = scopeA_privateField // ERROR
  22. val field2 = scopeA_protectedField
  23. val field3 = class1_privateField // ERROR
  24. val field4 = class1_protectedField
  25. val field5 = this_privateField // ERROR
  26. val field6 = this_protectedField
  27. }
  28. }

scope private/protected只能在该scope内部满足private/protected条件时候才能访问,这样就提供了更加细粒度的控制。

其中this scope是最严格的可见性,它表明可见性限制的字段只能在当前的scope或者type范围之内。

  1. package scopeA {
  2. class PrivateClass1(private[this] val privateField1: Int) {
  3. private[this] val privateField2 = 1
  4. def equalFields(other: PrivateClass1) =
  5. (privateField1 == other.privateField1) && // 错误
  6. (privateField2 == other.privateField2) && // 错误
  7. (nested == other.nested) // 错误
  8. class Nested {
  9. private[this] val nestedField = 1
  10. }
  11. private[this] val nested = new Nested
  12. }
  13. class PrivateClass2 extends PrivateClass1(1) {
  14. val field1 = privateField1 // 错误
  15. val field2 = privateField2 // 错误
  16. val nField = new Nested().nestedField // 错误
  17. }
  18. class PrivateClass3 {
  19. val privateClass1 = new PrivateClass1(1)
  20. val privateField1 = privateClass1.privateField1 // 错误
  21. val privateField2 = privateClass1.privateField2 // 错误
  22. val privateNField = privateClass1.nested.nestedField // 错误
  23. }
  24. }

我们先看一下类型范围的private[this],因为其是特定类型范围内,所以equalFields方法会编译错误,其无法被其他实例所访问。

除此之外,使用private[this] 修饰的类成员的可见性与未指定作用域范围的private 可见性一致。

再看一下包范围内的private[this] :

  1. package scopeA {
  2. private[this] class PrivateClass1
  3. package scopeA2 {
  4. private[this] class PrivateClass2
  5. }
  6. class PrivateClass3 extends PrivateClass1 // 错误
  7. protected class PrivateClass4 extends PrivateClass1 // 错误
  8. private class PrivateClass5 extends PrivateClass1
  9. private[this] class PrivateClass6 extends PrivateClass1
  10. private[this] class PrivateClass7 extends scopeA2.PrivateClass2 // 错误
  11. }
  12. package scopeB {
  13. class PrivateClass1B extends scopeA.PrivateClass1 // 错误
  14. }

在相同包中,无法成功地为一个private[this] 类型声明public 或protected 子类,你只能为其声明private 和private[this] 子类。与此同时,由于PrivateClass2 的可见性被限定在scopeA2 作用域内,因此你无法在scopeA2 作用域外声明其子类。

同理,在与scopeA2无关的scopeB 作用域内使用PrivateClass1 声明类同样会失败。

我们再看下private[T] 的可见性,其中T 代表了某一类型

  1. package scopeA {
  2. class PrivateClass1(private[PrivateClass1] val privateField1: Int) {
  3. private[PrivateClass1] val privateField2 = 1
  4. def equalFields(other: PrivateClass1) =
  5. (privateField1 == other.privateField1) &&
  6. (privateField2 == other.privateField2) &&
  7. (nested == other.nested)
  8. class Nested {
  9. private[Nested] val nestedField = 1
  10. }
  11. private[PrivateClass1] val nested = new Nested
  12. val nestedNested = nested.nestedField // ERROR
  13. }
  14. class PrivateClass2 extends PrivateClass1(1) {
  15. val field1 = privateField1 // ERROR
  16. val field2 = privateField2 // ERROR
  17. val nField = new Nested().nestedField // ERROR
  18. }
  19. class PrivateClass3 {
  20. val privateClass1 = new PrivateClass1(1)
  21. val privateField1 = privateClass1.privateField1 // ERROR
  22. val privateField2 = privateClass1.privateField2 // ERROR
  23. val privateNField = privateClass1.nested.nestedField // ERROR
  24. }
  25. }

由于可见性类型为private[PrivateClass1] 的成员对其他同类型实例可见, 因此equalFields 能够通过解析。

我们再看看包级的可见性:

  1. package scopeA {
  2. private[scopeA] class PrivateClass1
  3. package scopeA2 {
  4. private [scopeA2] class PrivateClass2
  5. private [scopeA] class PrivateClass3
  6. }
  7. class PrivateClass4 extends PrivateClass1
  8. protected class PrivateClass5 extends PrivateClass1
  9. private class PrivateClass6 extends PrivateClass1
  10. private[this] class PrivateClass7 extends PrivateClass1
  11. private[this] class PrivateClass8 extends scopeA2.PrivateClass2 // ERROR
  12. private[this] class PrivateClass9 extends scopeA2.PrivateClass3
  13. }
  14. package scopeB {
  15. class PrivateClass1B extends scopeA.PrivateClass1 // ERROR
  16. }

现在我们无法在scopeA2 作用域外将PrivateClass2 子类化。不过由于PrivateClass3 被声明为private[ScopeA] 类型,因此我们可以在scopeA 作用域内能将PrivateClass3 子类化。

再看看放在类型里面的包级可见性:

  1. package scopeA {
  2. class PrivateClass1(private[this] val privateField1: Int) {
  3. private[this] val privateField2 = 1
  4. def equalFields(other: PrivateClass1) =
  5. (privateField1 == other.privateField1) && // ERROR
  6. (privateField2 == other.privateField2) && // ERROR
  7. (nested == other.nested) // ERROR
  8. class Nested {
  9. private[this] val nestedField = 1
  10. }
  11. private[this] val nested = new Nested
  12. }
  13. class PrivateClass2 extends PrivateClass1(1) {
  14. val field1 = privateField1 // ERROR
  15. val field2 = privateField2 // ERROR
  16. val nField = new Nested().nestedField // ERROR
  17. }
  18. class PrivateClass3 {
  19. val privateClass1 = new PrivateClass1(1)
  20. val privateField1 = privateClass1.privateField1 // ERROR
  21. val privateField2 = privateClass1.privateField2 // ERROR
  22. val privateNField = privateClass1.nested.nestedField // ERROR
  23. }
  24. }

如果我们试图从某个与scopeA 无关的包scopeB 中访问scopeA 时,或者当我们尝试从嵌套包scopeA2 中访问成员变量时,便会出现错误

更多教程请参考 flydean的博客

猜你在找的Scala相关文章