java中的泛型

一 为啥要有泛型

泛型这个概念是在Java1.5提出来的,之前是没有的,那为什么之前没有,现在要提出来这个概念呢?那你就得想啊:

1、要么是之前的技术太垃圾了,得升级换代下
2、要么是技术发展,搞出来的新玩意,让Java更好用
3、要么就是填坑,之前的有部分,搞个出来填坑
4、……

那你看,这个泛型,有可能是啥,实际上它就是填坑的,说这个之前,咱们先来看一段代码:

在这里插入图片描述

这段代码没有看不懂的吧,就是简单的一个List集合,这里可能需要你额外注意的就是我这里定义的List不是这样的哦:

List<String> stringList = new ArrayList<String>();

不知道你看出来区别了吗?这个应该是大部分我们用的时候会定义的那种,熟悉泛型的可能知道这是怎么回事,但是不熟悉泛型的就记住这么用就ok了。

继续看上面我举的那个例子,这里我想说明的就是这里定义的List集合是什么都能装的,集合一般啥用,不就是往里面存放数据的嘛,把集合看做一个房子,里面可以进去老人和小孩,当然各种猫啊狗啊都可以进去,来,上图:

在这里插入图片描述

咋样,我的绘画功底还是可以吧,List就好比一个房子,里面是可以进人,当然也可以进动物,比如各种各样的小猫小狗啊,当然了,List这里可进入的就是数据了,比如字符串啊,整型啊等等。

这个时候就会产生一个问题,啥问题嘞,你看啊,这座房子里面可以进入各种各样的物种,就是各种类型的啊,如果这个房子会说话的话,它就说了“啥玩意啊,你们啥都往我这来,啥品种都行,也太乱了吧,都记不清楚你们谁是谁了,算了我也不记住你们谁是啥类型了,进来的统一当做‘活物’吧”

就是说啊,对于房子来说,不管你进来的是个啥,我统一把你们当做“活物”,在我这里你们就是一个类型的,同样的,放到List集合这里来说的话,也是这样的,就是你字符串啊,整型啊都可以放入List集合中,那么List也说了,我不记住你们到底哪个是字符串哪个是整型,在我这里统一把你们看做是Object类,至于为啥是Object类,这是因为Object是一切类的父类啊,所以没有比它更合适啦,不管你是字符串还是整型,你们一定都是Object类型的,这点容易理解吧。

这样看似挺完美的,但是也有潜在的问题啊,什么问题嘞,你看啊,我们还拿房子来说,对于房子来说,在房子里面的都被看成是“活物”类型了,那么如果我要从房子里找一个小狗出来,那么我找出来的类型都是“活物”,可是我要的是小狗啊,你给我来个“活物”,不符合我的要求啊,怎么办?大家都知道有个强制类型转换吧,好吧,我就把“活物”给你强制转换成小狗,这不就符合要求了,但是这样问题就来了,假如你找出来的就是个小狗,你把它强制转换成小狗,那倒也没啥,但是你也有可能会找出来个人啊,这时候你要把一个人强制转换成小狗,搁谁谁也不乐意啊,你说是不是。

同样的,对于List集合也是这样,你什么都可以往里面存储,然后统一被看成是Object类型,这个时候如果我们从List集合中取值的话,那就要用到强制转换了,需要把Object类型转换成我们要的类型,比如我们想要字符串,如果取出的本来就是字符串,那转成字符串没啥关系,但是如果取出来的是整型嘞,强制转换成字符串,那整型还不乐意嘞,于是乎,程序就要给你报错了,来来,看看代码:

在这里插入图片描述

咋一看,貌似没啥问题,编译也没报错啥的,我们运行一下看看:

在这里插入图片描述

吆喝,运行报错了,这个错也简单,就是不能将整型Integer转换成String字符串类型,就是类型不匹配啊,这里要记住这个错误类型叫做:ClassCastException

看到这里你也许就明白了,我定义一个List集合,本来只想往里面存入字符串嘞,但是不知怎么滴,里面混入了一个整型,因为List并不知道进来的都是什么类型,反正都看作Object类型,都可以进来,那么我们取数据的时候就会发生ClassCastException错误。

