14

「ThinkinginJava」を読んで、Inner Classesの章のex:6にとどまりました。


演習6:(2)独自のパッケージで、少なくとも1つのメソッドを使用してインターフェースを作成します。別のパッケージでクラスを作成します。インターフェイスを実装する保護された内部クラスを追加します。3番目のパッケージでは、クラスから継承し、メソッド内で、保護された内部クラスのオブジェクトを返し、戻り中にインターフェイスにアップキャストします。


これは私のコードです:

IOne.java

インターフェース

package intfpack;
public interface IOne{
        void    f();
}

COne.java

インターフェイスを実装する保護された内部クラスを持つクラス

package classpack;
import intfpack.*;
public class COne{
        protected class Inner implements IOne{
                public void f(){System.out.println("Inner class of COne");}
        } 
}

CTwo.java

保護された内部クラスを持つクラスからの継承

package thirdpack;
import classpack.*;
import intfpack.*;

public class CTwo extends COne{
        public IOne getInner(){
                IOne io = new Inner(); 
                return io;
        }
        public static void main(String[] args){
                CTwo ct = new CTwo();
                ct.getInner();
        }
}

コプミラーは次に言います:

javac CTwo.java
CTwo.java:9: Inner() has protected access in classpack.COne.Inner
                IOne io = new Inner(); 
                          ^
1 error

しかし、この本には、派生クラスの保護された内部クラスにアクセスできると書かれています。間違いはどこにありますか?

4

4 に答える 4

24

エラーメッセージは、クラスではなく、コンストラクタが保護されていることについて不平を言っています。ただし、投稿したコードでコンストラクターを明示的に定義していません。この場合、JLSに従って、デフォルトのコンストラクターが保護されます(クラスと同じ)。

于 2009-09-28T15:43:41.903 に答える
9

:のpublicコンストラクターを定義する必要があります。Inner class

public class COne {

    protected class Inner implements IOne{

        public Inner() { }

        public void f(){System.out.println("Inner class of COne");}
    }
}
于 2009-09-28T15:54:10.713 に答える
0

それは明らかです。しかし、ここに本当に奇妙なことがあります。

JLSによると、 CTwoがCOne.Innerを拡張する場合、Innerの保護されたコンストラクターにアクセスすることが期待されますが、実際にはアクセスしません...以下を参照してください。

package p1;
public class COne {
    public static class Inner {
        protected Inner() {}
    }
}

package p2;
public class CTwo extends COne.Inner {
    public void getIface() {
        new COne.Inner();
        // Compile time error anyway with the same complains:
        // "Inner() has protected access in p1.COne.Inner"
        // ...unlike my expectations...
    }
}  
于 2009-11-10T23:03:20.770 に答える
0

問題は、内部クラスではなく、継承に関するものです。

いくつかの実験をしましょう。

ファーストInnerOuterクラスの両方がお互いに完全にアクセスできます。したがって、次のコードはうまく機能します。

package com.ciaoshen.packA;

public class Outer {
        protected class Inner {
            public void foo() { System.out.println("Hello Ronald!"); }
        }
        protected Inner inner() {
            return new Inner();
        }
        public static void main(String[] args) {
            new Outer().inner().foo(); // Output: Hello Ronald!
        }
}

現在、別のパッケージで、DerivedOuterから派生していOuterます。クラスから継承されたメソッドをDerivedOuter呼び出します。それはまだ動作します!inner()Outer

package com.ciaoshen.packB;

class DerivedOuter extends Outer {
    public static void main(String[] args) {
        new DerivedOuter().inner().foo(); // Output: Hello Ronald!
    }
}

しかし、クラスのメソッドをオーバーライドすると、同じエラーが発生します。inner()DerivedOuter

package com.ciaoshen.packB;

class DerivedOuter extends Outer {
    @Override
    public Inner inner() { // this is not the inner() of Outer class. BOOM!
        return new Inner();
    }
    public static void main(String[] args) {
        new DerivedOuter().inner().foo(); // ERROR: Outer.Inner() has protected access in Outer.Inner
    }
}

Outer結論として、保護されたInnerコンストラクターは、元のクラススコープ内でのみアクセスできます。追加のメソッド(例:getInner()メソッド)は、保護されたInnerコンストラクターにアクセスできません。

重要な点は、DerivedOuterから継承する場合、 IS-AOuterを想像でき、そのメンバーとして内部にクラスが含まれていることです。しかし実際には、クラスに直接アクセスする ことはできず、彼のスーパークラスを使用することによってのみ機能します。DerivedClassOuterInnerDerivedOuterInnerOuter

于 2017-04-08T05:27:38.873 に答える