我想要访问一个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);
是一种方式,但是在调用函数时我不想使用任何类名。
答案 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();
}