那这不行啊,我给你List里面存一个数据,我是希望你记住我传入的是什么类型的数据的,其他的就不允许再传入了,这样我取值的时候也不用强制类型转换,也就不会发生ClassCastException了。

这个你能想到,那么JDK官方更加能想到,于是乎,在Java1.5版本中就引入了泛型的概念,而引入泛型的很大一部分原因就是为了解决我们上述的问题,说白了就是我希望集合可以记得住我存进去的数据是什么类型的,以此做一个筛选,不是同类型的就不允许在一块存放,这样也避免了ClassCastException错误的出现,因为都是同一类型,也就没必要做强制类型转换了。

所以,你现在知道了为啥要有泛型了吧,当然,泛型的引入大部分原因是为了弥补集合的一个缺点,但是泛型的应用是很广的,不仅仅局限于Java的集合。

二 泛型的定义和理解

以上还算详细的和大家介绍了为啥要有泛型的出现,那么泛型是如何定义的呢?

泛型就是参数化类型,也就是说把我们要操作的类型作为了一个参数,比如我们创建集合的时候,允许我们可以指定集合中元素的数据类型。

在JDK1.5中引入了“参数化类型”的概念,这个就是泛型,也就是说泛型和参数化类型是等价的,一回事,那么我们来理解理解啥是参数化类型。

参数化类型

我们看看字面意思,参数化参数化,你想啊,我们有时候看一些魔幻电视剧,比如说某个人兽化了,大致知道啥意思吧,就是他变成了一个怪兽,变形了,哈哈,那么这里的参数化意思大概是不是就是变成了一个参数的意思呢?那么后面还有一个类型,组合起来是不是就是“把类型变成了参数”,那类型是啥啊,不就是String类型,Integer类型这些嘛,现在把这些类型都作为了参数,这就是参数化类型了。

不知道我表达的是否清楚,你明白吗?

好了,来看看泛型到底长啥样吧:

List<String> stringList = new ArrayList<String>();

就是这个,我们经常这样操作的,它就是泛型的应用,你看看它和如下没有使用泛型的有啥区别:

List stringList = new ArrayList();

很容易看出,就是多了一个这个<String>,那么该如何进一步去理解它嘞?

理解泛型

还记得之前我们说的吧,泛型的引入很大一部分原因是为了让集合能够记住他里面的元素的数据类型,怎么让它记住嘞,实际上实现也很简单,就是只传入特定的类型,比如要传入字符串类型,那么久只能传入字符串类型,像整型类型及其他类型就是不允许进入的,这样的话就能保证集合中的元素都是统一的类型,集合自然就能记住了。

我们再来看之前举的那个房子的例子:

在这里插入图片描述

通俗易懂吧,之前这个房子是开放的,谁都能进,现在嘞,我这个房子是用作狗屋的,自然是只提供小狗来住,那么其他的就不允许进入,你一个人让你进你也不进啊,怎么搞嘞,那就是在门口搞个检查装置,就好比安检,首先告诉安检,只能让小狗进,其他的不让进,于是乎,每过来一个,安检都要检查下是不是指定的小狗类型,不是的话不让进,是的话就进去,如此一来这个屋子里就都是小狗了,名副其实的狗屋啊。

那放到集合也是一样的,现在要理解的就是如何给这集合加上安检啊,再来看没使用泛型的时候:

List stringList = new ArrayList();

这个时候是开放的,各个数据类型的都可以存放到这个List集合中,现在看下使用了泛型的:

List<String> stringList = new ArrayList<String>();

在这里插入图片描述

显而易见啊,报错了,说是我需要一个String,你给传入一个int,不符合要求,那就不能存入,所以啊,你看明白了吗?List是一个集合,可以往里面存入数据,现在要进行限制,不是什么类型的都能存入,那就对存入的数据进行检查,怎么搞,那就在List后面加个<String>,就成了List<String>,看到没,这个是不是就和我们上面举例子中的那个安检很像,负责检查进来的数据,首先给它指定一个数据类型,这里就是String,然后就是检查,不是String的都不让存进来,所以啊,这个就是一个安检的作用啊,其中的String就是指定的数据类型,这就是泛型啊,也就是参数化类型,String是字符串类型,这里就作为一个参数放在这里,保存进List集合中的元素都要是String类型的。

