2016-01-21 6 views
0

Я изучаю дженерики в java и сталкивался с этой проблемой.Передача ссылочного типа в качестве параметра и использование дженериков

У меня есть интерфейс погоды. EarthQuake и VirginiaWeather - это два класса, реализующих интерфейс Weather. Оба этих класса имеют статический метод - "parseData", которые анализируют данные из подачи атома. Метод getFeeds в классе Main имеет параметр "String type", который я использую, чтобы узнать, какой метод класса я должен назвать. Может кто-нибудь, пожалуйста, помогите мне понять, можно ли использовать дженерики, чтобы сделать код немного чище. Могу ли я передать тип класса в качестве аргумента метода и использовать этот тип класса для вызова метода parseData в соответствующем классе. я пытался сделать list.add(T.parseData((Element) nl.item(i))); но получил:

Метод parseData (Element) не определено для типа T

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; 
} 

} 
+2

'тип ==«Землетрясения»' EUH, что это не хорошо –

+0

Что RC означает, что вы должны сравнивать объекты с помощью 'Equals()' - и строки являются объектами , – Thomas

+0

Java Generics довольно странно в том, что параметры типа фактически не связаны с классом, поэтому вы видите такие вещи, как JAXB, с помощью java.lang.Class, а также типа Generic. Прагматический подход заключается в определении интерфейса, который преобразует текст в элемент; эзотерика должна использовать отражение, чтобы получить метод класса из класса и вызвать его. – Mark

ответ

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. Ваша программа будет очень медленной, если список большой.

+0

Спасибо, если использовать NodeList.item (i) будет медленным, можете ли вы предложить альтернативный метод –

+0

@BKVP Google «DOM против SAX». Вы используете DOM. –

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); 

Это могло бы быть более полезным в долгосрочной перспективе иметь класс фабрики, который управляет синтаксический, вместо объединения представления данных и анализа в том же классе.

0

Вы можете использовать типизированный класс.

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

А другой класс

public class EarthQuake implements Weather<EarthQuake> { 

    } 
Смежные вопросы