protected access

Figure 510. protected access Slide presentation
package model;

public abstract class Shape ❶{

  final protected long creationTime ❷= System.nanoTime();
...
}
----------------------------------------------------------------
package model.sub;

public class Rectangle ❸extends Shape {
  static final Logger log = LogManager.getLogger(Rectangle.class);

  @Override public double getArea() {
    log.info("Rectangle creation time:" + creationTime ❹);
    return width * height;
  } ...
}

❶

Defining superclass Shape in package model.

❷

Defining a protected instance attribute creationTime in superclass Shape.

❸

Deriving class Rectangle in different package model.sub from superclass Shape.

❹

Accessing superclass attribute creationTime across package boundary.


exercise No. 190

protected vs. “package private”

Q:

Implement Figure 510, “protected access ” in your IDE but exchanging Rectangle by Circle accordingly. Then execute Circle.getArea() and watch the logging outcome.

Now apply the following two changes:

  1. Remove creationTime's protected modifier.

  2. Move class Circle to package model.

Are you still able to run your code? Explain the result.

A:

Implementing class Circle is straightforward:

public class Circle extends Shape {
  static final Logger log = LogManager.getLogger(Circle.class);

  @Override public double getArea() {
    log.info("Circle creation time:" + creationTime );
    return Math.PI * radius * radius;
  }
  private double radius;
}

Executing new Circle().getArea() results in:

2018-01-03 08:31:18,811 INFO  [main] sup.Circle (Circle.java:11) - Circle creation time:3340216708709

Removing protected yields a compile time error:

public class Circle extends Shape {
  static final Logger log = LogManager.getLogger(Circle.class);

  @Override public double getArea() {

// Error: 'creationTime' is not public in 'testprotect.model.Shape'.
// Cannot be accessed from outside package
    log.info("Circle creation time:" + creationTime );
...

Moving class Circle to package model resolves the issue: Having both classes Shape and Circle in a common package model implies “package private” access. Thus every method in Circle has full access to all fields and methods of Shape.

Note

In a production environment this may or may not be desired and is thus a design choice.

exercise No. 191

protected access involving different instances

Q:

We reconsider class AlphaSub from Understanding access control :

package package_two;

import package_one.Alpha;

public class AlphaSub
              extends Alpha {

  void dummy(/* Inherited */) {
    int v;
    v = attribPublic;
    v = attribProtected;
    v = attribDefault;
    v = attribPrivate;
  }
}

If we try to access a different instance's attribProtected we fail:

package package_two;

import package_one.Alpha;

public class AlphaSub
              extends Alpha {

  void dummy(final Alpha a) {
    int v;
        ...
    v = a.attribProtected;
        ...
  }
}

Why is this access prohibited? Both the calling instance and the argument a still belong to the Alpha / AlphaSum class hierarchy. Explain the different behavior.

A:

protected inherited access grants an instance's subclass method access to a superclass attribute or method involving one common instance.

The current use case differs: We have two (presumably different) instances one trying to access another's protected attribute. This does not involve inheritance at all and thus fails.