java - 您可以将类型参数 <T> 限制为多个特定类吗

标签 java class generics bounded-wildcard

我正在编写一个泛型类Bla,类型参数为T

我可以限制T,以便只能使用我想支持的类吗?

public class Bla<T> {
    private T foo;
    private Class<T> fooClazz;
}

我希望 Bla 支持大多数原始类(Enum、Boolean、Integer、String……),以及我自己的接口(interface)Supportable

public interface Supportable {
    void doSpecific(Bla _bla);
}

Bla 有一个方法 do(),它处理支持的类,如果使用了我不支持的类,则抛出异常。

public void do() { 
    if (Enum.class.isAssignableFrom(fooClazz)) {
        // Do Enum specific code
    } else if (Boolean.class.isAssignableFrom(fooClazz)) {
        // Do Boolean specific code
    } else if (Integer.class.isAssignableFrom(fooClazz)) {
        // Do Integer specific code
    } else if (String.class.isAssignableFrom(fooClazz)) {
        // Do String specific code
    } else if (Supportable.class.isAssignableFrom(fooClazz)) {
        ((Supportable) foo).doSpecific();
    } else {
        throw new UnsupportedDataTypeException(fooClazz + "is not supported");
    }
}

我知道我能做到。

public class Bla<T extends Number> {}

所以只能使用扩展 Number 的类,但是有这样的东西吗?

public class Bla<T extends Number | String> {}

那么 String 也是可能的吗?

我能想到的唯一解决方案是为不同的类型制作多个 Bla 类。

public class BlaEnum {}
public class BlaBoolean {}
public class BlaInteger {}
public class BlaString {}
public class BlaSupportable {}

最佳答案

限制它的一种方法是使用静态重载工厂方法来构造对象。

public class Bla<T> {
    private final T foo;
    private final Class<T> fooClazz;

    private Bla(T foo, Class<T> fooClazz) { // Must be private
        this.foo = foo;
        this.fooClazz = fooClazz;
    }

    @SuppressWarnings("unchecked")
    public static <E extends Enum<E>> Bla<E> of(E foo) { // Caveat: Cannot handle null
        return new Bla<>(foo, (Class<E>) foo.getClass());
    }
    public static Bla<Boolean> of(Boolean foo) {
        return new Bla<>(foo, Boolean.class);
    }
    public static Bla<Integer> of(Integer foo) {
        return new Bla<>(foo, Integer.class);
    }
    public static Bla<String> of(String foo) {
        return new Bla<>(foo, String.class);
    }
    public static Bla<Supportable> of(Supportable foo) {
        return new Bla<>(foo, Supportable.class);
    }

    public void do() {
        // ...
    }

    // ...
}

它改变了调用者构造实例的方式,但实际上也简化了它,因为调用者不必传入 Class<T>。 ,例如

// With constructor (old way)
Bla<MyEnum> e2 = new Bla<>(MyEnum.A, MyEnum.class);
Bla<Boolean> b2 = new Bla<>(true, Boolean.class);
Bla<Integer> i2 = new Bla<>(42, Integer.class);
Bla<String> s2 = new Bla<>("", String.class);
Bla<Supportable> su2 = new Bla<>(supportable, Supportable.class);
// With static factory method (new way)
Bla<MyEnum> e1 = Bla.of(MyEnum.A);
Bla<Boolean> b1 = Bla.of(true);
Bla<Integer> i1 = Bla.of(42);
Bla<String> s1 = Bla.of("");
Bla<Supportable> su1 = Bla.of(supportable);
// Unsupported types are not allowed
Bla<Double> i1 = Bla.of(3.14); // Error: The method of(E) in the type Bla is not applicable for the arguments (double)

但是,而不是使用多路if do() 中的声明方法,它应该使用子类。子类对调用者是隐藏的,所以它没有外部差异,但它消除了多路的需要 if声明/switch声明:

public abstract class Bla<T> {
    private final T foo;
    private final Class<T> fooClazz;

    private Bla(T foo, Class<T> fooClazz) { // Must be private
        this.foo = foo;
        this.fooClazz = fooClazz;
    }

    @SuppressWarnings("unchecked")
    public static <E extends Enum<E>> Bla<E> of(E foo) { // Caveat: Cannot handle null
        return new Bla<>(foo, (Class<E>) foo.getClass()) {
            @Override
            public void do() {
                // Do Enum specific code
            }
        };
    }
    public static Bla<Boolean> of(Boolean foo) {
        return new Bla<>(foo, Boolean.class) {
            @Override
            public void do() {
                // Do Boolean specific code
            }
        };
    }
    public static Bla<Integer> of(Integer foo) {
        return new Bla<>(foo, Integer.class) {
            @Override
            public void do() {
                // Do Integer specific code
            }
        };
    }
    public static Bla<String> of(String foo) {
        return new Bla<>(foo, String.class) {
            @Override
            public void do() {
                // Do String specific code
            }
        };
    }
    public static Bla<Supportable> of(Supportable foo) {
        return new Bla<>(foo, Supportable.class) {
            @Override
            public void do() {
                foo.doSpecific(this);
            }
        };
    }

    public abstract void do(); // Is now abstract

    // ...
}

如果您愿意,您当然可以创建(私有(private))静态嵌套类或(包私有(private))顶级类,而不是匿名类。

使用子类允许 fooClass - 多种方法中的特定操作。如果您只有一种方法,则可以改用 lambda 表达式和/或方法引用:

public class Bla<T> {
    private final T foo;
    private final Class<T> fooClazz;
    private final Consumer<Bla<T>> doImpl;

    private Bla(T foo, Class<T> fooClazz, Consumer<Bla<T>> doImpl) { // Must be private
        this.foo = foo;
        this.fooClazz = fooClazz;
        this.doImpl = doImpl;
    }

    @SuppressWarnings("unchecked")
    public static <E extends Enum<E>> Bla<E> of(E foo) { // Caveat: Cannot handle null
        return new Bla<>(foo, (Class<E>) foo.getClass(), bla -> {
            // Do Enum specific code
        });
    }
    public static Bla<Boolean> of(Boolean foo) {
        return new Bla<>(foo, Boolean.class, bla -> {
            // Do Boolean specific code
        });
    }
    public static Bla<Integer> of(Integer foo) {
        return new Bla<>(foo, Integer.class, bla -> {
            // Do Integer specific code
        });
    }
    public static Bla<String> of(String foo) {
        return new Bla<>(foo, String.class, bla -> {
            // Do String specific code
        });
    }
    public static Bla<Supportable> of(Supportable foo) {
        return new Bla<>(foo, Supportable.class, foo::doSpecific);
    }

    public void do() {
        doImpl.accept(this);
    }

    // ...
}

关于java - 您可以将类型参数 <T> 限制为多个特定类吗,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/64525384/

相关文章:

java - 匹配不同卡片的正则表达式模式

java - Hibernate 标准获取 currentDate > startDate 且 < endDate 的所有行

python - 如何在没有无限递归错误的情况下实现 __getattribute__?

c++ - 不同的 C++ 类声明

c# - 如何定位具有相同跨度类的元素?

generics - Kotlin将类转换为Unit

generics - 在 kotlin 中编写 HashMap 的惯用方式

arrays - 在 swift 中使用通用数组

java - 在 Intellij-IDEA 中执行 svn 提交之前如何运行命令?

java - ERROR [main] master.HMasterCommandLine : Master exiting java. lang.RuntimeException: Master 构建失败