有效地获取对象的属性或强制执行类属性的声明

时间:2013-03-07 12:50:03

标签: java android static key-value-coding kvc

背景设定

我正在尝试创建一个用于在Android中访问和缓存Web服务数据的库,并且偶然发现了一个问题。

我的库管理的所有对象都从基类Entity类继承。任何Entity的派生类都可以声明其他字段 *或属性 *。

基类负责返回要从缓存(SQLite或File)或Web服务(REST或SOAP)读取的Entity属性。在我当前的实现中,Entity类使用反射执行此操作:它读取所有使用@Attribute注释标记的类字段名称。

问题

我在实现中遇到的问题如下:每次使用像Entity这样的函数请求所有static Set<String> getAttributes()的属性时,此函数必须创建{{1实现(目前使用Set进行快速查找)。

我希望每次发出对所有属性的请求时都避免分配和初始化HashSet

从我的角度来看,属性集特定于整个Set<String>类,而不是Entity对象。即:拥有Entity,所有class Customer extends Entity实例都具有相同的确切属性 - 每个实例都有一个名称,一个地址等等。

我目前的尝试是在每个扩展Customer的类中声明static Set<String> attributes,并使用类Entity块中的反射初始化Set,如下所示:

static

鉴于要初始化的类,class Customer extends Entity { private static final Set<String> attributes = new HashSet<String>(); static { Entity.populateAttributes(Customer.class); } } 类可以查找该类中标有Entity注释的所有字段及其基类(例如@AttributeCustomer extends Person将使用为Person extends Entity类声明的属性和从Customer.attributes类继承的属性填充Customer集合。

我遇到的问题是,可能没有为扩展Person的类定义attributes集,我想在编译时强制执行。

我已经看到这是为Eclipse中的Entity接口完成的:当创建一个实现Serializable的类时,如果您的类没有声明Serializable,Eclipse会显示警告。

问题

如果某个类没有声明字段,是否有任何方法可以强制执行[private] static final long serialVersionUID类的Serializable行为并显示警告或(更好)错误?

是否有不同的方法来返回Entity派生类的属性名称?

FOOTNOTE

* 我将术语Entity用于不应由库管理的对象属性,将术语field用于应由库管理的对象属性(可从Web服务或SQLite /文件缓存,并保存在Web服务或SQLite /文件缓存中)

编辑1

基本上,我想要实现的是以有效的方式获得一组attribute的属性*(参见上面的脚注)。帮助程序类使用此列表将对象值存储在数据库中(Entity查询可以从属性名称和类型中推断出来)或发送到Web服务。

此库用于缓存来自Web服务的值,并用于同步本地数据库(可能包含额外的用户输入值,可能缺少对象的服务器更新值)以及可通过Web服务访问的数据。它并不是要在具有通用访问器/ mutator的应用程序中替换per-field访问器/ mutator的使用。

这个概念称为键值编码,被许多框架和库使用。作为一个例子,我在Google搜索中找到的使用KVC的库的前两个例子是Cocoa和Sproutcore。参考文献:Apple developer documentationSproutcore wiki

KVC也用于Android开发。 CREATE TABLEBundleSQLiteCursor充分利用KVC。

1 个答案:

答案 0 :(得分:0)

由于我可能无法在派生类的定义中强制执行静态字段的声明,因此我将在上述Entity类的定义中存储属性集和类描述的映射。并确保在Entity构造函数中初始化派生类的属性集。

举个例子:

public class Entity
{
   private final static Map<Class<? extends Entity>, Set<String>> attributes = new HashMap<Class<? extends Entity>, Set<String>>();

   public static void populateAttributes(Class<? extends Entity> derivedClass)
   {
      //initialize the set of attributes for the derived class and 
      //add it to attributes map with "derivedClass" as key
   }

   static
   {
      populateAttributes(Entity.class);
   }

   public Entity()
   {
      //calling this.getClass() returns the object's actual (derived) class(*)
      if(!attributes.containsKey(this.getClass())
         populateAttributes(this.getClass());
   }

   //rest of class definition (including getAttributes method)
}

public class Customer extends Entity 
{
   @Attribute
   String someAttribute; //will be processed automatically
}

获取Entity属性的成本从解析所有类属性和创建新集合以使其保持在Map上的检查和检索操作上减少了,这应该非常小使用HashMap时。

通过对属性Entity(快速Map s)进行检查,可以提高创建HashMap实例的成本。初始化给定类的attributes集的成本可以忽略不计,因为每个派生类类型只执行一次。

考虑到在90%或更多场合下每个类实例至少请求一次属性,这应该提供比问题中描述的初始解决方案更好的整体性能。

(*)在基类实例方法中调用this.getClass()将返回对象的实际类。如果对象已初始化为派生类实例,则将返回派生类的描述(Class对象)。关于这方面的问题已在此处提出并回答:Which class does getClass() report inside a constructor of a base class