Java中的泛型

一. 泛型简介
泛型,即“参数化类型”。
作为Java中常用且重要的一个概念,泛型帮我们实现了代码重用,也保证了类型安全。但关于它的详细内容,目前很多同学还不清楚,所以接下来就带各位来学习这个重要的知识点。

  1. 背景

为了能够让大家更好地理解泛型的作用,在我们开始学习泛型之前,先给大家提个开发需求:

我们现在有一个需求,要求你编写一个对数组进行排序的方法,该方法能够对浮点型数组、整型数组、字符串数组或者是其他任何类型的数组进行排序,你该如何实现?

有的小伙伴会说,这很简单啊,我可以利用方法重载,针对每种类型的数组分别编写一个排序方法,需要为几种类型的数组排序,我就定义几个排序方法。如果你是这么实现的,只能哈哈哈了,这种做法明显不好,代码可重用性太差。

又有的小伙伴说了,可以定义一个方法,里面设置一个Object[]类型的参数,这样无论是哪种类型都可以处理了。这样定义方法,比上面那个同学的想法要稍好一点,但此时我们需要在Object类型和整型、String类型或其他类型之间进行强制类型转换。所以这样做就无法保证集合中元素的类型安全,稍一不慎就可能会导致 ClassCastException类型转换异常。

so,这也不行,那也不行,到底该怎么办?这不,为了解决这些问题,所以Java中就产生了泛型这个技术。

  1. 概念

泛型(generics) 这个技术是在JDK 5中引入的新特性,它的本质其实是类型参数化, 利用泛型可以实现一套代码对多种数据类型的动态处理,保证了更好的代码重用性。并且泛型还提供了编译时对类型安全进行检测的机制,该机制允许我们在编译时就能够检测出非法的类型, 提高了代码的安全性。

这种特性,使得泛型成了一种 “代码模板” ,让我们利用一套代码就能实现对各种类型的套用。也就是说,我们只需要编写一次代码,就可以实现万能匹配,这也是”泛型“这个概念的含义,你可以将其理解为”广泛的类型“、”非特定的类型“。咱们上面的那个需求,利用泛型就能轻松实现,还不需要进行类型的强制转换,并且也保证了数据的类型安全。

  1. 作用

所以根据上面泛型的概念,我们可以提取出泛型的核心作用:

泛型可以在编译时对类型进行安全检测,使得所有的强制转换都是自动隐式实现的,保证了类型的安全性;

泛型作为”代码模板“,实现了 一套代码对各种类型的套用, 提高了代码的可重用性。

  1. 使用场景

基于泛型的这些特性和作用,我们可以把泛型用在很多地方,在这里给大家做了一个总结,通常情况下,泛型可以用在如下场景中:

1.泛型集合:在各种集合中使用泛型,保证集合中元素的类型安全;2.泛型方法:在各种方法中使用泛型,保证方法中参数的类型安全;3.泛型类:在类的定义时使用泛型,为某些变量和方法定义通用的类型;4.泛型接口:在接口定义时使用泛型,为某些常量和方法定义通用的类型;5.泛型加反射:泛型也可以结合反射技术,实现在运行时获取传入的实际参数等功能。

但是我们要注意,无论我们在哪个地方使用泛型,泛型都不能是基本类型, 关于这一点,我会在讲解泛型擦除时再细说。

总之,泛型的应用场景有很多,以上只是给大家总结的几个重点使用场景,接下来就这几个场景分别给大家进行讲解。

二. 泛型集合

  1. 简介

泛型最常见的一个用途,就是在集合中对数据元素的类型进行限定。集合作为一个容器,主要是用来容纳保存数据元素的,但集合的设计者并不知道我们会用集合来保存什么类型的对象,所以他们就把集合设计成能保存任何类型的对象。这就要求集合具有很好的通用性,内部可以装载各种类型的数据元素。集合之所以可以实现这一功能,主要是集合的源码中已经结合泛型做了相关的设计,我们来看看Collection的源码,如下图所示:
在这里插入图片描述
而Collection的子类List中也增加了对泛型的支持,如下图所示:
在这里插入图片描述
上面的源码中,集合中的< E >就是泛型,至于泛型的名字为什么叫做”E“,后面再跟大家细说。但不管如何,从这些源码中我们就可以看出,Java的集合本身就支持泛型了。我们先不管集合底层是如何设计的,咱们先从基本用法开始学起。

  1. 语法

