2010-02-03 53 views
3

列表让每个对象的属性列表时,我有一个看起来像这样几个对象:的Java代码,防止重复从对象

class PhoneNumber 
{ 
    String getNumber(); 
    String getExtension(); 
    DateTime getLastCalled(); 
} 
class Address 
{ 
    String getCity(); 
    string getState(); 
    int getZip(); 
} 

我希望能够采取的列表任何一个这些对象并获得特定属性的列表。如果我要为每个属性编写函数,这是一个简单的操作,但据我了解,很多次重复代码是不好的做法。

所以我希望能够为任一对象的财产做这样的事情:

List<Address> AddressList = getAddresses(); 
List<String> CityList = getListOfProperties(AddressList, Address.getCity /*<--Instruction as to what property to populate the returned list with */) 

我绞尽脑汁想尝试与泛型做到这一点。我甚至不确定这是否可行,但据我了解,使用Java编程语言可以完成很多神奇的事情。

回答

2

您可以使用泛型和实用程序类来完成此工作。我喜欢这个比使用反射好一点,因为你会在编译时检查你正在检索的属性是否存在(并且不会拼写错误等)。

首先进行实际转换的类。请注意,当我们调用getListOfProperties()时,我们将在匿名内部类中重写的抽象“get”方法。

public abstract class ListPropertyGetter<R,T> 
{ 
    /** Given a source object, returns some property of type R. */ 
    public abstract R get(T source); 

    /** Given a list of objects, use the "get" method to retrieve a single property 
     from every list item and return a List of those property values. */ 
    public final List<R> getListOfProperties(List<T> list) 
    { 
    List<R> ret = new ArrayList<R>(list.size()); 
    for(T source : list) 
    { 
     ret.add(get(source)); 
    } 
    return ret; 
    } 
} 

然后你就这样使用它。不是一个漂亮的班轮,但编译时检查善良:

List<PhoneNumber> phoneNumbers = new ArrayList<PhoneNumber>(); 
// add some PhoneNumbers to the list 
List<String> extensions = 
    new ListPropertyGetter<String, PhoneNumber>() 
    { 
    @Override 
    public String get(PhoneNumber source) 
    { 
     return source.getExtension(); 
    } 
    }.getListOfProperties(phoneNumbers); 
+0

男人,在我放弃并发布这个问题之前,我非常接近类似的东西。太感谢了! – 2010-02-03 21:27:41

+0

您的'ListPropertyGetter'类是通用的,足以对输入项执行任何操作以生成输出项,而不仅仅是获取属性。这通常被称为'map'(除了Linq,它被称为'Select')。 – 2010-02-03 22:15:12

2

您可以使用Introspector来处理您的对象,如this SO answer

public <T > List<T > getMemberList(List<? > beanList, 
     String propertyName, Class<T > resultClass) throws Exception { 
    List<T > result = new ArrayList<T >(); 
    for(Object bean : beanList) { 
     result.add((T)new PropertyDescriptor( 
       propertyName, bean.getClass()).getReadMethod().invoke(bean)); 
    } 
    return result; 
} 

然后你就可以像这样的电话:

List<String > result = getMemberList(phonenumberList, "number", String.class); 
2

对于一些这个简单,你最好只提供getter和setter方法。拒绝复制一行代码会节省很多。更好的是,让你的IDE为你写。

+0

只要您提供存取方法,就会引发代码重复。 – 2010-02-22 17:54:20

1

您可以使用反射(java.lang.Class和java.lang.reflect。*)来获取方法名称;以“get”开头的是属性,其名称跟随“get”。

1

对于Java中的闭包来说,这是一个很好的例子;它来了,但它还没有到。

与此同时,你可以用反射做到这一点,虽然反射总是会有性能损失。反射可以做的一件事是让你调用一个对象的方法,或者通过指定方法/属性的名称作为一个字符串来检索一个属性;在你的情况下,你会想要做getListOfProperties(AddressList, "city")并在该方法中使用反射来检索指定的属性。

通过使用Apache Commons BeanUtils库,可以大幅简化此类事物。

import org.apache.commons.beanutils.BeanUtils; 

static List<String> getListOfProperties(List beans, String propertyName) { 
    List<String> propertyValues = new ArrayList<String>(); 
    for (Object bean:beans) { 
     propertyValues.add(BeanUtils.getProperty(bean, propertyName)); 
    } 
    return propertyValues; 
}