我的界面看起来像是:
package com.sample.service;
import com.sample.model.Request;
public interface Service<T> {
void add(T domain);
<E> boolean update(Request<E> request);
}
Request.java的位置
package com.sample.model;
public class Request<E> {
private final E entity;
public Request(E entity) {
this.entity = entity;
}
public E getEntity() {
return entity;
}
}
以下是我的实施
package com.sample.service;
import com.sample.domain.User;
import com.sample.model.Form;
import com.sample.model.Request;
public class UserServiceImpl implements Service<User> {
@Override
public void add(User user) {
System.out.println("add: " + user);
}
@Override
public <Form> boolean update(Request<Form> request) {
System.out.println("update: " + request);
Form form = request.getEntity();
//form.setUsername("some_username");//This line caused compile error
return true;
}
}
这是Form.java
package com.sample.model;
public class Form {
private String username;
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
@Override
public String toString() {
return username;
}
}
和User.java
package com.sample.domain;
public class User {
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return name;
}
}
当我编译并执行这些代码时,一切都很好。但是,当我取消注释UserServiceImpl中注释的行时,我收到了编译错误
UserServiceImpl.java:19: error: cannot find symbol
form.setUsername("some_username");
我的问题是为什么无法找到表单对象中的setUsername方法?表单对象是可变的。
答案 0 :(得分:6)
在您的代码中
public <Form> boolean update(Request<Form> request)
Form
不是com.sample.model.Form
。相反,它是另一个通用参数,就像
E
一样
<E> boolean update(Request<E> request);
。编译器对E
一无所知,即使您碰巧给它的名称与其中一个真实类的名称一致。编译器唯一能确定E
(或同一上下文中的Form
)的是它是Object
实例。 Object
没有任何getEntity
方法。
如果您来自C ++背景,那么您正在尝试对模板进行明确的专业化。但是,Java泛型不是模板。他们不生成代码。它们只提供一些编译时检查和运行时类型转换(有一些,但不多)。查找&#34; type erasure&#34;在Java Generics的上下文中。
要实现更有用的解决方案,您可以尝试确定update()
的参数必须具有哪种接口。如果存在必需的接口,请将其写为Java interface
并用作参数类型。如果没有(极少数情况下),您仍然可以使用空interface
进行标记,但是您需要自己重新构建参数 - 假设UserServiceImpl
知道传递给update()
的类型。
在以太网情况下,update()中可能不需要泛型。
答案 1 :(得分:4)
在Arkadiy的答案中解释了方法setUsername
未被识别的原因。但是,您的代码还存在其他问题。
在界面中
public interface Service<T> {
void add(T domain);
<E> boolean update(Request<E> request);
}
E
可以是任何类型。您不应该通过坚持update
类型为request
来尝试在具体类中实现Request<Form>
,因为update
方法具有不同的签名。
一种解决方案是使界面具有两个参数
public interface Service<T, E> {
void add(T domain);
boolean update(Request<E> request);
}
然后你需要
public class UserServiceImpl implements Service<User, Form>
具体类中update
方法的签名应为
public boolean update(Request<Form> request)
因为该方法不通用。