在集合中使用泛型其实比较简单,我们以List集合为例,其基本语法如下:
在这里插入图片描述
上面的语法,其含义是说我们定义了一个ArrayList集合,但该集合不能随便添加数据元素,只能添加String类型的元素。也就是说,在上面的语法中,我们通过泛型,限定了ArrayList集合的元素类型。当我们定义List集合时,如果已经限定了泛型类型,但后面添加元素时你非得违背这个类型,Java就会在编译阶段报错,如下图所示:
在这里插入图片描述
我们在定义集合时,可以省略后面ArrayList里的String,编译器可以自动根据前面< >里的类型,推断出后面< >里使用的泛型类型。另外Set和Map集合的用法,与List集合类似,我们可以通过下面这个案例来体会一下集合泛型的魅力。

  1. 代码案例

在本案例中,我们可以给List、Set、Map等集合设置泛型,从而限定集合中数据元素的类型。
在这里插入图片描述
在这个案例中,我们在集合中通过泛型限定了集合元素的数据类型。如果元素的类型与要求的不一致,在编译阶段就会检测出有错误,不需要进入到运行阶段才能发现类型不一致。而且我们 在获取集合中的元素时,也不需要进行强制类型转换,程序会自动进行隐式转换, 这就保证了数据的安全性,也提高了代码的执行效率。

另外我们所使用的泛型参数,也被称为类型变量,是用于指定泛型类型名称的标识符。我们可以根据需要,在集合、类、接口、方法等地方定义一个或多个泛型参数,这些泛型化的类型参数也被称为参数化的类或参数化的类型。

三. 泛型接口
我们除了可以在集合中使用泛型,还可以在定义接口时使用泛型,这也是泛型的常用形式之一。

  1. 语法

在定义接口时使用泛型的基本语法格式如下:
在这里插入图片描述
大家注意,这里泛型的名称T/M/N,其实是我们随意写的,我们并不一定非要使用T,也可以使用M、N、E等任意名称。而之所以使用T,只是采用了Type类型这个单词的首字母而已。虽然如此,但我们在实际开发时,为了尽量做到见名知意,请大家还是要尽量采用有意义的名称,通常会使用如下几个常用字母:

E - Element(表示集合元素,常在集合中使用);T - Type(表示Java类,常用在类和接口中);K - Key(表示键);V - Value(表示值);N - Number(表示数值类型);? - 表示不确定的Java类型。

另外,这里的T只是一种类型参数,你可以把它理解成是一个”表面的占位符“。在真正赋值时,它可以用任何实际的类型来替代,如Integer、String、自定义类型等。并且我们在定义接口时,可以根据实际需要,同时定义多个泛型,多个泛型之间用","逗号分割。而在实际使用时,我们需要在该接口名的后面加上一对尖括号,用来传入实际的类型。

  1. 代码案例
    2.1 定义泛型接口

接下来我们再通过一个案例来学习一下接口泛型如何使用,这里我们定义一个泛型接口ICompute,内部定义了一个用于计算的方法,如下所示:
在这里插入图片描述
2.2 实现泛型接口

接下来我们把这个接口进行实现,代码如下:
在这里插入图片描述
这里直接利用匿名内部类的写法进行实现,大家也可以编写一个类实现ICompute接口。我这里传入了两个Integer类型的具体参数,分别取代M和N,当然我们也可以根据需要,在实现时传入Float/Double等其他类型。

四. 泛型类
其实Java的类和接口在很多地方都很类似,所以我们在定义接口时可以使用泛型,也可以在定义类时使用泛型,泛型类常用于类中的属性类型不确定的情况下,这也是泛型的常用形式之一。

  1. 语法

