2013-02-19 105 views
2

我给一个基类是这样的:扩展基类

Class MyBase{ 

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

} 

我扩展它象下面这样:

Class MyClass extends MyBase{ 

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

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

    } 
} 

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

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

在此先感谢您的帮助。另外,如果有任何有用的资源/教程,您可以指出我的看法,那将很棒。再次感谢。

回答

2

如果你不能修改基类,那么就没有办法做到涉及泛型。你可以做两件事。一,检查对象的运行时类型,如果它是一个老师做一件事,如果不是另一件事。

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; 
    } 
} 

二,创建MyClass中,其中一个覆盖通用方法在基类,而只是需要教师作为参数的非通用的方法两个单独assign方法。

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; 
    } 
} 

当方法被调用时,如果在编译时类型是老师,编译器会选择哪种方法更具体的过载:

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); 
    } 
} 

不过,我更希望的一个修改MyBase的解决方案。

编辑补充:其实你可以声明第二,更具体的assign方法是一种通用的方法,像这样:

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

但这真的只是同上面的第二个例子。该方法不会覆盖基类中的方法,它依然依赖编译器在编译时选择更具体的过载,方法签名的删除与第二个示例中的非泛型方法完全相同:

public Student assign(Teacher) 

它只是看起来更有点像从基类方法的重写,因为它有一个泛型类型变量和参数被命名为object,而不是teacher。但是试着在其上注解一个@Override注解,编译器会告诉你它不会覆盖或实现超类型的方法。

而且你仍然有挂在其上的通用方法,它没有设置教师姓名,如果你有一个Teacher对象没有被声明为这样,编译器会选择错误的超载,你会挠挠脑袋,想知道为什么,如果对象是老师,老师的名字就没有设置在学生身上。

1

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

MyBase<T>

有方法使用该参数

public abstract Student assign (T object)

,然后专门为使用教师

MyClass extends MyBase<Teacher>

public Student assign (Teacher object)

晴我泛型方法是静态的正是这个原因 - 如果一个实例方法parametrised,这是合乎逻辑的类型参数属于类,而不是方法。当然,通常。

6

不能保证objectMyClassassign方法传递是一个Teacher,如果MyBase这样定义。如果你被允许修改MyBase,请执行下列操作:

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

,并与你的类扩展它:

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

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

    } 
} 

这将保证object传递的是一个Teacher,即使它是真的Teacher的子类的一个实例。

编辑:另一种方法来修改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(); 
     ...... 
    } 
} 

这是Oracle's Java Generics Tutorial

+0

感谢您的回复。但是如果我不能修改基类呢? – chapstick 2013-02-19 23:54:44