Java编程思想:擦除的补偿(数组泛型处,我有很多细节没有研究)
import sun.net.www.content.text.Generic; import java.lang.reflect.Array; import java.util.ArrayList; import java.util.Arrays; import java.util.List; public class Test { public static void main(String[] args) { // ClassTypeCapture.test(); // InstantiateGenericType.test(); CreatorGeneric.test(); } } /* 15.8 擦除的补偿 ——标记下,这个地方乱七八糟,我有点混乱 因为擦除的问题,我们有时候必须通过引入类型标签来对擦除进行补偿。这意味 着你需要显式地传递你的类型的Class对象,以便你可以在类型表达式中使用它。 在前面的例子中对instanceof的尝试最终失败了,因为其类型信息已经被擦除了。 如果引入类型便签,就可以转而使用动态的isInstance()。(前面的失败完全是 因为非要将一个具体类型标签符给一个没有指明的类型标签) */ class Building { } class House extends Building { } class ClassTypeCapture<T>{ Class<T> kind; public ClassTypeCapture(Class<T> kind){ this.kind=kind; } public boolean f(Object arg) { /* 这个地方应该涉及到了Class对象储存信息方面的问题 */ return kind.isInstance(arg); } public static void test() { // ClassTypeCapture<Building> ctt1 = new ClassTypeCapture<>(Building.class); // System.out.println("ctt1.f(new Building()):"+ctt1.f(new Building())); // System.out.println("ctt1.f(new House()):"+ctt1.f(new House())); // // System.out.println(); ClassTypeCapture<House> ctt2 = new ClassTypeCapture<>(House.class); System.out.println("ctt2.f(new Building()):"+ctt2.f(new Building())); System.out.println("ctt2.f(new House()):"+ctt2.f(new House())); } } /* 我把上一个案例的代码,和解读贴在这儿,帮助我理解一下这个问题: 即使kind被存储为Class<T>,擦除也就意味着它实际将被存储为Class,没有任何参数。 因此当你在使用它时,例如在创建数组时,Array.newInstance()实际上并未拥有kind 所蕴含的类型信息,因此这不会产生具体的结果,所以必须转型,这将产生一条令你无法满 意的警告。 */ class ArrayMaker<T>{ //运行时实际保存的是Class<Object> private Class<T> kind; public ArrayMaker(Class<T> kind) { //这个地方在运行时,把一个Class<T>赋给了Class<Object> this.kind=kind; } @SuppressWarnings("unckecked") T[] create(int size) { return (T[]) Array.newInstance(kind,size); } public static void test() { ArrayMaker<String> s = new ArrayMaker<>(String.class); String[] stringArray = s.create(); // System.out.println(Arrays.toString(stringArray)); } } /* 15.8.1 创建类型实例 需求: 解决在在泛型类中不能用T t创建对象的方案。Java中可以传递一个工厂对象,并使用它来 创建新的实例。最便利的工厂对象就是Class对象,因此如果使用类型标签,那么你可以使用 newInstance()来创建这个类型的新对象。 */ class ClassAsFactory<T>{ T x; T y; Class<T> k; public ClassAsFactory(Class<T> kind) { try{ x = kind.newInstance(); //这个地方没有将kind对象存给任何被擦除了的对象哦 System.out.println("x:"+x.getClass().getName()); /* 很奇怪,我这儿并有发生前文描述的任何问题? */ k=kind; y = k.newInstance(); System.out.println("y:"+y.getClass().getName()); } catch (IllegalAccessException e) { e.printStackTrace(); } catch (InstantiationException e) { e.printStackTrace(); } } } class Employee { } //这个方案由于问题不是在编译期报出来,故不推荐 class InstantiateGenericType { static void test() { new ClassAsFactory<Employee>(Employee.class); System.out.println("ClassAsFactory<Employee> succeeded"); // // ClassAsFactory<Integer> f1 = // new ClassAsFactory<>(Integer.class); } } //Sun建议使用的显式工厂 interface Factory<T>{ T create(); } class Foo2<T>{ private T x; public <F extends Factory<T>> Foo2(F factory){ x = factory.create(); } } class IntegerFactory implements Factory<Integer>{ @Override public Integer create() { ); } } /* 这个为什么会报错啊!!! class Widget{ //嵌套类实现一个工厂,但是报错了,说是循环实现 static class Factory implements Factory<Widget>{ public Widget create() { return new Widget(); } } } */ class FactoryConstraint{ static void test() { new Foo2<Integer>(new IntegerFactory()); // new Foo2<Widget>(new Widget.Factory()); } } /* 最后一种在泛型类中实例参数对象的方法:使用模板方法设计模式。 */ abstract class GenericWithCreate<T>{ final T element; GenericWithCreate(){ element=create(); } abstract T create(); } class X{} class Creator extends GenericWithCreate<X>{ @Override X create() { return new X(); } void f(){ System.out.println(element.getClass().getSimpleName()); } } class CreatorGeneric{ static void test() { Creator c = new Creator(); c.f(); } } /* 最后做一个自己的实验,验证一下现在真的不可以在泛型类中创建参数化对象么? */ class A<T>{ T t; A(){ //t = new T(); 果然不可以 } } /* 15.8.2 泛型数组 ——这部分东西,我暂时不研究了,很枯燥,而且感觉价值并不是太高 解决不能创建泛型数组的方案:在任何想要创建泛型数组的地方都使用ArrayList */ class ListOfGenerics<T>{ private List<T> array = new ArrayList<>(); public void add(T item){array.add(item);} public T get(int index){return array.get(index);} } /* 有时,你仍旧希望创建泛型类型的数组(例如,ArrayList内部使用的是数组)。有趣的是 你可以按照编译器喜欢的方式来定义一个引用,例如: */ class H<T> {} class ArrayOfH{ static H<Integer>[] gia; } /* 编译器接受这个程序,而不会产生任何警告。但是,永远都不能创建这个确切类型的数组(包括 参数类型),因此这有点令人困惑。既然所有数组无论它们持有的类型如何,都具有相同的结构 (每个数组槽位的尺寸和数组的布局),那么看起来你应该能够创建一个Object数组,并将其 装换成所希望的数组类型。事实上这可以编译,但是不能运行,它将产生ClassCaseException */ class ArrayOfGeneric{ ; static H<Integer>[] gia; @SuppressWarnings("unchecked") static void test() { gia = (H<Integer>[])new H[SIZE]; } } /* 成功创建泛型数组的唯一方式就是,创建一个被擦除类型的新数组,然后对其转型 */
Java编程思想:擦除的补偿(数组泛型处,我有很多细节没有研究)的更多相关文章
- Java编程思想学习(十二) 数组和容器
一.数组 1).数组的多种初始化方式 下面总结了初始化数组的多种方式,以及如何对指向数组的引用赋值,使其指向另一个数组对象.值得注意的是:对象数组和普通数组的各种操作基本上都是一样的:要说有什么不同的 ...
- Java中的泛型 --- Java 编程思想
前言 我一直都认为泛型是程序语言设计中一个非常基础,重要的概念,Java 中的泛型到底是怎么样的,为什么会有泛型,泛型怎么发展出来的.通透理解泛型是学好基础里面中非常重要的.于是,我对<Ja ...
- 《Java编程思想》第一二章
前段时间一直通过网络教程学习Java基础,把面向对象部分学完之后本来打算继续深入学习,但是感觉自己操之过急了,基础根本不够扎实,所以入手了一本<Java编程思想>,希望先把基础打好,再深入 ...
- Java编程思想—八皇后问题(数组法、堆栈法)
Java编程思想-八皇后问题(数组法.堆栈法) 实验题目:回溯法实验(八皇后问题) 实验目的: 实验要求: 实验内容: (1)问题描述 (2)实验步骤: 数组法: 堆栈法: 算法伪代码: 实验结果: ...
- Java编程思想(11~17)
[注:此博客旨在从<Java编程思想>这本书的目录结构上来检验自己的Java基础知识,只为笔记之用] 第十一章 持有对象 11.1 泛型和类型安全的容器>eg: List<St ...
- JAVA编程思想——分析阅读
需要源码.JDK1.6 .编码风格参考阿里java规约 7/12开始 有点意识到自己喜欢理论大而泛的模糊知识的学习,而不喜欢实践和细节的打磨,是因为粗心浮躁导致的么? cron表达式使用 设计能力.领 ...
- Java编程思想 笔记
date: 2019-09-06 15:10:00 updated: 2019-09-24 08:30:00 Java编程思想 笔记 1. 四类访问权限修饰词 \ 类内部 本包 子类 其他包 publ ...
- 《Java编程思想》读书笔记(二)
三年之前就买了<Java编程思想>这本书,但是到现在为止都还没有好好看过这本书,这次希望能够坚持通读完整本书并整理好自己的读书笔记,上一篇文章是记录的第一章到第十章的内容,这一次记录的是第 ...
- Java编程思想 (1~10)
[注:此博客旨在从<Java编程思想>这本书的目录结构上来检验自己的Java基础知识,只为笔记之用] 第一章 对象导论 1.万物皆对象2.程序就是对象的集合3.每个对象都是由其它对象所构成 ...
- Java 编程思想 Chapter_14 类型信息
本章内容绕不开一个名词:RTTI(Run-time Type Identification) 运行时期的类型识别 知乎上有人推断作者是从C++中引入这个概念的,反正也无所谓,理解并能串联本章知识才是最 ...
随机推荐
- 利用NPOI生成DOCX文档
首先安装NPOI控件: Install-Package NPOI 代码: using NPOI.OpenXmlFormats.Wordprocessing; using NPOI.XWPF.UserM ...
- git服务器创建,冲突解决,远程仓库获取指定文件
1.git服务器创建 在公司多人协作开发的情况下,不能简单地使用github,因为github是互联网公开的,这种情况公司的代码的保密性就会丧失了.这种情况下,需要创建git服务器. 登录服务器,使用 ...
- C#最基本的数据库增删改查
namespace access { public partial class Form1 : Form { //定义数据库的连接路径 string txtConn ="Provider=M ...
- SignalR--Web客户端
原文:SignalR--Web客户端 这里说web客户端其实是JavaScript起的作用,也可以说是JavaScript客户端. 官方的标题的JavaScript客户端. 下面的翻译,同样的代码的形 ...
- SGI地址模式: O32, N32和N64
背景 MIPS R10000芯片支持MIPS ABI.遵循这一标准的程序能够运行在遵循这一标准的任何处理器/系统上.目前,主要的支持者有SGI,西门子,Nixdof, Tandem, Pyramid, ...
- 将QT开发的界面程序封装成DLL,在VC中成功调用(必须有消息循环,所以使用了QTWinmigrate,附CSDN可下载的Demo)
最近手头的一个项目需要做一个QT界面,并且封装成DLL,然后再动态调用DLL给出的接口函数,使封装在DLL内部的QT界面跑起来,在网上查了很多资料,今天终于成功了,经验不敢独享,因为CSDN给了我很多 ...
- 解码mmo游戏服务器三:大地图同步(aoi)
问题引入:aoi(area of interest).在大地图中,玩家只需要关心自己周围的对象变化,而不需要关心距离较远的对象的变化.所以大地图中的数据不需要全部广播,只要同步玩家自己视野范围的消息即 ...
- 简单看看jdk7源码之java.lang包01
从今天开始简单开始读一遍jdk的源码,估计这个时间会很长,慢慢啃吧....(首先说一句抱歉,因为很多图都是直接百度扣的,图太多了不能为每一个图附上原版链接,不好意思!) 在网上看了很多的教程,读源码有 ...
- SQL Server 2012完全备份、差异备份、事务日志备份和还原操作;
SQL Server 2012完全备份.差异备份.事务日志备份和还原操作: 1.首先,建立一个测试数据库,TestA:添加一张表,录入二条数据:备份操作这里我就不详细截图和讲解了.相信大家都会备份,我 ...
- Git--将已有的项目添加到github
(2). 初始化本地仓库,并提交内容到本地 需要先打开 命令行终端,然后通过 cd 命令切换到需要添加到github 的项目的目录下,然后依次执行如下命令, 具体命令及其含义如下: 1). touch ...