其实泛型类的声明和普通类的声明类似,只是在类名后面多添加了一个关于泛型的声明。并且泛型类的类型参数部分,可以包含一个或多个类型参数,多个参数间用逗号隔开。一般我们在定义泛型类时,需要在类名后添加类型参数,语法格式与泛型接口一致,如下所示:
在这里插入图片描述
泛型类的要求和泛型接口完全一样,这里就不再赘述了。

  1. 代码案例
    2.1 定义泛型类

接下来定义一个泛型类Pair,它包含两个类型相同的成员变量:
在这里插入图片描述
在上述代码中,我们定义了一个泛型类Pair,它有两个类型相同的成员变量first和second,以及一个构造函数和两个访问成员变量的方法。在定义Pair类时,我们使用了类型参数T来代表类型,而在实例化该泛型类时,需要指明泛型类中的类型参数,并赋予泛型类属性相应类型的值,比如指定T是
String/Integer/Student/Person等任意类型。

2.2 使用泛型类

接下来是使用Pair类的具体代码:
在这里插入图片描述
在上述代码中,我们使用了Pair类,并将类型参数指定为String类型。然后我们创建了一个Pair对象,并通过getFirst和getSecond方法访问了成员变量。

五. 继承泛型类和实现泛型接口
在Java中,泛型不仅可以用于类、方法的定义,还可以用于类和接口的继承与实现。接下来就给大家详细介绍一下,该如何继承泛型类和实现泛型接口。

  1. 简介

大家要注意,一个被定义为泛型的类和接口,也可以被子类继承和实现。例如下面的示例代码,就给大家演示了如何继承一个泛型类。
在这里插入图片描述
但是如果我们想要SonClass类在继承FatherClass类时,能够保留父类的泛型类型,则需要在继承时就指定。否则直接使用extends FatherClass语句进行继承操作时,T1、T2 和 T3都会自动变为Object类型,所以一般情况下都是将父类的泛型类型保留。

接下来会分别给大家介绍一下如何继承泛型类和实现泛型接口。

  1. 继承泛型类
    2.1 定义泛型父类

在Java中,我们可以通过继承一个泛型类来实现泛型的重用。子类可以继承父类中定义的泛型类型,并根据自己的需要,增加、修改泛型类型的参数,从而实现泛型类的个性化定制。下面是一个泛型类的示例:
在这里插入图片描述
2.2 泛型子类继承父类

我们可以通过继承GenericClass类,来创建一个新的泛型类SonGenericClass,并增加新的泛型类型:
在这里插入图片描述
在上面的示例中,SonGenericClass类继承了GenericClass类,并增加了一个新的泛型类型T2。在构造方法中,调用父类的构造方法,并传入T1类型的数据,然后再将T2类型的数据赋值给类的成员变量otherData。通过这种方式,我们可以创建一个具有更多泛型参数的类,并且保留了原始泛型类的特性。我们来看看最终的测试结果:
在这里插入图片描述
这样,子类通过继承父类,也自动获得了父类中的泛型。

6、泛型方法

在java中,泛型类的定义非常简单,但是泛型方法就比较复杂了。尤其是我们见到的大多数泛型类中的成员方法也都使用了泛型,有的甚至泛型类中也包含着泛型方法,这样在初学者中非常容易将泛型方法理解错了。

泛型类:是在实例化类的时候指明泛型的具体类型;
泛型方法:是在调用方法的时候指明泛型的具体类型 。

/*** 泛型方法的基本介绍* @param tClass 传入的泛型实参* @return T 返回值为T类型* 说明:*     1)public 与 返回值中间<T>非常重要,可以理解为声明此方法为泛型方法。*     2)只有声明了<T>的方法才是泛型方法,泛型类中的使用了泛型的成员方法并不是泛型方法。*     3)<T>表明该方法将使用泛型类型T,此时才可以在方法中使用泛型类型T。*     4)与泛型类的定义一样,此处T可以随便写为任意标识,常见的如T、E、K、V等形式的参数常用于表示泛型。*/
public <T> T genericMethod(Class<T> tClass)throws InstantiationException ,IllegalAccessException{T instance = tClass.newInstance();return instance;
}