咋样,明白没?这就是泛型啊,把String作为一个参数,类型参数化了,你看,是不是这么回事。这样一看,是不是觉得泛型也挺好理解的,其实这只是对泛型的基本理解,泛型还是有不少内容的,在理解了泛型的基本概念之后,我们还需要看看泛型的其他内容,当然,我必须告诉你,即使上面我讲的你明白了,接下来的内容同样有可能让你费解,一起来看下!

三 泛型进阶

菱形语法

咋一看,这个很高级啊,啥意思嘞,其实看代码就知道怎么回事,我们上面举了这样的集合泛型代码:

List<String> stringList = new ArrayList<String>();

你平常是这样写的吗?我猜有这样写的:

List<String> stringList = new ArrayList<>();

有啥区别,很简单,就是后面的ArrayList后面有尖括号内有没有这个String,也就是类型参数,这个理解吧,按照我们上面说的,这里加上是为了指明集合中元素的数据类型,那么后面的不写也行吗?在Java7之前是必须写的,也就是必须是这样的形式:

List<String> stringList = new ArrayList<String>();

但是在Java7开始就可以这样写了:

List<String> stringList = new ArrayList<>();

因为在Java7中是可以通过前面的类型参数去推导出ArrayList中的数据类型的,也就是类型参数不需要了,但是这个<>尖括号是必须的,至于尖括号中的类型,是可以自动被推导出来的,这个就叫做菱形语法,为啥叫菱形语法嘞,因为这个<>尖括号像菱形啊……

理解类型参数(重点)

还记得什么是类型参数吗?看这行代码:

List<String> stringList = new ArrayList<>();

泛型的本质是参数化类型,就是把类型当做参数了,而这个类型参数就是尖括号内的东西了,在上面的这行代码中,所谓的类型参数就是这个String了,这点明白吧,另外啊,我们都是到Java中的方法中有形参和实参,这个都知道怎么回事吧,那么这里类型参数其实也是有区别的,它也是分为类型形参类型实参

那啥是类型形参,啥又是类型实参啊?是不是觉得理解不了?别着急,经过我下面的解释,你就会觉得这是如此的简单。

我们上面写的这行代码:

List<String> stringList = new ArrayList<>();

这里的类型参数String其实就是类型实参了,也就是实际的类型参数,这样的类型参数其实就是各个数据类型,泛型不就是参数化类型嘛,类型都被当做参数使用,所以这里的String其实就是实际的类型实参,是个字符串类型,咋样,理解吧?

那啥是类型形参呢?我们来看看List接口是如何定义的?

在这里插入图片描述

源码中List接口是这样定义的,当然,看到尖括号,这就是泛型,只不过好像跟我们之前看的不太一一样,之前这里的尖括号都是具体的类型,比如String,这里弄了一个E,这是啥玩意啊。

首先啊,你看,还记得Lsit集合人家是什么都可以存储的嘛,也就是整型啊,字符串都可以,现在使用泛型之后,相当于你可以这样写代码:

List<String> stringList = new ArrayList<>();

那么你这里的List集合就只能存储字符串类型的,当然,如果我想让List集合专门存储整型数据呢?那是不是要这样写:

List<Integer> list = new ArrayList<>();

可是这样的话,你发现问题没?那我源码中的List该怎样?现在要求就是我实际写代码中List后面的泛型可以写成各种数据类型,这就要求源码中的List定义必须是具备通用特性的,那就用个啥来做个抽象的,泛型中就是使用一些大写的英文字母来作为类型形参,比如这里的E就是一个类型形参,实际中你可以写成String啊或者Interger,以便达到List集合只存储特定类型数据的目的,而String这些就是类型实参了。

咋样,明白吧,我之前学习这里的时候也比较疑惑这个E是啥啊,想必大家也见过T,这都是啥,这些其实就是泛型中的类型形参,我们在创建具体的类,接口或者方法的时候可以把这些类型形参转换成具体的类型形参,大家可以看看Map的定义,是这样的:

在这里插入图片描述

这里是一个K和一个V,所以啊这些都是有个基本命名的,大致有如下这些:

