我有一个基类,它定义了一个集合List<Person>
。现在,一个扩展基类的特定类应该更改集合类型。
有可能吗?
public class Request {
private List<Person> persons;
//getter, setter
}
public class SubRequest1 extends Request {
}
public class SubRequest2 extends Request {
}
//only this class should define a different list type
public class SubRequest3 {
private List<SubRequest3.Person> persons;
//compiler error. this is invalid code!
@Override
public List<SubRequest3.Person> getPersons() {
return persons;
}
@Override
public void setPersons(List<SubRequest3.person> persons) {
this.persons = persons;
}
static class SubRequest3.Person extends Person {
}
}
答案 0 :(得分:1)
否,不可能。您无法覆盖字段,只能将其隐藏。
处理这种情况的正确方法是将Person
声明为公共接口。 Request
的子类可以使用Person
的不同实现,但是调用代码可能不必关心具体类型。
interface Person
{
//...
}
interface Request<T extends Person>
{
void setPeople(List<T> person);
List<T> getPeople();
}
abstract class DefaultRequest implements Request<Person>
{
private List<Person> persons;
public void setPeople(List<Person> people) { /* ... */ }
public List<Person> getPeople() { /* ... */ }
}
class SubRequest1 extends DefaultRequest
{
//...
}
class SubRequest2 extends DefaultRequest
{
//...
}
class SubRequest3 implements Request<SpecialPerson>
{
private List<SpecialPerson> persons;
public void setPeople(List<SpecialPerson> people) { /* ... */ }
public List<SpecialPerson> getPeople() { /* ... */ }
}
答案 1 :(得分:1)
子类不能重写方法并更改返回类型。允许子类在人员列表中发送不同类型的元素的方法有两种。
这两个都假设SpecialPerson
是Person
的子类:
1-使Request
类具有通用性:
public class Request<P extends Person> {
private List<P> persons;
public List<P> getPersons() {
//...
}
}
这样,SubRequest3
将声明为:
public class SubRequest3 extends Request<SubRequest3.Person> {
private List<SubRequest3.Person> persons;
}
所有其他SubRequest
类将声明extends Request<Person>
2-将所有内容保持在API级别,但将SubRequest3.Person
的实例添加到列表中,而不是尝试返回某些List<SubRequest3.Person>
。这利用了Person/SubRequest3.Person
的继承,同时避免了与List<Person>
/ List<SubRequest3.Person>
private List<SubRequest3.Person> persons;
public void setPersons(List<Person> people) {
//cast element by element
this.persons.clear(); //or whatever means of resetting
people.stream().forEach(p -> persons.add((SubRequest3.Person) p));
}
public List<SubRequest3.Person> getPersons() {
//Can also use a loop and add manually to a `List<Person>` object
return this.persons.stream().map(p -> (Person) p).collect(Collectors.toList());
}
答案 2 :(得分:1)
您只需声明您的类即可接受T
的通用类型extends Person
:
public class Request<T extends Person> {
private final List<T> people = new ArrayList<>(); // or any other implementation
public void setPeople(List<? extends T> people){
this.people.clear();
this.people.addAll(people);
}
public List<T> getPeople(){
return people;
}
}
然后让您的子类定义应使用的类型。例如:
public class SubRequest3 extends Request<SubRequest3.Person>{ /* ... */ }
您可能已经看到people
列表是最终列表,这意味着它将永远不会被覆盖。与仅接受任何List
实现相比,此尝试要安全得多,因为您可以确保该实现能够真正实现您想要的功能。例如。无法通过setPeople
传递有害列表。
与answer from @Michael类似,您可能还想声明一个默认实现,该实现将T
声明为Person
,然后让SubRequest1
和SubRequest2
扩展该默认类。