调用,返回

Object obj = genericMethod(Class.forName("com.test.test"));

静态方法有一种情况需要注意一下,那就是在类中的静态方法使用泛型:静态方法无法访问类上定义的泛型;如果静态方法操作的引用数据类型不确定的时候,必须要将泛型定义在方法上。

即:如果静态方法要使用泛型的话,必须将静态方法也定义成泛型方法 。

  1. Java 泛型擦除
Java 泛型的参数只可以代表类,不能代表个别对象。
由于 Java 泛型的类型参数之实际类型在编译时会被消除,所以无法在运行时得知其类型参数的类型。Java 编译器在编译泛型时会自动加入类型转换的编码,故运行速度不会因为使用泛型而加快。

泛型是Java SE 1.5的新特性,泛型的本质是参数化类型,也就是说所操作的数据类型被指定为一个参数。这种参数类型可以用在类、接口和方法的创建中,分别称为泛型类、泛型接口、泛型方法。 Java语言引入泛型的好处是安全简单。

泛型的好处是在编译的时候检查类型安全,并且所有的强制转换都是自动和隐式的,以提高代码的重用率。

Java中泛型其实是伪泛型;
例如:在编译阶段,泛型类Box会被实例化为Box和Box。编译器会根据需要插入类型转换代码来保证类型安全。
然而,在运行时,所有的泛型类型参数T都会被擦除,stringBox和integerBox实际上是相同的类型Box。因此,存放在盒子中的数据在运行时都被当作Object类型处理。
最后会多做一步强转,通过类型转换为泛型类型,这样可以确保获取到正确的数据类型。

JVM并不知道泛型的存在,因为泛型在编译阶段就已经被处理成普通的类和方法;
处理机制是通过类型擦除,擦除规则:

1.若泛型类型没有指定具体类型,用Object作为原始类型;
2.若有限定类型< T exnteds XClass >,使用XClass作为原始类型;
3.若有多个限定< T exnteds XClass1 & XClass2 >,使用第一个边界类型XClass1作为原始类型;

示例:

在Springboot中,调用RESTful api时常用的方法主要有两种:

通过自带的RestTemplate 或者 自己写http客户端访问工具来实现服务调用

基本上RestTemplate已经可以满足需要了

RestTemplate其实是对http请求中一些模块化代码的封装,比如建立连接、构造请求头 请求体、解析响应信息、关闭连接等,是Springboot对HttpClient的封装,简化了http请求过程,减少冗余代码。

主要方法:
RestTemplate封装了常用http请求,比如GET、POST、PUT、DELETE等,可以方便的调用,主要请求方法如下:

public <T> T getForObject(String url, Class<T> responseType, Object... uriVariables) throws RestClientExceptionpublic <T> ResponseEntity<T> getForEntity(String url, Class<T> responseType, Object... uriVariables) throws RestClientExceptionpublic <T> T postForObject(String url, @Nullable Object request, Class<T> responseType, Object... uriVariables) throws RestClientExceptionpublic <T> ResponseEntity<T> postForEntity(String url, @Nullable Object request, Class<T> responseType, Object... uriVariables) throws RestClientExceptionpublic void put(String url, @Nullable Object request, Object... uriVariables) throws RestClientExceptionpublic void delete(String url, Object... uriVariables) throws RestClientExceptionpublic <T> ResponseEntity<T> exchange(String url, HttpMethod method, @Nullable HttpEntity<?> requestEntity, Class<T> responseType, Object... uriVariables) throws RestClientExceptionpublic <T> T execute(String url, HttpMethod method, @Nullable RequestCallback requestCallback, @Nullable ResponseExtractor<T> responseExtractor, Object... uriVariables) throws RestClientException

这些方法使用起来是比较简单的,其中xxForObject返回的是接口返回值,xxForEntity返回的除了接口返回值 还包括http返回信息。

