数据结构前置知识(下)

1. 包装类

        Java为了让基本数据类型也能够继承Object,因此给每个基本数据类型提供了包装类,

这样就可以和平常的引用数据类型一样使用了,并且也可以应用在泛型上(后续讲)

基本数据类型包装类
byteByte
shortShort
intInterger
longLong
floatFloat
doubleDouble
charCharacter
booleanBoolean

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

        1.1 装箱和拆箱

        装包,装箱: 把基本数据类型给到引用数据类型

// 装包: 把基本数据类型给到引用数据类型public static void main(String[] args) {Integer a = 10;int i = 99;Integer b = i;//这俩个都是自动装包,隐式装包System.out.println(a);System.out.println(b);Integer aa = Integer.valueOf(10);//这个是显示装包,装箱      }
//
10
99

 Interger a = 10;  a是Interger引用数据类型

 int i = 99;  i是基本数据类型

Integer b = i;  我们把基本数据类型变量放在引用数据类型变量里面

以上完成了隐式装包操作

Integer aa = Integer.valueOf(10); 这个是显示装包

总结: 

引用数据类型 变量名 = 基本数据类型变量/传数值; 隐式装包

引用数据类型 变量名 = 引用数据类型.valueOf(基本数据类型变量/传数值); 显示装包

       拆箱,拆包: 把引用数据类型给到基本数据类型

    public static void main(String[] args) {//拆箱Integer a = 10;//隐式拆箱int i = a ;//把引用数据类型->基本数据类型(一般俩种都用到valueOf方法)System.out.println(i);//显示拆箱int aa = a.intValue();double d = a.doubleValue();//显示拆箱System.out.println(aa);System.out.println(d);}
//
10
10
10.0

Integer a = 10; a是引用数据类型

int i = a ; 这个是引用数据类型变量赋值给基本数据类型,完成了拆包过程

上面是隐式拆包

int aa = a.intValue(); 这个是显示拆包

总:

基本数据类型 变量名 = 引用数据类型变量名; 隐式拆包

基本数据类型 变量名 = 引用数据类型变量名.基本数据类型Value() 显示拆包

 再来看看这个代码

    public static void main(String[] args) {Integer a = 100;Integer b = 100;System.out.println(a == b);//[-128,127]Integer a1 = 200;Integer b1 = 200;//源码里面,如果超过127则会new一个新的对象System.out.println(a1 == b1);}
//
true
false

从这个代码我们可以看出,引用数据类型一旦超过了它所表示的范围就会new一个新的对象,比如上面这个例子Integer的范围是[-128,127],因此200超过了它的范围,会new出一个新的对象

2. 泛型

        所谓泛型就是适用于很多类型,从代码来说就是对类型实现了参数化

        2.1 引出泛型

        我们来看这么一个例子:实现一个类,类中包含一个数组成员,使得数组中可以存放任何类型的数据,也可以根据成员方法返回数组中某个下标的值?

class Myarray1 {//TODO 这个是尝试的法一public Object[] array = new Object[10];//存放数据public void setValue(int pos,Object val) {array[pos] = val;}//获取数据public Object getValue(int pos) {return array[pos];}
}

既然这个数组可以存放任何类型,那么我们就可以New一个Object类型的数组,我们又需要存放和得到数组里面的 数据,那么我们就要为数组提供set和get方法.这样写虽然感觉没问题,但是当我们在main里面创建这个对象并且调用set和get方法的时候就出现了问题

因为getValue返回的类型是个Object的类型,我们不能直接把父类类型放在子类类型里面,因此我们需要向下转型:

String str = (String) myarray.getValue(1);

 但是,如果每次放进去什么数据,拿出来的时候我们还需要对它进行对应类型的向下转型就太过于麻烦了.所以我们就引出了泛型,把数据类型当成参数传过去,就完成了数据类型不匹配的问题.我们来看以下代码:

class Myarray<T> {//<T>表示当前的类是个泛型类,它只是一个占位符//TODO 这个是法二,用的泛型//泛型表示我可以放进去的类型是我自己指定的类型public Object[] array = new Object[10];
//    public T[] a = new T[10];//泛型是编译时期存在的,当程序运行起来到JVM之后,就没有泛型的概念了,而对于数组而言,创建出来就需要是一个确定的类型//而且,我们无法确保Object类型有没有无参的构造方法//泛型在编译的时候是通过擦除机制,擦成了Object//,2:54:14public void setValue(int pos,T val) {array[pos] = val;}//获取数据public T getValue(int pos) {return (T)array[pos];//把返回的类型,强转为指定类型}}

我们来分析以下这个代码

class Myarray<T> 这里面的<T>表示当前的类是个泛型类,它只是一个占位符

然后里面所有牵扯到值的类型的时候,我们都用这个占位符表示

return (T)array[pos];这个代码就是把Object类型的数组类型的强转为指定类型的值,指定类型就是在main函数里面 <Integer>这里面的类型.然后我们可以看出,在后续我们getValue的时候就不需要强转了,就相当于在创建这个对象的时候我们已经从<Integer>这里晓得了这个就是个Integer类型的对象.我们需要传入什么数据类型的值,我们就创建对象的时候<>在这里面告诉编译器,我们要的是什么类型的数据,后续如果放入其他类型就会报错了.

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

        2.2 泛型的语法

        class 泛型名称 <类型参数列表> {   }

        class 泛型名称<T1,T2,T3...>

        class 泛型名称<类型参数列表>extends 继承类 {  }

        class 泛型名称<T1,T2,T3...>extends parentClass<T>{}

其中,<T>代表占位符,表示当前的类是一个泛型类

 【规范】类型形参一般使用一个大写字母表示,常用的名称有:(了解即可)

E 表示 Element

K 表示 Key

V 表示 Value

N 表示 Number T 表示 Type

S, U, V 等等 - 第二、第三、第四个类型

 泛型类的使用:

泛型类名<引用数据类型> 对象名 = new 泛型类名<引用数据类型>();

         2.3 泛型的上界

我们通过一个例子来说明一下

class Person {}
class Stundent extends Person  {}
//TODO T 一定是Number 或者Number的子类
class  TestGneric <T extends Number> {}
//一定是Person或者Person的子类
class TestGneric2 <T extends Person> {}
public class Test2 {public static void main(String[] args) {//TODO 泛型的上界TestGneric<Number> testGneric = new TestGneric<>();TestGneric<Integer> testGneric1 = new TestGneric<>();
//        TestGneric<String> testGneric2 = new TestGneric<String>();TestGneric2<Stundent> testGneric2 = new TestGneric2<>();
//一定是Person或者Person的子类TestGneric2<Person> testGneric21 = new TestGneric2<>();}
}

class TestGneric <T extends Number>{}这个类表示的泛型类, T一定是Number或者Number的子类

这个就说明了我们可以通过extends关键字,限制我们使用的泛型的类型,我们在main里面创建它的对象,我们在<>里面的的类型只能是Number或者Number的子类,我们不能放其他引用类型.

然后我们自己实现一个父子类关系来实验,Student继承自Person类,我们限制TestGneric2的泛型类型只能是Person或者是Person的子类 class TestGneric2 <T extends Person>;

不然就会报错.

           2.4 泛型方法

既然我们学会了写泛型类,那么我们也要学会写泛型方法

        我们先看语法:

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

看个例子:

写一个泛型类,求一个数组中的最大值

关于这个代码为什么报错,可以去看看我java分类,类和对象抽象类那一块,我简单解释一下,我们引用数据类型是必须是实现comparable接口才能够指定对什么进行比较,不能够直接进行比较.

因此我们需要进行修改

class Alg2<T extends Comparable<T>> {//把指定的类型放在类上public T findMaxValue(T[] array) {T max = array[0];for (int i = 0; i < array.length; i++) {if (max.compareTo(array[i]) < 0) {max = array[i];}}return max;}
}

在这个代码中,我们把Alg2限制为一个实现了Compareable接口的类或者其子类上

我们来观察一下Integer的源码:

 它是实现了Comparable接口的

Comparable本身是个泛型接口

因此上面代码可以找出最大值:8

但是我们任然用的是泛型类,下面我们来用法二

class Alg3 {public<T extends Comparable<T>> T findMaxValue(T[] array) {//把指定的类型放在方法上T max = array[0];for (int i = 0; i < array.length; i++) {if (max.compareTo(array[i]) < 0) {max = array[i];}}return max;}
}

这个玩意就是我们在普通类里面写一个泛型方法我们限定T是要实现Comparable 接口的类型

访问修饰限定符<T extends 接口<T>> T 方法名 (T 参数) {

}  

 

我们在main里面创建 这个对象,并且创建你想比较的实现了Comparable接口的引用类型数组.然后我们把数组当作参数传入方法里面进行计算.我们根据传进去实参的传值来推导此时的类型,缩写:System.out.println(alg3.findMaxValue(integers));//这个直接根据你传进去的参数来预判出是什么类型,完整写法System.out.println(alg3.<Integer>findMaxValue(integers));

我们写一个不需要实例化对象的静态方法

class Alg4 {public static <T extends Comparable<T>> T findMaxValue(T[] array) {//把指定的类型放在方法上T max = array[0];for (int i = 0; i < array.length; i++) {if (max.compareTo(array[i]) < 0) {max = array[i];}}return max;}
}public class Test {public static void main(String[] args) {Integer[] integers = {1,2,3,4,6,8};System.out.println(Alg4.findMaxValue(integers));System.out.println(Alg4.<Integer>findMaxValue(integers));}
}

静态的方法,我们直接用对象名来进行调用即可,其他用法和上述一样.

                2.5 擦除机制

我们学了这么多泛型的东西,那么我们来聊一下它底层是怎么实现的,

通过命令:javap -c 查看字节码文件,所有的T都是Object

在编译过程中,我们把所有的T替换成Object,这种机制就是擦除机制

然后,我们提出一个问题,我们在创建泛型的时候我们创建的类型为什么是Object类型的,为什么不能直接用泛型创建数组

因为泛型是通过类型擦除实现的,这意味着在运行时候泛型的具体类型会被擦除,编译器无法确定T的具体数据类型,而创建数组,我们是需要知道具体创建类型是什么的.具体硬是要实例化泛型数组就要用到反射机制了(自行了解)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.xdnf.cn/news/1560482.html

如若内容造成侵权/违法违规/事实不符,请联系一条长河网进行投诉反馈,一经查实,立即删除!

相关文章

在IDEA里用XDebug调试PHP,断点....

做程序开发,调试必不可少,这里最近用到了PHP,顺便写个关于PHP的调试安装使用: 1、首先是PHP先安装xdebug扩展(还有zend的),这个我的工具是IDEA,所以安装方法也相对简单,如果你是用VSCode等应该也是一样,如下图,找到这个PHP->DEBUG 2、直接点上面的Install XDebug 就可以帮你…

潜水打捞系统助力,破解汽车打捞难题

随着人类活动的不断扩展&#xff0c;汽车落水事故频发&#xff0c;成为救援工作中的一大难题。汽车因其重量和结构特性&#xff0c;一旦沉入水体&#xff0c;打捞工作将面临巨大挑战。传统的打捞方法往往效率低下&#xff0c;且在操作过程中可能会对汽车造成进一步的损害&#…

JMeter性能测试时,如何做CSV参数化

在现代软件开发中&#xff0c;性能测试是保证应用程序在高负载条件下稳定运行的重要环节。为了实现真实场景的测试&#xff0c;参数化技术应运而生。其中&#xff0c;CSV参数化是一种高效且灵活的方法&#xff0c;可以让测试人员通过外部数据文件驱动测试脚本&#xff0c;从而模…

九寨沟,智慧旅游新名片

九寨沟属于自然类景区&#xff0c;以优美的自然风光取胜&#xff0c;景区文化内涵相对缺失。智慧化和文旅融合是智慧文旅景区的两个必备条件&#xff0c;九寨沟在智慧文旅景区建设过程中&#xff0c;经历了两个阶段&#xff0c;先是从传统景区迈向智慧景区&#xff0c;然后是充…

Arduino UNO R3自学笔记24 之 Arduino如何使用MAX7219控制多个数码管?

注意:学习和写作过程中,部分资料搜集于互联网,如有侵权请联系删除。 前言:前面学习了单个数码管的控制,但是在大多场合一个数码管是满足不了使用场景的,因此对于数码管的学习,应该学会用尽可能少的端口去驱动更多的数码管,在此情况下,MAX7219比较适合我们使用。 1.M…

Qt_软件添加版本信息

文章内容: 给生成的软件添加软件的版权等信息 #include <windows.h> //中文的话增加下面这一行 #pragma code_page(65001)VS_VERSION_INFO VERSIONINFO

springmvc直接访问 上下文路径 302 后路径更改并跳转源码解析

【问题现状】 application.yml 配置如下属性&#xff1a; server:servlet:context-path: /learning直接访问&#xff1a;http://localhost:8888/learning 路径时&#xff0c;会返回302的响应状态&#xff1b;并跳转路径&#xff1a;http://localhost:8888/learning/ (原路径后…

【北京迅为】《STM32MP157开发板嵌入式开发指南》-第二十七章 交叉编译器的安装和使用

iTOP-STM32MP157开发板采用ST推出的双核cortex-A7单核cortex-M4异构处理器&#xff0c;既可用Linux、又可以用于STM32单片机开发。开发板采用核心板底板结构&#xff0c;主频650M、1G内存、8G存储&#xff0c;核心板采用工业级板对板连接器&#xff0c;高可靠&#xff0c;牢固耐…

STM32 实现 TCP 服务器与多个设备通信

目录 一、引言 二、硬件准备 三、软件准备 四、LWIP 协议栈的配置与初始化 五、创建 TCP 服务器 1.创建 TCP 控制块 2.绑定端口 3. 进入监听状态 4.设置接收回调函数 六、处理多个客户端连接 七、数据处理与通信管理 八、错误处理与资源管理 九、总结 一、引…

【STM32单片机_(HAL库)】4-5-2【定时器TIM】【感应开关盖垃圾桶项目】HC-SR04超声波模块实验

1.硬件 STM32单片机最小系统HC-SR04超声波模块 2.软件 hcsr04驱动文件添加main.c程序 #include "sys.h" #include "delay.h" #include "led.h" #include "uart1.h" #include "hcsr04.h"int main(void) {HAL_Init(); …

华为云应用侧Android Studio开发

本文将介绍如何使用AndroidStudio开发APP完成与接入华为云IoTDA设备的对接&#xff0c;包括属性参数获以及取命令下发。 一、鉴权认证 应用侧需要通过IAM服务鉴权&#xff0c;获取token&#xff0c;华为账号创建 IAM 用户&#xff0c; 可以为创建的用户分配权限 认证鉴权_设…

CSS @规则(At-rules)系列详解___@charset规则使用方法

CSS 规则(At-rules)系列详解 ___charset规则使用方法 本篇目录&#xff1a; 零、时光宝盒 一、charset规则定义和用法 二、CSS charset语法 三、charset 使用方法例子 1、正确使用方法 2、无效的&#xff0c;错误的使用方法 零、时光宝盒 &#xff08;https://blog.csd…

C++ | Leetcode C++题解之第472题连接词

题目&#xff1a; 题解&#xff1a; struct Trie {bool isEnd;vector<Trie *> children;Trie() {this->children vector<Trie *>(26, nullptr);this->isEnd false;} };class Solution { public:Trie * trie new Trie();vector<string> findAllConc…

C语言 | Leetcode C语言题解之第472题连接词

题目&#xff1a; 题解&#xff1a; typedef struct Trie {struct Trie * children[26];bool isEnd; }Trie;#define TRIE_INITIAL(node) do { \for (int i 0; i < 26; i) { \(node)->children[i] NULL; \} \(node)->isEnd false; \ }while(0);static void freeTri…

第二阶段:mysql(学完就隐藏版)

第一章&#xff1a;部署数据库系统&#xff08;注意关闭防火墙&#xff0c;selinux安装&#xff09; 安装mysql配置的相关文件&#xff1a;yum install https://dev.mysql.com/get/mysql80-community-release-el7-5.noarch.rpm&#xff08;centos9&#xff1a;yum install http…

iOS--理解MVC与MVVM

MVC MVC 是一种将应用程序分为三部分的架构模式&#xff1a;Model&#xff08;模型&#xff09;、View&#xff08;视图&#xff09;、Controller&#xff08;控制器&#xff09;。每部分负责不同的职责&#xff0c;使代码更加模块化、易于维护。 • Model&#xff1a;负责业…

jmeter入门:脚本录制

1.设置代理。 网络连接-》代理-》手动设置代理. ip&#xff1a; 127.0.0.1&#xff0c; port&#xff1a;8888 2. add thread group 3. add HTTP(s) test script recorder, target controller chooses Test plan-> thread Group 4. click start. then open the browser …

Java | Leetcode Java题解之第472题连接词

题目&#xff1a; 题解&#xff1a; class Solution {Trie trie new Trie();public List<String> findAllConcatenatedWordsInADict(String[] words) {List<String> ans new ArrayList<String>();Arrays.sort(words, (a, b) -> a.length() - b.length(…

PyQt 的Tree Widget中拖放和点击的异常行为

在 PyQt 的 QTreeWidget 中&#xff0c;如果你遇到 拖放 和 点击 的异常行为&#xff0c;可能是由于信号处理、事件拦截、拖放设置或树结构配置等问题导致的。以下是一些可能的常见问题和解决方案。 1、问题背景 一个 PyQt 应用程序中包含两个 Tree Widget&#xff0c;当用户从…

QUUID 使用详解

UUID 通常由 128 位&#xff08;16 字节&#xff09;组成&#xff0c;通常表示为 32 个十六进制数字&#xff0c;分为五个部分&#xff0c;格式如下&#xff1a; QUuid 是 Qt 框架中用于生成和处理 UUID&#xff08;通用唯一标识符&#xff09;的类。UUID 是一种标准的标识符格…