将派生类对象传入基类引用参数,如何获取完整派生类属性?
现有基类User及两个派生类Admin和Manager,代码如下:
基类 - User
public class User { public String userId; public String name; public String type; }
派生类 - Admin
public class Admin extends User { public String prop1; public String prop2; }
派生类 - Manager
public class Manager extends User { public String prop3; public String prop4; }
基类包含Admin和Manager共享的通用属性。当前有一个调用API创建用户的方法,可用于创建不同类型的用户,代码如下:
public class Response<T>{ public int statusCode; public T result; } public class UserCreation{ public static void main(String[] args){ RequestHandler requestHandler = new RequestHandler(); User userRequest = requestHandler.createUserCreationRequest("Admin"); UserCreationDao.createUser(userRequest); User userRequest = requestHandler.createUserCreationRequest("Manager"); UserCreationDao.createUser(userRequest); } } public class RequestHandler{ public User createUserCreationRequest(String userType) { switch (userType) { case "Admin": return createAdminRequest(); case "Manager": return createManagerRequest(); default: throw new IllegalArgumentException("Invalid processor"); } } private Admin createAdminRequest(){ Admin admin = new Admin(); admin.setName("Admin"); admin.setType("Admin"); admin.setProp1("prop1"); admin.setProp2("prop2"); return admin; } private Manager createManagerRequest(){ Manager manager = new Manager(); manager.setName("Manager"); manager.setType("Manager"); manager.setProp3("prop2"); manager.setProp4("prop3"); return manager; } } public class UserCreationDao{ public void createUser(User userRequest) { Response<User> response = userapi.createuser(HttpMethod.POST, "/users", userRequest, new ParameterizedTypeReference<Response<User>>() {}, key); } }
当前问题:执行UserCreationDao的createUser方法时,Response对象的result属性本应填充派生类(Admin或Manager)的完整信息,但由于指定了Response<User>类型,无法返回Admin和Manager的全部属性。希望仍使用同一个方法,让Response对象根据传入的派生类,填充对应派生类的完整属性到result中。
方案1:泛型化createUser方法
将UserCreationDao的createUser方法改为泛型方法,利用Java的类型推断动态生成ParameterizedTypeReference,确保反序列化时能识别传入的实际派生类类型。
修改后的UserCreationDao代码:
public class UserCreationDao{ public <T extends User> void createUser(T userRequest) { ParameterizedTypeReference<Response<T>> typeRef = new ParameterizedTypeReference<Response<T>>() {}; Response<T> response = userapi.createuser(HttpMethod.POST, "/users", userRequest, typeRef, key); // 此时response.result为对应Admin/Manager实例,包含所有派生类属性 } }
同时修正UserCreation中的重复变量名问题,并优化类型获取(可避免强制转换):
public class UserCreation{ public static void main(String[] args){ RequestHandler requestHandler = new RequestHandler(); Admin adminRequest = (Admin) requestHandler.createUserCreationRequest("Admin"); UserCreationDao.createUser(adminRequest); Manager managerRequest = (Manager) requestHandler.createUserCreationRequest("Manager"); UserCreationDao.createUser(managerRequest); } }
进一步优化RequestHandler为泛型方法,省去强制转换:
public class RequestHandler{ @SuppressWarnings("unchecked") public <T extends User> T createUserCreationRequest(String userType) { switch (userType) { case "Admin": return (T) createAdminRequest(); case "Manager": return (T) createManagerRequest(); default: throw new IllegalArgumentException("Invalid processor"); } } // 原createAdminRequest、createManagerRequest方法保持不变 }
调用时可直接获取对应类型:
Admin adminRequest = requestHandler.createUserCreationRequest("Admin"); Manager managerRequest = requestHandler.createUserCreationRequest("Manager");
方案2:显式传递类型令牌
如果泛型类型推断不够灵活,可在调用时传入派生类的Class对象,自定义ParameterizedTypeReference来指定具体的反序列化类型。
修改UserCreationDao的方法:
public class UserCreationDao{ public <T extends User> void createUser(T userRequest, Class<T> userClass) { ParameterizedTypeReference<Response<T>> typeRef = new ParameterizedTypeReference<Response<T>>() { @Override public Type getType() { return new ParameterizedType() { @Override public Type[] getActualTypeArguments() { return new Type[]{userClass}; } @Override public Type getRawType() { return Response.class; } @Override public Type getOwnerType() { return null; } }; } }; Response<T> response = userapi.createuser(HttpMethod.POST, "/users", userRequest, typeRef, key); } }
调用示例:
Admin adminRequest = (Admin) requestHandler.createUserCreationRequest("Admin"); UserCreationDao.createUser(adminRequest, Admin.class); Manager managerRequest = (Manager) requestHandler.createUserCreationRequest("Manager"); UserCreationDao.createUser(managerRequest, Manager.class);
方案3:利用序列化框架的多态支持
如果API返回的响应中包含type字段(如"type": "Admin"),可配置JSON序列化框架(如Jackson),让其根据该字段自动反序列化为对应的派生类。
以Jackson为例,在基类User上添加注解:
import com.fasterxml.jackson.annotation.JsonSubTypes; import com.fasterxml.jackson.annotation.JsonTypeInfo; @JsonTypeInfo( use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY, property = "type" ) @JsonSubTypes({ @JsonSubTypes.Type(value = Admin.class, name = "Admin"), @JsonSubTypes.Type(value = Manager.class, name = "Manager") }) public class User { public String userId; public String name; public String type; }
此时即使声明Response<User>,Jackson也会根据type字段自动将result反序列化为对应的Admin或Manager实例,包含所有派生类属性,无需修改业务方法逻辑。
内容的提问来源于stack exchange,提问作者YNP

