2016-03-18 4 views
2

私はJavaで次の擬似コードていない:私はMyClassSubとMyGenericClassの新しいインスタンスを作成すると、私は期待してい、そのタイプとしてのJavaのジェネリックは、TとTのメソッドを呼び出し、そのスーパークラスとして

class MyClassSuper{ 
    public static final String VALUE = "e"; 
} 

class MyClassSub extends MyClassSuper{ 
    public static final String VALUE = "f"; 
} 

class MyGenericClass<T extends MyClassSuper> { 
    public void print(){ 
     System.out.println(T.VALUE); 
    } 
} 

"f"を印刷する印刷方法ですが、代わりに "e"が印刷されます。 MyGenericClassに、Tが現在拡張しているスーパークラスを保持している間にTを実際の型として扱うことは可能ですか?

EDIT:

実際のコード(省略):

public class Bean implements Serializable { 

    public static final String FILE_EXT = ""; 
    private static final long serialVersionUID = 1L; 

} 

public class UserBean extends Bean{ 

    public static final String FILE_EXT = "u"; 
    private static final long serialVersionUID = 1L; 

    private String name; 

    public UserBean(String name){ 
     this.name = name; 
    } 
} 

public class BeanPersistence<T extends Bean> implements IBeanPersistence<T> { 

    public void printExtension(){ 
     System.out.println(T.FILE_EXT); 
    } 

} 

私が書くしようとしているコードです。基本的には、BeanPersistenceクラスが、初期化されたBeanのタイプに基づいて、書き込むファイルに使用する拡張子を知りたいとします。私がこれを収集するコメントから、これを行う間違った方法です、適切な方法は何でしょうか? (明らかにprintExtensionメソッドはテストするためのものです)

+0

してください、あなたは私たちに 'e'を印刷し、実際のコードを表示することができますか?これは 'T.VALUE'を書くことができないので何も印刷しません。 –

+1

@PaulBoddington実際には、私の実質的な驚きには、あなたがすることができます。'Class'にもかかわらず、これはコンパイルされます。 –

+0

@AndyTurner私の神よ、あなたは正しい。私はそれが 'T'がバイトコードの境界に置き換えられるからだと思います。あなたは毎日何か新しいことを学びます。 –

答えて

2

これは、適切なかもしれないが、あなたに応じて、場合。一般的に

public class BeanPersistence<T extends Bean> { 

    public void printExtension(Bean bean) { 
     System.out.println(bean.getExtension()); 
    } 

    public static void main(String[] args) { 

     BeanPersistence<Bean> persistence = new BeanPersistence<>(); 
     UserBean userBean = new UserBean(); 
     AdminBean adminBean = new AdminBean(); 
     persistence.printExtension(userBean); // prints u 
     persistence.printExtension(adminBean); // prints a 
    } 
} 

abstract class Bean { 

    abstract String getExtension(); 
} 

class UserBean extends Bean { 

    private static final String FILE_EXT = "u"; 

    @Override 
    String getExtension() { 
     return FILE_EXT; 
    } 
} 

class AdminBean extends Bean { 

    private static final String FILE_EXT = "a"; 

    @Override 
    String getExtension() { 
     return FILE_EXT; 
    } 
} 

あなたは直接ではなく、方法を通じてオブジェクトのプロパティにアクセスする必要があります。メソッドを呼び出すと、オブジェクト指向の振る舞い(多態性、動的ディスパッチ)によって正しいメソッドが呼び出されます。

も参照してください

1

私は今日までこれがコンパイルされることに気付きませんでした。起こっているのは、T extends MyClassSuperのため、クラスがバイトコードにコンパイルされるとき、TMyClassSuperとして扱われるため、T.VALUEは実際にはMyClassSuper.VALUEであるため、"e"を出力します。 (私はあなたが型パラメータの静的なフィールドとメソッドにアクセスすることができて驚いています - それは絶対に理由がわかりません)。

次に、オーバーライドはインスタンスメソッドだけで動作し、フィールドや静的なものでは動作しません。

あなたがしようとしている別の問題は、タイプ消去のためにタイプTが実行時に認識されないため、その値に基づいてStringを選択することができないということです。

問題の解決策の1つは、サブクラスでオーバーライドできる拡張のインスタンスメソッドを使用することです。これには、Tのインスタンスを保持するか、パラメータとして渡す必要があります(その他の回答を参照)。

2

正しいアプローチは、多型を使用することです:サブクラスでオーバーライドすることができ、MyClassSuperで非静的メソッドを追加し、MyGenericClassにインスタンスを提供します。

class MyClassSuper{ 
    public String getValue() { return "e"; } 
} 

class MyClassSub extends MyClassSuper{ 
    public String getValue() { return "f"; } 
} 

class MyGenericClass<T extends MyClassSuper> { 
    private final T instance; 

    MyGenericClass(T instance) { this.instance = instance; } 

    public void print(){ 
     System.out.println(instance.getValue()); 
    } 
} 
関連する問題