从java方法返回不同的类型

时间:2017-10-24 04:42:37

标签: java generics generic-programming

假设我有一个java基类:

class base {
    public Class<? extends base> type;
    // ...
}

type存储从base

继承的类的classtype

还有另一个类将base个对象存储在容器中,它还有一个get方法,它返回存储在该容器中的对象:

class container {
    private Vector<base> v;
    //...
    public <something here> get(int i){
        base b=v.get(i);
        return b.type.cast(b);
    }

如何实现这样一个函数(container.get),它在返回之前将对象强制转换为正确的类型? 能够以级联风格编程会很高兴:

JSONObject o;
//...
o.get("nestedObject").get("array").get(3);

4 个答案:

答案 0 :(得分:1)

  

type存储从base

继承的类的classtype

这相当于this.getClass()

  

如何实现这样一个函数(container.get),它在返回之前将对象强制转换为正确的类型?

理论上不可能。在编译和发布代码之后,人们将创建更多的子类并将其放入容器中。这就是拥有基类的目的 - 因此代码库的其他部分只需要使用单个接口/概念。

所以基本上你想写的只是一些通用的容器代码。

interface Container<T extends Base> {
    public T get(int i);
}

真实问题是容器如何容纳一组已知子类?只需使用不同的方法名称。 Gson做到了。

public class Container {
    public Base get(int i) { ... }
    public SubType1 getAsSubType1(int i) { ... }
    public SubType2 getAsSubType2(int i) { ... }
}

您也可以将自定义强制转换方法添加到Base

答案 1 :(得分:1)

你可能误解了&#34;演员&#34;在Java中。除了涉及原始类型的强制转换(例如将int投射到float)之外,强制转换根本不会更改对象。

您的一个实例变量是

private Vector<Base> v;

(请使用Java约定并使用大写字母开始类名。我已将base更改为Base以设置一个好示例。)

您在此向量中放置的对象可以是Base 类型或 Base的任何子类。构造对象时,对象的类型是固定的。假设Base有三个子类Child1Child2Child3。可以使用new Child1(...)new Child2(...)new Child3(...)来构建这些对象。只要您说new Child1(...),就会有一个类型为Child1的对象,而您无法做任何改变。但由于Child1Base,您可以在Child1的任何地方使用Base,例如将其放入向量v。< / p>

强制转换只会使编译器以不同的方式查看变量。假设你说

Base x = v.get(i);

x(如果不为null)将是Base或子类的某个对象。 x的类型将是您用于构造对象的任何类型。现在,如果你说

Child1 y = (Child1)x;

如果xChild1,则y将是与x相同的对象的引用。但编译器会知道yChild1,您可以访问Child1中定义的新方法。 (如果x不是Child1,则会出现例外情况。)但重要的是要注意投射不会创建新对象并且不会更改任何东西。它只是告诉编译器以不同的方式查看变量或表达式。

鉴于此,你不能通过尝试编写一个返回&#34;变量&#34;的方法来获得任何东西。类型。你也可以写一下

public Base get(int i){
    return v.get(i);
}

它返回的对象可以是BaseChild1Child2等;它将与将对象放入向量时的对象类型相同。当您致电get时,如果您希望结果为Child1,则可以说

Child1 child = (Child1)container.get(n);

如果对象不是child1,则会抛出异常。或者您可以使用instanceof来检查自己:

Base child = container.get(n);
if (child instanceof Child1) {
    ...
}

如果这还不够好,你需要更清楚地解释你想要完成什么以及为什么这不会起作用。

更多信息:阅读完编辑后,您说要执行以下操作:

JSONObject o;
//...
o.get("nestedObject").get("array").get(3);

你不需要任何演员来完成这个任务。您需要的是一个抽象的JSONValue基类型,它表示可以从JSON解析器返回的任何类型的值。子类将是&#34; object&#34;,&#34; array&#34;以及您需要的任何标量类型(整数,字符串等)。 get将返回JSONValue。实际上,它将返回其他类型之一的对象,但编译器需要知道的是它返回JSONValue

现在JSONValue需要两个get方法,一个采用String,另一个采用intInteger。这些将是多态方法。说vJSONValue,你说v.get("array"):它实际调用的方法可能会因v的实际类型而有所不同。如果v是您的&#34;对象&#34;类型,它将调用您为对象类型定义的方法;如果v是整数类型,它将调用为整数类型定义的方法,依此类推。您想要的是get方法,该方法需要String查找JSON&#34;对象&#34;的字段。键入,并为其他一切抛出异常。类似地,对于采用整数参数的get方法,JSON&#34;数组的方法&#34; type将查找列表或其他内容,JSONValue的每个其他子类的方法都将抛出异常。不,#34;铸造&#34;需要这个。 Casting是一个编译时的概念。在所有方面,编译器只会知道它正在使用JSONValue。但是在运行时,对象的实际类型用于确定调用哪个方法,因此编译器不需要知道任何其他方法。

这是所有Java程序员需要知道的基本概念(现在也是Javascript,Python和几乎所有其他语言,尽管在Javascript和Python等解释语言中多态性的处理方式不同)。教程https://docs.oracle.com/javase/tutorial/java/IandI/index.html涵盖了此概念和相关概念。关于&#34; polymorphism&#34;可能有更好的Java教程。也在那里。

答案 2 :(得分:0)

你做不到。泛型并不真正以这种方式工作。在编译时无法知道对象的确切子类型。

这个b.type.cast(b);转换需要在方法public <something here> get(int i)的结果上进行,无论它在哪里调用。

如果您已经很好地设计了系统,那么就不需要将对象强制转换回确切的子类(如果有的话)。

否则,最好的办法是在需要时进行instanceof类型检查。

答案 3 :(得分:-3)

我认为你指的是泛型

class container<GenericType> {
    private Vector<GenericType> v;
    //...
    public GenericType get(int i){
        GenericType b=v.get(i);
        return b;
    }
}