почему я не могу получить доступ к защищенному java-методу, даже если думал, что расширил класс?
-
06-07-2019 - |
Вопрос
Вот документация для защищенного метода:
/** Converts jmusic score data into a MIDI Sequence */
protected javax.sound.midi.Sequence scoreToSeq(Score score)
И я создал этот небольшой класс, чтобы расширить класс, из которого исходит метод 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;
}
}
Решение
(РЕДАКТИРОВАТЬ: они называют ответ меморти дает практические советы, как избежать этой проблемы в вашем случае.В этом ответе приводятся причины, по которым вы должны следовать этому совету, т.е.почему язык был разработан именно таким образом.)
Вы можете получить доступ только к защищенному элементу другого объекта, который имеет тот же тип, что и код доступа (или подкласс), даже если этот элемент объявленный в супертипе.
Из самого Спецификация языка Java, раздел 6.6.2:
Пусть C - класс, в котором объявлен защищенный член m.Доступ разрешен только в теле a подкласса-ов C.Кроме того, если Id обозначает поле экземпляра или метод экземпляра , то:
- Если доступ осуществляется по определенному имени Q.Id, где Q - это имя выражения, тогда доступ разрешен тогда и только тогда, когда тип выражения Q равен S или подклассу S.
- Если доступ осуществляется с помощью выражения доступа к полю E.Id, где E является основным выражением, или с помощью вызова метода выражение E.Id (...), где E является Основным выражением, тогда доступ разрешен тогда и только тогда, когда тип E равен S или подклассу S.
Это делается для того, чтобы позволить типу получать доступ к элементам, относящимся к его собственному дереву наследования, без нарушения инкапсуляции других классов.Например, предположим, что у нас есть:
A
/ \
B Other
/
C
и объявленный защищенным участником x
.Если бы правило не работало так, как оно работает, вы могли бы обойти инкапсуляцию, поместив элемент в Other
:
public int getX(A a)
{
return a.x;
}
и просто вызывая это, передавая экземпляр B
или C
- участник фактически стал бы общедоступным, потому что вы всегда могли бы обойти это, введя другой класс...не очень хорошая идея.С текущим правилом вам пришлось бы создать подкласс B
или C
- что, возможно, вам не удастся с самого начала.
Другие советы
Делая это:
MidiSynth synth = new MidiSynth();
sequence = synth.scoreToSeq(score);
На самом деле вы не используете тот факт, что вы расширили класс MidiSynth.
Если бы вы попробовали
this.scoreToSec(score);
Тогда вы обнаружите, что у вас есть доступ к защищенной функции.