【数据结构】 简单认识包装类与泛型

这篇具有很好参考价值的文章主要介绍了【数据结构】 简单认识包装类与泛型。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

包装类

【数据结构】 简单认识包装类与泛型,数据结构,数据结构,java,包装类,泛型
在Java中,由于基本类型不是继承自Object,为了在泛型代码中可以支持基本类型,Java给每个基本类型都对应了一个包装类型。

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

【数据结构】 简单认识包装类与泛型,数据结构,数据结构,java,包装类,泛型

除了 Integer 和 Character, 其余基本类型的包装类都是首字母大写。

拆箱和装箱

【数据结构】 简单认识包装类与泛型,数据结构,数据结构,java,包装类,泛型

装箱就是自动将基本数据类型转换为包装器类型;拆箱就是自动将包装器类型转换为基本数据类型,有了装箱拆箱,java可以根据上下文,自动进行转换,极大的简化相关编程。

自动装箱和自动拆箱

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

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

可以看到在使用过程中,装箱和拆箱带来不少的代码量,所以为了减少开发者的负担,java 提供了自动机制。

int i = 10;
Integer ii = i; // 自动装箱
Integer ij = (Integer)i; // 自动装箱

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

当我们查看实现逻辑时,发现java已经自动帮我们实现了
【数据结构】 简单认识包装类与泛型,数据结构,数据结构,java,包装类,泛型

包装类面试题

下列代码输出什么,为什么?

public class Main {
 
    public static void main(String[] args) {
         
        Integer i1 = 100;
        Integer i2 = 100;
        Integer i3 = 200;
        Integer i4 = 200;
 
        System.out.println(i1==i2);
        System.out.println(i3==i4);
    }
}

答案为

true
false

为什么会出现这样的结果?输出结果表明i1和i2指向的是同一个对象,而i3和i4指向的是不同的对象。此时只需一看源码便知究竟,下面这段代码是Integer的valueOf方法的具体实现:

public static Integer valueOf(int i) {
        if(i >= -128 && i <= IntegerCache.high)
            return IntegerCache.cache[i + 128];
        else
           return new Integer(i);
    }

而其中IntegerCache类的实现为:

private static class IntegerCache {
        static final int high;
        static final Integer cache[];
        static {
            final int low = -128;
            // high value may be configured by property
            int h = 127;
            if (integerCacheHighPropValue != null) {
                // Use Long.decode here to avoid invoking methods that
                // require Integer's autoboxing cache to be initialized
                int i = Long.decode(integerCacheHighPropValue).intValue();
                i = Math.max(i, 127);
                // Maximum array size is Integer.MAX_VALUE
                h = Math.min(i, Integer.MAX_VALUE - -low);
            }
            high = h;
            cache = new Integer[(high - low) + 1];
            int j = low;
            for(int k = 0; k < cache.length; k++)
                cache[k] = new Integer(j++);
        }
        private IntegerCache() {}
    }

从这两段代码可以看出,在通过valueOf方法创建Integer对象的时候,如果数值[-128,127]之间,便返回指向IntegerCache.cache中已经存在的对象的引用;否则创建一个新的Integer对象。

上面的代码中i1和i2的数值为100,因此会直接从cache中取已经存在的对象,所以i1和i2指向的是同一个对象,而i3和i4则是分别指向不同的对象

什么是泛型

【数据结构】 简单认识包装类与泛型,数据结构,数据结构,java,包装类,泛型

一般的类和方法,只能使用具体的类型: 要么是基本类型,要么是自定义的类。如果要编写可以应用于多种类型的代码,这种刻板的限制对代码的束缚就会很大。
----- 来源《Java编程思想》对泛型的介绍。

泛型是在JDK1.5引入的新的语法,通俗讲,泛型:就是适用于许多许多类型。从代码上讲,就是对类型实现了参数化

为什么要使用泛型

比如我们现在要实现一个类,类中包含一个数组成员,使得数组中可以存放任何类型的数据,也可以根据成员方法返回数组中某个下标的值

思路大致为:

  1. 我们以前学过的数组,只能存放指定类型的元素,例如:int[] array = new int[10]; String[] strs = new String[10];
  2. 所有类的父类,默认为Object类。我们将数组创建为Object;
    【数据结构】 简单认识包装类与泛型,数据结构,数据结构,java,包装类,泛型【数据结构】 简单认识包装类与泛型,数据结构,数据结构,java,包装类,泛型

