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

2016-02-24 09:15:31 +08:00
 cmuler

书里面这么写的:

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

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

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

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

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

Java 的泛型机制是类型擦除机制,无论怎么实现都不可能有复制的静态变量,所以任意静态元素都不可以使用类定义的模板类型,因为他们之间毫无关系。你这么理解,静态变量以及方法和方法和他们所依附( enclosing )的类之间是完全没有关系的,他们只是简单的被放在一起而已
SoloCompany
2016-02-24 10:50:45 +08:00
我觉得 Kotlin 把 static 关键字去除了是一个比较明智的选择
因为 static 的确是不太 OO 的,而且会造成有些概念上的混淆
用 package function 以及 compainion objet 来代替还是挺适合的
cmuler
2016-02-24 11:51:47 +08:00
@SoloCompany 用模板类来实现泛型应该是 c#的实现方式吧。请教一下,这两种实现方式哪种更加好一点
wizardforcel
2016-02-24 13:13:02 +08:00
泛型的类型参数只在编译时存在,编译之后会被擦除。比如你的 Singleton<String>和 Singleton<Integer>编译之后都是 Singleton , T 会变成 Object 。你是希望 Singleton<String>和 Singleton<Integer>有不同的 instance ,但实际上它们是冲突的,为了避免这种情况所以不能这么写。
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);
然后让编译器来动态生成每一种类型对应的方法
可以说这两种泛型完全是不同的概念

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/258632

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX