-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 是强类型的。你不能调用对象的方法,除非对象的类型暴露了这样的方法。就目前而言,当你从 a 中得到一些东西时,List它可以是任何类型的——所以 Java 编译器不能确定它list.get(0)方法的东西myFunction

所以你使用泛型参数到列表中,来限制可以添加哪些类型的对象。这样,当您检索对象时,它是已知类型的,因此可以调用适当的方法。那么 - 您的列表包含什么类型的对象?嗯,它是“水果”,但你还没有这个概念。

所以你可以定义一个接口来描述“实现这些方法的东西”。让我们像这样定义它:

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

这里的所有都是它的。您需要更改类的定义以声明它们确实实现了此接口(它不是自动的):

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

和同样的Orange现在你可以声明你的列表FruitsFruit. 所以你可以调用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类型必须有那个函数,所以你可以调用
苹果.myFunction()
. 但是如果你说
对象 o = new Apple();
您是在说“我想要一个遵守所有‘对象’类型约定的新对象,并且我希望它是一个苹果”。您可以这样做,因为所有类都隐含地存在 java.lang.Object,所以 new Apple() 也是一个新对象。但是如果你想调用
o.myFunction()
然后编译器说“哎呀,不可能。'o'遵守'Object'的所有约定,其他一切都是可选的。我在这里为对象提供的合同不包括名为myFunction的方法”。

现在,您的列表也会发生同样的情况。您正在创建一个Objects列表。编译器只能确定此列表中有对象 - 但不能做出其他假设。

但是,您可以通过使用 (Apple) 强制编译器将此特定对象视为Apple。

解决这个问题的另一种方法是使用泛型,这意味着,通过创建一个new ArrayList<Apple>. 这样,您只能将苹果存储在该列表中,并且 list.get(x) 将返回一个已知符合 Apple 标准的对象。

现在,如果你创建一个接口Fruit来定义一个方法myFunction并创建子类 Apple、Banane 以及任何实现 Fruit 的东西。您可以创建一个 Fruit 类型的 List 并将 Apples 和 Bananas 存储在其中并轻松调用 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 回答