V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
V2EX 提问指南
cmuler
V2EX  ›  问与答

java 核心技术 卷 1 里面泛型一章中“泛型类的静态上下文中类型变量无效”这一节不能理解

  •  
  •   cmuler · 2016-02-24 09:15:31 +08:00 · 3007 次点击
    这是一个创建于 3206 天前的主题,其中的信息可能已经有所发展或是发生改变。

    书里面这么写的:

    public class Singleton<T>
    {
        private static T singleInstance    //ERROR
        private static T getSingleInstance()    //ERROR
        {
            if(singleInstance == null)
                return singleInstance;
        }
    }
    

    类型擦除后,只剩下 Singleton 类,它只包含一个 singleInstance 域。因此,禁止使用带有类型变量的静态域和方法。

    不太理解什么意思,为什么跟类型擦除有关系?请高手指点一下

    9 条回复    2016-02-24 13:58:41 +08:00
    ipeony
        1
    ipeony  
       2016-02-24 10:09:10 +08:00   ❤️ 1
    初始化顺序问题吧
    fwrq41251
        2
    fwrq41251  
       2016-02-24 10:12:59 +08:00   ❤️ 1
    泛型类上的泛型类型在实例化时确定。
    比如:
    Singleton<String> singletonForString= new Singleton();
    Singleton<Boolean> singletonForBoolean= new Singleton();
    而静态成员是被该类的所有对象共享的,显然你的泛型类型不能应用到静态成员上。
    sadwxds
        3
    sadwxds  
       2016-02-24 10:17:47 +08:00   ❤️ 1
    我是这么想的,如果你的泛型能够用在静态的属性或方法中。
    那么你在
    A 处 new Singleton<Integer>;
    B 处 new Singleton<YouClass>;
    那么当你调用 Singleton.getSingleInstance();
    你知道你将要返回的是什么样的类型结果吗?
    yrom
        4
    yrom  
       2016-02-24 10:26:22 +08:00   ❤️ 1
    类( Class )的类型参数( Type Parameters )只存在于类的实例的方法域和成员变量域。换句话说,必须实例化你这个类( Singleton )才知道那个类型参数“ T ”是什么鬼。 再比如, new Singleton<String>() , 这个时候"T"就是 String 。不知道明白了没。。
    SoloCompany
        5
    SoloCompany  
       2016-02-24 10:47:36 +08:00   ❤️ 1
    看你怎么理解, static 不能使用模板类型可以说和类型擦除有关也可以说无关
    具体到 java 泛型里面主要在于模板类型 T 的作用范围,本身规定就只是成员(变量以及方法)
    静态变量的作用范围完全不一样,所以不能使用模板类型
    从这一点上来说,可以说和类型擦除不一定相关

    但如果考虑到实现机制的话,就有可能相关,泛型有一种实现机制就是生成模板衍生类
    比如你举的这个例子 Singleton<T> 对应的是一个独立的衍生类 Singleton_T
    如果静态变量也复制一份的话,那么静态方法 /变量就可以使用模板类型
    就是说 Singleton<A>.singleInstance 和 Singleton<B>.singleInstance 可以不一样(被复制)

    Java 的泛型机制是类型擦除机制,无论怎么实现都不可能有复制的静态变量,所以任意静态元素都不可以使用类定义的模板类型,因为他们之间毫无关系。你这么理解,静态变量以及方法和方法和他们所依附( enclosing )的类之间是完全没有关系的,他们只是简单的被放在一起而已
    SoloCompany
        6
    SoloCompany  
       2016-02-24 10:50:45 +08:00
    我觉得 Kotlin 把 static 关键字去除了是一个比较明智的选择
    因为 static 的确是不太 OO 的,而且会造成有些概念上的混淆
    用 package function 以及 compainion objet 来代替还是挺适合的
    cmuler
        7
    cmuler  
    OP
       2016-02-24 11:51:47 +08:00
    @SoloCompany 用模板类来实现泛型应该是 c#的实现方式吧。请教一下,这两种实现方式哪种更加好一点
    wizardforcel
        8
    wizardforcel  
       2016-02-24 13:13:02 +08:00 via Android
    泛型的类型参数只在编译时存在,编译之后会被擦除。比如你的 Singleton<String>和 Singleton<Integer>编译之后都是 Singleton , T 会变成 Object 。你是希望 Singleton<String>和 Singleton<Integer>有不同的 instance ,但实际上它们是冲突的,为了避免这种情况所以不能这么写。
    SoloCompany
        9
    SoloCompany  
       2016-02-24 13:58:41 +08:00
    @cmuler 模板衍生类互相之间没有一个公共的基类,类型不相容(更别谈赋值相容了),并且类的数量不好彩的话会爆炸(要知道泛型是嵌套的,考虑一下 List<List<List<Map<?,?>>>>)
    其实这点内存占用还不是最要命的,最要命的是没有公共基类了,就别想有任何兼容性可言了,也就是说,之前已经写好的(包括大量第三方)类库,都无法使用泛型版本的类,除非改写为只适用于某特定泛型版本的。 Java 里面也有这样的例子,你看一眼 java.uitil.Arrays 的实现就知道了,就是一个典型的模板方式实现的泛型,因为基本类型不是 Object 。
    其实 java 也可以创造一种模板方式的泛型语法,比如增加一个关键字 template , Arrays.binarySearch 就可以这样定义
    public static <template t> binarySearch(t[] a, t key);
    然后让编译器来动态生成每一种类型对应的方法
    可以说这两种泛型完全是不同的概念
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   1037 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 30ms · UTC 19:49 · PVG 03:49 · LAX 11:49 · JFK 14:49
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.