代码之家  ›  专栏  ›  技术社区  ›  Xorty

替换泛型类型的字段

  •  0
  • Xorty  · 技术社区  · 14 年前

    我有通用结构,需要使用各种通用类型的属性进行搜索。

    让我们考虑以下实现:

    public class Person {
      private int id;
      private String name;
      // + getters & setters
    }
    

    现在我有了自定义的数据结构,其中一个方法如下:

    public T search(T data) { ... }
    

    那当然是胡说八道。我在代码中真正需要的是:

    Person p = structure.search(12); // person's id
    

    Person p = structure.search("Chuck N."); // person's name
    

    所以在pseudojava(:)中,代码应该是这样的:

    public T search(T.field key)
    

    当然,这是不可能的:(但是,如何处理这种情况呢?重点是:我不想强迫客户机的类(如Person)实现我自己的接口或扩展我自己的类。有什么解决办法吗?

    4 回复  |  直到 14 年前
        1
  •  2
  •   Tom Hawtin - tackline    14 年前

    看起来您需要某种中间策略对象,它提取一个值,比较一个值,或者提供一个哈希代码或比较函数。

    比如:

    interface Matcher<T> {
        boolean matches(T obj);
    }
    

    或方法,如:

        boolean matches(T obj, V value);
    
        V get(T obj);
    
        int hash(T obj);
    
        int compare(T a, T b);
    

    使用与当前Java语法有点冗长(可以为JDK 8更改)。

    你最终会得到这样的结果:

    Person p = structure.search(
        new Matcher<Person>() { public boolean matches(Person person) {
            return person.getID() == 12;
        })
    );
    

    或:

    Person p = structure.search(
        new Matcher<Person,Integer>() {
            public boolean matches(Person person, Integer id) {
                return person.getID() == id;
            }
        ),
        12
    );
    

    在JDK8中,可能类似于:

    Person p = structure.search(
        { Person person -> person.getID() == 12 }
    );
    

    或:

    Person p = structure.search(
        { Person person, Integer id -> person.getID() == id },
        12
    );
    

    或:

    Person p = structure.search(
        { Person person -> person.getID() },
        12
    );
    

    或:

    Person p = structure.search(
        Person#getID, 12
    );
    
        2
  •  2
  •   matt b    14 年前

    通过添加类参数,可以使搜索的签名包含类型参数。例如:

    //replace 'id' with whatever your identifier types are
    public <T> T search(int id, Class<T> entityClass) { ... }
    

    然后客户端必须使用

    Person p = foo.search(123, Person.class);
    NotAPerson n = foo.search(234, NotAPerson.class);
    

    必须包括课程可能看起来有点难看,但当你真正思考问题时——客户不总是知道它在搜索什么吗?难道后面的代码 search() 需要知道要搜索哪种类型-如果有不同类型共享的ID怎么办?

    如果您的ID类型不一致,可以将签名更改为

    public <T> T search(Serializable id, Class<T> entityClass) { ... }
    
        3
  •  0
  •   AlexR    14 年前

    我建议您使用类似的接口。

    person p=structure.searchunique(new fieldfilter(“id”,12));//搜索id为12的人 person[]p=structure.searchall(new fieldfilter(“name”,“john”));//搜索名为john的人

    此外,我们可以实现允许搜索目标类的所有可用字段的过滤器:

    person[]p=structure.searchall(new fieldfilter(“john”));//搜索所有john

    如何实现这一点?这里有一些提示。

    首先,“结构”是什么?它是一个封装集合,将来可能包含一些索引功能。此类应具有类似

    结构(收集数据);

    它的搜索方法迭代给定的集合并调用FieldFilter的compateto()方法,该方法实现可比较的:

    用于(元素:集合){ if(filter.compareto(elem))。{ 结果.添加(elem); } } 返回结果;

    FieldFilter应该如下所示:

    公共类FieldFilter实现可比较的{ 私有字符串字段名; 私有V字段值; 公共字段筛选器(字符串fieldname,v fieldvalue){ this.fieldname=fieldname; this.fieldValue=字段值; } 公共布尔比较{ field field=elem.getClass().getField(字段名); field.setaccessible(真); 返回field.getValue()。等于(fieldValue); } }

    请注意,该代码是直接以应答形式编写的,从未编译过,因此不能按原样使用。但我希望它能描述这个想法。

        4
  •  0
  •   Luke Hutteman    14 年前

    如果要通过正在搜索的类型与传递给search()方法的参数类型之间的泛型强制执行映射,则必须在某个地方指定此映射。我认为如果没有客户端类的通用标记接口,就没有任何方法可以做到这一点。

    例如,这样的方法是可行的:

    public interface Searchable<T> { }
    
    public class Person implements Searchable<String> {
        // ...
    }
    
    public <T extends Searchable<K>, K> T search(K key) { 
        // ...
    }
    

    所以现在编译器将允许:

    Person p = search("John Doe");
    

    但不是:

    Person p = search(5);
    

    如果连标记接口都不是一个选项,恐怕您最好希望使用基于参数类型的特定搜索方法,例如:

    public <T> T searchByInt(int key) { 
        // ...
    }
    
    public <T> T searchByString(String key) { 
        // ...
    }
    

    但这当然意味着无效的案例,比如

    Person p = searchByInt(5);
    

    不会在编译时捕获,而是需要在运行时检查。