我试图理解java中的泛型,并尝试这个简单的例子,但不能使它工作;它回来时有错误
线程中的异常" main" java.lang.Error:未解决的编译问题: 对于类型T,方法base()未定义 在javaTest.Main.testShape(Main.java:21) 在javaTest.Main.main(Main.java:25)
以下是代码
class Shape{
int id=1;
void base(){
System.out.println("Shape.base()");
}
}
// unrelated class, but same func name
class OtherShape{
float id=1.1f;
void base(){
System.out.println("OtherShape.base()");
}
}
public class Main {
static <T>void testShape(T shape){
shape.base();
}
public static void main(String[] args) {
testShape(new Shape() );
testShape(new OtherShape());
}
}
关于如何使其发挥作用的任何想法?
答案 0 :(得分:8)
在Java中,泛型是在没有外部上下文的情况下编译的,因此代码必须是有效的,而不知道最终它将如何被调用。
声明某些内容<T>
意味着您可以传递任何对象,因此T var
表示在编译时var
应该只是java.lang.Object
。因此,var.base()
没有意义,因为java.lang.Object
不提供名为base()
的方法。
例如,您可以通过声明T
告诉Shape
至少<T extends Shape>
,然后您可以传递从Shape
继承的任何内容。但是,您的第二个示例仍然不起作用,因为OtherShape
未从Shape
继承,即它不满足条件<T extends Shape>
。
要完全修复它,它应该如下所示:
class Shape{
int id=1;
void base(){
System.out.println("Shape.base()");
}
}
// unrelated class, but same func name
class OtherShape extends Shape{
float id=1.1f;
@Override
void base(){
System.out.println("OtherShape.base()");
}
}
public class Main {
static <T extends Shape> void testShape(T shape){
shape.base();
}
...
}
向前迈出的一步是让Shape
成为一个界面,而是创建实现该界面的每个形状类(TriangleShape
,OtherShape
,...)。
请注意,在您的示例中,您并不真正需要泛型,如果您稍后需要引用相同的类型,它们非常有用,例如将其从方法返回:
static <T extends Shape> T testShape(T shape){
shape.base();
return shape;
}
在上面的示例中,您仍然可以将此方法的结果分配给您在参数中传递的相同类型,因为参数类型和返回类型相同(T
)。
答案 1 :(得分:1)
我相信你遇到了这个问题,因为你没有将T转换为任何对象类型。试试这样做。
class Shape{
int id=1;
void base(){
System.out.println("Shape.base()");
}
}
// unrelated class, but same func name
class OtherShape extends Shape{
float id=1.1f;
void base(){
System.out.println("OtherShape.base()");
}
}
public class Test {
static void testShape(Shape shape){
shape.base();
}
public static void main(String[] args) {
testShape(new Shape() );
testShape(new OtherShape());
}
}
答案 2 :(得分:1)
您收到的实际错误消息是:
The method base() is undefined for the type T
这正是您的问题:您的方法旨在对T
类型进行操作,并且您已经说T
可以字面上任何对象类型。由于T
可能是String
,或Number
,或其他人创建的其他随机对象,因此您无法假设它将在对象上使用任何特定方法。因此,类型base()
的方法T
未定义,因为T
不一定是具有base()
方法的类型。这有意义吗?
如果您希望在任何具有base()
方法的类型上运行,那就是structural typing,其中 Java很遗憾不支持即可。 (Java的类型系统改为nominative。)
接下来最好的事情是定义一个接口来保存你的base()
方法,并在你的两个类中实现该接口:
interface ShapeInterface {
void base();
}
class Shape implements ShapeInterface {
...
}
class OtherShape implements ShapeInterface {
...
}
但是你不再需要参数多态(即泛型),因为你可以使用普通的subtype polymorphism代替:{{1} }和Shape
都支持与OtherShape
的 is-a 关系,您的ShapeInterface
方法可以接受testShape
并直接与其进行互动:
ShapeInterface
答案 3 :(得分:0)
只有为类实现相同的接口时才能执行此操作。
interface S {
void base();
}
static void testShape(S shape){
shape.base();
}