通用技术 浅谈 java 泛型 (一)

陈子昂 · 2018年10月15日 · 最后由 陈子昂 回复于 2018年10月17日 · 2254 次阅读

泛型的背景

很多语言都支持泛型,他的核心思想是当你编写程序时,需要用创建 1 个对象(先一个实体类-->实现类),然后这个对象有几个类似的功能,一个功能需要处理数据是基础类型,一个则是复合类型,这个时候如果根据一个类型处理写一个,代码会比较拖沓,所以采取用泛型的方式来合并代码。
并且泛型还有类型检查的疗效,如下:

`**Item.java**`
public class Item {

    private int ItemNum; //道具数量
    private String ItemName; //道具名称

    public int getItemNum() {
        return ItemNum;
    }

    public void setItemNum(int itemNum) {
        ItemNum = itemNum;
    }

    public String getItemName() {
        return ItemName;
    }

    public void setItemName(String itemName) {
        ItemName = itemName;
    }

    public Item(int ItemNum_, String ItemName_){   //Item的构造函数
        //这里的形参和静态变量做了区分,其实可以不做区分,在内存中private是在类实例化之前就载入的,形参都在栈中和静态变量不是1个区域。
         this.ItemNum =ItemNum_;
         this.ItemName =ItemName_;
    }

    public String toString(){  //实例化后超类toString
            return "道具数量"+this.ItemNum+"道具名称"+this.ItemName;
    }

    public void checkType(){
        //System.out.println("ItemNum类型"+ItemNum.getClass().getName());
        System.out.println("ItamName类型"+ItemName.getClass().getName());
        //思考后的
        Integer ItemNum = (Integer) new Object(); //强自转型成Integer
        System.out.println("ItamName类型"+ItemNum.getClass().getName());
    }
}

实现类
`**Itemvalue.java**`

public class Itemvalue{

    static Item item1 = new Item(10,"HP药水");
    static Item item2 = new Item(8,"MP药水");

    public static void main(String[] args){
        item1.checkType(); #//检查对象数据类型
    }
}

然后注意上面 checkType 的注释。在 checkType() 下一句,因为 ItemNum 是 int 基础类型的,所以只能通过 Object 在转型成 Int 对应的包装类 Integer.
最后发现错误信息是

ItamName类型java.lang.String
Exception in thread "main" java.lang.ClassCastException: java.lang.Object cannot be cast to java.lang.Integer
    at Tools.Item.checkType(Item.java:37)
    at Tools.ItemVaule.main(ItemVectory.java:13)

这个就是编译器阶段语法阶段是对的,一旦运行起来是错误的,没有考虑到这个是运行时才会出现的问题。使用 java 语法糖泛型就可以降低在强制转换类型时,也减少一些运行时的消耗的时间。
后面来讲诉 java 泛型语法糖。

如果觉得我的文章对您有用,请随意打赏。您的支持将鼓励我继续创作!
共收到 8 条回复 时间 点赞

java 的泛型只是个语法糖,而 C# 的泛型才是真泛型

SinDynasty 回复

好牛逼哦

SinDynasty 回复

是的,我后面准备会讲语法糖和 jvm 的关系。就是因为是糖,所以才有了可以擦除

SinDynasty 回复

底层难道不是一样的么?

恒温 回复

不一样

Java 在编译时会进行类型擦除,所以在运行期 GenericClass<int>和 GenericClass<string>是同一个类型

而 C# 不一样,C# 在生成 IL 代码时,会用一个占位符来代替泛型类型,在实例化时,JIT 会根据指定的类型来生成相应的本机代码,所以 C# 在运行期时 GenericClass<int>和 GenericClass<string>不是同一个类型

SinDynasty 回复

哦,java 是在父类的 genericClass 里放了标识

恒温 回复

当初轮子哥在回忆自己在写编译器的时候,这么说道:“Java 那个时候的泛型实现好像也是刚刚出现的,但是我不知道,我也从来没想过泛型要怎么实现。所以当时我想来想去做了一个决定,泛型只让编译器去检查就好了,编译的时候那些 T 都当成 object 来处理,然后就把东西做出来了。我本来以为我这种偷工减料拆东墙补西墙忽悠傻逼用户的方法是业界所不容的,不过后来发现 Java 竟然也是那么做的,让我觉得我一定要黑他一辈子”

SinDynasty 回复

泛型实现本质就 2 类,一块是代码特化,英文比较长。。一块是 code sharing 的机制 也就是代码共享。后者 obj<?>无论在钻石运算符里面是什么类型,编译阶段后共享一份代码文件。也就是哪怕是<复合 OR 字面值>都是同一份。C# 就不是 每新增类型在编译器那边都增加一份 编译阶段后就是多份。C 开头的语言应该都是代码特化。。

需要 登录 后方可回复, 如果你还没有账号请点击这里 注册