java包装类&简单认识泛型

2023-11-19

1 包装类

Java 中,由于基本类型不是继承自 Object ,为了在泛型代码中可以支持基本类型, Java 给每个基本类型都对应了一个包装 类型。类中比如由属性/方法 使用比较方便

1.1 基本数据类型和对应的包装类  

1.2 装箱和拆箱

装包/装箱 : 基本数据类型=>包装类类型

拆箱/拆包 : 包装类型=>基本类型 

int i = 10;
// 装箱操作,新建一个 Integer 类型对象,将 i 的值放入对象的某个属性中
Integer ii = Integer.valueOf(i);
Integer ij = new Integer(i);   // 显示装箱 底层还是调用Integer.valueOf(i);

// 拆箱操作,将 Integer 对象中的值取出,放到一个基本数据类型中
int j = ii.intValue();  // 显示拆箱

1.3 自动装箱和自动拆箱  

可以看到在使用过程中,装箱和拆箱带来不少的代码量,所以为了减少开发者的负担, java 提供了自动机制
int i = 10;
Integer ii = i; // 自动装箱
Integer ij = (Integer)i; // 自动装箱

int j = ii; // 自动拆箱
int k = (int)ii; // 自动拆箱

阿里面试题

下列代码输出什么,为什么?
public static void main(String[] args) {
Integer a = 127;
Integer b = 127;
Integer c = 128;
Integer d = 128;
System.out.println(a == b);
System.out.println(c == d);
}

答案: 

解释: 四行代码都是对应自动装箱操作, 而自动装箱操作底层还是调用Integer.valueOf(i);

cache 是一个提前开辟好的长度为256的数组,

cache[0] 存放的是 -128  (-128 + (- ( -128 ) ) = 0 )

cache[255]存放的是127 (127 + (- ( -128 ) ) = 0 )

也就是说当传入valueOf()的值范围在-128~127之间时, 返回的值都是实现设置好的,因此为true

但128超出范围, 必须new一个新值, 两个值在不同地址上因此只能是false 

2 什么是泛型

一般的类和方法,只能使用具体的类型 : 要么是基本类型,要么是自定义的类。如果要编写可以应用于多种类型的代码,这种刻板的限制对代码的束缚就会很大。--- Java 编程思想》对泛型的介绍。
通俗讲,泛型: 就是适用于许多许多类型 从代码上讲,就是对类型实现了参数化。
可以认为传递的是类型

3 引出泛型

实现一个类,类中包含一个数组成员,使得数组中可以存放 任何类型 的数据,也可以根据成员方法返回数组中某个下标位置上的值?
思路:
  1. 我们以前学过的数组,只能存放指定类型的元素,例如:int[] array = new int[10]; String[] strs = new String[10];
  2. 所有类的父类,默认为Object类。数组是否可以创建为Object?
class MyArray {
    public Object[] objects = new Object[10];
    public Object getPos(int pos) {
        return objects[pos];
    }
    public void setVal(int pos,Object val) {
        objects[pos] = val;
    }
}
public class TestDemo {
    public static void main(String[] args) {
        MyArray myArray = new MyArray();
        myArray.setVal(0,10);
        myArray.setVal(1,"hello");//字符串也可以存放
        String ret = myArray.getPos(1);//编译报错
        System.out.println(ret);
    }
}

编译报错地方  必须进行强制类型转化才能输出

String ret = (String)myArray.getPos(1);//编译报错
System.out.println(ret);
问题:以上代码实现后 发现
1. 任何类型数据都可以存放
2. 1 号下标本身就是字符串,但是确编译报错。必须进行强制类型转换
虽然在这种情况下,当前数组任何数据都可以存放,但是,更多情况下,我们还是希望他只能够持有一种数据类型。而不是同时持有这么多类型。所以,泛型的主要目的:就是指定当前的容器,要持有什么类型的对象。让编译 器去做检查。 此时,就需要把类型,作为参数传递。需要什么类型,就传入什么类型。
/**
 * @param <T>  T是一个占位符,表示当前类是一个泛型类
 *
 */
