访问arraylist中的实例的功能

时间:2012-06-17 20:52:26

标签: java oop class

我想要访问一个arraylist中的实例的函数。 如果不使用实例的类名,有没有办法做到这一点?

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);是一种方式,但是在调用函数时我不想使用任何类名

6 个答案:

答案 0 :(得分:3)

是的 - 您需要使用 generics 和接口。

您目前需要“使用”类名的原因是Java是强类型的。除非对象的类型公开这样的方法,否则不能在对象上调用方法。就像现在一样,当你从List得到一些东西时,它可以是任何类型 - 所以Java编译器不能确定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);
}

答案 1 :(得分:2)

你要求的东西在Java中是不可能的,而不是没有反思。或者使用构建在其上的框架,就像表达式语言解析器一样。 Java是一种静态类型语言,编译器不会让你调用他看不到的方法。

您可以考虑的另一种选择是使用接口。

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

现在让两个实现实现它,你可以在不知道它是哪个类的情况下调用该方法。

答案 2 :(得分:2)

由于到目前为止所给出的答案仅涵盖解决方案,但没有解释为什么有效,我会用非常简单的话语告诉你幕后真正发生的事情:

该列表中可以有任意对象。这意味着,它可以是没有方法myFunction()的对象。

不,将类定义视为合同。如果您像这样生成一个类型为apple的新Object

Apple apple = new Apple(); 
你说的是“我想要一个新的对象,它遵循'apple'类型的所有约定,我希望它成为一个新的苹果”。 因此,编译器知道您的Apple类型必须具有该功能,因此您可以调用
apple.myFunction()
。 但是如果你说的话
Object o = new Apple();
你说的是“我想要一个符合'对象'类型的所有约定的新对象,我希望它成为一个苹果”。你可以这样做,因为所有类都隐含地执行java.lang.Object,所以新的Apple()也是一个新对象。 但是如果你想调用
o.myFunction()
那么编译器说“哎呀,不可能。”o遵守'Object'的所有约定,其他一切都是可选的。我在这里对一个对象的控制不包括一个名为myFunction的方法“。

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

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

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

现在,如果你创建了一个接口 Fruit ,它定义了一个方法myFunction并创建了子类Apple,Banane以及实现Fruit的东西。你可以创建一个类型为Fruit的List并在其中存储苹果和香蕉,并轻松调用list.get(x).myFunction(),因为该列表中的每个对象必须一个Friut,因此必须方法myFunction()。

答案 3 :(得分:1)

您需要使用泛型,以及abstract类或接口:

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

List<Fruit> list= new ArrayList<Fruit>();

答案 4 :(得分:1)

也许这不是最佳解决方案,但您可以将list.get(0)投射到apple

if (list.get(0) instanceof apple)
{
    ( (apple)list.get(0) ).myFunction(1);
}

答案 5 :(得分: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();
    }