对于exchange和execute使用起来就比较灵活了,里面有个参数 HttpMethod,可以使用各种请求方式进行请求,比如用HttpMethod.GET方法进行GET请求。

HttpMethod是一个枚举:
在这里插入图片描述

RestTemplate exchange方法使用:
1、先新建一个springboot工程,端口取默认 8080,然后新建一个Controller,如下:

@RestController
public class RemoteRestController {@GetMapping("rest")public String usedForRemoteRest(){return "Hi there, from remote";}
}

如果调用成功,会返回一个字符串

2、再新建一个springboot工程,端口取8081,工程名比如取ex,方便辨认

server.port=8081

3、在新建的ex工程中,新建一个Controller,准备调用RestTemplate方法,去访问第一个工程中的接口:

@RestController
public class RestTestController {private static final String REMOTE_URL = "http://localhost:8080/";@GetMapping("rtest")public String restGetValue(HttpServletRequest req){RestTemplate restTemplate = new RestTemplate();String ret = restTemplate.getForObject(REMOTE_URL + "rest", String.class);System.out.println("====================ret: " + ret);ResponseEntity<String> retEntity = restTemplate.getForEntity(REMOTE_URL + "ret", String.class);return "";}
}

分别运行两个spring工程,在浏览器中输入http://localhost:8081/rtest ,可以看到返回:
在这里插入图片描述
在ex工程中下断点,可以看到getForObject和getForEntity返回值的区别:
在这里插入图片描述
在这里插入图片描述
可以看到getForEntity返回信息会包括http的信息。

上面是简单的使用
在源码中我们可以看到,xxForObject, xxForEntity都是有返回值,而对于put, delete访问需要得到返回值,使用:

public void put(String url, @Nullable Object request, Object... uriVariables) throws RestClientExceptionpublic void delete(String url, Object... uriVariables) throws RestClientException

这两个方法就无能为力了

这时我们可以使用exchange方法来使用,具体如下:

在测试springboot工程中,写一个put方法的controller:

@PutMapping("restput")public String putMethod(){return "PUT method invoke";}

可以封装一个exchange方法:

