使Java类具有通用性,但仅限于两种或三种类型

时间:2014-05-18 12:54:16

标签: java generics

(我很惊讶不能在stackoverflow上找到这个问题,我只能通过一切手段指出重复的... ...

这是一个玩具类,它返回与你放入的相反的玩具类。目前它适用于整数,但只需要非常小的更改就可以使用String。

public class Mirror {

  int value;

  public int get() {
    return reverse(value);
  }

  private int reverse(int value2) {
    String valueString = value + "";
    String newString = reverse(valueString);
    return Integer.parseInt(newString);
  }

  private String reverse(String valueString) {
    String newString = "";
    for (char c : valueString.toCharArray()) {
      newString = c + newString;
    }
    return newString;
  }

  public void set(int value) {
    this.value = value;
  }

}

我想做的是使该类具有通用性,但仅限于两种或三种可能的类型。所以我想写的是:

public class Mirror<X, where X is one of Integer, String, or MagicValue {

X value

public X get(){
[...]

正确的语法是什么?我的Google-fu让我失望...... :(

编辑:它似乎不是一个正确的语法,似乎无法完成,所以我的主要问题是:为什么?这似乎是人们在创建类真正泛型之前可能想要做的事情......

编辑编辑:管理今天与一些同事一起解决原因,所以在下面添加了相关原因。

7 个答案:

答案 0 :(得分:8)

不幸的是,java不直接提供这样的功能。不过,我建议你做以下工作:

使用私有构造函数和3个静态工厂方法创建参数化类Mirror,这些方法使用特定参数创建Mirror实例:

public class Mirror<T> {
    private T value
    private Mirror(T value) {
        this.value = value;
    }

    public static Mirror<Integer> integerMirror(Integer value) {
        return new Mirror(value);
    } 

    public static Mirror<String> stringMirror(String value) {
        return new Mirror(value);
    } 

    public static Mirror<MagicValue> magicMirror(MagicValue value) {
        return new Mirror(value);
    } 
}

修改的 显然,你可以(并且可能应该)将类Mirror与其创建分开,例如将工厂方法放在单独的类MirrorFactory中。在这种情况下,构造函数应该受到包保护。

如果您想支持大量但数量有限的类,则只能实现一种通用工厂方法

    public static <T> Mirror<T> createMirror(T value) {
        checkTypeSupported(value);
        return new Mirror(value);
    } 

方法checkTypeSupported(value);可能会使用某种元数据(例如属性,JSON等文件)来获取支持的类型。但在这种情况下,您将无法享受编译时验证。

其他解决方案是要求所有受支持的类型扩展某些基类或实现接口:

public class Mirror<T extends MyInterface> {}

但是这个解决方案似乎与您的要求不符,因为您需要IntegerStringMagicValue

答案 1 :(得分:3)

各种方法来做你需要的......这是另一种选择。没有吸气剂或吸气剂。
要处理的每种类型的一个Mirror实例。一个reverse()方法。 根据需要调整。添加错误检查/处理。

public class Mirror<T> {

public T reverse(final T value) {
    T result = null;
    while (true) {
        if (value instanceof String) {
            System.out.println("Do for String");
            result = value;
            break;
        }
        if (value instanceof Integer) {
            System.out.println("Do for Integer");
            result = value;
            break;
        }
        if (value instanceof JFrame) {
            System.out.println("Do for JFrame");
            result = value;
            break;
        }
        throw new RuntimeException("ProgramCheck: Missing handler for type " + value.getClass().getSimpleName());
    }
    return result;
}

测试仪:

    final Mirror<String> testerString = new Mirror<>();
    testerString.reverse("string");

    final Mirror<Integer> testerInteger = new Mirror<>();
    testerInteger.reverse(41);
    testerInteger.reverse(42);
    testerInteger.reverse(43);

    final Mirror<JFrame> testerJFrame = new Mirror<>();
    testerJFrame.reverse(new JFrame());

结果:

Do for String
Do for Integer
Do for Integer
Do for Integer
Do for JFrame

答案 2 :(得分:2)

另一种方法是接受这样一个事实:你无法控制String / Integer的类型层次结构,并创建一个接口,为你可以控制的类提供一个通用类型

public int reverse(int value) {
    return Integer.valueOf(new StringBuilder(value + "").reverse()
            .toString());
}

public String reverse(String value) {
    return new StringBuilder(value + "").reverse().toString();
}

public <T extends Reversible> T reverse(T value) {
    value.reverse();
    return value;
}

public interface Reversible {
    public void reverse();
}

答案 3 :(得分:2)

如果你只想要一个Mirror类的一个实例......使用泛型方法。

public class Mirror {

public <T> T reverse(final T value) {
    T result = null;
    while (true) {
        if (value instanceof String) {
            System.out.println("Do for String");
            result = value;
            break;
        }
        if (value instanceof Integer) {
            System.out.println("Do for Integer");
            result = value;
            break;
        }
        if (value instanceof JFrame) {
            System.out.println("Do for JFrame");
            result = value;
            break;
        }
        throw new RuntimeException("ProgramCheck: Missing handler for type " + value.getClass().getSimpleName());
    }
    return result;
}

测试器:

    final Mirror tester = new Mirror();
    String s = tester.reverse("string");
    Integer i41 = tester.reverse(41);
    Integer i42 = tester.reverse(42);
    Integer i43 = tester.reverse(43);
    JFrame j = tester.reverse(new JFrame());

结果:

Do for String
Do for Integer
Do for Integer
Do for Integer
Do for JFrame

答案 4 :(得分:1)

您不能将通用参数绑定到值范围。但是,您可以以编程方式对其进行限制:

public abstract class AbstractMirror<T> {

    T value;

    protected AbstractMirror(Class<T> clazz) {
        if (clazz != Integer.class && clazz != String.class && clazz != MagicValue.class)
            throw new IllegalArgumentException();
    }

    public abstract T get();

    protected abstract T reverse(T value);

}

答案 5 :(得分:1)

您可以使用所谓的“见证”类型来使编译器执行您想要的操作。

public interface Reversible< T > {
    public static final class IntReversible implements Reversible< Integer > {}
    public static final class StringReversible implements Reversible< String > {}
    public static final class MagicReversible implements Reversible< MagicValue > {}
}

public abstract class Mirror< T, R extends Reversible< T > > {
    // ...
}

public class IntMirror extends Mirror< Integer, IntReversible > {
    // ...
}

然而,你的例子没有任何意义的原因是因为你在这种情况下使用泛型几乎没有任何收获。什么算法可以反转整数或字符串或MagicValue而不诉诸糟糕的运行时类型检查和转换?代码将是所有三个反向算法,包含一个可怕的if - 梯形图。

答案 6 :(得分:0)

所以这是为什么(在工作中解决)

泛型总是来自一个子类,虽然它看起来像

Public class Thing<T> {}

将允许其中的任何类型,它的真正含义是它将允许Object的任何子类型。即

Public class Thing<T extends Object> {}

这有效地作为继承工作,事实上,the Oracle Website向我们展示了当语法糖被删除时发生的事情:

  

在以下示例中,通用Node类使用有界类型   参数:

public class Node<T extends Comparable<T>> {

    private T data;
    private Node<T> next;

    public Node(T data, Node<T> next) {
        this.data = data;
        this.next = next;
    }

    public T getData() { return data; }
    // ...
}
     

Java编译器用第一个替换有界类型参数T.   绑定类,可比较:

public class Node {

    private Comparable data;
    private Node next;

    public Node(Comparable data, Node next) {
        this.data = data;
        this.next = next;
    }

    public Comparable getData() { return data; }
    // ...
}

...所以答案结果证明你不能以这种方式限制类型的原因是因为它有效地变成了多重继承,这是令人讨厌的,我很乐意避免....