首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >具体类型的Java包装类子类

具体类型的Java包装类子类
EN

Stack Overflow用户
提问于 2014-12-17 19:17:18
回答 4查看 2.4K关注 0票数 2

假设我有一个学生,如下所示:

代码语言:javascript
复制
public class Person {
   String name;
   int age;
}

和一些子类,例如

代码语言:javascript
复制
public class Student extends Person {
   // extra fields and methods
}
public class Teacher extends Person {
   // extra fields and methods
}

现在,考虑到对于某些应用程序,我需要为每个person实例分配一个整数id,但我不想扩展Person接口以在那里添加getId()和一个保存id的字段。一个简单的解决方案是使用一个包装器,如:

代码语言:javascript
复制
public class PersonWrapper extends Person {
    public PersonWrapper(Person p, int id) { // assign the id and other fields }
    public int getId() { return id; }
}

这样,客户端代码仍然可以与person接口一起工作,并且包装的人员可以被视为Person。这种方法的问题在于,PersonWrapper是Person的子类,而不是教师或学生的子类,这样的代码无法工作:

代码语言:javascript
复制
Teacher t = new PersonWrapper(teacher, 1);
t.giveGrade();

当然,可以为Person的所有子类创建具体的包装器类型,但我想知道是否有更优雅的解决方案。理想的解决方案是这样的:

代码语言:javascript
复制
public class PersonWrapper<T extends Person> extends T

因此,任何PersonWrapper都是它封装的类型的子类,但在Java中是不可能的,我怀疑这种定义在任何语言中都是不可能的。

在任何情况下,我如何为子类分配In而不更改与person及其子类一起工作的客户端代码,而不为每个子类创建一个具体的包装器?

EN

回答 4

Stack Overflow用户

回答已采纳

发布于 2014-12-17 19:25:59

你说得对,你不能做你想做的事。假设您不能将具体的类更改为(例如,Student extends Person implements Identifiable ),最好的方法是将包装器真正视为包装器,并有一个返回其不同元素的getter:

代码语言:javascript
复制
public class Wrapper<T> {
    private final T item;
    private final int id;

    ...

    public int getId() { return id }

    public T getItem() { return item; }

}

使用起来有点麻烦,因为您必须做一些类似wrapper.getItem().giveGrade()的事情,而不仅仅是wrapper.giveGrade()。这也意味着您不能将包装器塞进List<Teacher>中,然后再将其降到TeacherWrapper中--但这有点脆弱,而且通常有更好的方法来实现您想要的结果。在大多数情况下,这种“纯”包装方法可以做您想做的事情。

请注意,我甚至没有T extends Person。如果包装类不需要使用任何Person方法,那么人工限制泛型没有什么好处。无论哪种方式,呼叫站点都会受到限制。一个不同之处是,如果调用站点有一个Wrapper<?>,那么我的代码将只允许您以Object的形式获取该项,而限制性更强的T extends Person将允许您以Person的形式获取该项。

票数 0
EN

Stack Overflow用户

发布于 2014-12-17 19:20:18

包装器不一定需要扩展到包装的类。所以,只需使用PersonWrapper<T extends Person>

代码语言:javascript
复制
public class PersonWrapper<T extends Person> {
    T person;
    int id;

    public PersonWrapper(T person, int id) {
        this.person = person;
        this.id = id;
    }
    //getters and setters...
}

另外,一个类只能在编译时从另一个类扩展,因此这个PersonWrapper不可能同时从StudentTeacher扩展,这使得您所要寻找的内容不可能实现。

唯一的解决方案是使用像cglib这样的库动态创建代理类。例如,当需要动态地向类添加功能时,Spring为类创建代理,例如为方法或整个类添加事务管理。

票数 4
EN

Stack Overflow用户

发布于 2014-12-17 19:31:20

这个问题的常见解决方案是使Person成为一个interface

代码语言:javascript
复制
interface Person {

    public String getName();

    public int getAge();
}

class ActualPerson implements Person {

    private final String name;
    private final int age;

    ActualPerson(String name, int age) {
        this.name = name;
        this.age = age;
    }

    @Override
    public String getName() {
        return name;
    }

    @Override
    public int getAge() {
        return age;
    }
}

class PersonWithId implements Person {

    private final Person person;
    private final int id;

    PersonWithId(Person person, int id) {
        this.person = person;
        this.id = id;
    }

    @Override
    public String getName() {
        return person.getName();
    }

    @Override
    public int getAge() {
        return person.getAge();
    }
}

不要害怕太多的代码--与你花在后悔的时间相比,编写代码的时间是微不足道的--一开始你没有正确地写代码。老家伙,2014

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/27533138

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档