java 在java中扩展包含抽象泛型方法的基类

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/14969268/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-31 18:02:33  来源:igfitidea点击:

Extending base class containing abstract generic method in java

javagenericsjava-7abstract

提问by chapstick

I am given a Base class like this:

我得到了一个像这样的基类:

 Class MyBase{

   public abstract <T> Student assign (T object);

 }

I am extending it like below:

我像下面这样扩展它:

 Class MyClass extends MyBase{

   @Override
   public abstract <T> Student assign (T object){

     Student stew = new Student();
     ......

   }
 }

My intended use is: the passed in object should be of type Teacher. Within the method I want to create a new Student which will get some values by invoking functions on Teacher. (For example, stew.setTeacherName = teacher.getName();) And then return Student to the caller.

我的预期用途是:传入的对象应该是教师类型。在该方法中,我想创建一个新的 Student,它将通过调用 Teacher 上的函数来获取一些值。(例如,stew.setTeacherName = Teacher.getName();)然后将Student返回给调用者。

Questions: a) How do I get the intended behavior? b) Whats the difference between declaring MyBase the current way vs. doing MyBase ? c) I am interested in knowing the solution in case where I CAN change Base class and I CANNOT change the Base class.

问题:a) 我如何获得预期的行为?b) 以当前方式声明 MyBase 与执行 MyBase 有什么区别?c) 我有兴趣知道在我可以更改基类但不能更改基类的情况下的解决方案。

Thanks in advance for your help. Also, if there are any useful resources/tutorials you can point me to that would be great. Thanks again.

在此先感谢您的帮助。此外,如果有任何有用的资源/教程,您可以指点我,那就太好了。再次感谢。

回答by rgettman

You cannot guarantee that the objectbeing passed in to MyClass's assignmethod is a Teacher, if MyBaseis defined this way. If you are allowed to modify MyBase, do the following:

如果以这种方式定义,则不能保证object传入 toMyClassassign方法是 a 。如果允许修改,请执行以下操作:TeacherMyBaseMyBase

abstract class MyBase
{
   public abstract <T extends Teacher> Student assign (T object);
}

and extend it with your class:

并用你的班级扩展它:

class MyClass extends MyBase
{
   @Override
   public <T extends Teacher> Student assign (T object){

     Student stew = new Student();
     ......

   }
}

This will guarantee that the objectbeing passed in is a Teacher, even if it's really an instance of a subclass of Teacher.

这将保证object传入的是 a Teacher,即使它确实是 的子类的实例Teacher

EDIT: Another way to modify MyBase. Make the generic parameter part of the class definition instead of the method definition.

编辑:另一种修改方法MyBase。使泛型参数成为类定义的一部分,而不是方法定义。

abstract class MyBase<T extends Teacher>
{
   public abstract Student assign (T object);
}

class MyClass<T extends Teacher> extends MyBase<T>
{
   @Override
   public  Student  assign (T object)
   {
      Student stew = new Student();
      ......
   }
}

// Could also do this...
class MyClass2 extends MyBase<Teacher>
{
   @Override
   public  Student  assign (Teacher object)
   {
      Student stew = new Student();
      ......
   }
 }

Here's Oracle's Java Generics Tutorial.

这是Oracle 的 Java 泛型教程

回答by David Conrad

If you cannot modify the base class, there isn't really a way to do it that involves generics. There are two things you could do. One, check the run-time type of the object and do one thing if it is a teacher, another if not.

如果您不能修改基类,那么实际上没有涉及泛型的方法。你可以做两件事。一,检查对象的运行时类型,如果是老师,则做一件事,如果不是,则另一件事。

public class MyClass extends MyBase {
    @Override public <T> Student assign(T object) {
        Student student = new Student();
        if (object instanceof Teacher) {
            Teacher teacher = (Teacher) object;
            student.setTeacherName(teacher.getName());
        } else {
            student.setTeacherName("unknown");
        }
        return student;
    }
}

Two, create two separate assignmethods in MyClass, one which overrides the generic method in the base class, and a non-generic method that just takes a Teacher as a parameter.

