来自:http://www.jesperdj.com/2016/01/08/scala-access-modifiers-and-qualifiers-in-detail/

Just like Java and other object-oriented programming languages, Scala has access modifiers to restrict access to members of classes, traits, objects and packages. Scala’s access modifiers are slightly different than Java’s; in this post I explain the difference. Besides modifiers, Scala also has qualifiers which allow more fine-grained access control. This is a feature that doesn’t exist in Java.

Access modifiers in Java and Scala

Java has four access levels:

Java access levels
Modifier Class Package Subclass World
public Y Y Y Y
protected Y Y Y N
no modifier Y Y N N
private Y N N N

Scala has three access levels, and they differ slightly from Java’s levels:

Scala access levels
Modifier Class Companion Subclass Package World
no modifier Y Y Y Y Y
protected Y Y Y N * N
private Y Y N N * N

*: Top-level protected and private members are accessible from inside the package.

Notable differences between Java and Scala are:

  • There is no public keyword in Scala. The default access level (when no modifier is specified) corresponds to Java’s public access level.
  • Unlike in Java, in Scala members that are protected are not accessible from other unrelated classes, traits or objects in the same package.
  • There is no direct equivalent to Java’s default access level in Scala.
  • In Scala, members that are private are accessible not only inside the class itself, but also in the class’ companion object (and vice versa: aprivate member in an object is accessible also in the object’s companion class).
  • You can make a top-level type private or protected in Scala (see below); this is not possible in Java.

In my opinion, Scala’s access levels make more sense than Java’s; the default access level in Java (package-wide access) is hardly ever used in practice, so it’s strange to have this as the default, and the fact that protected members are accessible to unrelated classes in the same package is most of the time not what you want. In Java, it’s not possible to make members accessible only to other members in the class itself and to subclasses, but not other classes in the same package.

Private top-level types

In Java, top-level classes and interfaces can only have one of two access levels: public or the default (package-scope) access level. You cannot make a top-level class or interface private or protected in Java.

In Java and also in Scala, when you make a nested class private, it means that the class is accessible only from the enclosing class. The meaning of private for a top-level class in Scala is just an extension of this idea, but now the enclosing scope is the package in which the class is defined instead of an enclosing class.

So, at first sight, it looks like a private top-level class in Scala is the same as a top-level class in Java with no access modifier; in both cases, the class is accessible only from the package that it is defined in. But this is not entirely correct. In Java, a class with no access modifier is not accessible in a nested package:

 
1
2
3
4
5
6
7
8
9
// Java example
package com.jesperdj.example;
 
// Top-level class with package-level accessibility
class Example {
    public void sayHello() {
        System.out.println("Hello World");
    }
}
 
1
2
3
4
5
6
7
8
9
10
11
12
// Nested package (under com.jesperdj.example)
package com.jesperdj.example.nested;
 
// ERROR: class Example is not accessible
import com.jesperdj.example.Example;
 
public class FromNestedPackage {
    public void method() {
        // ERROR: class Example is not accessible
        new Example().sayHello();
    }
}

In Scala, a private top-level class is also accessible from nested packages. This makes sense, since the enclosing scope of both the private class and the nested package is the same (it’s the package inside which both are defined), and private means that the class is accessible from anywhere within its enclosing scope.

 
1
2
3
4
5
6
7
// Scala example
package com.jesperdj.example
 
// Private top-level class
private class Example {
  def sayHello(): Unit = println("Hello World")
}
 
1
2
3
4
5
6
7
// Nested package (under com.jesperdj.example)
package com.jesperdj.example.nested
 
class FromNestedPackage {
  // OK: class Example is accessible because this is in the same enclosing scope
  def method(): Unit = new Example().sayHello()
}

This difference comes from the fact that the idea of nested packages do not really exist in Java, even though it seems that way. The Java compiler treats the packages com.jesperdj.example and com.jesperdj.example.nested as two unrelated packages. The fact that the second package looks like it is inside the first package doesn’t mean anything to the Java compiler.

The Scala compiler does have a notion of nested packages, which can also be seen by the fact that we didn’t have to import the classcom.jesperdj.example.Example like we would have to do in Java.

Another difference is that Scala does not allow you to let a private class escape from its enclosing scope. For example, Scala doesn’t allow you to write a public method that returns a private class. This makes sense, since the method can be called from anywhere because it’s public, but its return type is not accessible from everywhere.

 
1
2
3
4
5
6
7
8
// Scala example
package com.jesperdj.example
 
class ExampleFactory {
  // Public method which returns an instance of a private class
  // ERROR: private class Example escapes its defining scope
  def createExample(): Example = new Example
}

