泛型二 泛型和数组

2023-05-16

数组和泛型容器有什么区别

  要区分数组和泛型容器的功能,这里先要理解三个概念:协变性(covariance)、逆变性(contravariance)和无关性(invariant)。

  若类A是类B的子类,则记作A ≦ B。设有变换f(),若:

 


       当A ≦ B时,有f(A)≦ f(B),则称变换f()具有协变性;

    当A ≦ B时,有f(B)≦ f(A),则称变换f()具有逆变性;

    如果以上两者皆不成立,则称变换f()具有无关性。  

 

 

 

  在Java中,数组具有协变性,而泛型具有无关性,示例代码如下:


Object[] array = new String[10];
//编译错误 ArrayList
<Object> list=new ArrayList<String>();

 

  这两句代码,数组正常编译通过,而泛型抛出了编译期错误,应用之前提出的概念对代码进行分析,可知:

 


1、String ≦ Object

2、数组的变换可以表达为f(A)=A[],通过之前的示例,可以得出下推论:

  f(String) = String[] 以及 f(Object) = Object[];

4、通过代码验证,String[] ≦ Object[] 是成立的,由此可见,数组具有协变性。  

  又可知:


  5、ArrayList泛型的变换可以表达为 f(A)= ArrayList<A>,得出推论:

    f(String) = ArrayList<String> 以及 f(Object) = ArrayList<Object>;

  6、通过代码验证,ArrayList<String> ≦ ArrayList<Object>不成立,由此可见,泛型具备不变性  

 


  

  最终得出结论,数组具备协变性,而泛型具备不变性

  所以,为了让泛型具备协变性和逆变性,Java引入了有界泛型(参见3.1.2小节内容)概念。

  除了协变性的不同,数组还是具象化的,而泛型不是

  什么是具象化(reified,也可以称之为具体化,物化)?

  在《Java语言规范》里,明确的规定了具象化类型的定义:

完全在运行时可用的类型被称为具象化类型(refiable type),会做这种区分是因为有些类型会在编译过程中被擦除,并不是所有的类型都在运行时可用。

它包括:

1、非泛型类声明,接口类型声明;

2、所有泛型参数类型为无界通配符(仅用‘?’修饰)的泛型参数类;

3、原始类型;

4、基本数据类型;

5、其元素类型为具象化类型的数组;

6、嵌套类(内部类,匿名内部类等,比如java.util.HashMap.Entry),并且嵌套过程中的每一个类都是具象化的。

 

  不论是在编译时还是运行时,数组都能确切的知道自己的所属的类型。但是泛型在编译时会丢失部分类型信息,在运行时,它又会被当作Object处理。

  这里要涉及到类型擦除的相关知识,会在后面详细解释。在当前,只需要知道,Java的泛型最后都被当作上界(此概念会在后面说明)处理了。

  引申:数组具备协变性,是Java的一个缺陷,因为极少有地方需要用到数组的协变性,甚至,使用数组的协变会引起不易检查的运行时异常,参见下面代码:

Object[] array = new String[10];

array[0] = 1;

  很明显,这会在运行期抛出异常:java.lang.ArrayStoreException。

  鉴于有如此多的不同,在Java里,数组和泛型是不能混合使用的。参见下面代码:

List<String>[] genericListArray = new ArrayList<String>[10];

T[] genericArray = new T[];

 

  它们都会在编译期抛出Cannot create a generic array错误。这是因为,数组要求类型是具象化(refied)的,而泛型恰好不是。

 

  换言之,数组必须清楚的知道自己内部元素的类型,并且会一直保存这个类型信息,在添加的时候元素的时候,该信息会用于做类型检查,而泛型的类型不确定。所以,在编译器层面就杜绝了这个问题。这在《Java语言规范》里有明确的说明:

 

If the element type of an array were not reifiable,the virtual machine could not perform the store check described in the preceding paragraph. This is why creation of arrays of non-reifiable types is forbidden. One may declare variables of array types whose element type is not reifiable, but any attempt to assign them a value will give rise to an unchecked warning .

如果数组的元素类型不是具象化的,虚拟机将无法应用在前面章节里描述过的存储检查。这就是为什么禁止创建(实例化)非具象化的数组。你可以定义(声明)一个元素类型是非具象化的数组类型,但任何师徒给它分配一个值的操作,都会产生一个unchecked warning。