存在问题:我们发现以上代码实现后发现

  • 任何类型数据都可以存放
  • 1号下标本身就是字符串,但是确编译报错。必须进行强制类型转换

虽然在这种情况下,当前数组任何数据都可以存放,但是,更多情况下,我们还是希望他只能够持有一种数据类型。而不是同时持有这么多类型。

所以,泛型的主要目的:就是指定当前的容器,要持有什么类型的对象。让编译器去做检查。此时,就需要把类型,作为参数传递。需要什么类型,就传入什么类型

泛型类的创建语法

class 泛型类名称<类型形参列表> {
	// 这里可以使用类型参数
}
class ClassName<T1, T2, ..., Tn> {
}

也可以实现继承,并继承里面的泛型类

class 泛型类名称<类型形参列表> extends 继承类/* 这里可以使用类型参数 */ {
	// 这里可以使用类型参数
}
class ClassName<T1, T2, ..., Tn> extends ParentClass<T1> {
	// 可以只使用部分类型参数
}

那么刚刚上述代码就可以变为
【数据结构】 简单认识包装类与泛型,数据结构,数据结构,java,包装类,泛型
上面代码涉及了许多新的东西,这里会一一做出解释

代码解释:

  1. 类名后的 代表占位符,表示当前类是一个泛型类
    了解: 【规范】类型形参一般使用一个大写字母表示,常用的名称有

E 表示 Element
K 表示 Key
V 表示 Value
N 表示 Number
T 表示 Type
S, U, V 等等 -第二、第三、第四个类型

  1. 注释1处,不能new泛型类型的数组,意味着
T[] ts = new T[5];//是不对的

上述的代码:T[] array = (T[])new Object[10];是否就足够好,答案是未必的。这块问题一会儿介绍。

  1. 注释2处,类型后加入 指定当前类型

  2. 注释3处,不需要进行强制类型转换

  3. 注释4处,代码编译报错,此时因为在注释2处指定类当前的类型,此时在注释4处,编译器会在存放元素的时候帮助我们进行类型检查。

泛型类的使用

语法

泛型类<类型实参> 变量名; // 定义一个泛型类引用
new 泛型类<类型实参>(构造方法实参); // 实例化一个泛型类对象

示例

MyArray<Integer> list = new MyArray<Integer>();

注意:泛型只能接受类,所有的基本数据类型必须使用包装类!

类型推导(Type Inference)

当编译器可以根据上下文推导出类型实参时,可以省略类型实参的填写

MyArray<Integer> list = new MyArray<>(); // 可以推导出实例化需要的类型实参为 Integer

裸类型(Raw Type)

裸类型是一个泛型类但没有带着类型实参,例如 MyArrayList 就是一个裸类型

MyArray list = new MyArray();

注意: 我们不要自己去使用裸类型,裸类型是为了兼容老版本的 API 保留的机制下面的类型擦除部分,我们也会讲到编译器是如何使用裸类型的。

小结:

  1. 泛型是将数据类型参数化,进行传递
  2. 使用 表示当前类是一个泛型类。
  3. 泛型目前为止的优点:数据类型参数化,编译时自动进行类型检查和转换

泛型如何编译的

擦除机制

那么,泛型到底是怎么编译的?通过命令:javap -c 查看字节码文件,所有的T都是Object
【数据结构】 简单认识包装类与泛型,数据结构,数据结构,java,包装类,泛型
在编译的过程当中,将所有的T替换为Object这种机制,我们称为:擦除机制

Java的泛型机制是在编译级别实现的。编译器生成的字节码在运行期间并不包含泛型的类型信息
有关泛型擦除机制的文章截介绍

为什么不能实例化泛型类型数组

例如以下代码
【数据结构】 简单认识包装类与泛型,数据结构,数据结构,java,包装类,泛型
原因:替换后的方法为:将Object[]分配给Integer[]引用,程序报错

public Object[] getArray() {
	return array;
}

通俗讲就是:返回的Object数组里面,可能存放的是任何的数据类型,可能是String,可能是Person,运行的时候,直接转给Integer类型的数组,编译器认为是不安全的
向下转型不安全

那么我们有没有正确的方式呢?这里也是有的,博主在这里给大家提供一种