The Java compiler doesn’t complain when you write a public method that returns a package-scope class. Instead of complaining about the method definition, it’s going to complain at the point where you try to use the package-scope class.

 
1
2
3
4
5
6
7
8
9
// Java example
package com.jesperdj.example;
 
public class ExampleFactory {
    // OK: Public method which returns an instance of a package-scope class
    public Example createExample() {
        return new Example();
    }
}
 
1
2
3
4
5
6
7
8
9
10
11
12
// Different package
package com.jesperdj.other;
 
// ERROR: class Example is not accessible
import com.jesperdj.example.Example;
 
public class SomewhereElse {
    public void method() {
        // ERROR: class Example is not accessible
        Example example = new ExampleFactory().createExample();
    }
}

What the Scala compiler does is better; it reports the error closer to the actual source of the error. Java will let you write a library with a method that returns an inaccessible type, and you wouldn’t discover the error until somebody would try to use your library.

Protected top-level types

Even though Scala allows it, there is not much benefit to make a top-level class protected instead of private – they effectively mean the same thing.

To understand this, think about nested classes. When you make a nested class protected instead of private, it means its accessible not only in its enclosing class, but also in subclasses of its enclosing class. For top-level classes, the enclosing scope is a package instead of a class. Since there is no inheritance between packages (a package cannot extend another package, like a class can extend a superclass), protected doesn’t mean something else than private from the viewpoint of packages.

Access qualifiers

Scala’s protected and private access modifiers have an interesting feature that give you more fine-grained control. You can add a qualifier after the keywords protected and private, between square brackets. The qualifier can be one of two things: the name of an enclosing scope (package, class, trait or object), or the keyword this. These two kinds of qualifiers have different meanings.

Qualified access to an enclosing scope

With a qualifier that refers to an enclosing scope, you can widen the accessibility of a private or protected member to that scope, so that it’s not only accessible in the immediate enclosing scope, but in a scope that is one or more levels higher up. For example:

 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
package outside {
  package inside {
    object Messages {
      // Accessible up to package 'inside'
      private[inside] val Insiders = "Hello Friends"
 
      // Accessible up to package 'outside'
      private[outside] val Outsiders = "Hello People"
    }
 
    object InsideGreeter {
      def sayHello(): Unit =
        // Can access both messages
        println(Messages.Insiders + " and " + Messages.Outsiders)
    }
  }
 
  object OutsideGreeter {
    def sayHello(): Unit =
      // Can only access the 'Outsiders' message
      println(inside.Messages.Outsiders)
  }
}

Note that the name between the square brackets must be a simple name; it cannot be a fully-qualified name (with parts separated by dots).

Qualified access to ‘this’

Normally, in both Java and Scala, when a member of a class or trait is private or protected, this means that the access is restricted to the class or trait. Access is not restricted to individual instances; an instance of a class can access the same member in other instances of the same class.

In Scala it is possible to restrict access to the same instance only by qualifying the access modifier with [this], making the member object-private or object-protected. This means that an instance of a class or trait can only access the member in the current instance, and not in other instances. For example:

 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
class Counter {
  // Normal private member variable
  private var total = 0
 
  // Object-private member variable
  private[this] var lastAdded = 0
 
  def add(n: Int): Unit = {
    total += n
    lastAdded = n
  }
 
  def copyFrom(other: Counter): Unit = {
    // OK, private member from other instance is accessible
    total = other.total
 
    // ERROR, object-private member from other instance is not accessible
    lastAdded = other.lastAdded
  }
}

Conclusion

The access modifiers in Scala are slightly different than in Java. In my opinion, they are better in Scala, for the following reasons:

  • Public is the default in Scala, which is more useful than Java’s default access level, which is rarely useful in practice in Java code.
  • protected has the same meaning in Scala as in C++; only accessible in the class itself and in subclasses. Fortunately Scala didn’t inherit Java’s weird idea, where protected members are also accessible in unrelated classes that happen to be in the same package.
  • The meaning of private top-level types in Scala makes sense.
  • When you accidentally expose a type that has restricted access from a less restricted method, Scala gives you an error at the declaration of the method (the actual source of the error) rather than at the point where you try to call the method.
  • With qualifiers, and because Scala understands nested packages, you have more fine-grained control over accessibility in Scala than in Java.
  • In Scala you can make members really really private by restricting access to only the current instance, which isn’t possible in Java.

In this post I’ve descibed Scala’s access control in detail. It’s possible to go even deeper, by looking at how the Scala compiler implements these features at the JVM-level. I suspect that the class file format that the JVM uses is really geared towards Java’s access control model, and I wonder how Scala manages to implements its own features, which are different and go beyond Java’s model, using what the class file format and the JVM offer. That will be a topic for another day.