存储检查:这里涉及到Array的基本原理,可以自行参阅《Java语言规范》或者参考5.1.1ArrayList相关章节

 

 

 

  这不得不说,又是Java在泛型设计上的一点缺陷,为什么Java的泛型设计会有这么多缺陷呢?难道真的是Java语言不够好吗?这些内容将在3.3节泛型历史中解答。

 

 

泛型使用建议

  泛型在Java开发和设计中占据了重要的地位,如果正确高效的使用泛型尤为重要。下面通过介绍两条使用泛型时的建议,来加深对泛型的理解:

  1、泛型类型只能是类类型,不能是基本数据类型,如果要使用基本数据类型作为泛型,应当使用其对应的包装类。比如,如果期望在List中存放整形变量,因为int是基本类型,所以不能使用List<int>,应该使用int的包装类Integer,所以正确的使用方法为List<Integer>。

  当然,泛型不支持基本数据类型,试图使用基本数据类型作为泛型的时候必须转化为包装类这点,是Java泛型设计之初的缺陷。

  2、使用到集合的时候,尽量的使用泛型集合来替代非泛型集合。一般来说,软件的开发期和维护期时间占比,也是符合二八定律的,维护期的时长能超出开发期数倍。使用了泛型的集合至少,在IDE工具上,是类型确定的,可以提高代码的可读性,并在编译期就避免一些严重的BUG。

  3、不要使用常见类名(尤其是String这种属于java.lang的)作为泛型名,会造成编译器无法区分开类和泛型,并且不会抛出异常。

 

 

泛型擦除

 

  在学习泛型擦除之前,明确一个概念:Java的泛型不存在于运行时。这也是为什么有人说Java没有真正的泛型。

  泛型擦除(类型擦除),它是指在编译器处理带泛型定义的类\接口\方法时,会在字节码指令集里抹去全部泛型类型信息,被擦除后泛型,在字节码里只保留泛型的原始类型(raw type)。

  原始类型,是指抹去泛型信息后的类型,在Java中,它必须是一个引用类型(非基本数据类型),一般而言,它对应的是泛型的定义上界。

  举例:<T>中的T对应的原始泛型是Object,<T extends String>对应的原始类型就是String。

 泛型信息会在编译时擦除

 

  如何证明泛型会被擦除呢?这里提供了一段测试代码:


class TypeErasureSample<T> {

public T v1;

public T v2;

public String v3;

}

 

/**

 * 泛型擦除示例

 */

public class Generic3_2 {

public static void main(String[] args) throws Exception {

TypeErasureSample<String> type = new TypeErasureSample<String>();

type.v1 = "String value";

 

// 反射设置v2的值为整型数

Field v2 = TypeErasureSample.class.getDeclaredField("v2");

v2.set(type, 1);

 

for (Field f : TypeErasureSample.class.getDeclaredFields()) {

System.out.println(f.getName() + ":" + f.getType());

}

 

/*

 * 此处会抛出java.lang.ClassCastException: java.lang.Integer cannot be cast

 * to java.lang.String

 */

System.out.println(type.v2);

}

}  

 

  程序运行结果为:

v1:class java.lang.Object

v2:class java.lang.Object

v3:class java.lang.String

Exception in thread "main" java.lang.ClassCastException: java.lang.Integer cannot be cast to java.lang.String

at capter3.generic.Generic3_2.main(Generic3_2.java:29)

  v1和v2的类型被指定为泛型T,但是通过反射发现,它们实质上还是Object,而v3原本定义的就是String,和前两项一比对,证明反射本身并无错误。

  代码在输出type.v2的过程中抛出了类型转换异常,这说明了两件事:

  1、为v2设置整型数已经成功(可以自行写一段反射来验证);

  2、编译器在构建字节码的时候,一定做了类似于(String)type.v2的强行转换,关于这一点,可以通过反编译验证(反编译工具为jd-gui),结果如下所示:

 


public class Generic3_2

{

  public static void main(String[] args) throws Exception

