protected access

Figure 486. 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. 173

protected vs. package private

Q:

Implement Figure 486, “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. 174

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.