class MyArray2<T> {
    //public Object[] objects = new Object[10];
    public T[] objects = (T[])new Object[10];
    //public T[] objects = new T[10];  //1

    public T getPos(int pos) {
        return objects[pos];
    }
    public void setVal(int pos,T val) {
        objects[pos] = val;
    }
}
public static void main2(String[] args) {
        MyArray<Integer> myArray1 = new MyArray<Integer>(); //2
        myArray1.setVal(0,48);
        myArray1.setVal(1,10);
        int val = myArray1.getPos(1); //3
        System.out.println(val);
        System.out.println("=======");
        MyArray<String> myArray2 = new MyArray<>();
        myArray2.setVal(0,"hello");
        myArray2.setVal(1,"bit");
        String ret = myArray2.getPos(1);
        System.out.println(ret);
    }
1.注释 1 处,不能 new 泛型类型的数组
        意味着: T [] ts = new T [ 5 ]; // 是不对的, 这样写会报错, 报错原因后边说
        因为泛型不能在运行中被识别, 只能在编译中才能被识别
        课件当中的代码:T[] array = (T[])new Object[10]; 是否就足够好,答案是未必的。这块问题一会儿介绍。

2. 注释 2 处,类型后加入 <Integer> 指定当前类型
3. 注释 3 处,不需要进行强制类型转换

泛型存在的意义:

  1. 在编译的时候, 帮我进行类型的检查
  2. 在编译的时候, 帮我进行类型的转换

运行的时候是没有泛型概念的, JVM当中是没有泛型的

4. 泛型是如何编译的 

4.1 擦除机制

那么,泛型到底是怎么编译的?这个问题,也是曾经的一个面试问题。泛型本质是一个非常难的语法,要理解好他 还是需要一定的时间打磨
在编译的过程当中,将所有的 T 替换为 Object 这种机制,我们称为: 擦除机制

Java的泛型机制是在编译级别实现的。编译器生成的字节码在运行期间并不包含泛型的类型信息。  

4.2 提出问题:

4.2.1

为什么,public T[] objects = new T[10]; 是不对的,编译的时候,替换为Object,不是相当于:Object[] ts = new Object[5]吗?那既然会替换为Object为什么会报错呢?

答案: 因为Java数组语法上要求new后边必须跟一个具体类型