  {

    TypeErasureSample type = new TypeErasureSample();

    type.v1 = "String value";

 

    Field v2 = TypeErasureSample.class.getDeclaredField("v2");

    v2.set(type, Integer.valueOf(1));

 

    for (Field f : TypeErasureSample.class.getDeclaredFields()) {

      System.out.println(f.getName() + ":" + f.getType());

    }

 

    System.out.println((String)type.v2);

  }

}  

 

  可以看到,如果编译器认为type.v2有被申明为String的必要的时候,都会加上(String)强行转换。可以进行测试:

  Object o = type.v2;

  String s = type .v2;

  后者会抛出类型转换异常,而前者是正常执行的。由此,可以得出结论,编译器会在构建字节码的时候,抹去一些泛型信息。

 

编译器保留的泛型信息有哪些?

 

  上一节中介绍了编译器会擦除全部泛型信息,那么是不是所有的泛型信息都会在编译的过程中消失呢,答案是否定的字节码里指令集之外的地方,会保留部分泛型信息。下面的泛型在编译阶段是会被保留的:

  1、泛型接口、类、方法定义上的所有泛型;

  2、成员变量声明处的泛型。

  参考下面的代码:


/**

 * 定义了泛型参数的接口

 */

interface GI<T> {

}

 

/**

 * 定义了泛型参数并实现了泛型接口的类

 */

class GC<T> implements GI<T> {

// 两种使用了泛型的成员变量

T m1;

ArrayList<T> m2 = new ArrayList<T>();

 

/**

 * 定义了泛型参数的方法,并在返回值、参数和异常抛出位置使用了该泛型

 */

<K extends Exception> ArrayList<K> method(K p) throws K {

// 在方法体中使用了泛型

K k = p;

ArrayList<K> list = new ArrayList<K>();

list.add(k);

return list;

}

}  

 

  代码涵盖了泛型的各种声明和使用情况。接下来使用反编译工具看看结果,可以注意到,接口、类、方法定义的位置,大部分泛型信息依然存在,字段中使用到泛型作为声明的位置,泛型同样存在,而在所有在局部代码快对泛型做引用的位置,泛型内容消失了:

 

 

abstract interface GI<T>{

}

 

class GC<T>  implements GI<T>{

  T m1;

  ArrayList<T> m2 = new ArrayList();

 

  <K extends Exception> ArrayList<K> method(K p) throws Exception{

    Exception k = p;

    ArrayList list = new ArrayList();

    list.add(k);

    return list;

  }

}

 

  可以注意到,在之前没有提及的位置,比如GC.m2成员变量的实例化位置,method方法体里的泛型信息全部被擦除。

  为什么Java会这么设计?这也很好理解:

    1、如果不保留泛型定义,那么除非拥有源码,不然无法使用泛型。

    2、即使保留了泛型定义,定义位置的泛型信息并未初始化,也就是说,泛型参数没有绑定为特定的某个类,对使用者不具备意义。而且,泛型信息在运行时也会被处理为上界,对使用并不会有影响。

  相信注意细节的读者已经发现了,之前提及的“会被保留泛型信息的位置”里,“异常抛出位置”的K被替换为了Exception,这不正说明它被擦除了?

  事实上,如果通过反射来获取泛型信息的时候(方法将在下一小节详细讲解),会发现,依然可以得到异常的泛型信息。得出结论,作为抛出异常的泛型参数,没有消失

  这是为什么呢?

  既然反编译工具没有记录下泛型信息,只能说明某些反编译工具没有解析二进制文件里的某些信息。这些信息是什么呢?这里要引入的一个概念,方法签名(Method Signatrue)。

  下面列出的是上一个例子的部分字节码内容(也就是class文件反编译的原始内容):

  // Method descriptor #31 (Ljava/lang/Exception;)Ljava/util/ArrayList;

  // Signature: <K:Ljava/lang/Exception;>(TK;)Ljava/util/ArrayList<TK;>;^TK;

  // Stack: 1, Locals: 2

  java.util.ArrayList method(java.lang.Exception p) throws java.lang.Exception;

    0  aconst_null

    1  areturn

      Line numbers:

        [pc: 0, line: 40]

      Local variable table:

        [pc: 0, pc: 2] local: this index: 0 type: capter3.generic.GC

        [pc: 0, pc: 2] local: p index: 1 type: java.lang.Exception

      Local variable type table:

        [pc: 0, pc: 2] local: this index: 0 type: capter3.generic.GC<T>

        [pc: 0, pc: 2] local: p index: 1 type: K

 

  这段内容不长,也无需细看,如果稍微观察下,可以注意到第四行开始就是方法的定义部分,包括返回值ArrayList,参数Exception,抛出的异常Exception,注意到没有?它们,统统不带泛型信息,而在更早之前的位置(1-3行)可以看到三段注释,这就是之前所说的方法签名了

  方法签名是方法定义的一部分,它规定了方法的参数列表和返回值等信息。下面来详细解释下各个部分的概念。

