2016-05-28 52 views
0

注意:我真的不知道如何问我的问题,所以我的标题可能没有任何公正。如何通过ArrayList <SubClass> as ArrayList <BaseClass>

我开始写一个RSS解析器。我希望用户能够指定他们想要的信息,并且我的parseInnerXmlByTag方法将返回该类型的ArrayList。问题是不同的标签具有不同的属性,这意味着我将不得不为每种类型的标签(“项目”,“通道”,“条目”...)创建类别。所以我决定创建一个空的RSSElement类。然后我创建了一个扩展它的RSSItem类。所以我的parseInnerXmlByTag现在返回一个ArrayList < RSSElements>。 我的目标是让用户只调用一个方法来指定他们想要的信息。假设他们指定了“item”,该方法应该返回ArrayList < RSSItem>。

但是像这样的生产线将无法工作,因为这两种类型不techically有关系:

ArrayList<RSSElement> data = (method returning ArrayList<RSSItem>) 

我有麻烦缠绕我的头周围通配符和亚型,所以我在想,如果有人可以看看我到目前为止给我的想法。这里是我的代码

public class RSSParser { 
public static ArrayList<RSSElement> parseInnerXmlByTag(String in, String tag) 
     throws XmlPullParserException, IOException{ 
    ArrayList<RSSElement> data = new ArrayList<>(); 
    StringReader input = new StringReader(in); 
    try{ 
     XmlPullParser parser = Xml.newPullParser(); 
     parser.setInput(input); 
     parser.nextTag(); 
     data = readFeed(parser, tag); 
    } 
    finally { 
     input.close(); 
     return data; 
    } 
} 

/* 
Returns an ArrayList of parsed RSSElements specified by "tag" 
*/ 
private static ArrayList<RSSElement> readFeed(XmlPullParser parser, String tag) 
     throws XmlPullParserException, IOException{ 
    ArrayList<RSSElement> data = new ArrayList<>(); 
    int event = parser.getEventType(); 

    //Parse until input is consumed 
    while(event != XmlPullParser.END_DOCUMENT){ 
     switch (event){ 
      case XmlPullParser.START_TAG: 
       if(parser.getName().equalsIgnoreCase(tag)){ 
        RSSItem item = RSSItem.processItem(parser); 
        data.add(RSSItem.processItem(parser)); 
       } 
       break; 
     } 
     event = parser.next(); 
    } 
    return data; 
} 

public static abstract class RSSElement{ 
    //Private constructor prevents instantiation 
    private RSSElement(){} 
} 

public static class RSSItem extends RSSElement{ 
    String title = ""; 
    String description = ""; 
    public RSSItem(String t, String d){ 
     title = t; 
     description = d; 
    } 

    @Override 
    public String toString() {...} 

    /* 
    Parses an RSS item tag into a container RSSItem (ONLY GRABS TITLE RIGHT NOW) 
    */ 
    protected static RSSItem processItem(XmlPullParser parser) 
      throws XmlPullParserException, IOException{ 
     String currentTag = ""; 
     String title = ""; 
     /* 
      while end tag hasn't been reached yet: 
      reaching the end tag means parser.getEventType == END_TAG && parser.getName = tag 
     */ 
     while(!(parser.next() == XmlPullParser.END_TAG && parser.getName().equalsIgnoreCase("item"))){ 
      Log.i("rssparser", "process entry"); 
      if(parser.getEventType() == XmlPullParser.START_TAG){ 
       currentTag = parser.getName(); 
      } 
      else if(parser.getEventType() == XmlPullParser.TEXT && currentTag.equalsIgnoreCase("title")){ 
       title = parser.getText(); 
       break; 
      } 
     } 
     return new RSSItem(title, description); 
    } 
} 
} 

现在这段代码完成并返回ArrayList。另外我知道它是根据我的日志正确解析RSSItems。 但这里是我用它(又名原因,我在这里发帖)

   @Override 
       public void onResponse(String response){ 
        ArrayList<? extends RSSParser.RSSElement> items = null; 
        try { 
         items = RSSParser.parseInnerXmlByTag(response, "entry"); 
        }... 

        if(items != null) { 
         for(int i = 0; i < items.size(); i++){ 
          //****DOESNT WORK**** 
          redditOutputTextView.append(items.get(i).title + "\n"); 
         } 
        } 
        else redditOutputTextView.setText("Items null"); 
       } 

该行存在显然无法工作,因为它不知道它的RSSItems的数组。所以希望有人能够弄清楚我想要做什么并提出一些建议。

回答

2

能否请您替换下面的代码片段

//****WORKS**** 
Object obj=items.get(i); 
if(obj instanceof RSSItem){ 
    RSSItem rssItem = (RSSItem)obj; 
    redditOutputTextView.append(rssItem .title + "\n"); 
} 

和看到的结果?

+0

已修复它!那么这个和我注意到的事实的结合,我在一行中调用了processItem方法两次,可能创建了空对象。谢了哥们。 – sadelbrid

0

变化

ArrayList<? extends RSSParser.RSSElement> items = null; 

ArrayList<RSSParser.RSSElement> items = null; 

基本上,你现在有可以采取的RSSElement

任何子类的项目的旧是一个列表,可能只需要一个列表从RSSElement派生的某些类的项目,并且由于您使用了通配符,因此该类型可能是任何内容,因此编译器不知道。您可以拨打get并使用它,因为您知道元素的超类:RSSElement。请参阅this answer。通过下面的语句

//****DOESNT WORK**** 
redditOutputTextView.append(items.get(i).title + "\n"); 

+0

但是说我的方法返回ArrayList 并把它放在项目中,我将如何访问RSSItem属性? – sadelbrid

+0

您将最终需要检查事物的类型,因此要么执行instanceof树,要么创建抽象类的方法 –

0

您可以正餐返回乐趣这样的代码:

public static List<? extends Parent> test2(){ 
     List<Parent> parents = new ArrayList<Parent>(); 
     parents.add(new Son1()); 
     return parents; 
} 

,并获得名单如下:

List<? extends Parent> parents = test2(); 

和OBV,CLSS SON1()扩展父。

相关问题