4.2.2 为什么T[] array = (T[])new Object[10 不够好

       我们提供一个getArray()方法来 实例化泛型类型数组
当我们运行getArray()方法时候就会报错,哪怕强转都会报错,  因为擦除机制编译时返回的是Object类型,
而Object类型无论如何都不能转为Integer具体类型
返回的 Object 数组里面,可能存放的是任何的数据类型,可能是 String ,可能是 Person ,运行的时
候,直接转给 Integer 类型的数组,编译器认为是不安全的
改进方法1: 用Object类型接收 

既然不允许强转Object  那就只能用Object类型接收 

class MyArray2<T> {
    //public Object[] objects = new Object[10];
    public T[] objects = (T[])new Object[10];
    //public T[] objects = new T[10];  //1

    public T getPos(int pos) {
        return objects[pos];
    }
    public void setVal(int pos,T val) {
        objects[pos] = val;
    }
    public Object[] getArray() {   // 也可以返回T[] 都一样最后也编译成Object[]
        return objects;
    }
}
public static void main2(String[] args) {
    MyArray<Integer> myArray1 = new MyArray<Integer>(); 
    Object[] integers = myArray1.gerArray();    
}

要是必须用具体Integer类型来接收呢? 更好的

改进方法2: 用反射创建指定类型的数组(了解即可)

改进方法1 myArray1内部创建过程中用是泛型类型数组, 而方法2内部创建过程中直接使用指定类型数组, 当然就不在需要因为擦除机制编译成Object类型了

class MyArray2<T> {
    //public Object[] objects = new Object[10];
    public T[] objects;
    //public T[] objects = new T[10];  //1

    /**
    * 通过反射创建,指定类型的数组
    * @param clazz
    * @param capacity
    */
    public MyArray(Class<T> clazz, int capacity) {
        array = (T[])Array.newInstance(clazz, capacity);
    }

    public T getPos(int pos) {
        return objects[pos];
    }
    public void setVal(int pos,T val) {
        objects[pos] = val;
    }
    public T[] getArray() {
        return objects;
    }
}
public static void main2(String[] args) {
    MyArray2<Integer> myArray2 = new MyArray2<>(Integer.class,10);
    Integer[] integers = myArray2.getArray();   
}
最佳方法

那在实际工作中通常只需要直接使用Object类型数组就可以了, 只需要注意一下setVal()时存放T类型就可以了, getPos()取数据时候强制类型转换就可以了, 当然也需要用Object类型数组接收getArray()结果

我们以后就用这个方式写代码 

 

5. 泛型的上界

问题引入 , 红色部分出现的原因?

答案:
<>当中必须存放引用数据类型, 而引用数据类型的数据之间比较大小必须通过 实现 Comparable 接口,并调用其中的compareTo()方法
但是泛型T在编译的时候被擦除成Object类型, 而Object类型并没有实现Comparable接口,因此出现报错
这个  extends Comparable <E > 就是为泛型添加一个上界, 避免被擦除成Object , 而是擦除成实现了 Comparable 接口的类型(即上界)
另外传入的泛型T 必须 实现Comparable 接口的类型(即上界类型)
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

java包装类&简单认识泛型 的相关文章

随机推荐

  • element组件库中tab表格利用cellStyle方法单独改变单元格样式

    公司项目中已经封装了一个公共的tab组件 新的需求需要对表格中特定的单元格字体颜色做改变 查询了官方文档发现有cellStyle这个属性 在公共组件中加了标签属性 一开始是使用 emit方法触发父传子 使用该表格是自定义该事件 但是样式不生
  • 最大似然估计【MLE】与最大后验概率【MAP】

    最大似然估计 Maximum likelihood estimation 简称MLE 和最大后验概率估计 Maximum a posteriori estimation 简称MAP 是很常用的两种参数估计方法 如果不理解这两种方法的思路 很
  • matlab 回归

    我发现这两天写题目 回归真的是个万能方法 但是我只会最简单的线性回归 为此特地记录一下以下几种方法 1 regress 简单线性回归 可以是一元 也可以是多元 具体用法可以看这个图片 这个方法最简单 也最好用 但是也有局限 比如非线性的时候
  • Unity与Andriod交互错误合集

    一 无法调用安卓中的方法no non static method with name 报错如下 在保证代码中的方法名没有问题 并且调用的方法名的返回值和传递的参数等都没有问题的情况下 第一 查看在Unity项目中jar包存放的位置是否正确
  • 前言 在学习达梦数据库数据存储过程中有接触到行式存储和列式存储方面的内容 在此作简单的学习分享 通过本文你可以了解到行存储模式 列存储模式 它们的优缺点以及列存储模式的优化等知识 Row vs Column Oriented Databas
  • 怎样用计算机的计算器的程序员进行进制,使用系统自带计算器进行二进制运算(示例代码)...

    int x 110 int y 10 Console WriteLine x y Console WriteLine x y 想亲自算一下这种计算的时候 打开windows自带的计算器calc exe 调到 程序员计算器 模式即可 选择DE
  • 华为OD机试 - 日志限流(Java )

    题目描述 某软件系统会在运行过程中持续产生日志 系统每天运行N单位时间 运行期间每单位时间产生的日志条数保行在数组records中 records i 表示第i单位时间内产生日志条数 由于系统磁盘空间限制 每天可记录保存的日志总数上限为to
  • 详解人工智能领域重大突破:GPT-3

    2020 09 14 16 09 导语 GPT 3是自然语言处理 领域迄今为止发布出来最大的Transformer模型 超过之前的记录 微软研究院Turing LG的170亿参数 约10倍 英语原文 Exploring GPT 3 A Ne
  • 剑指 Offer 18. 删除链表的节点 -- 双指针

    0 题目描述 leetcode原题链接 剑指 Offer 18 删除链表的节点 1 双指针解法 删除值为 val 的节点分需为两步 定位节点 修改引用 定位节点 遍历链表 直到 head val val 时跳出 即可定位目标节点 修改引用
  • 荐读

    本文转自 链闻 ChainNews 作者 Karen 虽然区块链技术诞生至今不过短短十余年 但是东西方天然的文化差异在加密世界中同样留下了一些痕迹 当社交媒体上关于 东方区块链 只关心币价 利益和投机而只有 西方区块链 才关心底层技术的革新
  • “元宇宙”既是机遇也是挑战

    一次性看懂元宇宙 是开疆拓土还是新一轮割韭菜 众所周知 随着AI VR AR MR XR 区块链 云计算 物联网 数字孪生 量子技术 5G技术等新兴技术的快速发展 推动刚刚过去的2021年成为元宇宙元年 先是3月Robolox上市 开启了元
  • 基于Dpabi的功能连接

    1 预处理 这里预处理用Gretna软件进行 共分为以下几步 1 DICOM转NIfTI格式 2 去除前10个时间点 Remove first 10 times points 由于机器刚启动 被试刚躺进去也还需适应环境 导致刚开始扫描的数据
  • 分享一个开源免费、功能强大的视频播放器库

    99 的前端开发者都关注了这个公众号 点击上方 前端开发博客 关注并 设为星标 回复加群 自助秒进前端群 最近在开发一个前端项目 用到播放视频的功能 所以就查了下有什么前端的视频播放器库可以使用 今天来分享一下给大家 这个库的名字叫做 Pl
  • Zabbix之自定义监控MySQL主从状态和延迟

    zabbix之自定义监控MySQL主从状态和延迟 文章目录 监控MySQL主从状态 1 安装Mariadb配置主从 2 配置监控脚本 3 web界面添加监控项 4 添加触发器 5 触发验证 监控MySQL主从延迟 配置监控脚本 web界面添
  • 机器学习-knn近邻分类算法

    算法原理 本质是通过距离 欧式距离 判断两个样本是否相似 如果距离够近就认为他们足够相似属于同一类别 算法优缺点 主要参数k 标记数据周围几个数作为参考对象 需要根据数据来决定 k值越大 模型偏差大 对噪声数据不敏感 可能造成欠拟合 k值越
  • 若依文件下载

    若依文件下载 都看我的 2021 4 17 找了一圈 每一个写的简单的 还得自己完成 提示 文章写完后 目录可以自动生成 如何生成可参考右边的帮助文档 文章目录 前言 一 前台代码 二 加入js代码 总结 前言 提示 若依框架的文件下载 提
  • css 让内容可滑动,css实现隐藏滚动条并可以滚动内容

    代码预览 行走在光阴里的人 谁不对初见怀揣一份美好向往和期待 谁不对初见心存一份眷恋和不舍 假如人生是一场途经 初见一定是人生路上最美的绽放 人生在世 不管你是青丝如云 还是白发如霜 当你念及 人生若只如初见 时 你的嘴角一定会不由自主地泛
  • ChatGTP套壳网站总结更新

    总结一批ChatGTP套壳网站供大家学习参考 前10个网站经过测试可用 所以套壳网站 就是使用ChatGPT提供的API与ChatGPT系统连接 使用自己的网站来实现交互展示 效果与在ChatpGPT网站上聊天是一样的 ChatGTP套壳网
  • HTC-VIVE手柄使用代码

    using UnityEngine using System Collections 检测手柄功能的脚本 这个脚本挂到手柄上 controler right 和controler left 上 public class ButtonTouc
  • java包装类&简单认识泛型

    1 包装类 在 Java 中 由于基本类型不是继承自 Object 为了在泛型代码中可以支持基本类型 Java 给每个基本类型都对应了一个包装 类型 类中比如由属性 方法 使用比较方便 1 1 基本数据类型和对应的包装类 1 2 装箱和拆箱