E 元素 集合框架使用
K 键 映射关系键的类型
V 值 映射关系中值得类型
N 数字 主要用于表示数字
T 通用类型1
S 通用类型1
U 通用类型1
V通用类型1

咋样,看到这里是不是有种豁然开朗的感觉呢?这些就是实际的类型形参,比如上面的Map,类型形参是这样的:

Map<K,V>

实际的类型实参是这样的:

Map<String,String>

ok了吧!理解力类型参数的形参和实参,我们再看接下来的内容。

四 泛型使用

我们在上面介绍泛型的时候,基本上都是使用集合类来说明,这很大一部分原因是因为泛型的提出有相当大的原因是为了弥补集合的缺陷,当然我也说了,泛型绝不仅仅是局限于集合,我们可以自定义泛型,比如自定义泛型接口和泛型类以及方法。

1、定义泛型接口

我们还是再来看下JDK中的List的定义,就是它:

在这里插入图片描述

这是定义了一个泛型的List接口,接下来我们来自己定义一个泛型接口,看看是怎么定义的,来,上代码:

在这里插入图片描述

我们这里自定义了一个泛型接口,这个泛型的类型形参是E,包含一个showTypeName方法,目的是打印出泛型实际类型实参的类型名称,接下来写一个类去实现这个泛型接口:

在这里插入图片描述

这里要注意了,我们写一个类,然后去实现上面我们自定义的泛型接口,这时候我们的类名后面也是要写上泛型的,就是不能这样,否则报错:

在这里插入图片描述

然后就是实现泛型接口中的方法了,获取传入的类型实参的类型名称,接下来我们使用这个类看下:

在这里插入图片描述

到这里是不是就比较熟悉啦,跟我们之前一直举例的List集合有点相似吧,我们看输出结果:

在这里插入图片描述

得出我们输入的类型形参类型是String类型,以上就是泛型接口定义的一个非常简单的例子了,咋样,不知道你看明白了吗?

2、自定义泛型类

上面我们简单说了下泛型接口的自定义,大致上就是你要知道泛型接口如何定义,类如何去实现一个泛型接口,接下来我门来看如何自定义一个泛型类,直接看代码:

在这里插入图片描述

这里简单自定义了一个泛型类,这里要注意,我门上面说过了什么是类型形参,并且介绍了几个约定俗成的,实际上这里的类型形参,你用任何一个大写的英文字母都是ok的,比如这里我就用了一个大写的G,然后看看如何使用这个泛型类:

在这里插入图片描述

我们再来看看输出结果:

在这里插入图片描述

咋样,泛型类的自定义是不是也比较简单,接下来我们看看,一个类如何去继承一个泛型类。

3、继承泛型类

直接看代码吧:

在这里插入图片描述

这里就是直接继承了上述我们实现的泛型类,这里要注意了,我们继承的泛型类,不能再是类型形参的形式了,也就是不能这个样子:

在这里插入图片描述

也就是当你继承了一个泛型类的时候,就要指定真实的类型实参,这个时候就要确定类型了。

4、原始类型

我们上面说了继承泛型类的时候,后面不能再跟泛型形参的形式了,但是你是可以完全去除泛型的,也就是这样的形式:

在这里插入图片描述

这样也可以的,这被称作是原始类型,那么这样的话,实际使用输出是什么呢?我们来使用这个类:

在这里插入图片描述

这时候其实就是把原先的类型形参G当做Object类型的了,而之前我们这样的形式:

在这里插入图片描述

就相当于把原先的类型形参G全部当做是String类型了,所以你这里就会报错了:

在这里插入图片描述

因为这时候就只能传入String了。

5、并不存在泛型类

ArrayList<String>类,是一种特殊的ArrayList类。该ArrayList<String>对象只能添加String对象作为集合元素。但实际上,系统并没有为ArrayList<String>生成新的class文件,而且也不会把ArrayList<String>当成新类来处理。因为不管泛型的实际类型参数是什么,它们在运行时总有同样的类(class)

// 分别创建List<String>对象和List<Integer>对象
List<String> l1 = new ArrayList<>();
List<Integer> l2 = new ArrayList<>();
// 调用getClass()方法来比较l1和l2的类是否相等
System.out.println(l1.getClass() == l2.getClass());        // 输出true

