Java language oddities

Java's handling of arrays and a few other language elements may surprise you

1 2 Page 2
Page 2 of 2
public class PrivateAccess
{
   private int i;

   public PrivateAccess(int i)
   {
      this.i = i;
   }

   private void noAccess()
   {
      System.out.println("should not be able to access");
   }

   public void foo(PrivateAccess pa)
   {
      if (i == pa.i)
         System.out.println("equal");
      else
         System.out.println("not equal");
   }

   public static void main(String[] args)
   {
      PrivateAccess pa1 = new PrivateAccess(1);
      PrivateAccess pa2 = new PrivateAccess(2);
      PrivateAccess pa3 = new PrivateAccess(1);
      pa1.foo(pa2);
      pa1.foo(pa3);
      System.out.println(pa1.i);
      pa2.noAccess();
   }
}

Listing 5 reveals a PrivateAccess class with a private field named i and a private method named noAccess(). It also declares a public constructor, a public method named foo(), and a public and static method named main().

Examine the foo() method and note expression i == pa.i. This expression is accessing another object's (pa) private field (i). Examine main() and you'll observe pa1.i and pa2.noAccess() expressions that should be illegal.

Compile Listing 5 as follows:

javac PrivateAccess.java

Compiliation should succeed. Now, run the application as follows:

java PrivateAccess

You should observe the following output:

not equal
equal
1
should not be able to access

Before we examine what's going on, consider Listing 6.

Listing 6. ExternalClass.java

public class ExternalClass
{
   public static void main(String[] args)
   {
      PrivateAccess pa1 = new PrivateAccess(3);
      PrivateAccess pa2 = new PrivateAccess(3);
      pa1.foo(pa2);
//      System.out.println(pa1.i);
//      pa2.noAccess();
   }
}

As it stands, you can compile ExternalClass.java and run the resulting application, and observe the following output:

equal

However, if you uncomment either commented-out line and recompile, you'll observe an error message:

i has private access in PrivateAccess

or

noAccess() has private access in PrivateAccess

To sum up, we can directly access i or noAccess() from class PrivateAccess but not from class ExternalClass. What's going on?

Section 6.6.1. Determining Accessibility in the Java Language Specification provides an answer. Essentially, it states that if the member (field or method) or constructor is declared private, access is permitted if and only if it occurs within the body of the top level type that encloses the declaration of the member or constructor. Because PrivateAccess declares i and noAccess(), these private members can be accessed directly from within this class (but not from beyond).

Does this behavior violate security? I would say no. The class is which the private member is declared has full access control. This member can be accessed only from objects of the class type.

Conclusion

Java might appear to be eccentric in some of its behaviors. However, there are rational reasons for these oddities. Convenience is one reason: treating arrays as objects makes it easy to write code that conveniently handles reference type arrays, primitive type arrays, and single objects in one place (e.g., Objects.deepEquals()). Another reason is performance: a 32-bit JVM runs faster when 32-bit instead of 8-bit/16-bit values are pushed/popped. And it's a bit smaller (taking up less memory) if 8-bit/16-bit instructions for addition and other integral operations aren't required.

Performance and convenience may also be the reasons for supporting direct access to private fields and methods. Consider that an overriding equals() method might be executed many times during an object's lifetime (perhaps during a sort or search operation). That method should run faster if it doesn't have to invoke an accessor method to obtain a private field's value. Also, it's convenient to not have to create accessor methods, which adds to the size of a class file, and enter their names just to access field values. The same logic applies to invoking private methods.

download
Get the source code for the Java applications in this post. Created by Jeff Friesen for JavaWorld.

The following software was used to develop the post's code:

  • 64-bit JDK 9ea+181

The post's code was tested on the following platform(s):

  • JVM on 64-bit Windows 10
1 2 Page 2
Page 2 of 2