8

を使用せずに、オブジェクトのタイプに基づいていくつかの操作を実行したいと思いますinstanceof。最初は、型に基づいてメソッドをオーバーロードすることを考えていました (以下を参照)。Java が適切にメソッドを選択するのではないかと考えていました (オブジェクトの最も具体的なクラスに基づいて)。

import java.util.ArrayList;
import java.util.List;


public class TestA {

    public static void main(String[] args)
    {
        List<Object> list = new ArrayList();
        list.add(new A());
        list.add(new B());
        list.add(new C());
        list.add(new Object());

        TestA tester = new TestA();

        for(Object o: list)
        {
            tester.print(o);
        }
    }

    private void print(A o)
    {
        System.out.println("A");
    }

    private void print(B o)
    {
        System.out.println("B");
    }

    private void print(C o)
    {
        System.out.println("C");
    }

    private void print(Object o)
    {
        System.out.println("Object");
    }
}

class A {

}

class B extends A {

}

class C {

}

出力は次のとおりです。

Object
Object
Object
Object

ただし、私が求めている出力は次のとおりです。

A
B
C
Object
  • パラメータオブジェクトの最も具体的なタイプに基づいてJavaにメソッドを選択させる方法はありますか?
  • そうでない場合、そのような機能のためにどのような代替手段を検討できますか?instanceof
  • 私は実際にビジターパターンをシミュレートしようとしていましたが、ビジターパターンが機能するのは、関数呼び出し中に「受け入れられる」パラメーターが正しいタイプになる二重ディスパッチのためです。特に、visitor.accept(this)関数が呼び出されるclass A原因となりますvisitor.accept(A o).
  • 私はinstanceofそれを使用することは悪い習慣であると読んだので、正直に反対です。この場合、それはまだ悪い習慣でしょうか?
4

9 に答える 9

4

この回答では、特定のクラスとその関係を変更することはオプションではないと考えています。

パラメータオブジェクトの最も具体的なタイプに基づいてJavaにメソッドを選択させる方法はありますか?

おそらくそれはあなたが望むものではないので、Javaコンパイラはこれをキャストできません(あなたの場合はそれがあなたが望むものですが、他の人はこの動作を望まず、彼らは彼らにとって解決策ではないでしょう)。Objectへの参照を渡しているためprint()、コンパイラは を呼び出しますprint(Object)

そうでない場合、instanceofの助けを借りずに、そのような機能のためにどのような代替案を検討できますか

Object次のように、ラッパー クラスでその型をラップできます。

public class ObjectWrapper {
    private final Object object;
    private final int type;
}

Objectこのようにして、を使用せずに の型に安全にキャストできますinstanceof。この私見は単純に使用するよりも複雑ですがinstanceof、実際には独自のものを作成するだけinstanceofです...

私は正直に instanceof に反対しています。この場合、それはまだ悪い習慣でしょうか?

プログラミングでは、常に悪い習慣はありません。すべては状況次第です。instanceofこの状況では、設計上必要なため、安全でないキャストを使用して実行できると思います。とにかく、instanceof演算子が言語に存在する場合は、それが使用されているためです。常に悪い習慣である場合、それは言語の一部として存在しませinstanceofん。これこれを参照してください。

私は実際にビジターパターンをシミュレートしようとしていましたが、ビジターパターンが機能するのは、関数呼び出し中に「受け入れられる」パラメーターが正しいタイプになる二重ディスパッチのためです。特に、visitor.accept(this)クラス A では、関数 visitor.accept(A o) が呼び出されます。

訪問者パターンの使用に関する短所については、2 番目のリンクを確認してください。

于 2013-08-09T14:14:18.977 に答える
2

Visitor デザイン パターンhttp://en.wikipedia.org/wiki/Visitor_patternを検討してください。A、B、C の変更が必要になりますが、それ以外の方法はありません。

于 2013-08-09T14:09:30.513 に答える
1

