将列表中的对象作为CustomObject返回,而不仅仅是raw <t> Object

时间:2016-12-27 23:05:46

标签: java generics

我将CustomObject声明为原始类型<T>。当我使用List<CustomObject>新实例填充CustomObject时,我无法将其作为Object取回,仅作为public class CustomObject<T> { private String name; private T value; // getters and setters }

public class CustomObject {

    private class SubCustomObject<T> {
        private String name;
        private T value;
    }

    public CustomObject() {
        this.customObject = new SubCustomObject();

    private SubCustomObject customObject;

    // getters and setters
}

但是很明显,当我使用子类时,一切都在按预期工作;

public class CustomObject<T> {
    private String name;
    private T value;
    private boolean isGroup;

    // getters and setters

    private void setValue(T value) {

        if (value instanceof String) {
            this.value = value;
            this.isGroup = false;
        }

        if (value instanceof CustomObject) {
            if (isGroup()) {
                ((List<CustomObject>) this.value).add((CustomObject) value);
            } else {
                this.value = (T) new ArrayList<CustomObject>();
                this.isGroup = true;
                setValue(value);
            }
        }
    }
}

public void getItemByName(String name) {
    // say the list is already populated
    for (CustomObject object : listOfCustomObject) {
        String nameField = object.getName();
        if (name.equals(nameField) {
            System.out.println(nameField);
        }
    }
}

有没有办法让第一个例子表现得像第二个例子,并避免使用额外的对象,所以我可以这样做:

public void getItemByName(String name) {
    // say the list is already populated
    for (Object object : listOfCustomObject) {
        String nameField = ((CustomObject)object).getName();
        if (name.equals(nameField) {
            System.out.println(nameField);
        }
    }
}

而不是这一个:

public class MetadataEntry {

    public MetadataEntry() {
        this.entity = new Entry();
    }

    private class Entry<T> {
        private String name;
        private T value;
        private boolean isGroup;

        private void setValue(T value) {

            if (value instanceof String) {
                this.value = value;
                this.isGroup = false;
            }

            if (value instanceof MetadataEntry) {
                if (isGroup()) {
                    ((List<MetadataEntry>) this.value).add((MetadataEntry) value);
                } else {
                    this.value = (T) new ArrayList<MetadataEntry>();
                    this.isGroup = true;
                    setValue(value);
                }
            }
        }

    }

    private Entry entity;


    public void setName(String name) {
        this.entity.name = name;
    }

    public String getName() {
        return this.entity.name;
    }

    public void setValue(String value) {
        entity.setValue(value);
    }

    public void setValue(MetadataEntry value) {
        entity.setValue(value);
    }

    public boolean isGroup() {
        return this.entity.isGroup;
    }

    public List<MetadataEntity> getChildNodes() {
        if (isGroup()) {
            return (List<MetadataEntry>) this.entity.value;
        }

        return null;
    }

    public String getValue() {
        if (!isGroup()) {
            return (String) this.entity.value;
        }

        return null;
    }
}

//将此行为应用于此并避免使用内部类。

ControlValueAccessor

4 个答案:

答案 0 :(得分:0)

您不能列出不同类型的X,Y,Z并将其放在W类型的单个容器中。您需要在原始类型上定义一个边界参数,以便您的项目和列表具有相同的类型。可能你的T应该受某些接口类型的限制,或者它应该扩展一些类。

答案 1 :(得分:0)

这是我的建议。我放弃了仿制药。现在有一个带有两个子类的抽象内部类,而不仅仅是一个内部类,一个用于组,一个用于不是组的条目。好消息:任何地方都不需要演员表。

public class MetadataEntry {

    private String name;

    static abstract class Entry {
        abstract Entry setValue(String value);
        abstract Entry setValue(MetadataEntry value);
        abstract boolean isGroup();
        abstract List<MetadataEntry> getChildNodes();
        abstract String getSimpleValue();

    }

    static class SimpleEntry extends Entry {
        private String value;

        public SimpleEntry(String value) {
            this.value = value;
        }

        @Override
        Entry setValue(String value) {
            this.value = value;
            return this;
        }

        @Override
        Entry setValue(MetadataEntry value) {
            return new GroupEntry(value);
        }

        @Override
        public boolean isGroup() {
            return false;
        }

        @Override
        public List<MetadataEntry> getChildNodes() {
            return null;
        }

        @Override
        public String getSimpleValue() {
            return value;
        }
    }

    static class GroupEntry extends Entry {
        List<MetadataEntry> value;

        public GroupEntry(MetadataEntry value) {
            this.value = new ArrayList<>();
            this.value.add(value);
        }

        @Override
        Entry setValue(String value) {
            return new SimpleEntry(value);
        }

        @Override
        Entry setValue(MetadataEntry value) {
            this.value.add(value);
            return this;
        }

        @Override
        public boolean isGroup() {
            return true;
        }

        @Override
        public List<MetadataEntry> getChildNodes() {
            return value;
        }

        @Override
        public String getSimpleValue() {
            return null;
        }
    }

    private Entry entity;

    public void setName(String name) {
        this.name = name;
    }

    public String getName() {
        return this.name;
    }

    public void setValue(String value) {
        entity = entity.setValue(value);
    }

    public void setValue(MetadataEntry value) {
        entity = entity.setValue(value);
    }

    public boolean isGroup() {
        return this.entity.isGroup();
    }

    public List<MetadataEntry> getChildNodes() {
        return entity.getChildNodes();
    }

    public String getValue() {
        return entity.getSimpleValue();
    }
}

我使用了类似于1987年所说的关于返回其自身实例的类的想法。我将它应用于内部类只是为了让外部类的用户免于关心这个诡计。如果您愿意,我相信它可以应用于外部类。那么你将在外层有一个带有两个子类的abstrat类,并且不再需要内部类。这是你要求的事情之一,所以你可能更喜欢它,但它需要付出代价:任何在外层上调用setValue()的人都需要记住他们有一个新的实例。

答案 2 :(得分:0)

  

我将CustomObject声明为<T>的原始类型。

这没有意义。您要么具有原始类型,要么具有泛型,而不是通用的原始类型。

  

当我使用新的实例填充列表时,我无法将其作为CustomObject取回,仅作为Object

因为您的列表不是通用的(总是很糟糕)。当您声明List<Something>时,它会在Something来电时返回getSomething可以是通用的或原始类型。 List<CustomObject<String>>将不接受CustomObject<Integer>,并且使用原始类型List<CustomObject>将以灾难结束,因此原始类型存在危险。

现在让我们来看看你的代码。班级

public class CustomObject<T> {
    private String name;
    private T value;
}

定义对任何类型的行为相同的对象。从本质上讲,你所拥有的仅仅是一个荣耀的Object,并附有String作为其名称。

然而,现在你做了

private void setValue(T value) {

    if (value instanceof String)
        // ...

    if (value instanceof CustomObject)
        // ...
}

分隔不同类型的行为。如果泛型类型不是StringCustomObject

会发生什么

让我们尝试解决您的问题。由于仿制药旨在统一行为,因此,让我们看一下您试图获得的统一行为:

public void getItemByName(String name) {

    for (CustomObject object : listOfCustomObject) {
        String nameField = object.getName();
        // ...
        }
    }
}

基本上,您要求listOfCustomObject中的所有项都实现String getName()方法。就我的问题而言,这就是我的意思。这意味着您的CustomObject<T>应该使用该方法实现接口或扩展类(称为Superthing)。然后,您只需将列表声明为List<? extends Superthing>

至于CustomObject本身,它并不需要是通用的,因为你暗示你只想处理2种类型的泛型(你有2 if s,但没有else处理一般情况)。看起来你想要的是2个不同的类,其中不同的行为都实现或扩展了一个共同的超类型。

尝试这样的事情:

abstract class AbstractEntry {

    private String name;
    protected boolean isGroup;

    public void setName(String name) {

        this.name = name;
    }

    public String getName() {

        return name;
    }

    public boolean isGroup() {

        return isGroup;
    }
}

class MetaEntry extends AbstractEntry {

    AbstractEntry value;

    MetaEntry(AbstractEntry value) {

        this.value = value;
        // handle isGroup
    }   

    public void setValue(AbstractEntry value) {

        this.value = value;
    }

    public AbstractEntry getValue() {

        if (!isGroup)
            return value;
        return null;
    }
}

class StringEntry extends AbstractEntry {

    String value;

    StringEntry(String value) {

        this.value = value;
        isGroup = false;
    }

    public void setValue(String value) {

        this.value = value;
    }

    public String getValue() {

        return value;
    }
}

答案 3 :(得分:0)

我认为不需要列表,因为它总是只包含一个元素。正如@Ole V.V所述,该要求自然要求使用组合,事实上,通用不符合您的要求。以下是我将如何解决您的要求:

public interface Named {

public String getName();
public String getValue();
}

public class CustomObject implements Named {
private String name;
private String value;
private boolean isGroup;

// getters and setters

private boolean isGroup() {

    return isGroup;
}

public String getName() {
    return name;
}

public void setName(String name) {
    this.name = name;
}

public String getValue() {
    return value;
}

public void setValue(String value) {
    this.value = value;
}
}

public class CustomObject2 implements Named {

private String name;
private CustomObject value;


public String getName() {
    return name;
}
public void setName(String name) {
    this.name = name;
}
public String getValue() {
    return value.getValue();
}
public void setValue(CustomObject value) {
    this.value = value;
}

}

public class DriverCustomObject {

public static void main(String arg[]) {
    CustomObject t = new CustomObject();
    t.setName("key1");
    t.setValue("value1");
    CustomObject2 t2 = new CustomObject2();
    t2.setName("complex");
    t2.setValue(t);

    List<Named> list = new ArrayList<Named>();
    list.add(t);
    list.add(t2);
    for (Named l : list) {
        System.out.println(l.getName());
        System.out.println(l.getValue());

    }
}

}