第一行:

  // Method descriptor #31 (Ljava/lang/Exception;)Ljava/util/ArrayList;

  Method descriptor是标志方法签名的开始。

  #ID是该方法的id号,在同一个方法体内不会重复。

  (参数列表)表示方法有一个Exception类型的形参,类名前的L是引用类型的标记;基础数据类型的标记是对应类型的首字母大写,比如int对应I。数组的标记是在原始标记前加上符号[,比如double[]对应[D,String[]对应[Ljava/lang/String。

  最后的位置是返回值,比如Ljava/util/ArrayList;表示方法的返回值是ArrayList。

 

第二行:

  // Signature: <K:Ljava/lang/Exception;>(TK;)Ljava/util/ArrayList<TK;>;^TK;

  Signature是签名的意思,标识开始的关键字,这一行对应的就是泛型了。

  <泛型参数名:上界>这部分对应的是方法的泛型描述。

  (参数列表)和第一行的大体意思一致,但是多了泛型的定义,在字节码中,泛型会用其上界来替代(擦除),如果没有定义上界,则默认为Object,真正的泛型的定义就出现在本行的这个位置。用T前缀来表示泛型,比如泛型K就对应TK;。

  紧跟着参数列表的是返回值。该返回值描述和第一行的返回值描述一致,不过,同样多了泛型的描述,也是用T前缀来表达,比如返回值是java.util.ArrayList,这里就变为Ljava/util/ArrayList<TK;>;。

  ^泛型异常,用于描述用泛型表达的异常,如果异常不是泛型,则该部分描述不会生成。比如throws K就会被描述为^TK;。

 

第三行:

   // Stack: 1, Locals: 2

  Stack,表达的是调用栈(call stack),用于描述在调用栈上最多有多少个对象。为什么会有个这个栈呢?是因为“局部变量”这个概念对于虚拟机来说,是不存在的,所以在某个方法被调用前,需要把该方法要用到的变量都加载到一个全局调用栈内。方法被虚拟机唤起的时候,只需要按顺序传入变量类型,然后自动从调用栈里按需取得变量。

  每次操作执行完成后,栈被清空,所以,栈深等同为变量最多的操作的变量数。

  Locals,用于描述使用到的本地变量,读者可能会疑惑,该方法里明明只用到了一个形参K,为什么会有两个变量呢?这是因为java默认给方法注册了一个this,作为本地变量。

  懂得了字节码的真相,也就懂得了Java泛型的实现原理。

  Java的方法泛型没有记录在方法体内部,而是在方法签名内做了实现。同样,可以在字节码里找到类\接口签名,类字段(成员变量)签名等等。

 

  换言之,Java的泛型是由编译时擦除和签名来实现的。

  Java这样的设计,是为了兼容性的考虑,低版本的字节码和高版本基本上只有签名上的不一样,不影响功能本体,所以,可以不做任何改动就在高版本的虚拟机里运行。

 

 反射获取泛型信息

 

  上一节中提到了如下的一些泛型信息不会被擦除:

  1、泛型接口、类、方法定义上处的所有泛型

  2、成员变量声明处的泛型

  可以得出推论,这些泛型信息应当能够被反射获取。

  对这些能被反射获取的内容,按照泛型的分类来进行讨论:

  1、泛型接口和泛型类。它们对应的反射对象都是java.reflect.Class,该类提供了三个方法:

 

1
2
3
4
5
public Type getGenericSuperclass(){...}
 
public Type[] getGenericInterfaces() {...}
 
public TypeVariable<Class<T>>[] getTypeParameters() {...}

 

 

  分别对应:获取超类的完整类型,获取接口的完整类型,以及获取自身的类型变量。

  java.lang.reflect.Type是一个空接口,在使用标准JDK的情况下,一般来说,泛型的实现类是:sun.reflect.generics.reflectiveObjects.ParameterizedTypeImpl。

  它提供了获取原始类型和泛型类型的方法。

  java.lang.reflect.TypeVariable是Type的子接口,它提供的方法就比Type要详细一些,这些多出来的方法包括:

 

1
2
3
4
5
Type[] getBound(),获取上界;
 
   D getGenericDeclaration(),获取泛型定义;
 
   String getName(),获取泛型参数名,也就是<T>中的T。

 

  2、声明为泛型的字段。它对应的反射对象是java.reflect.Field,提供了一个方法:

1
public Type getGenericType() {...}

  该方法的使用方式和上文一致。

 

  3、泛型方法。对应的反射对象是java.reflect.Method,提供了三个方法:

1
2
3
4
5
public Type getGenericReturnType() {...}
 
public Type getGenericParameterTypes() {...}
 
public Type getGenericExceptionTypes() {...}

 

  分别对应返回值泛型,参数泛型和异常泛型。

  注意!虽然这里可以获取到泛型的定义,但不论是哪一种方式,其获取到的泛型,都不会是具体的某一个类。给定一个泛型的定义<T>,能获取到的只有T这个关键字。

  这是因为,Java目前的泛型实现已经在原理上(泛型擦除)堵死了“反射获取泛型的确定类型”的可能性。

 

  泛型的原理和基本概念到这里已经讲解得差不多了,后面会介绍一下Java泛型的历史,以说明为什么Java的泛型为什么有这么多的“缺陷”。


本文来源于:http://www.w2bc.com/article/169766

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

泛型二 泛型和数组 的相关文章

  • 基于数传电台的多主通讯系统的实现

  • JNI基础简介

    导读 在前面的几篇文章中 xff0c 笔者介绍了C 43 43 中的指针 引用 智能指针 多线程 类型转换 异常处理等相关知识点 xff0c 如果想要熟练掌握 xff0c 并能在实际项目中运用 xff0c 光是看肯定是毫无用处 xff0c
  • C++ class

    namespace 在变量或函数前面加上命名空间 xff0c 用来区分其它位置中的同名函数或变量 span class token macro property span class token directive keyword incl
  • realsense r200使用过程记录

    realsense r200 相机 采用的结构光 43 双目立体视觉 xff0c 使用可以使用室外场景 xff0c 但是有些注意的事项 xff0c 该款相机在sdk 方面貌似总有些bug 相比之前的测过的zed astra kinectv1
  • 从io模型到ppc,tpc,reactor,preactor

    所有的系统I O都分为两个阶段 xff1a 等待就绪和操作 读就是等待系统可读和真正的读 写就是等待系统可写和真正的写 1 网络io模型 这是我们常见的一张图 1 传统的bio 就是同步阻塞的 当调用socket read的时候 会阻塞 直
  • ip校验和 及 udp校验和 的计算方法

    一 ip校验和的计算 计算方法 1 ip包头 共20个字节 按照每16个bit作为一个值依次进行相加 2 将计算结果的进位加到低16位上 3 将结果取反 ip包头的内存内容 eg 45 00 00 20 0F B8 00 00 80 11
  • 轻量化固态激光雷达的三维定位与建图

    点云PCL免费知识星球 xff0c 点云论文速读 文章 xff1a Lightweight 3 D Localization and Mapping for Solid State LiDAR 作者 xff1a Han Wang Chen
  • 嵌入式Linux下CAN接口socket发送调试

    1 简介 最近在做嵌入式linux can通讯的调试 xff0c 需要用到扩展帧 xff0c 参照示例代码和linux库改为扩展帧格式发送 参考链接 链接 https blog csdn net toradexsh article deta
  • 矩阵转置与矩阵相乘

    1 转置矩阵 1 1转置矩阵简介 把矩阵A的行换成同序数的列得到的新矩阵 xff0c 叫做A的转置矩阵 Transpose of a Matrix xff0c 记作ATAT 例如 xff1a 因此 xff0c 转置矩阵的特点 xff1a x
  • Python+Opencv:解决打开摄像头慢的问题,现在秒开视频

    前言 打开摄像头非常慢 大概需要5 11秒才能输出视频 这个问题困扰了我很久 一直没得到解决 今天终于得到解决 实现了秒开 值得记录和庆贺一下 我的开发环境 不同的开发环境可能不会遇到我这样的问题 1 操作系统是windows10 64位
  • WAP网页游戏

    最近利用空余时间开发了一款类似3GQQ家园的网页游戏 使用apache 43 mysql 43 php 游戏地址 xff1a www cmdandxgz top bug可能很多 xff0c 正在测试 游戏页面如下
  • WPS里公式居中、编号右对齐

    WPS里 xff0c 我目前没找到公式自动编号的方式 xff0c 在此提供一种还算编辑的手动编号并右对齐的方式 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 6
  • 【计算机视觉基础】8.内部参数描述

    目录 1 Film Coords gt Pixel Coords 2 变换 2 1 平移 2 2 尺度变换 2 3 旋转 2 4 刚体运动 2 5 刚体 43 尺度变换 2 6 仿射变换 2 7 投影变换 3 2D变换总结如下图 1 Fil
  • 【计算机视觉基础】5.投影变换扩展(单应性Homograph估计)

    1 投影变换 投影变换分为平行投影 xff08 正交投影 xff09 和中心投影 xff08 透视投影 xff09 xff0c 投影变换是联系三维空间物体与二维图形的桥梁 基础的变换参考之前的博客 计算机视觉基础 3 矩阵变换图形 xff0
  • 人类3D的感觉是什么

    目录 一 人是如何 看 到3d物体的 1 xff0c 眼睛的对焦距离 2 xff0c 两只眼睛同时观看物体的差别 3 xff0c 眼睛在移动中观测物体的差别 4 xff0c 特定物体的大小 5 xff0c 物体的几何形变 6 xff0c 光
  • ubuntu命令行访问网页

    sudo apt get install w3m w3m www baidu com使用命令行访问网页 xff0c 但效果不是很好
  • Linux下使用matlab运行.m文件

    在Linux下安装完matlab后 xff0c 会在 usr local bin 下生成matlab文件 xff0c 可以使用matlab命令 Usage matlab h help n e arch v 61 variant v 61 a
  • numpy数组与list之间的转换

    a 61 3 234 34 3 777 6 33 a为python的list类型 将a转化为numpy的array np array a array 3 234 34 3 777 6 33 将a转化为python的list a tolist
  • SSD深度解析:MLC颗粒和TLC颗粒到底有多大差别?

    计算机技术发展到今天 xff0c CPU和内存性能早已不是性能瓶颈 xff0c 但是硬盘依然是电脑常见瓶颈 xff01 固态硬盘的出现极大的改善机械硬盘的存储效率 xff0c 但是因为固态硬盘还处于行业发展初期 xff0c 所以成本很高 x
  • 泰勒(Taylor)展开式(泰勒级数)

    目录 泰勒公式 余项 1 佩亚诺 Peano xff09 余项 xff1a 2 施勒米尔希 罗什 Schlomilch Roche xff09 余项 xff1a 3 拉格朗日 xff08 Lagrange xff09 余项 xff1a 4

随机推荐

  • 【计算机视觉基础】4.仿射变换

    主要看这个哦 xff1a 马同学 xff1a 如何通俗地讲解 仿射变换 这个概念 xff1f 知乎 简单来说 xff0c 仿射变换 就是 xff1a 线性变换 43 平移 目录 1 线性变换 1 1 旋转 1 2 推移 xff08 图像学中
  • Selenium+Python自动化脚本环境搭建

    本文仅介绍环境的搭建 xff0c 不包含任何脚本编写教程 先整体说一下需要用到工具 1 Python环境 xff08 包括pip xff09 2 谷歌浏览器 xff08 包括对应的WebDriver xff09 详细步骤 xff1a 一 P
  • CUDA之nvidia-smi命令详解

    nvidia smi是用来查看GPU使用情况的 我常用这个命令判断哪几块GPU空闲 xff0c 但是最近的GPU使用状态让我很困惑 xff0c 于是把nvidia smi命令显示的GPU使用表中各个内容的具体含义解释一下 这是服务器上特斯拉
  • CMakeLists之引入头文件(五)

    1 新建项目 新建项目t4 目录结构如下 xff1a 该程序引入了自建的hello h程序库包含了函数func main c的内容如下所示 xff1a main c include lt hello h gt int main func r
  • 用HttpPost登陆验证时,用户名和密码放在请求头部header中的处理方法,形式为Authorization: username password。

    xfeff xfeff post setHeader 34 Authorization 34 34 your token 34 这里主要是要搞清楚your token是什么 xff0c 把认证信息传递正确 xff0c 这个认证信息是通过用户
  • vs code 运行C语言并调试

    vs code 运行C语言 2022 03 19 mingw64下载地址更新 xff08 window xff09 task json文件修改launch json文件修改 更新版 xff08 window xff09 1 下载MinGW编
  • 【Http认证方式】——Basic认证

    今天在访问请求 xff1a http 192 168 2 113 8080 geoserver rest workspaces时 xff0c 浏览器弹出窗口需要输入用户名和密码 xff0c 并且 xff0c 如果不输入或者输入错误 xff0
  • 大小端介绍与分析

    1 字节序 字节序即字节的存储顺序 xff0c 如果数据都是单字节的 xff0c 那怎么存储无所谓了 xff0c 但是对于多字节数据 xff0c 比如int xff0c double等 xff0c 就要考虑存储的顺序了 字节序是硬件层面的东
  • Emgu-WPF 激光雷达研究-定位实现

    特定位置或障碍物位置定位实现 读取激光雷达数据并存储于本地作为测试数据 每一帧数据对同一障碍物的定位信息均存在偏差 所以先对需要定位的点进行数据取样 取样过程中 xff0c 遇到数据丢失 xff0c 或检测到多个障碍物 不满足障碍物生存指数
  • Jetson NX性能介绍

    NX的各个工作模式及功耗 xff1a 与其他jetson系列板卡的对比
  • 移远EC200UCN_LA 4G通信模块 OpenCPU二次开发过程中遇到的各种坑

    这里主要记录一下我在使用移远开发板进行 EC200UCN LA 4G通信模块开发中遇到的各种坑 注 xff1a Q为遇到的问题 A为问题的解决办法 T为注意事项 Q 串口demo无法正常接收和发送消息 A demo里用的UART2 xff0
  • GPS数据格式解析

    GPS数据格式解析 简介 GPS发送数据以行为单位 xff0c 数据格式如下 xff1a 信息类型 xff0c x xff0c x xff0c x xff0c x xff0c x xff0c x xff0c x xff0c x xff0c
  • 线程的sleep()方法的简单使用

    线程的sleep方法签名位 xff1a public static void sleep long millis throws InterruptException 是静态方法 xff0c 使目前正在执行的线程休眠millis毫秒 pack
  • 栈和堆的生长方向

    C 43 43 作为一款C语言的升级版本 xff0c 具有非常强大的功能 它不但能够支持各种程序设计风格 xff0c 而且还具有C语言的所有功能 我们在这里为大家介绍的是其中一个比较重要的内容 xff0c C 43 43 内存区域的基本介绍
  • mysql关于bit类型用法

    本文来源于 xff1a http www server110 com mysql 201403 7117 html Mysql关于bit类型的用法 xff1a 官方的资料如下 xff1a 9 1 5 位字段值 可以使用b 39 value
  • Ajax 简单购物车工程

    工程结构图 xff1a index jsp lt 64 page language 61 34 java 34 contentType 61 34 text html charset 61 utf 8 34 pageEncoding 61
  • Oracle scott账户被锁定,scott默认密码,sys,system默认密码

    oracle帐号scott被锁定如何解锁 具体操作步骤如下 xff1a C gt sqlplus 请输入用户名 xff1a sys 输入口令 xff1a sys as sysdba 注意 xff1a 在口令这里输入 的密码后面必须要跟上 a
  • Linux将输出放到文件中

    一 xff0c 如何把命令运行的结果保存到文件当中 这个问题太简单了 xff0c 大家都知道 xff0c 用 gt 把输出转向就可以了 例子 lhd 64 hongdi ls gt ls txt lhd 64 hongdi cat ls t
  • 理解interrupt()方法

    java interrupt 方法只是设置线程的中断标记 xff0c 当对处于阻塞状态的线程调用interrupt方法时 xff08 处于阻塞状态的线程是调用sleep wait join 的线程 xff0c 会抛出InterruptExc
  • 泛型二 泛型和数组

    数组和泛型容器有什么区别 要区分数组和泛型容器的功能 xff0c 这里先要理解三个概念 xff1a 协变性 xff08 covariance xff09 逆变性 xff08 contravariance xff09 和无关性 xff08 i