不管为泛型的类型形参传入哪一种类型实参,对于Java来说,它们依然被当成同一个类处理,在内存中也只占用一块内存空间,

因为泛型是与类实例相关的,而静态方法不依赖于类的实例。因此在静态方法、静态初始化块或者静态变量的声明和初始化中不允许使用类型形参

public class R<T>
{static T info;    // 代码错误,不能在静态变量声明中使用类型形参T age;public void foo(T msg){}public static void bar(T msg){}    // 代码错误,不能在静态方法声明中使用类型形参
}

由于系统中并不会真正生成泛型类,所以instanceof运算符后不能使用泛型类。

if(cs instanceof List<String>)
{...
} 

6、通配符

泛型中还有个通配符的概念,这个该怎么理解呢?还是看例子比较好理解,来看代码:

在这里插入图片描述

假如这里有这么一个方法,也没啥特别,要非说特别那就是方法中的参数是一个List,为啥特别,因为List是一个泛型接口啊,你看:

在这里插入图片描述

但是上面我们的List并没有指定实际的类型实参,这样就会产生一些问题,它会产生泛型警告的问题,那么最好我们还是指定实际的类型形参,但是这里也有问题啊,就是这里我并不确定以后传入过来的List的实际类型实参是啥,也就是说可能传入这样的一个List:

List<String> stringList = new ArrayList<>();

也有可能传入这样的一个List:

List<Integer> integerList = new ArrayList<>();

那该怎么指定嘞?这样吗:

在这里插入图片描述

看着好像很对,我们试试:

在这里插入图片描述

很不幸,这里报错了,其实这里一句话可以概括:

String是Object的子类,但是List<String>却不是List<Object>的子类

记住这个,就知道这里肯定是不行的,那该怎么办嘞?这里就要使用到通配符了,就是这样:

在这里插入图片描述

就一个问号就搞定啦,这个时候我们使用这个Test方法的时候就是既可以传入这样的List:

List<String> stringList = new ArrayList<>();

也可以传入这样的List:

List<Integer> integerList = new ArrayList<>();

所以啊,使用通配符之后可以传入的类型就多了,但是有的时候可能不需要传入所有的,希望还是有一定的限制的,这个时候就需要通配符的上下限设置了,关于这个,限于篇幅问题,就不展开来讲了。

7、泛型方法

这里把泛型方法单独拿出来讲是觉得这个泛型方法理解起来还是需要费点劲儿的!实际情况也确实如此,泛型方法有点不好理解。

那啥是泛型方法嘞,简单来说啊,泛型方法就是:

声明方法的时候,可以定义一个或多个泛型形参

这里我们拿泛型类来对比一下,对于泛型类,比如这个:

在这里插入图片描述

我们在实例化这个类的时候需要指明具体的类型实参,比如是String还是Intenger之类的,那么对于泛型方法而言,它就是在定义的时候是泛型形参,而实际调用的时候需要指定泛型实参(也就是泛型的具体类型)

定义及使用泛型方法

接下来我们来看如何定义泛型,首先我们来看一个正常的方法定义:

在这里插入图片描述

这是一个很正常的方法定义,但是里面的逻辑似乎不正常,为啥?觉得这样没必要啊,你看我们这里需要给参数传入的就是String类型,你这里还输出类型名称,好像只有给你输出来你才相信似的,好像是这儿回事,那我们接着来看,如何定义一个泛型方法。

你想啊,我们怎么定义类,是不是有个关键字class,如何定义接口呢?是不是用关键字interface,所以,定义这些比较特殊的东西,必定有个特殊的东西,那么如何定义泛型方法呢?你看:

在这里插入图片描述

这里就简单定义了一个泛型方法,这里需要注意的就是,你凭啥说你定义的是一个泛型方法呢?这里的一个象征就是红框中的泛型,也就是说啊,你要定义一个泛型方法的话,那么你就必须在权限修饰符(这里是public)和返回值之间写上,这个是泛型标志,代表你这个是一个泛型方法,对了,这里的T就是个泛型形参,也可以是其他的大写字母,这个之前讲过的,所以啊,你在看这个泛型方法,比如我们调用这个泛型方法:

在这里插入图片描述

