在面向对象编程中,访问修饰符是控制成员访问权限的重要机制。在C#和Java这两种流行的编程语言中,protected关键字用于定义成员的访问级别。尽管在很多情况下,这两个语言中的protected关键字行为相似,但它们在某些特定的上下文中却表现出微妙的差异。
在C#中,如果使用protected关键字标记一个字段,那么这个字段将对拥有它的类及其派生类可用。而在Java中,访问范围更广。不仅是拥有者和派生类可以访问该字段,同一包中的所有类也可以访问。在C#中,要实现类似的效果,可以使用protected internal访问级别。这样标记的成员具有internal(同一程序集)和protected级别的访问权限的联合。需要注意的是,Java的包和C#的程序集的概念并不等价。C#的程序集可以跨越多个命名空间,并且与物理单元(EXE、DLL)相关,它保存中间代码和元数据。Java的包更类似于C#中的命名空间,但关键的区别是它影响访问权限。
以下是两个展示Java和C#中protected访问级别差异的项目。C#程序是在Visual Studio 2015 Community中创建的,目标是.NET 4.5.2。Java程序是在IntelliJ IDEA 15 Community Edition中创建的,设置为使用Java 8。Java/.NET的版本并不重要,这些项目没有什么特别的——完全可以在记事本中轻松完成,但如今能够免费获得如此出色的IDE,难道不令人兴奋吗?
Base.java
public class Base {
protected int someProtectedField = 123;
public void testAccessInBaseClass() {
// 在Java和C#中的行为相同
System.out.println(someProtectedField);
}
}
Derived.java
public class Derived extends Base {
public void testAccessInDerivedClass() {
// 在Java和C#中的行为相同
System.out.println(someProtectedField);
// 在Java中的行为不同
// 因为类在同一个包中,所以可以访问protected字段
System.out.println(new Base().someProtectedField);
// 在C#中,字段必须是public或protected internal
}
}
NotDerived.java
public class NotDerived {
public void testAccessInNotDerivedClass() {
// 在Java中的行为不同
System.out.println(new Base().someProtectedField);
// 在C#中,字段必须是public或protected internal
}
}
DerivedInAnotherPackage.java
import com.example.Base;
public class DerivedInAnotherPackage extends Base {
public void testAccessInDerivedClassFromAnotherPackage() {
// 在Java和C#中的行为相同
System.out.println(someProtectedField);
// 在Java中的行为不同
// 字段必须是public
System.out.println(new Base().someProtectedField);
}
}
Base.cs
public class Base {
protected int someProtectedField = 123;
public void TestAccessInBaseClass() {
// 在Java和C#中的行为相同
System.Console.WriteLine(someProtectedField);
}
}
Derived.cs
public class Derived : Base {
public void TestAccessInDerivedClass() {
// 在Java和C#中的行为相同
System.Console.WriteLine(someProtectedField);
// 在C#中的行为不同
// 字段必须是public或protected internal
System.Console.WriteLine(new Base().someProtectedField);
}
}
NotDerived.cs
public class NotDerived {
public void TestAccessInNotDerivedClass() {
// 在C#中的行为不同
System.Console.WriteLine(new Base().someProtectedField);
}
}
DerivedInAnotherAssembly.cs
using Protected;
public class DerivedInAnotherAssembly : Base {
public void TestAccessInDerivedClassFromAnotherAssembly() {
// 在Java和C#中的行为相同
System.Console.WriteLine(someProtectedField);
// 在C#中的行为不同
// 字段必须是public
System.Console.WriteLine(new Base().someProtectedField);
}
}
希望代码中的注释能够清楚地解释一切,这个干燥的话题已经讨论得差不多了。刚刚为Arduino订购了一个USB盾牌,如果它工作正常,下一篇文章将是关于如何使用PlayStation控制器来控制它。