¿Por qué no puedo acceder al método protegido de Java aunque creí que había extendido la clase?
polymorphism in java (2)
Al hacer esto:
MidiSynth synth = new MidiSynth();
sequence = synth.scoreToSeq(score);
En realidad, no estás aprovechando el hecho de que has extendido la clase MidiSynth.
Si fueras a probar
this.scoreToSec(score);
Luego, verá que tiene acceso a la función protegida.
Aquí está la documentación para el método protegido:
/** Converts jmusic score data into a MIDI Sequence */
protected javax.sound.midi.Sequence scoreToSeq(Score score)
E hice esta pequeña clase para extender la clase de la que proviene el método de scoreToSeq:
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;
}
}
(EDITAR: la respuesta de theycallmemorty brinda consejos prácticos para evitar este problema en su caso. Esta respuesta explica los motivos por los que debe seguir ese consejo, es decir, por qué el lenguaje ha sido diseñado de esa manera).
Solo puede acceder a un miembro protegido de otro objeto que sea del mismo tipo que el código de acceso (o una subclase), aunque el miembro esté declarado en un supertipo.
De la Especificación del lenguaje Java, sección 6.6.2 :
Sea C la clase en la que se declara un miembro protegido m. El acceso solo se permite dentro del cuerpo de una subclase S de C. Además, si Id denota un campo de instancia o un método de instancia, entonces:
- Si el acceso es por un nombre calificado Q.Id, donde Q es un nombre de expresión, entonces el acceso está permitido si y solo si el tipo de la expresión Q es S o una subclase de S.
- Si el acceso es por una expresión de acceso de campo E.Id, donde E es una expresión primaria, o por una expresión de invocación de método E.Id (...), Donde E es una expresión primaria, entonces el acceso está permitido si y solo si el tipo de E es S o una subclase de S.
Esto es para permitir que un tipo acceda a miembros relevantes para su propio árbol de herencia, sin derrotar la encapsulación de otras clases. Por ejemplo, supongamos que tenemos:
A
/ /
B Other
/
C
y A declaró un miembro protegido x
. Sin que la regla funcione de la forma en que lo hace, puede obtener una encapsulación completa al poner un miembro en Other
:
public int getX(A a)
{
return a.x;
}
y simplemente llamando a esa aprobación en una instancia de B
o C
, el miembro se haría público de manera efectiva, porque siempre se podría evitar introduciendo otra clase ... no es una buena idea. Con la regla actual, tendrías que hacer una subclase B
o C
, que no podrás en primer lugar.