Java and C# are very similar languages so if you have to switch between the two it’s easy to overlook subtle differences. One of the tricky bits is the meaning of protected access modifier.

In C#, if you mark a field with protected keyword it will be available to the class that owns it and to its derived classes. In Java access will be broader. Not only the owner and derived classes will be able to access the field but also all classes defined in the same package. In C# similar effect can be achieved by assigning protected internal access level. Member marked like that has access which is a union of internal (same assembly) and protected levels. Important thing to note is that concepts of Java package and C# assembly are not equivalent. C# assembly can span multiple namespaces and is related to physical unit (EXE, DLL) that keeps intermediate code and metadata. Package in Java is more similar to namespace in C# with key (not only) difference that it has an impact on accessibility…

Below are two projects that show protected access level differences between Java and C# (both are available in this GitHub repository). C# program was made in Visual Studio 2015 Community and targets .NET 4.5.2. Java program was made in IntelliJ IDEA 15 Community Edition and is set to use Java 8. Version of Java/.NET is not relevant and there’s nothing special in the projects - could’ve been easily done in notepad but isn’t it great that this days we can get such awesome IDEs for free? :)

package com.example;
public class Derived extends Base {
public void testAccessInDerivedClass() {
// SAME BEHAVIOR IN JAVA AND C#
// The class can access inherited protected field
System.out.println(someProtectedFiled);
// DIFFERENT BEHAVIOR IN JAVA AND C#!
// Access to protected field is possible because classes are in the same package
// (notice access through qualifier of type Base instead of Derived)
System.out.println(new Base().someProtectedFiled);
// In C# the field would have to be public or protected internal (otherwise CS1540 error is produced)
}
}

NotDerived.java

package com.example;
public class NotDerived {
public void testAccessInNotDerivedClass() {
// DIFFERENT BEHAVIOR IN JAVA AND C#!
// Access to protected field is possible because classes are in the same package
System.out.println(new Base().someProtectedFiled);
// In C# the field would have to be public or protected internal (otherwise CS0122 error is produced)
}
}

DerivedInAnotherPackage.java

package com.example.another;
import com.example.Base;
public class DerivedInAnotherPackage extends Base {
public void testAccessInDerivedClassFromAnotherPackage() {
// SAME BEHAVIOR IN JAVA AND C#
// The class can access inherited protected field even from another package
System.out.println(someProtectedFiled);
// SAME BEHAVIOR IN JAVA AND C#
// For the below to work (instead of compilation error) the field would have to be public
// (notice access through qualifier of type Base instead of DerivedInAnotherPackage):
// System.out.println(new Base().someProtectedFiled);
}
}

namespace Protected
{
public class Derived : Base
{
public void TestAccessInDerivedClass()
{
// SAME BEHAVIOR IN JAVA AND C#
// The class can access inherited protected field
System.Console.WriteLine(someProtectedFiled);
// DIFFERENT BEHAVIOR IN JAVA AND C#!
// For the below to work (instead of CS1540 compilation error) the field would have to be public
// or protected internal (notice access through qualifier of type Base instead of Derived):
// System.Console.WriteLine(new Base().someProtectedFiled);
}
}
}

NotDerived.cs

namespace Protected
{
public class NotDerived
{
public void TestAccessInNotDerivedClass()
{
// DIFFERENT BEHAVIOR IN JAVA AND C#!
// For the below to work (instead of CS0122 compilation error) the field would
// have to be public or protected internal:
// System.Console.WriteLine(new Base().someProtectedFiled);
}
}
}

DerivedInAnotherAssembly.cs

using Protected;
namespace AnotherAssembly // Namespace doesn't matter
{
public class DerivedInAnotherAssembly: Base
{
public void TestAccessInDerivedClassFromAnotherAssembly()
{
// SAME BEHAVIOR IN JAVA AND C#
// The class can access inherited protected field even from another assembly
System.Console.WriteLine(someProtectedFiled);
// SAME BEHAVIOR IN JAVA AND C#
// For the below to work (instead of CS1540 compilation error) the field would have to be public
// (notice access through qualifier of type Base instead of DerivedInAnotherAssembly):
// System.Console.WriteLine(new Base().someProtectedFiled);
}
}
}

I hope that comments in the code make everything clear and this dry topic is exhausted... I've just orderd USB shield for my Arduino so if it works the next post will be about moving this thing with PlayStation controller :)