是不是觉得逻辑没啥问题啊,因为传入的是个泛型,所以这里通过一个泛型方法,可以传入不同的类型,以便查看其类型,这里要注意了,我们写的平常的方法,方法传入的是确定的类型,但是使用泛型后,可以传入各种类型,那么就可以测试一些不知道是什么类型的类型名称了,可能有点绕,理解下!

所以啊,泛型方法的定义的语法如下:

修饰符 <T,E,……> 返回值类型 方法名称(形参列表){
方法体……
}

我们来对照一下我们定义的泛型方法:

在这里插入图片描述

这里的public就是修饰符,<T>就是泛型列表,为啥说列表,其实是它可以包含多个泛型形参名称,也就是那些个大写的英文字母,后面的void就是返回值类型了,然后就是方法名称和形参列表了。

重点总结

我们还是来看这个泛型方法的定义:

在这里插入图片描述

这里有几个知识点需要强调一下:

1、权限修饰符和返回值中间的这个泛型列表,也即是很重要,就相当于是泛型方法的标志,有了这个你才能叫做泛型方法
2、代表将使用泛型类型T,只有这个时候,你在方法中才可以使用泛型类型T
3、另外你需要知道的就是这个T啊就是泛型形参的命名,可以是T,E,K等等这些,反正就是大写的英文字母就ok了

8、泛型擦除与转换

这个泛型擦除是啥嘞?一般的话面试的时候要是问泛型的话,那就大概率会被问到这个泛型擦除了,先来看一段代码:

在这里插入图片描述

猜想一下,这两个ArrayList的类型一样吗?看一下结果:

在这里插入图片描述

可以看到,这两个是完全一样的,也就是说,这里的泛型实参String和Integer并没有对ArrayList造成什么本质上的影响,其实这里蛮好理解的:

这里的泛型就相当于一个安检,指定了一个具体的数据类型,想要往这个集合中存入数据就得经过泛型这个安检检查,和指定数据类型不一样的都不允许存储,这就保证了存储的类型都是指定的类型,也就是说啊,我这个集合只想存储统一的数据类型,怎么做嘞,那就搞个检查装置(就是泛型),起到一个过滤数据的作用,但是你这检查装置只是起到一个检查过滤的作用,并不影响我本身,举个例子就是好比我要开个针对程序员的大会,选了一个酒店,那么这个酒店目前只允许程序员进入,所以找个保安(泛型)站在门口,只允许程序员进入,不是程序员的不让进,那么在大会开始之前(编译阶段),保安会在门口把门,只让程序员进,等到人员都到场了,那么可以确定的是酒店里都是程序员了,那么保安此时的任务就结束了,然后保安就可以撤了(泛型擦除),然后我们就开始开会了(运行阶段)

这就是泛型擦除了,咋样,我说的够明白吗?也就是说啊,泛型就是在编译阶段做了一个检查,在编译阶段,不符合你指定的类型的数据都会检查报错,比如下面的代码:

ArrayList<String> stringArrayList = new ArrayList<>();

因为指定了具体的泛型实参String,那么你这里就只能添加字符串,编译阶段是会检查的,一旦你添加的不是字符串,它就会报错,你看:

在这里插入图片描述

等你添加完毕,这个ArrayList里面就都是字符串类型了,到了运行阶段,这里的泛型信息就被擦除了,没泛型啥事了,也就是本身ArrayList啥都可以存储,现在是加了个泛型,可以确保我存储的都是同种类型的。

再举个例子就是,有一座茅草屋,本来这个茅草屋谁都可以进去,但是现在规定(相当于加了泛型),身价一个亿的才能进去,但是即使进去的都是身价一个亿的,这个茅草屋还是原来那个茅草屋,它也不可能变成豪华别墅啊(只是举例子,拒绝杠精)

除了擦除,还有个转换,举个例子也就很容易明白,看代码:

在这里插入图片描述

这是我们之前自定义的一个简单的泛型类,现在我们使用这个类:

在这里插入图片描述

我们这里指定具体的泛型实参是String字符串类型,那么这个时候,代码的实际编译阶段,这个G就全部被替换成了String,也就是变成了这个样子:

在这里插入图片描述

这就是一个类型的转换了,说的简单点就是你定义的泛型形参在编译的阶段会被全部替换成你实际指定的泛型实参。

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【数据结构】算法的空间复杂度

