Java中没有泛型参数的通用方法

doe*_*man 35 java generics

在C#中我可以这样做:

//This is C#
static T SomeMethod<T>() where T:new()
{
  Console.WriteLine("Typeof T: "+typeof(T));
  return new T();
}

//And call the method here
SomeMethod<SomeClassName>();
Run Code Online (Sandbox Code Playgroud)

但由于某种原因,我不能让它在Java中工作.

我想要做的是,在超类上创建一个静态方法,这样子类就可以转换为XML.

//This is Java, but doesn't work
public static T fromXml<T>(String xml) {
  try {
    JAXBContext context = JAXBContext.newInstance(T.class);
    Unmarshaller um = context.createUnmarshaller();
    return (T)um.unmarshal(new StringReader(xml));
  } catch (JAXBException je) {
    throw new RuntimeException("Error interpreting XML response", je);
  }
}

//Also the call doesn't work...
fromXml<SomeSubObject>("<xml/>");
Run Code Online (Sandbox Code Playgroud)

Tom*_*ine 52

public static <T> T fromXml(Class<T> clazz, String xml) {
Run Code Online (Sandbox Code Playgroud)

被称为:

Thing thing = fromXml(Thing.class, xml);
Run Code Online (Sandbox Code Playgroud)

或更明确地:

Thing thing = MyClass.<Thing>fromXml(Thing.class, xml);
Run Code Online (Sandbox Code Playgroud)

更令人困惑的是,您可以拥有构造函数,这些构造函数都构造泛型类型并且本身具有泛型参数.不记得语法,并且从未见过它在愤怒中使用过(无论如何,你最好使用静态创建方法).

演员表(T)是不安全的,你不能写T.class.因此,将T.class作为参数包含(同样JAXBContext.newInstance如此),如果类型错误则抛出相关的异常.

public static <T> T fromXml(Class<T> clazz, String xml) {
    try {
        JAXBContext context = JAXBContext.newInstance(clazz);
        Unmarshaller um = context.createUnmarshaller();
        Object obj = um.unmarshal(new StringReader(xml));
        try {
            return clazz.cast(obj);
        } catch (ClassCastException exc) {
             throw new RelevantException(
                 "Expected class "+clazz+
                  " but was "+obj.getClass()
             );
        }
    } catch (JAXBException exc) {
        throw new RelevantException(
            "Error unmarshalling XML response",
            exc
         );
    }
}
Run Code Online (Sandbox Code Playgroud)

我相信JAXB的下一个版本(在6u14?中)对于类中的JAXB这类事情有一些方便的方法.

  • 甚至不会编译...你不能写T.class (2认同)
  • 我并不是说在方法中写T.class.我说是一个argumnet.并且调用函数可能没有(或者可能将它作为argumnet传递). (2认同)

Avi*_*Avi 5

在Java中,泛型是仅编译时的数据,在运行时会丢失.所以,如果你调用这样的方法,JVM就无法知道它是什么T.class.解决此问题的常用方法是将类实例对象作为参数传递给方法,如下所示:

public static <T> T fromXml(Class<T> clazz, String xml) {
  try {
    JAXBContext context = JAXBContext.newInstance(clazz);
    Unmarshaller um = context.createUnmarshaller();
    return (T)um.unmarshal(new StringReader(xml));
  } catch (JAXBException je) {
    throw new RuntimeException("Error interpreting XML response", je);
  }
}

fromXml(SomeSubObject.class, "<xml/>");
Run Code Online (Sandbox Code Playgroud)


spa*_*y21 5

像 Java 这样的方法有这样的Collections.emptySet()签名:

public static final <T> Set<T> emptySet()
Run Code Online (Sandbox Code Playgroud)

并被这样调用:

Set<Foo> foos = Collections.<Foo>emptySet();
Run Code Online (Sandbox Code Playgroud)

Mockito 的anyObject()方法是另一个例子。我个人认为这两种语法都不是非常棒。将类型作为方法参数传入是可行的,但总是感觉很笨拙。以emptySet()看起来更简洁的方式提供参数,但方法允许指定类型并不总是很明显。