import java.lang.reflect.Array;
import java.util.ArrayList;
import java.util.List;

public class Test {
    public static void main(String[] args) {
//        ErasureAndInheritance.test();
//        ArrayMaker.test();
        FilledListMaker.test();
    }
}

/*
    15.7 擦除的神秘之处

    Class.getTypeParameters()将返回一个TypeVariable对象数组,表示有
    泛型声明所声明的类型参数。我之前确实有过这种需求,但是这个方法不可能给
    我想要的结果

    问题:
        因此,你可以知道诸如类型参数标识符和泛型类型边界这类的信息——你却无法知道用来
        创建某个特定实例的实际的类型参数。Java泛型是使用擦除来实现的,这意味着当你在
        使用泛型的时候,任何具体的类型信息都被擦除了,你唯一知道的就是你在使用一个对象
        因此List<String>和List<Integer>在运行时事实上是相同的类型。这两种类型都被
        擦除成了它们的“原生”类型,即List。理解擦除以及应该如何处理它,是你在学习Java
        泛型时面临的最大障碍。

            ——既然被擦除了,为什么我们还能取到我们想要的类型

            ——C++中如果你用了泛型,编译器就会对应的生成这个类,这一点还是蛮
            舒服的。
 */

/*
    15.7.1 C++的方式
    C++:
        template<class T> class Manipulator
        {
            T obj;
            public:
            Manipulator(T x) { obj = x;}
            void manipulator() { obj.f();}
        }

    Java: 无法通过编译
        class Manipulator<T>
        {
            T obj;
            public Manipulator(T x) { obj = x; }
            void manipulator() { obj.f();}
        }

    解决问题:
        为了调用f(),我们必须协助泛型类,给定泛型类的边界,以此告知
        编译器只能接受这个边界的类型。这里重用了extends关键字

    <T extends HasF> : 声明T必须具有类型HasF或者从HasF导出的类型,
    我们说泛型类型参数将擦除到它的第一个边界(可能会有多个边界)。
 */
class HasF {
    public void f() {}
}
class Manipulator<T extends HasF>
{
    T obj;
    public Manipulator(T x) { obj = x; }
    void manipulator() { obj.f();}
}

/*
    在我们的案例中,泛型没有任何贡献。我们完全可以自己执行泛型擦除。这一点很重要:
    只有当你希望使用的类型参数比某个具体类型(以及它的所有子类型)更加“泛化”时——
    也就是说,当你希望代码能够跨多个类工作时,使用泛型才有所帮助。
        ——额,为什么不用接口呢?接口不也是这种功能么,甚至比这个还有强大一点

    因此,类型参数和它们在有用的泛型代码中的应用,通常比简单的类替换要更复杂。但是,
    不能因此而认为<T extends HasF>形式的任何东西都是有缺陷的。例如,如果某个类有
    一个返回T的方法,那么泛型就有所帮助,因此它们之后将返回确切的类型。
        ——我想知道,既然类型已经被擦除了,那返回时是如何返回成T的了,
        难道是编译器私下里进行了一次强制转换?
 */

/*
    15.7.3 擦除的问题

    擦除的主要的正当理由是非泛型的代码到泛型到泛型代码的转变过程。擦除的代价是
    显著的。泛型不能用于显式的引用运行时类型的操作之中,例如转型、instanceof
    操作和new表达式。因为所有关于参数的类型的信息都丢失了。
 */

class GenericBase<T>{
    private T element;
    public void set(T arg) { element = arg;}
    public T get(){return  element;}
}

class Dervied1<T> extends GenericBase<T> {}
class Dervied2 extends GenericBase {}

class ErasureAndInheritance{
    static void test() {
        Dervied2 d = new Dervied2();
        Object obj = d.get();
        d.set(obj);
    }
}

/*
    17.5.4 边界处的动作
 */

/*
    编译器不会给出任何警告,尽管我们从擦除中知道在create()内部的new ArrayList<T>
    中的<T>被移除了——在运行时,这个类的内部没有任何的<T>。但是,即使编译无法知道有
    关create()中的T的任何信息,但是它仍旧可以在编译期间确保你放置到result中的对象
    具有T类型,使其适合ArrayList<T>。
 */
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));
    }
}
class ListMaker<T>{
    List<T> create(){return new ArrayList<T>();}

    public static void test() {
        ListMaker<String> s = new ListMaker<>();
        List<String> strs = s.create();
    }
}
class FilledListMaker<T> {
    List<T> create(T t, int n) {
        List<T> result = new ArrayList<T>();
        ; i < n; i++) {
            result.add(t);
        }
        return  result;
    }

    public static void test() {
        FilledListMaker<String> stringMaker = new FilledListMaker<>();
        List<String> list = stringMaker.create();
        System.out.println(list);
    }
}

/*
    因为擦除在方法体中移除了类型信息,所以在运行时的问题就是边界:即对象进入和
    离开方法的地点。这些正是编译器在编译期执行类型检查并插入转型代码的地点。
 */