ここだけ使いinstanceofます。シンプルで明確です。

使用しないという厳しいルールinstanceofがあるわけではありません。難しいルールはありません:) をたくさん使用するinstanceofということは、コンパイラがより多くの作業を行うように変更できることを示している可能性があります。それが実際に行う価値があるかどうかは、ケースバイケースで検討する必要があります。あなたの場合、問題のクラスを変更できないと言っているので、それはオプションではありません。

于 2013-08-09T14:53:08.813 に答える
0

私の見解では、instanceof を使用するかどうかは問題ではありません。問題は、この状況によって得られる影響を最小限に抑える方法です。したがって、処理する操作がいくつかある場合は、ここでインスタンス アダプターをお勧めします。そうすれば、少なくともその複雑さがシステム全体に広がるのを避けることができます。

public abstract class Adapter {
  public abstract void print();

  public static Adapter wrap(Object o) {
    if (o instanceof A) {
      return new AAdapter();
    }
    if (o instanceof B) {
      return new BAdapter();
    }
    return new ObjectAdapter():
}

public class AAdapter {
  public void print() {
    System.out.printLn("A");
  }
}

次にループします。

for (Object o: things) {
  Adapter.wrap(o).print();
}

もちろん、メソッド名が示すように、アダプタにはラップされたオブジェクトへの参照があります。そうすれば、これらのクラスの直接変更に近いコーディング モデルを取得できます。

于 2013-08-09T14:51:30.143 に答える
0

上記の回答を読んだ後

私が提案できる1つの解決策は、使用しo.getClassて続行してオブジェクトタイプをチェックすることです

ただし、多くのより良い解決策が投稿されています。@krisna kishor shetty が言ったことに完全に同意します

于 2013-08-09T14:20:55.377 に答える
0

instanceof を使用せずに頭に浮かぶのは、次のとおりです。

  • それらすべてに共通のインターフェースを使用して、共通のメソッドを共有します。

コード:

public interface YourInterface {
    public void doStuff();
}

public class A implements YourInterface {
    @Override
    public doStuff() {
        System.out.print("A");
    }
}

public class B implements YourInterface {
 @Override
    public doStuff() {
        System.out.print("A");
    }
}

List<YourInterface> list = new ArrayList<YourInterface>();
    list.add(new A());
    list.add(new B());

for(YourInterface e: list)
{
    e.doStuff();
}        
  • あなたが持っているすべてのタイプによって実装される抽象メソッドを宣言する Enum を使用します。

コード:

public enum YourEnum { 
    TYPE1 {
    @Override
    public void doStuff() {
        System.out.print("Type 1"); 
    },

    TYPE2 {
    @Override
    public void doStuff() {
        System.out.print("Type 2");         
    };

    public abstract void doStuff();
}

List<YourEnum> list = new ArrayList<YourEnum>();
    list.add(YourEnum.TYPE1);
    list.add(YourEnum.TYPE2);

for(YourEnum e: list)
{
    e.doStuff();
}        
于 2013-08-09T14:19:38.333 に答える
0
    package com.ank.says;
    import java.util.ArrayList;
    import java.util.List;

    class Base{
        public void print(){
            System.out.println("Base");
        }

    }

    class A extends Base{
        @Override
        public void print() {
            System.out.println("A");
        }
    }

    class B extends Base{
        @Override
        public void print(){
            System.out.println("B");
        }
    }

    class C extends Base{
        @Override
        public void print(){
            System.out.println("C");
        }
    }



    public class TestPlayGround {

        public static void main(String[] args) throws ParseException {
              List<Base> list = new ArrayList<Base>();
                list.add(new A());
                list.add(new B());
                list.add(new C());
                list.add(new Base());

                TestPlayGround tester = new TestPlayGround();

                for(Base o: list)
                {
                    o.print();
                }

        }


    }

出力 : - A B C ベース

于 2013-08-09T14:09:22.953 に答える