1

我有一个经常用泛型类型的参数调用的方法,我希望它的行为根据参数的特定子类而有所不同。例如,下面的代码:

public class Foo {

    public static void fooMethod(Foo f) {
        System.out.println("fooMethod Foo");
    }

    public static void fooMethod(Bar b) {
        System.out.println("fooMethod Bar");
    }

    public static void main (String[] args) {

        Foo f = new Foo();
        Bar b = new Bar();

        Baz<Bar> bz1 = new Baz<>();
        bz1.setT(b);
        Baz<Foo> bz2 = new Baz<>();
        bz2.setT(f);

        System.out.println("calling fooMethod with foo");
        fooMethod(f);
        System.out.println("calling fooMethod with bar");
        fooMethod(b);
        System.out.println("calling bazMethod with foo");
        bz2.bazMethod();
        System.out.println("calling bazMethod with bar");
        bz1.bazMethod();
    }

    private static class Bar extends Foo {

    }

    private static class Baz<T extends Foo> {

        private T t;

        public void setT(T t) {
            this.t = t;
        }

        public void bazMethod() {
            Foo.fooMethod(this.t);
        }
    }
}

产生以下输出:

calling fooMethod with foo
fooMethod Foo
calling fooMethod with bar
fooMethod Bar
calling bazMethod with foo
fooMethod Foo
calling bazMethod with bar
fooMethod Foo

我原以为它会在第 4 行调用 bar 方法,因为在这种情况下 T 是 bar ,但它始终将其识别为父类并提供默认行为。

我曾考虑过在方法中对 instanceOf 进行大量调用,但这感觉有点 hacky。我想到的另一个解决方案是在每个调用正确方法的子类中重写一个抽象方法,但这似乎也很hacky。有没有正确的方法来做到这一点?或者,如果我处理这一切都错了,有没有更好的方法来处理这种情况?

4

1 回答 1

2

您在这里处理的问题是类型擦除。您可以在 Oracle 网站上详细了解它。

本质上,您的 Baz 对象必须将所有输入视为 Foo 变量,因为它不知道输入可能具有的任何附加功能。要解决此问题,您可以使 Foo 和 Bar 具有自己的非静态版本,fooMethod()以便 BarfooMethod()覆盖 Foo 类fooMethod()

public class Foo {

    public void fooMethod() {
        System.out.println("fooMethod Foo");
    }

    public static void main (String[] args) {

        Foo f = new Foo();
        Bar b = new Bar();

        Baz<Bar> bz1 = new Baz<>();
        bz1.setT(b);
        Baz<Foo> bz2 = new Baz<>();
        bz2.setT(f);

        System.out.println("calling fooMethod with foo");
        f.fooMethod();
        System.out.println("calling fooMethod with bar");
        b.fooMethod();
        System.out.println("calling bazMethod with foo");
        bz2.bazMethod();
        System.out.println("calling bazMethod with bar");
        bz1.bazMethod();
    }

    private static class Bar extends Foo {

        public void fooMethod() {
            System.out.println("fooMethod Bar");
        }
    }

    private static class Baz<T extends Foo> {

        private T t;

        public void setT(T t) {
            this.t = t;
        }

        public void bazMethod() {
            t.fooMethod();
        }
    }
}

运行这个的输出:

calling fooMethod with foo
fooMethod Foo
calling fooMethod with bar
fooMethod Bar
calling bazMethod with foo
fooMethod Foo
calling bazMethod with bar
fooMethod Bar
于 2019-08-15T07:14:23.123 回答