Why can't I access protected java method even thought I've extended the class?

Matt picture Matt · Oct 25, 2009 · Viewed 20.2k times · Source

Here's the documentation for the protected method:

/** Converts jmusic score data into a MIDI Sequence */
protected  javax.sound.midi.Sequence scoreToSeq(Score score)

And I made this little class to extend the class that scoreToSeq method comes from:

public class MidiSequence extends MidiSynth{

    public Sequence getSequence(Score score){
        MidiSynth synth = new MidiSynth();
        Sequence sequence = null;
        try
        {
                    // Here I get the error saying that the method has
                    // protected access in MidiSynth
            sequence = synth.scoreToSeq(score);

        }
        catch (InvalidMidiDataException e)
        {
            /*
             *  In case of an exception, we dump the exception
             *  including the stack trace to the console.
             *  Then, we exit the program.
             */
            e.printStackTrace();
            System.exit(1);
        }

        return sequence;

    }
}

Answer

Jon Skeet picture Jon Skeet · Oct 25, 2009

(EDIT: theycallmemorty's answer gives the practical advice to avoiding this problem in your case. This answer gives the reasons for why you have to follow that advice, i.e. why the language has been designed that way.)

You can only access a protected member of another object which is of the same type as the accessing code (or a subclass) - even though the member is declared in a supertype.

From the Java Language Specification, section 6.6.2:

Let C be the class in which a protected member m is declared. Access is permitted only within the body of a subclass S of C. In addition, if Id denotes an instance field or instance method, then:

  • If the access is by a qualified name Q.Id, where Q is an ExpressionName, then the access is permitted if and only if the type of the expression Q is S or a subclass of S.
  • If the access is by a field access expression E.Id, where E is a Primary expression, or by a method invocation expression E.Id(. . .), where E is a Primary expression, then the access is permitted if and only if the type of E is S or a subclass of S.

This is to allow a type to access members relevant to its own inheritance tree, without defeating encapsulation of other classes. For example, suppose we have:

     A
    / \
   B   Other
  /
 C

and A declared a protected member x. Without the rule working the way it does, you could get round encapsulation by putting a member in Other:

public int getX(A a)
{
    return a.x;
}

and just calling that passing in an instance of B or C - the member would effectively become public, because you could always work around it by introducing another class... not a good idea. With the current rule, you'd have to subclass B or C - which you may not be able to in the first place.