我对Java中的泛型主题有疑问: 让我们说我在课堂上遵循通用(静态)方法。在这种方法中,我希望能够访问真实类的某些方法/字段。静态语言Java中是否存在一些类型安全的方法?或者有任何解决方法吗?
public class GenericClassUtil {
public static <T> void workWithRealTypeAttr(T objectClass) {
//here get access to values of Easel, Cat, Dog or some other class
}
}
GenericClassUtil.workWithRealTypeAttr(new Easel());
GenericClassUtil.workWithRealTypeAttr(new Cat());
GenericClassUtil.workWithRealTypeAttr(new Dog());
答案 0 :(得分:1)
如果将泛型类型限制为扩展某个基类的类,则可以执行此操作。
例如,如果您的方法仅在Animal
类上运行,那么您将拥有:
public static <T extends Animal> workWithRealTypeAttr(T objectClass) {
objectClass.someAnimalMethod()
}
public class Animal {
public void someAnimalMethod() {
}
}
Easel
,Cat
和Dog
中的每一个都必须扩展Animal
。尝试使用不扩展workWithRealTypeAttr
的参数调用Animal
会导致编译时间错误。
通过使用接口而不是类,您当然可以为自己提供更大的灵活性。泛型将以完全相同的方式工作。
您只需要一个界面Animal
,而Easel
,Cat
和Dog
这两个类就会实现该界面。
注意强>
正如@ user3218114非常正确地指出的那样,在这种简单的情况下不需要使用泛型。您可以将Animal
作为workWithRealTypeAttr
的参数。但是我没有发布这个答案,因为我想向OP展示仿制品如何在他/她提出的情况下起作用。如果该方法适用于Collection或其他可以充分利用泛型的方法,那么解决方案显然会更加适用。
答案 1 :(得分:1)
创建一个界面并将Easel
,Cat
,Dog
类扩展到该界面。
public static <T extends ThatInterface> workWithRealTypeAttr(T objectClass) {
//here get access to values of Easel, Cat, Dog or some other class
}
有时,您可能希望限制可在参数化类型中用作类型参数的类型。例如,对数字进行操作的方法可能只想接受Number或其子类的实例。这是有界类型参数的用途。
要声明有界类型参数,请列出类型参数的名称,然后是extends关键字,后跟其上限,在此示例中为Number。请注意,在此上下文中,extends在一般意义上用于表示“extends”(如类中)或“implements”(如接口中)。
public class Box<T> {
private T t;
public void set(T t) {
this.t = t;
}
public T get() {
return t;
}
public <U extends Number> void inspect(U u){
System.out.println("T: " + t.getClass().getName());
System.out.println("U: " + u.getClass().getName());
}
public static void main(String[] args) {
Box<Integer> integerBox = new Box<Integer>();
integerBox.set(new Integer(10));
integerBox.inspect("some text"); // error: this is still String!
}
}
答案 2 :(得分:1)
我希望能够访问真实类的某些方法/字段
如果您想访问真实班级的方法/字段,请使用不同的重载方法
class GenericClassUtil {
public static void workWithRealTypeAttr(Bird objectClass) {
// call a method specific to Bird (Easel)
}
public static void workWithRealTypeAttr(Mammal objectClass) {
// call a method specific to Mammal (Cat, Dog etc)
}
}
您可以将类分组为Mammal,Bird,并使该方法更通用。
您可以根据设计模式根据行为对类进行分组。
class GenericClassUtil {
public static void workWithRealTypeAttr(Flyable objectClass) {
// call a method specific to Flyable
}
public static void workWithRealTypeAttr(Swimmable objectClass) {
// call a method specific to Swimmable
}
}
interface Swimmable { public void swim() }
interface Flyable { public void fly() }
中有更好的解释
答案 3 :(得分:0)
虽然它不优雅但你可以使用如下构造。您可以尝试使用instanceof和cast。
public static <T> workWithRealTypeAttr(T objectClass) {
if (objectClass instanceof Easel) {
((Easel) objectClass).toSomehtingEaselsDo());
} elseif (objectClass instanceof Cat) {
((Cat) objectClass).toSomehtingCatsDo());
} elseif (objectClass instanceof Dog) {
((Dog) objectClass).toSomehtingDogsDo());
} else {
//do something to inform about not supported class.
}
}
另一种方式可能是使用通用界面(如其他答案所示)<T extends yourInterface>
或装饰器模式。
答案 4 :(得分:0)
你唯一能做的就是让你的所有类都实现一个通用接口,并在该接口中保留一个通用方法。
你必须为你的T指定边界(考虑动物是所有你提到的类的超级类)
然后你可以访问
里面的t.commonMethod()例如 有像
这样的界面public interface Animal {
void commonMethod();
}
在你的方法中
<T extends Animal> tryWithGenerics(T t) {
t.commonMethod(): //call like this
}
注意: 你的所有类都应该实现Animal接口
答案 5 :(得分:0)
是的,你可以。
有两种(或更多)方法可以实现它。
您可以使用Animal接口/类并使用这样的通配符:
public static <T extends Animal> void makeAnimalEat(T animal) {
animal.eat();
}
或使用这样的反射:
public static <T> void makeAnimalEatReflection(T animal) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
animal.getClass().getMethod("eat").invoke(animal);
}
动物界面:
interface Animal{
void eat();
}
有关通用卡和通配符的其他信息,请访问http://docs.oracle.com/javase/tutorial/extra/generics/wildcards.html