Java编程思想:擦除的神秘之处的更多相关文章

  1. Java编程思想(11~17)

    [注:此博客旨在从<Java编程思想>这本书的目录结构上来检验自己的Java基础知识,只为笔记之用] 第十一章 持有对象 11.1 泛型和类型安全的容器>eg: List<St ...

  2. Java中的泛型 --- Java 编程思想

    前言 ​ 我一直都认为泛型是程序语言设计中一个非常基础,重要的概念,Java 中的泛型到底是怎么样的,为什么会有泛型,泛型怎么发展出来的.通透理解泛型是学好基础里面中非常重要的.于是,我对<Ja ...

  3. 《Java编程思想》读书笔记(二)

    三年之前就买了<Java编程思想>这本书,但是到现在为止都还没有好好看过这本书,这次希望能够坚持通读完整本书并整理好自己的读书笔记,上一篇文章是记录的第一章到第十章的内容,这一次记录的是第 ...

  4. 《Java编程思想》读书笔记(四)

    前言:三年之前就买了<Java编程思想>这本书,但是到现在为止都还没有好好看过这本书,这次希望能够坚持通读完整本书并整理好自己的读书笔记,上一篇文章是记录的第十七章到第十八章的内容,这一次 ...

  5. Java 中的泛型详解-Java编程思想

    Java中的泛型参考了C++的模板,Java的界限是Java泛型的局限. 2.简单泛型 促成泛型出现最引人注目的一个原因就是为了创造容器类. 首先看一个只能持有单个对象的类,这个类可以明确指定其持有的 ...

  6. JAVA编程思想——分析阅读

    需要源码.JDK1.6 .编码风格参考阿里java规约 7/12开始 有点意识到自己喜欢理论大而泛的模糊知识的学习,而不喜欢实践和细节的打磨,是因为粗心浮躁导致的么? cron表达式使用 设计能力.领 ...

  7. JAVA编程思想(第四版)学习笔记----4.8 switch(知识点已更新)

    switch语句和if-else语句不同,switch语句可以有多个可能的执行路径.在第四版java编程思想介绍switch语句的语法格式时写到: switch (integral-selector) ...

  8. MyEclipse导入ant项目——Java编程思想

    北门煎饼东门串儿: <JAVA编程思想(Think in Java)>一书中提供了大量源代码,可是项目是用ant构建的.对于用惯了eclipse,netbeans等IDE的同学们可能有些手 ...

  9. Java编程思想第四版勘误

    坊间传说这本书翻译得很烂,我倒觉得还好.虽然看原文更准确,但是如果在具备一定编程思维和基础.能够看出来疑问的情况下,还是看中文更快一些,而且这本书本身也不适合初学者看.当然,错误和不通顺还是有的,而且 ...

随机推荐

  1. Windows Phone开发参考资料

    Windows Phone API 参考 http://msdn.microsoft.com/zh-cn/library/windows/apps/ff626516(v=vs.105).aspx Wi ...

  2. Solr Principal - 工作原理/机制

    From http://lucene.apache.org/solr/guide/7_1/overview-of-documents-fields-and-schema-design.html The ...

  3. Office Add-in Model 简介

    原文地址:http://simpeng.net/office-add-in/office-add-in-model-%e7%ae%80%e4%bb%8b/ , 为了本博客内容的完整性,转载至此. Of ...

  4. IntelliJ IDEA Maven工程保证JDK版本不变

    创建maven项目后修改pom文件idea会默认将jdk版本调回到1.5,这是因为没有在pom里面设置项目的jdk版本 解决方法: 在pom文件中设定jdk版本即可,以下这种写法会自动更新idea中的 ...

  5. 如何判断操作系统是64位还是32位(GetNativeSystemInfo和IsWow64Process两种方法)

    64位Wnidows 里面有个叫Wow64的模拟器技术,可以使32位的程序在64位Windows 上运行. 当你想在程序里面针对32b位/ 64位系统执行不同代码的时候, 需要判断操作系统是32位还是 ...

  6. 教你如何在 Visual Studio 2013 上使用 Github

    介绍 我承认越是能将事情变简单的工具我越会更多地使用它.尽管我已经知道了足够的命令来使用Github,但我宁愿它被集成到IDE中.在本教程中,我会告诉你使用Visual Studio 2013如何实现 ...

  7. chrome和safari字体粗细问题

    因为我用的是mac电脑,写项目所遇到的问题,这也是我上网和手动试了多次,觉得有效,分享给大家 -webkit-font-smoothing: subpixel-antialiased; -webkit ...

  8. python 之 面向对象基础(定义类、创建对象,名称空间)

    第七章面向对象 1.面向过程编程 核心是"过程"二字,过程指的是解决问题的步骤,即先干什么再干什么 基于该思想编写程序就好比在编写一条流水线,是一种机械式的思维方式 优点:复杂的问 ...

  9. 使用 Python 识别并提取图像中的文字

    1. 介绍 介绍使用 python 进行图像的文字识别,将图像中的文字提取出来,可以帮助我们完成很多有趣的事情. 2. 必备工具 tesseract-ocr 下载地址: https://github. ...

  10. Windows新终端中玩转ASCII和Emoji游戏的正确姿势

    Windows新终端中玩转ASCII和Emoji游戏的正确姿势 前一段时间,我搬运了几个Windows Terminal中玩游戏的视频,详情请看 发布在即!来一睹官方团队如何玩转 Windows Te ...