2016-07-11 13 views
1

私は(de-)直列化したいクラスがあります。私は、コードはすべてのクラスで表示したくないので、私は私はこのようなこの抽象基底クラスから子クラスのオブジェクトを返します

public class Swan extends Animal {} 

と、基本クラスのような子クラス作ってあげると思った:

public abstract class Animal { 
    protected String name; 
    // ... 


    public void saveAnimal(String filename) { 
     //ObjectOutputStream, save name... 
    } 

    public static /*returntype*/ loadAnimal(String filename) { 
     //ObjectInputStream... 
    } 
} 

は基本的に私はこれをしたいです仕事に:動物が抽象的である場合

Swan s1 = new Swan("name"); 
s1.saveAnimal("/pathToSaveFile"); 
Swan s2 = (Swan)loadAnimal("/pathToSaveFile") OR 
Swan s2 = loadAnimal("/pathToSaveFile") 

は、私はこれをどのように行うのですか?この方法が次のような場合:

public static <T extends Animal> T loadAnimal(String filename) { 
    //loadFromFile 
    } 

私はnew T(name) //parameter cannot be instantiated directlyを返すことはできません。リフレクションについて少し読んだが、ジェネリック型Tのクラスを取得することはできません。これの回避策は、型のクラスをコンストラクタに渡すことですが、Animalは抽象型にする必要があります。

+0

この質問はあなたに少し役立ちますか?:http://stackoverflow.com/questions/20638749/chaining-returning-base-objects-and-type-mismatch-to-extended-classes – Adam

答えて

1

newInstance()することができます。これには、引数のないコンストラクタか、適切なコンストラクタを見つけて呼び出すためのコードが必要ですが、それは基本的なことです。 Swanloadメソッドを指定すると、Classの必要性を隠すことができます。継承された静的メソッドは多態性に関与しないため、これはオーバーライドではありません。 Swan.loadは、Animalから同等のメソッドを単に隠すだけです。

+0

ああ、私はまだ引数としてスワンのクラスを渡さなければなりません。私は、オブジェクトを作成し、それを型変換するなどの別の方法があると思いました。ありがとう! –

+0

はい。 'Swan.load'の中の' Class'オブジェクトの必要性を埋める第3のオプションで、ほとんどあなたが望むものを得ることができます。 –

0

あなたがこれを行うにして、インスタンスをチェックすると、それが動作する...

public static Animal loadAnimal(String filename) { 
    //ObjectInputStream... 
} 

例:

Swan s1 = new Swan("name"); 
s1.saveAnimal("/pathToSaveFile"); 
Animal s2 = loadAnimal("/pathToSaveFile") //it is ok since Swan is an animal.. 
if(s2 instanceOf Swan){ 
    Swan sccc = (Swan)s2; 
} 
+0

ええ、動物がインスタンス化されないようにする。だから私は、クラスAnimalは抽象クラスだと言いました。とにかくありがとう:-) –

+1

@FrankHaubenreisser動物この答えではインスタンス化されていません。それはただのタイプです。 – LeTex

0

それを解決する最も簡単な方法 - インスタンスタイプを(含まれているラッパーを作成特定の動物クラス)とシリアライゼーション本体。したがって、適切なクラスをインスタンス化して読み込むよりも、まず型を読み込みます。あなたがそうClassオブジェクトへのアクセス権を持っている必要がありTをインスタンス化するために

public class Foo { 

    public static class Animal { 
     public void save(String filename) 
     { 
      // Write to file 
     } 
     public static <T extends Animal> T load(String filename, Class<T> cls) throws Exception 
     { 
      T result = cls.newInstance(); 
      // initialize result 
      return result; 
     } 
    } 

    public static class Swan extends Animal { 
     public static Swan load(String filename) throws Exception 
     { 
      return load(filename, Swan.class); 
     } 
    } 

    public static void main(String[] args) throws Exception 
    { 
     Swan s = new Swan(); 
     s.save("somefile"); 
     Swan s2 = Swan.load("somefile", Swan.class); 
     // OR equivalently 
     Swan s3 = Animal.load("somefile", Swan.class); 
     // OR also equivalent 
     Swan s4 = Swan.load("somefile"); 
    } 
} 

:あなたは正確に何をしたいけど、ここでは3つの選択肢を示したいくつかのコードであることができないため型消去に

+0

なぜこれは 'Serializable'で必要でしょうか?データに既に型情報が含まれていてはなりませんか? –

0

抽象クラスである戻り値の型を宣言する際には問題ありません。これはオブジェクト指向プログラミングの重要なツールです。たとえば、メソッドArrays.asList(…),Collections.emptyList(),Collections.unmodifiableList(…)の戻り値の型は、インタフェースであるListです。これは、Listがインスタンス化されていることを意味するものではありません。それは、そのインタフェースの指定されていないサブタイプ(実装)が返されることを意味します。

Animalにオブジェクトをキャストすることは成功したのであれば、あなたは、単に、Animalを返すと、それは、逆シリアル化が生産何でも返却できるようにあなたの方法を宣言することができ、それがはおそらくSwanAnimal具象サブクラスです。あなたは、発信者側でキャストタイプを削除する場合

は、あなたがしかし

Swan s2 = loadAnimal("/pathToSaveFile", Swan.class); 

として呼び出すことができるパラメータ

public static <T extends Animal> T loadAnimal(String filename, Class<T> type) { 
    //loadFromFile 
    return type.cast(loadedObject); 
} 

として期待タイプを提供することができ、これはそうではありません明示的な型キャストよりも安全性を提供します。コンパイル時に、外部ファイルからロードされた特定のオブジェクトに任意の他の動物ではなくSwanが含まれることを保証する方法はありません。

これは、プロパティの代わりにAnimalインスタンス全体をデシリアライズしたことを前提としています。そうでない場合は、Classオブジェクトを使用して、適切なインスタンスを作成することができます。その特性を読み取る前にnewInstanceを介して。しかし、これは疑わしい設計であることに注意してください。通常、異なるサブクラスを作成します。サブクラスは異なるプロパティを持つためです。

関連する問題