class MyArray<T> {
    public T[] array;
    public MyArray() {
    }
    / **
    *通过反射创建,指定类型的数组
    * @param clazz
    * @param capacity
    */
    public MyArray(Class<T> clazz, int capacity) {
        array = (T[])Array.newInstance(clazz, capacity);
    }
    public T getPos(int pos) {
        return this.array[pos];
    }
    public void setVal(int pos,T val) {
        this.array[pos] = val;
    }
    public T[] getArray() {
        return array;
    }
}
public static void main(String[] args) {
    MyArray<Integer> myArray1 = new MyArray<>(Integer.class,10);
    Integer[] integers = myArray1.getArray();
}

泛型的上界

在定义泛型类时,有时需要对传入的类型变量做一定的约束,可以通过类型边界来约束。

语法

class 泛型类名称<类型形参 extends 类型边界> {
	...
}

示例

public class MyArray<E extends Number> {
	...
}

只接受 Number 的子类型作为 E 的类型实参

MyArray<String> l2; // 编译错误,因为 String 不是 Number 的子类型
MyArray<Integer> l1; // 正常,因为 Integer 是 Number 的子类型

结果为

error: type argument String is not within bounds of type-variable E
	MyArrayList<String> l2;
			^
where E is a type-variable:
	E extends Number declared in class MyArrayList

没有指定类型边界 E,可以视为 E extends Object

复杂示例

public class MyArray<E extends Comparable<E>> {
	...
}

E必须是实现了Comparable接口的

此时我们可以用这个知识对任意数组进行寻找最大值

class Alg<T extends Comparable<T>> {
    public T findMax (T[] array) {
        T max = array[0];
        for (int i = 1; i < array.length; i++) {
            if(max.compareTo(array[i]) < 0 ) {
                max = array[i];
            }
        }
        return max;
    }
}
 public static void main(String[] args) {
        Alg<Integer> alg = new Alg<>();
        Integer[] array = {1,2,3,4};
        Integer ret = alg.findMax(array);
        System.out.println(ret);
    }

泛型方法

你可以写一个泛型方法,该方法在调用时可以接收不同类型的参数。根据传递给泛型方法的参数类型,编译器适当地处理每一个方法调用。

下面是定义泛型方法的规则:

  • 所有泛型方法声明都有一个类型参数声明部分(由尖括号分隔),该类型参数声明部分在方法返回类型之前(在下面例子中的 )。
  • 每一个类型参数声明部分包含一个或多个类型参数,参数间用逗号隔开。一个泛型参数,也被称为一个类型变量,是用于指定一个泛型类型名称的标识符。
  • 类型参数能被用来声明返回值类型,并且能作为泛型方法得到的实际参数类型的占位符。
  • 泛型方法体的声明和其他方法一样。注意类型参数只能代表引用型类型,不能是原始类型(像 int、double、char 等)。

定义语法

方法限定符 <类型形参列表> 返回值类型 方法名称(形参列表) { … }

示例

class Alg{
    //泛型方法
    public static<T extends Comparable<T>> T findMax (T[] array) {
        T max = array[0];
        for (int i = 1; i < array.length; i++) {
            if(max.compareTo(array[i]) < 0 ) {
                max = array[i];
            }
        }
        return max;
    }
}
public static void main(String[] args) {
    Integer[] array = {1,2,3,4};
    Integer ret = Alg2.<Integer>findMax(array);
    System.out.println(ret);
}

此处的Interger可以选择不加,java可以根据你array里面值的类型进行推导

 Integer ret = Alg2.<Integer>findMax(array);
  Integer ret = Alg2.findMax(array);

总结

关于《 【数据结构】 简单认识包装类与泛型》就讲解到这儿,感谢大家的支持,欢迎各位留言交流以及批评指正,如果文章对您有帮助或者觉得作者写的还不错可以点一下关注,点赞,收藏支持一下!文章来源地址https://www.toymoban.com/news/detail-654320.html

