0

我是新来的,所以如果我不遵守标准礼仪,我会提前道歉。

我想知道如何使用 ArrayLists 从子类中获取数据。

import java.io.*;
import java.util.*;

public class MyProgrammingLab {

    public static void main(String[] args){
        ArrayList<Test> testArray = new ArrayList<>();

        testArray.add(new Test("First"));
        testArray.add(new SubTest("Last"));

        System.out.println(testArray.get(0).getFirstName());
        System.out.println(testArray.get(1).getLastName());
    }
}

public class Test {
    private String firstName;

    public Test(){
    }

    public Test(String firstName){
        this.firstName = firstName;
    }

    public String getFirstName() {
        return firstName;
    }
}

public class SubTest extends Test{
    private String lastName;

    public SubTest(){
        super();
    }

    public SubTest(String lastName){
        this.lastName = lastName;
    }


    public String getLastName(){
        return lastName;
    }
}

我的主要“System.out.println(test.Array.get(1).getLastName());”中的行 向我抛出错误,我不知道为什么?

在我的主程序中,我将使用大小大于 1 的 ArrayList。

先感谢您!

4

5 回答 5

4

我建议在使用我即将提出的解决方案时非常谨慎,但是:

System.out.println(((SubTest) testArray.get(1)).getLastName());

但是,只有在您确定位置 1 的元素是 SubTest 时才执行此操作,否则您将得到一个ClassCastException.

如果你不确定,你应该检查一下。

Test whatIGot = testArray.get(1);
if(whatIGot instanceof SubTest) {
   SubTest whatIActuallyGot = (SubTest)whatIGot;
   System.out.println(whatIActuallyGot.getLastName());
}

一般来说,当你有一个超类类型的变量时,你应该避免依赖子类的属性。这样做是一种代码味道,可能是由糟糕的设计引起的。

正确的解决方案是问自己以下两个问题:

  • 您绝对确定getLastName属于SubTest而不属于Test吗?如果getLastName()Test,那将完全解决问题。
  • 你真的需要getLastName从一个testArray元素访问吗?

如果getLastName() 确实属于Test(所有实例Test都有一些姓氏),但您没有很好的默认值,那么请考虑Test使用抽象方法创建一个抽象类getLastName。请注意,这会使new Test()停止工作。

于 2012-11-26T23:34:11.853 回答
1

您的列表被声明为Arraylist<Test>. 这意味着它是灵活的:您可以将任何实例Test(包括子类的实例)放入其中。

这种灵活性带来了一个限制:稍后,当您再次取出一个元素时,您只能知道该元素是一个实例Test- 正如您所发现的,如果没有特定的类型检查,您无法判断该条目是否是一个Test或一个SubTest。(考虑一下如果列表必须返回条目的确切类型,你甚至会如何编写get方法ArrayList——方法的返回类型会根据传入的索引而改变!)

如果您需要这种灵活性(并且您的示例代码建议您这样做,因为您还存储了的实例TestSubTest,您最简单的选择是检查类型和强制转换:

Test secondEntry = testArray.get(1);
if (secondEntry instanceof SubTest) {
    System.out.println(((SubTest) secondEntry).getLastName());
}

尽管正如其他人所指出的那样,这在某种程度上违背了使用泛型的意义。

其他替代方案包括:

  • 将您的getLastName方法向上移动到父类,然后在子类中覆盖它(如果父类具有此方法有意义);
  • 使用基于类型的调度来实现策略模式。

这看起来像:

import java.io.*;
import java.util.*;

public class MyProgrammingLab {

    public static void main(String[] args) {
        ArrayList<Test> testArray = new ArrayList<Test>();

        testArray.add(new Test("First"));
        testArray.add(new SubTest("Last"));

        for (Test aTest : testArray) {
            emit(aTest);
        }

    }

    public static void emit(Test aTest) {
        if (aTest instanceof SubTest) {
            System.out.println(((SubTest) aTest).getLastName());
        } else {
            System.out.println(aTest.getFirstName());
        }
    }
}
于 2012-11-26T23:47:00.377 回答
0

查看Java 继承教程可能会有所帮助。

当您声明一个 ArrayList 时,您明确表示您期望一个完全是 Test. 您可以使用泛型来包含 Test 和任何扩展它的东西,这就是ArrayList<? extends Test>它的作用。

虽然这可以解决您的确切问题,但您应该知道扩展具体类是糟糕的设计,您应该使用中间实例变量(例如Test test1 = testArray.get(0))以避免违反Demeter 定律

于 2012-11-26T23:41:53.917 回答
0

testArray.get(1) is returning type Test, not SubTest. If you're absolutely sure it's a SubTest (you can do instanceof to check), then you can use

System.out.println(((SubTest) testArray.get(1)).getLastName());
于 2012-11-26T23:37:14.210 回答
0

Because you declared it like this:

ArrayList<Test> testArray;

Java only knows that the ArrayList contains Test objects. Therefore, it does not know about any methods in the child class, even if the object has that method.

If you add this:

public String getLastName(){
    return ""; // do nothing
}

To your Test class, it will compile and work as you expect, because now Test objects have the getLastName() method.

Other solutions suggest casting, but I strongly recommend against casting here because that defeats the purpose of using generics. You don't want to be in situations where you cast and then handle ClassCastExceptions. The point of generics is to elegantly handle situations exactly like yours.

于 2012-11-26T23:38:01.867 回答