• 2005-08-11

    虚假的泛型

    Tag:向上走

    版权声明:转载时请以超链接形式标明文章原始出处和作者信息及本声明
    http://www.blogbus.com/dreamhead-logs/1352796.html

    一位网友引发了一次关于泛型数组创建的讨论大胃给出了自己的回答。我也想就这个问题讨论一下,因为这也是我曾经遇到过的一个问题。

    简而言之,在Java中,下面这段代码行不通。
    public static T[] create(T t) {
        return new T[100];
    }

    在讨论这个话题之前,我们必须知道的一个事实是Java的泛型并不是我们常说的那种真正的泛型。下面是一个简单泛型程序:
    public class Generic {
        public static void main(String[] args) {
            String s = transition("hello");
        }

        public static T transition(T t) {
            return t;
        }
    }

    如果把编译之后的结果反编译过来,一切的魔术就将揭开:
    public class Generic {
        public static void main(String args[]) {
            String s = (String)transition("hello");
        }

        public static Object transition(Object obj) {
            return obj;
        }
    }
    从这里我们不难看出,编译器将从前版本中需要的手工转型给自动化了。

    既然要达到一种可用的自动化,一个很重要的标准就是不能把原本做得很好的事情给破坏了。泛型在于把类型作为参数,而我们前面已经看到了,交给虚拟机的class文件里根本没有类型信息,也就是说,Java的泛型都是编译器上的工作。除非用户明确要求怎么做(比如强制转型),否则能够通过编译器的在类型问题上一定是清清楚楚、明明白白的,不能有任何含糊。

    在回头看最初的问题便不难解释了。我们预期创建泛型数组,但实际上,因为类型信息将会在编译阶段丢失,那么到了运行时,不知类型,何谈创建。在类型问题上想蒙混过关,谈何容易。因此,这样的代码是无法编译通过的。由此可以看出,这个问题本身与数组没有太大的干系,完全是类型问题在作祟。

    说好听点,是为了安全,实际上,只是不想给人留下口实而已。关于这个话题,《Generics in the Java Programming Language》7.3节进行了更为细致的讨论,你会看到如果在类型上不较真将会出现怎样的遗漏。

    Java泛型如此选择有其历史原因。作为Java泛型的雏形泛型Java形成之初,势单力孤,尚无力改变Java的历史进程,因此,它只有选择在Java编译器上动手脚,而不敢动Java虚拟机毫分,因此,Java的泛型就注定了其虚假的本质。事实上,这也大多数新思想介入Java时遇到的问题,比如AspectJ。运用同样的反编译技术,我们不难发现,Tiger中大多数的新语法都是在不伤及虚拟机的情况下加入。Annotation是一个例外,它所带来改变class文件,这也使得Java泛型的努力显得如此不伦不类:要么都不改,要改就改得彻底一些。

    如果说C++的泛型带来的是一场思维革命,那Java的泛型至多只是一种简化代码编写的手段而已。不过这也符合Tiger的口号:简化开发。

    分享到:

    历史上的今天:

    引用地址:

    评论

  • 看来这种范型只是流于形式的~~~
    回复tracy说:
    它的目的是简化代码编写,从这个角度来看,它的目的是达到了。只不过,没有C++泛型影响那么深远罢了!
    2005-09-08 19:07:35
  • 那就困惑了,能否解释一下呢?
  • 如果这样写呢?

    public class Generic {

    public static void main(String[] args) {

    String s = transition("hello");

    }



    public static T[] transition(T t) {

    return new T[100];

    }

    }

    你只是说

    public static T[] create(T t) {

    return new T[100];

    }

    编译不过去,如果我在编译的时候就告知Java类型为String是否就编译过去了呢?谢谢
    回复Killvin说:
    不可以!这个问题你试一下就知道了。
    2005-08-15 17:47:12