&#x1f984;个人主页:修修修也 &#x1f38f;所属专栏:数据结构 ⚙️操作环境:Visual Studio 2022 算法空间复杂度的定义 算法的时间复杂度和空间复杂度是度量算法好坏的两个重要量度,在实际写代码的过程中,我们完全可以用空间来换时间,比如说,我们要判断某某年是不是闰年,大…

github创建个人网页登录后404无法显示的问题

1.首先必须要有内容&#xff0c;默认是会找index.html文件&#xff0c;找不到该文件会找readme.md文件&#xff0c;也就是说最简单的方法是&#xff0c;创建了与用户名同名的repository后username.github.io后&#xff0c;添加一个readme.md文件&#xff0c;得在readme里打点字…

【算法-动态规划】最长上升子序列-力扣 300

&#x1f49d;&#x1f49d;&#x1f49d;欢迎来到我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里可以感受到一份轻松愉快的氛围&#xff0c;不仅可以获得有趣的内容和知识&#xff0c;也可以畅所欲言、分享您的想法和见解。 推荐:kuan 的首页,持续学…

设计模式-相关内容

文章目录 一、设计模式概述二、UML图1.类的表示方法2.类与类之间关系的表示方法(1)关联关系(2)聚合关系(3)组合关系(4)依赖关系(5)继承关系(6)实现关系 三、软件设计原则1.开闭原则2.里氏代换原则3.依赖倒转原则4.接口隔离原则5.合成复用原则6.迪米特法则 一、设计模式概述 创…

驾驶数字未来:汽车业界数字孪生技术的崭新前景

随着数字化时代的到来&#xff0c;汽车行业正经历着前所未有的变革。数字孪生技术&#xff0c;作为一种前沿的数字化工具&#xff0c;正在为汽车行业带来革命性的影响&#xff0c;不仅改变着汽车制造和维护的方式&#xff0c;也为消费者带来了前所未有的体验。让我们一起探讨&a…

[sqoop]hive导入mysql,其中mysql的列存在默认值列

一、思路 直接在hive表中去掉有默认值的了列&#xff0c;在sqoop导入时,指定非默认值列即可&#xff0c; 二、具体 mysql的表 hive的表 create table dwd.dwd_hk_rcp_literature(id string,literature_no string,authors string,article_title string,source_title string…

OLED透明拼接屏:福州鼓山风景区:徜徉于城市壮丽之

福州是中国福建省的省会城市&#xff0c;历史悠久&#xff0c;文化底蕴深厚。 该城市曾是唐宋时期的重要港口城市&#xff0c;也是丝绸之路海上丝绸之路的起点之一。 福州以其独特的地理位置和丰富的历史遗产而闻名于世。 福州拥有众多的历史景点&#xff0c;其中最著名的是…

MySQL为什么用b+树

索引是一种数据结构&#xff0c;用于帮助我们在大量数据中快速定位到我们想要查找的数据。 索引最形象的比喻就是图书的目录了。注意这里的大量&#xff0c;数据量大了索引才显得有意义&#xff0c;如果我想要在[1,2,3,4]中找到4这个数据&#xff0c;直接对全数据检索也很快&am…

动态盘转换为基本盘

问题描述 不小心将磁盘0&#xff08;C和D是基本盘&#xff0c;蓝颜色&#xff09;改成了动态盘&#xff08;C和D是动态盘&#xff0c;橘黄色&#xff09;&#xff1f;如何修改回来呢&#xff1f; 解决方案&#xff1a; 使用DiskGenius将动态磁盘转换为基本磁盘 操作之前一定…

风电光伏混合储能功率小波包分解、平抑前后波动性分析、容量配置、频谱分析、并网功率波动分析(Matlab代码实现)

&#x1f4a5;&#x1f4a5;&#x1f49e;&#x1f49e;欢迎来到本博客❤️❤️&#x1f4a5;&#x1f4a5; &#x1f3c6;博主优势&#xff1a;&#x1f31e;&#x1f31e;&#x1f31e;博客内容尽量做到思维缜密&#xff0c;逻辑清晰&#xff0c;为了方便读者。 ⛳️座右铭&a…