到了这里,关于【数据结构】 简单认识包装类与泛型的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 【数据结构】树的认识

    一个人的未来不是预测出来的,而是创造出来的。                        -- 亚当·詹姆斯 目录 🍁前言: 🍀一.什么是树? 🍑二.树有什么用?  ❤️1. 数据库 🧡2. 文件系统 💛3. 编程语言 💚4. 网络 💜5. 人工智能 🍂三.树的基础知识 🌳四.树的存储结构 🍐1.双亲表示

    2024年02月06日
    浏览(45)
  • 对数据结构的初步认识

    牛牛开始更新 数据结构 的知识了.本专栏后续会分享用c语言实现 顺序表 , 链表 , 二叉树 , 栈 和 队列 , 排序 算法等相关知识,欢迎友友们互相学习,可以私信互相讨论哦! 🎈个人主页:🎈 :✨✨✨初阶牛✨✨✨ 🐻推荐专栏: 🍔🍟🌯 c语言初阶 🔑个人信条: 🌵知行合一 🍉本篇

    2024年02月01日
    浏览(50)
  • 【开卷数据结构 】指针的初步认识

    说到指针,想必大家都不陌生,指针的最大特点就是难以理解,它是编程中很基础也是很重要的概念,指针可以有效的实现像树,链表这类高级的数据结构。 在了解指针是什么之前,我们需要先了解什么是计算机的内存,什么是地址。 内存: 计算机内存大部分时候指的是随

    2023年04月16日
    浏览(41)
  • 深入学习 Redis - 常用数据类型,结构认识

    目录 一、Redis数据类型  Redis 数据类型结构简单认识 每个数据类型具体的编码方式 1.string  2.hash 3.list 4.set 5.zset 典中典:记数字!!! 6.查看 key 对应 value  的实际编码方式 如果本文有帮助到你,不妨给个三连吧~ Redis 中所有的 key 都是 string 类型,不同的是 value 的数据类型

    2024年02月16日
    浏览(53)
  • 【java数据结构】泛型的初步认识(2)

    hellohello~,大家好💕💕,这里是E绵绵呀✋✋ ,如果觉得这篇文章还不错的话还请点赞❤️❤️收藏💞 💞 关注💥💥,如果发现这篇文章有问题的话,欢迎各位评论留言指正,大家一起加油!一起chin up!👍👍  💥 个人主页: E绵绵的博客 💥 所属专栏: JAVA知识点专栏

    2024年04月26日
    浏览(36)
  • 数据结构对链表的初步认识(一)

    已经两天没有更新了,今天就写一篇数据结构的链表吧,巩固自己也传授知识,不知道各位是否感兴趣看看这一篇有关联表的文章。 目录 链表的概念与结构  单向链表的实现 链表各个功能函数 首先我在一周前发布了一篇有关顺序表的文章,其中我们通过简单的介绍和代码实

    2024年02月19日
    浏览(42)
  • 【数据结构】认识链表和模拟实现单链表

    即使骑的小电驴,也要奋力前进 目录 1.链表 1.1 链表的概念  1.2 链表的逻辑结构图和物理结构图 1.2.1 链表的逻辑结构图  1.2.2 链表的物理结构图  1.3链表结构的分类 1.3.1 链表通过什么进行结构的分类  1.3.2 不同链表结构的逻辑图 2.模拟实现一个单向链表  2.1 MyLinkedList类的

    2024年02月14日
    浏览(55)
  • springboot第49集:【思维导图】多线程,常用类与基础API,集合框架,泛型,数据结构源码...

    多线程创建方式一:继承Thread类 多线程创建方式二:实现Runnable接口 jdk5.0新增两种创建多线程的方式 image.png image.png image.png image.png image.png image.png image.png image.png image.png image.png image.png image.png image.png 优先级 image.png image.png image.png image.png image.png image.png 线程安全问题 image.p

    2024年01月21日
    浏览(46)
  • 【从零开始学习Redis | 第八篇】认识Redis底层数据结构(下)

    目录 前言:   ZipList: Ziplist的特性: QucikList: QuicList特征: SkipList: 跳表特征: RedisObijct:  小心得: 总结:           在现代软件开发中,数据存储和处理是至关重要的一环。为了高效地管理数据,并实现快速的读写操作,各种数据库技术应运而生。其中,Redis作为一种

    2024年04月12日
    浏览(51)
  • [JAVA数据结构] 认识 Iterable、Collection、List 的常见方法签名以及含义

            (一)Iterable                 1. 介绍                 2. 常见方法         (二)Collection                 1. 介绍                  2. 常见方法         (三) List                  1. 介绍                 2. 常见方法

    2024年02月02日
    浏览(43)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包