二、assign在 MyClass 中创建两个单独的方法,一个覆盖基类中的泛型方法,一个非泛型方法只将一个 Teacher 作为参数。

public class MyClass extends MyBase {
    @Override public <T> Student assign(T object) {
        return new Student();
    }

    public Student assign(Teacher teacher) {
        Student student = new Student();
        student.setTeacherName(teacher.getName());
        return student;
    }
}

When the method is called, if the compile-time type is Teacher, the compiler will choose the more specific overload of the method:

当方法被调用时,如果编译时类型是Teacher,编译器会选择方法的更具体的重载:

public class Main {
    /**
     * Gets a teacher but calls it an Object.
     *
     * @return an Object that happens to be a Teacher
     */
    public static Object getTeacher() {
        return new Teacher();
    }

    public static void main(String[] args) {
        /** A Teacher, and is declared as such */
        Teacher teacher = new Teacher();

        /**
         * Some Object, which just so happens to actually
         * be a Teacher (but the compiler can't see that)
         */
        Object something = getTeacher();

        MyClass mc = new MyClass();

        Student withTeacher = mc.assign(teacher);
        Student withoutTeacher = mc.assign(something);
    }
}

However, I would much prefer one of the solutions that modifies MyBase.

但是,我更喜欢修改 MyBase 的解决方案之一。

Edited to add:You could actually declare the second, more specific assignmethod to be a generic method, like so:

编辑添加:您实际上可以将第二个更具体的assign方法声明为通用方法,如下所示:

public <T extends Teacher> Student assign(T object) {
    Student student = new Student();
    student.setTeacherName(object.getName());
    return student;
}

But this is really just the same as the second example above. The method does not override the method in the base class, it still relies on the compiler picking the more specific overload at compile time, and the erasure of the method signature is exactly the same as the non-generic method in the second example:

但这实际上与上面的第二个示例相同。该方法不会覆盖基类中的方法,它仍然依赖于编译器在编译时选择更具体的重载,并且方法签名的擦除与第二个示例中的非泛型方法完全相同:

public Student assign(Teacher)

It just looks a bit more like an override of the method from the base class because it's got a generic type variable and the parameter is named objectinstead of teacher. But try sticking an @Overrideannotation on it and the compiler will tell you it does not override or implement a method from a supertype.

它看起来更像是对基类方法的覆盖,因为它有一个泛型类型变量,并且参数被命名object而不是teacher. 但是尝试@Override在其上粘贴注释,编译器会告诉您它不会覆盖或实现来自超类型的方法。

And you still have the <T>generic method hanging around which doesn't set the teacher name, and if you ever have a Teacher object which is not declared as such, the compiler will choose the wrong overload and you'll be scratching your head wondering why, if the object is a Teacher, the teacher name didn't get set on the student.

而且你仍然有一个<T>没有设置教师名称的泛型方法,如果你有一个没有这样声明的教师对象,编译器会选择错误的重载,你会挠头想知道为什么, 如果对象是教师,则没有在学生上设置教师姓名。

回答by entonio

Generic methods are usually meant to work with any type supplied, as opposed to generic classes, which can be specialised to work with concrete types. It's a functional vs OO approach. So what you probably want is to have a generic class with a T parameter:

泛型方法通常用于处理提供的任何类型,而不是泛型类,泛型类可以专门用于处理具体类型。这是一种功能性与面向对象的方法。所以你可能想要的是有一个带有 T 参数的泛型类:

MyBase<T>

MyBase<T>

have the method use that parameter

让方法使用该参数

public abstract Student assign (T object)

public abstract Student assign (T object)

and then specialise it to use teachers

然后专门用于使用教师

MyClass extends MyBase<Teacher>

MyClass extends MyBase<Teacher>

with a

public Student assign (Teacher object)

public Student assign (Teacher object)

Mostly my generic methods are static for exactly this reason - if an instance method is parametrised, it is logical that the type parameter belongs to the class rather than the method. Usually, of course.

大多数情况下,我的泛型方法是静态的,正是出于这个原因——如果实例方法是参数化的,那么类型参数属于类而不是方法是合乎逻辑的。通常,当然。