Typesafe强制转换为通用

时间:2014-08-18 08:46:23

标签: java generics

我对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());

6 个答案:

答案 0 :(得分:1)

如果将泛型类型限制为扩展某个基类的类,则可以执行此操作。

例如,如果您的方法仅在Animal类上运行,那么您将拥有:

public static <T extends Animal>  workWithRealTypeAttr(T objectClass) {
   objectClass.someAnimalMethod()
}

public class Animal {

    public void someAnimalMethod() {

    } 
}

EaselCatDog中的每一个都必须扩展Animal。尝试使用不扩展workWithRealTypeAttr的参数调用Animal会导致编译时间错误。

通过使用接口而不是类,您当然可以为自己提供更大的灵活性。泛型将以完全相同的方式工作。

您只需要一个界面Animal,而EaselCatDog这两个类就会实现该界面。

注意

正如@ user3218114非常正确地指出的那样,在这种简单的情况下不需要使用泛型。您可以将Animal作为workWithRealTypeAttr的参数。但是我没有发布这个答案,因为我想向OP展示仿制品如何在他/她提出的情况下起作用。如果该方法适用于Collection或其他可以充分利用泛型的方法,那么解决方案显然会更加适用。

答案 1 :(得分:1)

创建一个界面并将EaselCatDog类扩展到该界面。

public static <T extends ThatInterface>  workWithRealTypeAttr(T objectClass) {
//here get access to values of Easel, Cat, Dog or some other class
}

Ref:

  

有时,您可能希望限制可在参数化类型中用作类型参数的类型。例如,对数字进行操作的方法可能只想接受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,并使该方法更通用。

enter image description here


您可以根据设计模式根据行为对类进行分组。

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

enter image description here

Head First Design Pattern

中有更好的解释

答案 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