泛型调用构造函数

时间:2009-11-06 03:46:35

标签: java

我正在尝试做一些我通常不会做的事情,这有点奇怪,但我想让它发挥作用。基本上我有一个工厂必须通过使用不同类型的数据调用构造函数来创建对象(A和B在下面的代码中采用不同的类型)。我似乎已经让我的自我陷入了泛型路线(我确实需要代码作为编译时类型安全)。我不反对以不同的方式编写代码(如果可能的话,我想保留工厂的想法,我不想添加强制转换 - 所以“data”参数不能是“对象”)。

有关如何使用泛型修复代码的任何想法或其他符合我要求的方法吗?

(从技术上讲,这是作业,但我是教练尝试新的东西......所以这不是真正的功课: - )

public class Main2
{
    public static void main(String[] args) 
    {
        X<?> x;

        x = XFactory.makeX(0, "Hello");
        x.foo();

        x = XFactory.makeX(1, Integer.valueOf(42));
        x.foo();
    }

}

class XFactory
{
    public static <T> X<T> makeX(final int i,
                                 final T   data)
    {
        final X<T> x;

        if(i == 0)
        {
            // compiler error: cannot find symbol constructor A(T)
            x = new A(data);
        }
        else
        {
            // compiler error: cannot find symbol constructor B(T)
            x = new B(data);
        }

        return (x);
    }
}

interface X<T>
{
    void foo();
}

class A
    implements X<String>
{
    A(final String s)
    {
    }

    public void foo()
    {
        System.out.println("A.foo");
    }
}

class B
    implements X<Integer>
{
    B(final Integer i)
    {
    }

    public void foo()
    {
        System.out.println("B.foo");
    }
}

4 个答案:

答案 0 :(得分:1)

我不认为没有施法你可以做的事情。

使用强制转换,您有两个选项

if(i == 0)
        {
            x = new A((Integer)data);
        }
        else
        {
            x = new B((String)data);
     }
}

class A
    implements X<String>
{
    A(final Object s)
    {
    }
}

...

class B
    implements X<Integer>
{
    B(final Object i)
    {
    }
}

答案 1 :(得分:1)

在保持静态类型安全和懒惰构造的同时,你可能得到的最接近的东西是:

public static void main(String[] args) {
    X<?> x;

    x = aFactory("Hello").makeX();
    x.foo();

    x = bFactory(42).makeX();
    x.foo();
}

private static XFactory aFactory(final String value) {
    return new XFactory() { public X<?> makeX() {
        return new A(value);
    }};
}

public static XFactory bFactory(final Integer value) {
    return new XFactory() { public X<?> makeX() {
        return new B(value);
    }};
}

interface XFactory() {
     X<?> makeX();
}

因此,我们创建了一个抽象工厂的实例,该实例使用适当的参数创建适当的实例。作为工厂,该产品仅按需建造。

显然必须要付出一些代价。你期望XFactory.makeX(1, "Hello")做什么?

答案 2 :(得分:1)

我没有办法让它发挥作用。我真的不认为它应该工作。调用你的makeX()函数时,调用代码需要知道哪个整数参数对应于要传入的数据类型.IOW,你的抽象首先是非常漏洞的,你真正实现的是一个基本的多态的形式,你也可以使用方法重载,即:

X makeX(String data) {
  return new A(data);
}

X makeX(Integer data) {
  return new B(data);
}

当然,这是一个玩具问题。使其工作的一种方法是使客户端了解实现类并添加通过反射实例化的Class<T>参数。但我想这会破坏目的。

答案 3 :(得分:0)

如果没有施法,这是不可能的。正如我在其他地方所说的那样 - 仿制药不会消除铸造的需要,但它们意味着你可以在一个地方完成所有的铸造。

在您描述的设置中,工厂方法正是所有引擎盖工作发生的地方。这是你的代码告诉编译器的地方“我知道不知道这些类型是什么,但做,所以放松。

如果i == 1,那么你的工厂方法完全合法,那么数据必须是Integer类型,并用cast来检查/强制执行。