将引用类型作为参数传递并使用泛型

时间:2016-01-21 17:28:13

标签: java generics

我正在学习java中的泛型并遇到了这个问题。

我有一个Weather界面。 EarthQuakeVirginiaWeather是实现Weather接口的两个类。这两个类都有一个静态方法 - "parseData",它解析来自atom feed的数据。 Main类中的getFeeds方法有一个参数"String type",我用它来找出哪个类&#39}。方法我应该打电话。 任何人都可以帮助我理解是否可以使用泛型来使代码更清洁。我可以将类类型作为参数传递给方法,并使用该类类型在相应的类中调用parseData方法。 我试着这样做 list.add(T.parseData((Element) nl.item(i))); 但得到了:

  

对于类型T

,方法parseData(Element)未定义
public class Main {

public static void main(String[] args) {
    List<EarthQuake> quakes = getFeeds("http://earthquake.usgs.gov/earthquakes/feed/v1.0/summary/all_hour.atom", "quakes");
    List<VirginiaWeather> weather = getFeeds("http://alerts.weather.gov/cap/va.php?x=0", "weather");
    //Get Earthquake data
    System.out.println("Earthquake data");
    for (EarthQuake e: quakes)
        System.out.printf("%s\t%s\t%f\t%s\n",(e.getDate()),e.getLocation(),e.getMagnitude(),e.getDetails());
    //Get Virginia weather data
    System.out.println("Virginia Weather");
    for (VirginiaWeather vw: weather)
        System.out.printf("%s\t%s\t%s\t%s\t%s\n",vw.getUpdated(),vw.getTitle(),vw.getEvent(),vw.getEffective(),vw.getExpires());
}


private static <T> List<T> getFeeds(String url, String type) {
    List<T> list = new ArrayList<>();
    try {
        URL usgsUrl = new URL(url);
        URLConnection urlConnection = usgsUrl.openConnection();
        HttpURLConnection httpConnection = (HttpURLConnection) urlConnection;
        int response = httpConnection.getResponseCode();

        if(response == HttpURLConnection.HTTP_OK)
        {
            InputStream in = httpConnection.getInputStream();

            DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
            DocumentBuilder db = dbf.newDocumentBuilder();

            Document document = db.parse(in);
            Element element = document.getDocumentElement();
            NodeList nl = element.getElementsByTagName("entry");

            if(nl != null && nl.getLength() > 0)
                for(int i =0 ; i<nl.getLength() ; i++)
                {
                    if(type.equals("quakes"))
                    {
                        list.add((T) EarthQuake.parseData((Element) nl.item(i)));
                    }
                    if(type.equals("weather"))
                    {
                        list.add((T) VirginiaWeather.parseData((Element) nl.item(i)));
                    }
                }
        }
    } catch (MalformedURLException e) {
        e.printStackTrace();
    } catch (IOException e) {
        e.printStackTrace();
    } catch (ParserConfigurationException e) {
        e.printStackTrace();
    } catch (SAXException e) {
        e.printStackTrace();
    }
    finally{

    }
    return list;
}

}

3 个答案:

答案 0 :(得分:2)

我会使用打字的工厂。首先创建一个界面:

interface WeatherDataFactory<T> {
    T parse(Element element);
}

然后编写具体的气象数据工厂:

class VirginiaWeatherDataFactory implements WeatherDataFactory<VirginiaWeather> {
    @Override
    public VirginiaWeather parse(final Element element) { ... }
}

然后您的getFeeds方法将如下所示:

private static <T> List<T> getFeeds(String url, WeatherDataFactory<T> factory) {
    ...
    if(nl != null && nl.getLength() > 0) {
        for(int i =0 ; i<nl.getLength() ; i++) {
            list.add(factory.parse(nl));
        }
    }
}

顺便说一下,NodeList#item(int)的大多数实现都像链表那样执行,因为必须遍历整个列表以获取元素 n 。如果列表很大,你的程序将会非常慢。

答案 1 :(得分:1)

为什么不使用Java 8的设施?

private static <T> List<T> getFeeds(String url, Function<Element, T> parser) { 
   // [..snip..]
   for(int i =0 ; i<nl.getLength() ; i++) {
        list.add(parser.call((Element) nl.item(i)));
   }
   // [..snip..]
 }

你这样使用它:

List<EarthQuakes> eq = getFeeds("http://....", EarthQuake::parseData);
List<VirginiaWeather> eq = getFeeds("http://....", VirginiaWeather::parseData);

从长远来看,拥有一个管理解析的工厂类可能更有用,而不是在同一个类中合并数据表示和解析。

答案 2 :(得分:0)

您可以使用键入的类。

 public interface Weather<T>(){
        private static <T> List<T> getFeeds(String url, String type);
} 

另一个班级

 public class EarthQuake implements Weather<EarthQuake> {

     }