Scala access modifiers and qualifiers in detail的更多相关文章

  1. Part 48 to 51 Talking about Access Modifiers in C#

    Part 48 Difference between Types and Type Members Part 49 Access Modifiers in C# Part 50 Internal an ...

  2. Java Access Levels(访问控制)

    Access Levels Modifier Class Package Subclass World public Y Y Y Y protected Y Y Y N no modifier Y Y ...

  3. The third column indicates whether subclasses of the class declared outside this package have access to the member.;

    总结1.modifier 改性剂 修饰符 修饰语 调节器access modifier 访问修饰符 存取权限 存取修饰词 存取修饰字官网“can”Access level modifiers dete ...

  4. Core Java Volume I — 5.1. Classes, Superclasses, and Subclasses

    5.1. Classes, Superclasses, and SubclassesLet's return to the Employee class that we discussed in th ...

  5. 【转】Basic C# OOP Concept

    This Article will explain a very simple way to understand the basic C# OOP Concept Download ShanuBas ...

  6. Visual C#每一次新版本的变化

    What's New in Visual C# .NET 2003[Visual Studio .NET 2003] What's New in Visual C# 2005 What's New i ...

  7. Java Interview Reference Guide--reference

    Part 1 http://techmytalk.com/2014/01/24/java-interview-reference-guide-part-1/ Posted on January 24, ...

  8. Unity 官方教程 学习

    Interface & Essentials Using the Unity Interface 1.Interface Overview https://unity3d.com/cn/lea ...

  9. 高级数据库及一步一步搭建versant数据库

    总的来说,高级数据库课程分为分布式数据库和面向对象数据库两块.分布式数据库介绍了分布式数据库的方方面面,包括数据库系统的设计.查询处理优化.事务管理和恢复.并发控制.可靠性.安全性与目录管理等.面向对 ...

随机推荐

  1. Oracle中改变表的Owner和tablespace

    初用Oracle,很多的不熟悉,建完库,没有建用户,也没创建表空间,就直接system用户建表添加数据,几个月过去,表建了近百个,数据添加了几万条,才越来越觉得这种方式缺点太多: 在PL/SQL中系统 ...

  2. 新浪微博SDK的使用

    花了两天时间研究了一下新浪微博SDK,遇到了不少问题,有必要整理一下 1.首先下载下weiboSdk,导入weiboSDKD和weiboSDKDemo两个项目,这时发现导入的weiboSDKDemo项 ...

  3. Mac上创建cocos2d-x工程

    1.自选版本-下载 http://www.cocos2d-x.org/download 2.解压(自选路径) 3.在cocos2d-x解压目录下新建 Projects 文件夹. 3.打开终端 4.进入 ...

  4. jQuery学习总结(一)

    jQuery当中独有的对象:jQuery对象: jQuery对象的缩写形式“$”:所以在使用时,我们都是用$来代替jQuery. 所以我们在页面元素选择或执行功能函数的时候可以这么写:$(functi ...

  5. struts2的运行原理及配置文件

    struts2官方运行原理图: 1,客户发送请求(url地址就是请求),tomcat接到请求会找到相应的应用web.xml配置文件. 2,web.xml中filter拦截器把你的请求接收到,并进入Fi ...

  6. Windows下Qt5搭建Android开发环境笔记

    Windows很大的特点是配置使用几乎都可以图形化进行,和Linux比起来在很多时候配置环境也要方便很多.所以,搭建Qt for Andorid也是十分简单的.需要以下工具: 1.最方便的Qt官方包, ...

  7. Android--入门

    之前自己在学校写过一些安卓应用,那时候没有系统地学过安卓,用到什么就网上找博客.找Demo,然后自己跟着敲一遍,有些东西也不太理解,现在打算做android开发这一块了,趁毕业之前赶紧多学些技术.先是 ...

  8. http://www.cnbeta.com/articles/306769.htm

    事实上,很少有方法可以帮你做到.有些人可能会想到试着把Vim打造成C语言IDE的,比如c.vim:也有把Vim集成到Eclipse里的Eclim .但是我想要告诉你的是一个更加通用的,只用插件实现的方 ...

  9. iOS开发常用的第三方类库

    在iOS开发中不可避免的会用到一些第三方类库,它们提供了很多实用的功能,使我们的开发变得更有效率:同时,也可以从它们的源代码中学习到很多有用的东西. Reachability 检测网络连接 用来检查网 ...

  10. 创建一个简单的HTTP服务(自动查找未使用的端口)

    var t = new Thread(new ThreadStart(() => { HttpListener listener = new HttpListener(); var prefix ...