2

问题

我正在尝试使用 Java 泛型来替换具有类似方法的类。我发现的所有示例都包含简单示例,但我不确定 Java 泛型是否打算以这种方式使用。

我有 2 个父类和 2 个具有几乎相同方法的子类。两个父类也派生自不同的类。最终,我希望能够使用一个代码块来创建和操作其中一个父类,然后是它的子类,而不需要大量的 switch 语句或其他具有重复代码的流控制。

这就是我的想法,尽管我还没有能够让它以这种方式工作,无论是语法,还是不是泛型的功能。

家长班

public class FooParent
{
    private FooChild fooChild;
    public FooChild getChild()
    {
        return fooChild;
    }
}

public class BarParent
{
    private BarChild barChild;
    public BarChild getChild()
    {
        return barChild;
    }
}

子班

public class FooChild
{
    public void print()
    {
        System.out.println("I'm a foo child");
    }
}

public class BarChild
{
    public void print()
    {
        System.out.println("I'm a bar child");
    }
}

泛型类

public class GenericParent<T>
{
    private T self;
    public GenericParent(T self)
    {
        this.self = self;
    }

    public GenericChild getChild()
    {
        return new GenericChild(self.getChild());
    }
}

public class GenericChild<T>
{
    private T self;
    public GenericChild(T self)
    {
        this.self = self;
    }

    public void print()
    {
        self.print();
    }
}

如何使用它们

public static void main(String args[])
{
    GenericParent parent;

    // Only the initialization of the parent variable needs specialized code
    switch(args[0])
    {
        case "foo":
            parent = new GenericParent(new FooParent());
        break;

        case "bar":
            parent = new GenericParent(new BarParent());
        break;
    }

    // From here on out, it's all generic
    parent.getChild().print();
}

用法和期望的输出

java genericExample foo
> I'm a foo child

java genericExample bar
> I'm a bar child

最后的问题

也许“孩子”和“父母”用词不当,因为我知道它们实际上并没有被继承,但最重要的是,一个类用某些方法返回它的“孩子”。所以这是一个问题的很多代码,实际上可能无法通过这种方式解决,但希望你能回答我这个问题:

  1. 这是Java泛型可以完成的事情吗?
  2. 如果没有,Java中是否有解决此问题的方法?

谢谢!

编辑

我无法编辑我的“Foo”和“Bar”课程。我的最终问题是:我可以在不使用公共父类的情况下将任一类的一个实例存储在单个变量中吗?

4

4 回答 4

3

I think you want polymorphism, not generics:

public class test {
    public class FooParent implements hasPrintableChildren
    {
        private FooChild fooChild;
        public FooChild getChild()
        {
            return fooChild;
        }
    }

    public class BarParent implements hasPrintableChildren
    {
        private BarChild barChild;
        public BarChild getChild()
        {
            return barChild;
        }
    }


    public class FooChild implements canPrint
    {
        public void print()
        {
            System.out.println("I'm a foo child");
        }
    }

    public class BarChild implements canPrint
    {
        public void print()
        {
            System.out.println("I'm a bar child");
        }
    }

    public interface hasPrintableChildren{
        public canPrint getChild();
    }
    public interface canPrint{
        public void print();
    }



    public static void main(String args[])
    {
        hasPrintableChildren parent;
        // Only the initialization of the parent variable needs specialized code
        switch(args[0])
        {
            case "foo":
                parent = new FooParent();
            break;

            case "bar":
                parent = new BarParent();
            break;
        }

        // From here on out, it's all generic
        parent.getChild().print();
    }
}

OP clarified that he would be interested in the reflection option:

    public static void main(String args[]) throws IllegalArgumentException, SecurityException, IllegalAccessException, InvocationTargetException, NoSuchMethodException
    {
        Object parent;
        // Only the initialization of the parent variable needs specialized code
        switch(args[0])
        {
            case "foo":
                parent = new FooParent();
            break;

            case "bar":
                parent = new BarParent();
            break;
        }

        // From here on out, it's all generic
        Object child = parent.getClass().getMethod("getChild").invoke(parent);
        child.getClass().getMethod("print").invoke(child);
    }

Note: I would not recommend this sort of hard coded reflection. Code like this generally stinks of a bigger design problem.

于 2014-05-27T17:42:10.807 回答
0

No. This is not usually something you would use Generics for, this is something you would use an Interface or an Abstract class for, and in your example, probably anonymous inner classes.

Here is an example that pretty much shows all that:

Main.java

public class Main {
    public static void main(String args[])
    {
        AbstractParent parent;
        // Only the initialization of the parent variable needs specialized code
        switch(args[0])
        {
            case "foo":
                parent = new FooParent();
                break;

            default:
                parent = new BarParent();
                break;
        }

        // From here on out, it's all generic
        parent.getChild().print();
    }
}

Child.java

public interface Child {
    void print();
}

AbstractParent.java

public abstract class AbstractParent {
    protected Child child;

    public Child getChild() {
        return child;
    }
}

BarParent.java

public class BarParent extends AbstractParent {
    public BarParent() {
        child = new Child() {
            @Override
            public void print() {
                System.out.println("I'm a bar child");
            }
        };
    }
}

FooParent.java

public class FooParent extends AbstractParent {
    public FooParent() {
        child = new Child() {
            @Override
            public void print() {
                System.out.println("I'm a foo child");
            }
        };
    }
}

With some of the new language features in Java 8, you can do even cooler things. But let's leave that for another time.

于 2014-05-27T17:54:24.260 回答
0

你的父母似乎是一个包装器,一个包装器是一个容器,所以的,它可能是可以从类型参数中受益的东西。

但是除了构造函数签名之外,我看不到任何类型参数(什么是self?没有界限,没有提示,没有任何东西......),所以在这里使用泛型类型对你没有任何好处。如果您感兴趣的方法返回 void 并声明一个空参数列表,那么引入类型参数是没有用的。

这里是指导:如果你的类中的方法会受益于有一个类型参数,即如果一个类型参数在任何方法返回类型或签名中有用,那么泛化你的类。否则,坚持你目前拥有的。

于 2014-05-27T17:39:34.540 回答
0

是的,泛型和多态性可以帮助您:

public class Foo {} // declared elsewhere


public class Bar {} // declared elsewhere


public abstract class GenericParent<T> {
    private T self;

    public GenericParent(T self) {
        this.self = self;
    }

    protected T getSelf() {
        return self;
    }

    public abstract GenericChild<T> getChild();
}


public class FooChild extends GenericChild<Foo> {
    public FooChild(Foo foo) {
        super(foo);
    }
}


public class BarChild extends GenericChild<Bar> {
    public BarChild(Bar bar) {
        super(bar);
    }
}


public class FooParent extends GenericParent<Foo> {

    public FooParent(Foo foo) {
        super(foo);
    }

    public FooParent() {
        this(new Foo()); 
    }

    @Override
    public GenericChild<Foo> getChild() {
        return new FooChild(getSelf());
    }
}


public class BarParent extends GenericParent<Bar> {

    public BarParent(Bar bar) {
        super(bar);
    }

    public BarParent() {
        this(new Bar());
    }

    @Override
    public GenericChild<Bar> getChild() {
        return new BarChild(getSelf());
    }
}

您还必须稍微更改您的主要方法:

public static void main(String args[]) {
    GenericParent<?> parent;

    // Only the initialization of the parent variable needs specialized code
    switch(args[0]) {
        case "foo":
            parent = new FooParent();
            break;

        case "bar":
            parent = new BarParent();
            break;
    }

    parent.getChild().print();
}
于 2014-05-27T18:08:02.473 回答