【问题标题】:Why can't I access protected java method even thought I've extended the class?为什么即使我已经扩展了类,我也不能访问受保护的 java 方法?
【发布时间】:2010-12-09 23:35:25
【问题描述】:

这里是受保护方法的文档:

/** 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;

    }
}

【问题讨论】:

  • 来自 Najib Tounsi(没有足够的代表发表评论):尽管,synth.scoreToSeq(score); 应该是合法的。

标签: java inheritance protected


【解决方案1】:

(编辑:theycallmemorty's answer 给出了在您的情况下避免此问题的实用建议。此答案给出了您必须遵循该建议的原因,即为什么语言是这样设计的。)

您只能访问与访问代码(或子类)具有相同类型的另一个对象的受保护成员 - 即使该成员在超类型中声明

来自Java Language Specification, section 6.6.2

设 C 是一个类 声明了受保护的成员 m。使用权 只允许在一个体内 C 的子类 S。此外,如果 Id 表示实例字段或实例 方法,然后:

  • 如果通过限定名称 Q.Id 进行访问,其中 Q 是 ExpressionName, 如果和 仅当表达式 Q 的类型 是 S 或 S 的子类。
  • 如果通过字段访问表达式 E.Id 进行访问,其中 E 是 Primary 表达式,或通过方法调用 表达式 E.Id(. . .),其中 E 是 初级表达式,则访问为 当且仅当 E 的类型是允许的 是 S 或 S 的子类。

这是为了允许一个类型访问与其自己的继承树相关的成员,而不会破坏其他类的封装。例如,假设我们有:

     A
    / \
   B   Other
  /
 C

A 声明了一个受保护的成员 x。如果规则没有按照它的方式工作,您可以通过将成员放入 Other 来获得圆形封装:

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

并且只是在BC 的实例中调用它——该成员实际上会变成公共的,因为你总是可以通过引入另一个类来解决它......这不是一个好主意。根据当前规则,您必须继承 BC - 您可能一开始就无法做到这一点。

【讨论】:

  • 我想我(大部分)理解 JLS 摘录:-),但反例似乎没有说服力。受保护的字段 x 位于 A 而不是 B 或 C 上,因此其他人应该可以看到它。它不会暴露 B 或 C 的其他字段。当然,这主要是令人费解的,因为答案是“规范是这样说的”,我们不太可能更改规范 :-)
  • @Jon 在你的倒数第二行中“因为你总是可以通过引入另一个类来解决它”是什么意思?
  • @Geek:任何人都可以创建另一个扩展A的类,并提供对A任何其他子类的实例的访问。
  • @JonSkeet 我在这里问了related question。能回答一下吗?
  • 我觉得最后一个例子应该是:public static void getX(A a) {return a.x;}
【解决方案2】:

通过这样做:

MidiSynth synth = new MidiSynth();
sequence = synth.scoreToSeq(score); 

您实际上并没有利用您已扩展 MidiSynth 类这一事实。

如果你想尝试

this.scoreToSec(score);

然后你会发现你可以访问受保护的功能。

【讨论】:

  • 或者通过创建一个新的 MidiSequence 而不是 MidiSynth(并且也改变合成器变量的类型)。
猜你喜欢
  • 2011-10-06
  • 2010-10-08
  • 2023-03-12
  • 2015-08-14
  • 1970-01-01
  • 2013-10-20
  • 1970-01-01
  • 2013-11-25
  • 2022-01-03
相关资源
最近更新 更多