Scala access modifiers and qualifiers in detail
来自: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:
| 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:
| 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的更多相关文章
- 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 ...
- Java Access Levels(访问控制)
Access Levels Modifier Class Package Subclass World public Y Y Y Y protected Y Y Y N no modifier Y Y ...
- 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 ...
- 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 ...
- 【转】Basic C# OOP Concept
This Article will explain a very simple way to understand the basic C# OOP Concept Download ShanuBas ...
- 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 ...
- Java Interview Reference Guide--reference
Part 1 http://techmytalk.com/2014/01/24/java-interview-reference-guide-part-1/ Posted on January 24, ...
- Unity 官方教程 学习
Interface & Essentials Using the Unity Interface 1.Interface Overview https://unity3d.com/cn/lea ...
- 高级数据库及一步一步搭建versant数据库
总的来说,高级数据库课程分为分布式数据库和面向对象数据库两块.分布式数据库介绍了分布式数据库的方方面面,包括数据库系统的设计.查询处理优化.事务管理和恢复.并发控制.可靠性.安全性与目录管理等.面向对 ...
随机推荐
- 阿里云配置nginx+php+mysql
#yum -y install php mysql mysql-server mysql-devel php-mysql php-cgi php-mbstring php-gd php-fastcgi ...
- cocos2d-x 之 CCArray 的遍历(3)
cocos2d-x中CCArray的遍历,需要几个宏.现代C++程序设计建议尽量不要使用宏,所以数组的遍历也可以自己写. 但cocos2d-x官方已经提供了几个方便数组遍历的几个宏,用好了,能方便许多 ...
- 进程调度算法Linux进程调度算法
这次介绍一下操作系统的进程调度算法 操作系统的调度分为三种:1.远程调度(创建新进程):2.中程调度(交换功能的一部分):3.短程调度(下次执行哪个进程) 这次讲述的就是短程调度,可以简单的看作咱们平 ...
- 1055: [HAOI2008]玩具取名
Description 某人有一套玩具,并想法给玩具命名.首先他选择WING四个字母中的任意一个字母作为玩具的基本名字.然后 他会根据自己的喜好,将名字中任意一个字母用"WING" ...
- 2006Jam的计数法
题目描述 Description Jam是个喜欢标新立异的科学怪人.他不使用阿拉伯数字计数,而是使用小写英文字母计数,他觉得这样做,会使世界更加丰富多彩.在他的计数法中,每个数字的位数都是相同的(使用 ...
- 对angular实现延迟加载template和controller
1.在lib目录中添加 script.js 文件,并在index.html其他<script>之前引用之: <script src="lib/script.js" ...
- Circle3Quit数到三的人退出
public class Circle3Quit {public static void main(String args[]) {boolean arr[] = new boolean[500];/ ...
- lnmp memcache出问题
打开另一台用0.9装好的memcache 的PHP配置文件,找到了“extension = "memcache.so" ,将这个加入到了1.0的php.ini重启后 执行/memc ...
- 解决VS2013+IE11调试DevExpress ASP.NET MVC的性能问题
将一个MVC项目从12.2升级到14.2,VS2012升到2013,发现使用IE11调试非常慢卡死,CPU占用100%,后来经过排除,发现只有DevExpress的MVC项目有这个问题. 最后在Dev ...
- 学一点Git--20分钟git快速上手
(图片已修复)在Git如日中天的今天,不懂git都不好意思跟人说自己是程序猿.你是不是早就跃跃欲试了,只是苦于没有借口(契机). 好吧,机会就在今天. 给我20分钟,是的,只要20分钟, 让你快速用上 ...