-2

配列リストにあるインスタンスの関数にアクセスしようとしています。インスタンスのクラス名を使用せずにそれを行う方法はありますか?

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

class apple {
    int price;

    public void myFunction(int iPrice)
    {
        price=iPrice;
    }
}

class orange {
    int price;

    public void myFunction(int iPrice)
    {
        price=iPrice;
    }
}

public class main {

    public static void main(String[] args) {
        List list= new ArrayList();

        //create 3 apple object to list
        list.add( new apple() );
        list.add( new apple() );
        list.add( new orange() );

        list.get(0).myFunction(1); /* Error: The method myFunction(int) is undefined for the type Object*/

    }
}

そんなこと知ってる; ((apple) list.get(0)).myFunction(1);方法ですが、関数の呼び出し中にクラス名を使用したくありません。

4

6 に答える 6

3

はい-ジェネリックスとインターフェースを使用する必要があります。

現時点でクラス名を「使用」する必要がある理由は、Javaが強く型付けされているためです。オブジェクトの型がそのようなメソッドを公開しない限り、オブジェクトのメソッドを呼び出すことはできません。現時点では、何かを取得するときは、どのタイプでもかまいません。そのため、Javaコンパイラーは、それがメソッドを持っているものであるListかどうかを確認できません。list.get(0)myFunction

したがって、リストに汎用パラメーターを使用して、追加できるオブジェクトのタイプを制限します。このように、オブジェクトを取得するとき、そのオブジェクトは既知のタイプであるため、適切なメソッドを呼び出すことができます。それで、あなたのリストはどのタイプのオブジェクトを保持していますか?まあ、それは「果物」ですが、あなたはまだこれの概念を持っていません。

したがって、「これらのメソッドを実装するもの」を記述するためにインターフェースを定義できます。次のように定義しましょう。

public interface Fruit {
    void myFunction(int iPrice);
}

これですべてです。クラスの定義を変更して、クラスが実際にこのインターフェイスを実装していることを宣言する必要があります(自動ではありません)。

class Apple implements Fruit {
    // rest as before
    // ...
}

と同じですOrange。 これで、リストが保持されていることを宣言できますFruits何かを取得したときに、それがであると確信できますFruit。そして、あなたはそれを呼び出すことができますmyFunction(int)

したがって、メインの方法では:

public static void main(String[] args) {
    List<Fruit> list= new ArrayList<Fruit>();

    //create 3 apple object to list
    list.add( new Apple() );
    list.add( new Apple() );
    list.add( new Orange() );

    list.get(0).myFunction(1);
}
于 2012-06-17T21:07:38.610 に答える
2

あなたが求めることは、Javaでは不可能です。または、式言語パーサーのように、その上に構築されたフレームワークを使用します。Javaは静的に型付けされた言語であり、コンパイラーは、彼が見ないメソッドを呼び出すことを許可しません。

検討できる代替案は、インターフェースの使用です。

public interface Fruit{
    void doSomething(int i);
}

ここで、両方の実装にそれを実装させ、どのクラスであるかを知らなくてもメソッドを呼び出すことができます。

于 2012-06-17T20:55:42.657 に答える
2

これまでに与えられた回答は解決策のみをカバーしており、それが機能する理由を説明していないため、舞台裏で実際に何が起こっているかを非常に簡単な言葉で説明します。

そのリストには任意のオブジェクトが存在する可能性があります。これは、メソッドのないオブジェクトである可能性があることを意味しますmyFunction()

いいえ、クラス定義をコントラクトと考えてください。次のようにタイプappleの新しいオブジェクトを生成すると

アップル アップル = 新しいアップル();
あなたは、「タイプ「リンゴ」のすべての規則に従う新しいオブジェクトが必要であり、それを新しいリンゴにしたい」と言っています。したがって、コンパイラは、Appleその関数が必要であることを認識しているため、呼び出すことができます
apple.myFunction()
. でも言ってるなら
オブジェクト o = 新しい Apple();
「「オブジェクト」タイプのすべての規則に従う新しいオブジェクトが必要で、それをリンゴにしたい」と言っているのです。すべてのクラスが暗黙的に java.lang.Object を拡張するため、これを行うことができます。つまり、new Apple() も新しいオブジェクトです。しかし、あなたが呼び出そうとしているなら
o.myFunction()
次に、コンパイラは「おっと、不可能です。「o」は「オブジェクト」のすべての規則に従い、他のすべてはオプションです。そして、オブジェクトに対してここにあるcontrctには、myFunctionという名前のメソッドが含まれていません」.

これで、リストでも同じことが起こります。オブジェクトのリストを作成しています。コンパイラは、このリストにオブジェクトがあることを確実に認識しているだけですが、他の仮定を行うことはできません。

ただし、 (Apple) を使用してキャストすることにより、コンパイラにこの特定のオブジェクトを Apple として処理させることができます。

これを解決する別の方法は、ジェネリックを使用することです。これは、new ArrayList<Apple>. この方法では、そのリストにリンゴのみを格納でき、list.get(x) は、Apple の標準に準拠することが知られているオブジェクトを返します。

ここで、メソッドを定義するインターフェイスFruitmyFunctionを作成し、サブクラス Apple、Banane など、Fruit を実装するものを作成するとします。タイプ Fruit の List を作成し、そこに Apple と Banana の両方を格納し、list.get(x).myFunction() を簡単に呼び出すことができます。これは、そのリスト内のすべてのオブジェクトがFriut でなけれならないため、メソッド myFunction(を持たなければならないためです。 )。

于 2012-06-17T21:30:20.787 に答える
1

abstractクラスまたはインターフェースと一緒にジェネリックを使用する必要があります。

abstract class Fruit {
    public abstract void myFunction(int price);
}

List<Fruit> list= new ArrayList<Fruit>();
于 2012-06-17T20:54:45.917 に答える
1

たぶんこれは最善の解決策ではありませんが、次のようにキャストできlist.get(0)ますapple

if (list.get(0) instanceof apple)
{
    ( (apple)list.get(0) ).myFunction(1);
}
于 2012-06-17T20:57:55.463 に答える
0

ジェネリックス/キャスティング/拡張抽象クラスFruitを本当に使用できない/使用したくない場合は、いつでもリフレクションを試すことができます:)

    List list = new ArrayList();

    // create 2 apple and 1 orange to list
    list.add(new apple());
    list.add(new apple());
    list.add(new orange());


    Object o=list.get(0);
    // if class of "o" object contains method "myFunction" we can call
    // it this way
    try {
        o.getClass().getDeclaredMethod("myFunction", int.class).invoke(o, 1);
    } catch (NoSuchMethodException | SecurityException
            | IllegalAccessException | IllegalArgumentException
            | InvocationTargetException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }
于 2012-06-17T21:14:15.067 に答える