【java|golang】多字段排序以及排序规则

奖励最顶尖的 K 名学生 给你两个字符串数组 positive_feedback 和 negative_feedback &#xff0c;分别包含表示正面的和负面的词汇。不会 有单词同时是正面的和负面的。 一开始&#xff0c;每位学生分数为 0 。每个正面的单词会给学生的分数 加 3 分&#xff0c;每个负面的词…

智慧空开让用电更安全、管理更智能——电脑APP远程控制开合闸

安科瑞 崔丽洁 01 什么是低压断路器&#xff1f;低压断路器的定义是&#xff1a;能够接通、承载及分断正常电路条件下的电流&#xff0c;也能在规定的非正常电路条件&#xff08;过载、短路、特别是短路&#xff09;下接通、承载一定时间和分断电流的开关电器。 断路器的分类&…

拼多多商品品牌数据接口,拼多多商品详情数据接口,拼多多优惠券数据接口,拼多多API接口

拼多多商品品牌数据采集方法如下&#xff1a; 手动数据采集。直接在拼多多平台上搜索并手动复制商品数据&#xff0c;适合采集小批量的商品数据&#xff0c;但不适用于大规模数据采集。手动采集需要手动输入搜索词&#xff0c;进行筛选后再复制所需的数据&#xff0c;该方法需…

白银做期货还是做现货?

现货白银和期货白银都是保证金交易品种&#xff0c;都具有一定的资金杠杆&#xff0c;新手投资者在它们之间进行选择的时候&#xff0c;可能会遇到一定的困难&#xff0c;但是只要投资者真正了解过它们的区别&#xff0c;在选择时思路就会更加清晰&#xff0c;能够根据自己的实…

Stable Diffusion XL搭建

本文参考&#xff1a;Stable Diffusion XL1.0正式发布了&#xff0c;赶紧来尝鲜吧-云海天教程 Stable Diffision最新模型SDXL 1.0使用全教程 - 知乎 1、SDXL与SD的区别 &#xff08;1&#xff09;分辨率得到了提升 原先使用SD生成图片&#xff0c;一般都是生成512*512&…

VMWare配置桥接

一、设置网络模式 二、编辑网卡配置 ip配置的子网掩码和默认网关保持和宿主机一致&#xff0c;ip局域网内不冲突。 # cd /etc/sysconfig/network-scriptslsvim ifcfg-ens160 TYPEEthernet PROXY_METHODnone BROWSER_ONLYno BOOTPROTOnone DEFROUTEyes IPV4_FAILURE_FATALno IP…

hive 之select 中文乱码

此处的中文乱码和mysql的库表 编码 latin utf 无关。 直接上案例。 有时候我们需要自定义一列&#xff0c;有时是汉字有时是字母&#xff0c;结果遇到这种情况了。 说实话看到这真是糟心。这谁受得了。 单独select 没有任何问题。 这是怎么回事呢&#xff1f; 经过一番检查&…

C++11新特性(lambda,可变参数模板,包装器,bind)

lambda表达式是什么&#xff1f;包装器又是什么&#xff1f;有什么作用&#xff1f;莫急&#xff0c;此篇文章将详细带你探讨它们的作用。很多同学在学习时害怕这些东西&#xff0c;其实都是方便使用的工具&#xff0c;很多情况下我们学这些新的东西觉得麻烦&#xff0c;累赘&a…

服务器数据恢复-DS5300存储raid5硬盘出现坏道离线的数据恢复案例

服务器数据恢复环境&#xff1a; 某单位一台DS5300存储&#xff0c;1个主机4个扩展柜&#xff0c;组建了2组RAID5&#xff08;一组27块硬盘&#xff0c;一组23块盘&#xff09;。27块盘的那组RAID5阵列存放Oracle数据库文件&#xff0c;存储系统一共分了11个卷。 服务器故障&a…

linux C++ vscode连接mysql

1.linux使用Ubuntu 2.Ubuntu安装vscode 2.1 安装的是snap版本,直接打开命令行执行 sudo snap install --classic code 3.vscode配置C 3.1 直接在扩展中搜索C安装即可 我安装了C, Chinese, code runner, 安装都是同理 4.安装mysql sudo apt update sudo apt install mysql-…