private <T, A> T exchange1(String url, HttpMethod method, Class<T> responseBodyType, A requestBody) {RestTemplate template = new RestTemplate();// 请求头HttpHeaders headers = new HttpHeaders();MimeType mimeType = MimeTypeUtils.parseMimeType("application/json");MediaType mediaType = new MediaType(mimeType.getType(), mimeType.getSubtype(), Charset.forName("UTF-8"));// 请求体headers.setContentType(mediaType);// 发送请求HttpEntity<A> entity = new HttpEntity<>(requestBody, headers);ResponseEntity<T> resultEntity = template.exchange(url, method, entity, responseBodyType);return resultEntity.getBody();}

responseBody: 代表返回值类型

requestBody: 代表请求体中的body参数

在ex工程中写一个测试请求接口:

@GetMapping("rput")public String restPUTValue(HttpServletRequest req){String ret = exchange(REMOTE_URL + "restput", HttpMethod.PUT, String.class, null);return "RETURN: " + ret;}

在浏览器中输入:

http://localhost:8081/rput

会发现返回结果显示出来了:
在这里插入图片描述
exchange方法返回值中有泛型类型情况:
前面介绍的exchange方法是处理RestTemplate自带的put, delete方法中没有返回值的情况,但是包括get, post等方法,如果返回值中有泛型值,RestTemplate自带的getForEntity, getForObject等其实也是处理不了的,这时也可以使用exchange来代替,具体如下:

可以对上面封装的exchange方法进行改造,传入一个ParameterTypeReference对象:

public static <T, A> T exchange2(String url, HttpMethod method, ParameterizedTypeReference<T> responseBodyType, A requestBody) {RestTemplate restTemplate = new RestTemplate();// 请求头HttpHeaders headers = new HttpHeaders();MimeType mimeType = MimeTypeUtils.parseMimeType("application/json");MediaType mediaType = new MediaType(mimeType.getType(), mimeType.getSubtype(), Charset.forName("UTF-8"));// 请求体headers.setContentType(mediaType);// 发送请求HttpEntity<A> entity = new HttpEntity<>(requestBody, headers);ResponseEntity<T> resultEntity = restTemplate.exchange(url, method, entity, responseBodyType);return resultEntity.getBody();}

测试代码:

两个springboot工程分别,服务提供方、服务消费方:

场景1:泛型 返回字符串

服务提供方代码:
@PostMapping("/rpctop")public String rpctop(@RequestBody UserVO userVO){return "张贵";}服务消费方代码:
public String getUserName() throws JsonProcessingException {HttpHeaders headers = new HttpHeaders();headers.add("x-auth-token","123");headers.setContentType(MediaType.APPLICATION_JSON);ObjectMapper objectMapper = new ObjectMapper();Map<String, Object> map = new HashMap<>();map.put("name", "1111");map.put("age", "19");HttpEntity requestEntity = new HttpEntity(map, headers);//调用方式1Integer response = restTemplate.exchange("http://127.0.0.1:8080/ccbServer/tx/rpctop", HttpMethod.POST, String.class, map);//调用方式2//ParameterizedTypeReference<String> responseBodyType = new ParameterizedTypeReference<String>() {};//Person response = restTemplate.exchange("http://127.0.0.1:8080/ccbServer/tx/rpctop", HttpMethod.POST, responseBodyType, map);return response;}

场景2:泛型 返回Integer数据

服务提供方代码:
@PostMapping("/rpctop")public Integer rpctop(@RequestBody UserVO userVO){return 666;}服务消费方代码:
public Integer getUserName() throws JsonProcessingException {HttpHeaders headers = new HttpHeaders();headers.add("x-auth-token","123");headers.setContentType(MediaType.APPLICATION_JSON);ObjectMapper objectMapper = new ObjectMapper();Map<String, Object> map = new HashMap<>();map.put("name", "1111");map.put("age", "19");HttpEntity requestEntity = new HttpEntity(map, headers);//调用方式1Integer response = restTemplate.exchange("http://127.0.0.1:8080/ccbServer/tx/rpctop", HttpMethod.POST, Integer.class, map);       //调用方式2//ParameterizedTypeReference<Integer> responseBodyType = new ParameterizedTypeReference<Integer>() {};//Person response = restTemplate.exchange("http://127.0.0.1:8080/ccbServer/tx/rpctop", HttpMethod.POST, responseBodyType, map);return response;}

场景3:泛型 返回Person实体

服务提供方代码:
@PostMapping("/rpctop")public Person rpctop(@RequestBody UserVO userVO){Person person = new Person();person.setName("zjg");person.setAge(10);return person;}服务消费方代码:
public Integer getUserName() throws JsonProcessingException {HttpHeaders headers = new HttpHeaders();headers.add("x-auth-token","123");headers.setContentType(MediaType.APPLICATION_JSON);ObjectMapper objectMapper = new ObjectMapper();Map<String, Object> map = new HashMap<>();map.put("name", "1111");map.put("age", "19");HttpEntity requestEntity = new HttpEntity(map, headers);//调用方式1Person response = restTemplate.exchange("http://127.0.0.1:8080/ccbServer/tx/rpctop", HttpMethod.POST, Person.class, map);//调用方式2//ParameterizedTypeReference<Person> responseBodyType = new ParameterizedTypeReference<Person>() {};//Person response = restTemplate.exchange("http://127.0.0.1:8080/ccbServer/tx/rpctop", HttpMethod.POST, responseBodyType, map);return response.getName();}

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

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

相关文章

ArduPilot开源飞控之GCS显示DPS310异常问题

ArduPilot开源飞控之GCS显示DPS310异常问题 1. 源由2. 现象3. 分析3.1 Mission Planner3.2 Ardupilot3.3 AP_Baro分析3.4 AP_Baro定位 4. 修复5. 效果6. 参考资料7. 补充7.1 Ardupilot提交PR注意事项7.2 修复主要使用到的命令 1. 源由 2020年Ardupilot官网论坛就有开始讨论DPS…

计算机竞赛 深度学习卫星遥感图像检测与识别 -opencv python 目标检测

文章目录 0 前言1 课题背景2 实现效果3 Yolov5算法4 数据处理和训练5 最后 0 前言 &#x1f525; 优质竞赛项目系列&#xff0c;今天要分享的是 &#x1f6a9; **深度学习卫星遥感图像检测与识别 ** 该项目较为新颖&#xff0c;适合作为竞赛课题方向&#xff0c;学长非常推荐…

python基于轻量级卷积神经网络模型GhostNet开发构建养殖场景下生猪行为识别系统

养殖业的数字化和智能化是一个综合应用了互联网、物联网、人工智能、大数据、云计算、区块链等数字技术的过程&#xff0c;旨在提高养殖效率、提升产品质量以及促进产业升级。在这个过程中&#xff0c;养殖生猪的数字化智能化可以识别并管理猪的行为。通过数字化智能化系统&…

idea 通过tomcat 配置 https方式访问

步骤1&#xff1a;管理员模式打开cmd命令进行生成密匙 D:\software\apache-tomcat-8.5.93\bin\tomcat.keystore 是生成密匙存放的路径&#xff0c;修改成自己tomcat的路径即可 keytool -genkeypair -alias "tomcat" -keyalg "RSA" -keystore "D:\s…

【新版】系统架构设计师 - 案例分析 - 架构设计<Web架构>

个人总结&#xff0c;仅供参考&#xff0c;欢迎加好友一起讨论 文章目录 架构 - 案例分析 - 架构设计&#xff1c;Web架构&#xff1e;Web架构知识点单台机器 到 数据库与Web服务器分离应用服务器集群负载均衡负载均衡技术静态与动态算法Session共享机制有状态与无状态 持久化技…

使用香橙派 在Linux环境中安装并学习Python

前言 在实际项目中&#xff0c;经常会遇到需要使用人工智能的场景&#xff0c;如人脸识别&#xff0c;车牌识别等...其一般的流程就是由单片机采集数据发送给提供人工智能算法模型的公司&#xff08;百度云&#xff0c;阿里云...&#xff09;&#xff0c;然后人工智能将结果回…

C++ 继承详解

目录 C 继承介绍 继承中的特点 public 继承 protected 继承 private 继承 在类里面不写是什么类型&#xff0c;默认是 private 的 如果继承时不显示声明是 private&#xff0c;protected&#xff0c;public 继承&#xff0c;则默认是 private 继承&#xff0c;在 struct …

如何给Nginx配置访问IP白名单

一、Nginx配置访问IP白名单 有时部署的应用需要只允许某些特定的IP能够访问&#xff0c;其他IP不允许访问&#xff0c;这时&#xff0c;就要设置访问白名单&#xff1b; 设置访问白名单有多种方式&#xff1a; 1.通过网络防火墙配置&#xff0c;例如阿里云/华为云管理平台 2.…

百度资源搜索平台出现:You do not have the proper credential to access this page.怎么办?

Forbidden site not allowed You do not have the proper credential to access this page. If you think this is a server error, please contact the webmaster. 如果你的百度资源平台&#xff0c;点进去出现这个提示&#xff0c;说明您的网站已经被百度清退了。如果你的网站…

C语言数组和指针笔试题(三)(一定要看)

目录 字符数组四例题1例题2例题3例题4例题5例题6例题7 结果字符数组五例题1例题2例题3例题4例题5例题6例题7结果字符数组六例题1例题2例题3例题4例题5例题6例题7 结果 感谢各位大佬对我的支持,如果我的文章对你有用,欢迎点击以下链接 &#x1f412;&#x1f412;&#x1f412;个…

【数值计算方法】非线性方程(组)和最优化问题的计算方法:非线性方程式求根的二分法、迭代法、Newton 迭代法及其Python实现

目录 一、非线性方程式求根 1、二分法&#xff08;Bisection Method、对分法&#xff09; a. 理论简介 b. python实现 2、迭代法&#xff08;Iterative Method&#xff09; a. 理论简介 b. python实现 3、Newton 迭代法&#xff08;Newtons Method&#xff09; a. 理论…

电脑入门:电脑不认新硬盘时该怎么办?

电脑不认新硬盘时该怎么办? 当新硬盘加进后,正常工作时,没有什么问题。若电脑遇到特殊情况时,电脑对新硬盘“不认”,可采取以下措施让电脑重新“认”新硬盘,显示新分区(如G、H、I、J)。 咱的目的是保持S-ATA的开启,把控制板载S-ATA设定值由No变成Yes就可以。 首…

【数据结构与算法】链表的实现以及一些基本算法

目录 单选链表的基本实现 有序列表的合并&#xff08;双指针法&#xff09; 链表的反转 链表实现两数之和 判定链表是否有环 单选链表的基本实现 public class LinkedList1 {//头节点Node first;//尾节点Node last;//大小int size 0;//头插法public void addFirst(int…

微信小程序学习笔记3.0

第3章 资讯类:仿今日头条微信小程序 3.1 需求描述及交互分析 需求描述 仿今日头条微信小程序,要具有以下功能。 (1)首页新闻频道框架设计,包括底部标签导航设计、新闻检索框设计及新闻频道滑动效果设计。 (2)首页新闻内容设计,包括新闻标题、新闻图片及新闻评论设计…

TikTok的媒体革命:新闻业如何适应短视频时代?

在数字时代&#xff0c;媒体行业一直在不断演变和创新&#xff0c;以适应观众的变化需求和技术的发展。而在这个进化的过程中&#xff0c;短视频应用TikTok已经崭露头角&#xff0c;成为了一个重要的信息传播平台。 这篇文章将深入探讨TikTok如何引领了媒体的一场革命&#xf…

转载-C#学习笔记-基本概念(CLR、CTS、CLS...)

1. CLR(Common Language Runtime&#xff0c;公共语言运行时(库)) 可由多种.NET语言使用的运行时环境&#xff0c;其主要作用是定位、加载和管理.NET类型、内存管理、安全检查、线程管理等。.NET运行库提供了一个定义明确的运行库层&#xff0c;可以被支持.NET的所有语言和平台…

2、Linux中静态IP与动态IP的修改

修改为静态IP 打开文件 sudo vim /etc/network/interfaces修改如下 # interfaces(5) file used by ifup(8) and ifdown(8) auto lo iface lo inet loopbackauto ens33#配置网络为DHCP模式 #iface ens33 inet dhcp#配置网络 ens33为静态IP模式 iface ens33 inet static #设置…

基于Vue+ELement搭建动态树与数据表格实现分页

基于VueELement搭建动态树与数据表格实现分页 一、前言二、左侧动态树实现2.1.后台数据接口定义2.2.前端导航菜单绑定2.3.根据数据渲染页面 3.分页 一、前言 在上一篇博文我们搭建了首页导航和左侧菜单&#xff0c;但是我们的左侧菜单是死数据今天我们就来把死的变成活的&#…

自学WEB后端01-安装Express+Node.js框架完成Hello World!

一、前言&#xff0c;网站开发扫盲知识 1.网站搭建开发包括什么&#xff1f; 前端 前端开发主要涉及用户界面&#xff08;UI&#xff09;和用户体验&#xff08;UX&#xff09;&#xff0c;负责实现网站的外观和交互逻辑。前端开发使用HTML、CSS和JavaScript等技术来构建网页…

Leetcode 386. 字典序排数

文章目录 题目代码&#xff08;9.22 首刷看解析&#xff09; 题目 Leetcode 386. 字典序排数 代码&#xff08;9.22 首刷看解析&#xff09; 迭代DFS class Solution { public:vector<int> lexicalOrder(int n) {vector<int> ret(n);int number 1;for(int i 0…