一文精通常量池

2023-11-18

大家好!今天来和大家一起探索下Java的常量池!在阅读本篇之前,我为大家准备了一个测试,共15道判断题,每题1分,满分15分。大约花费1~2分钟时间。 如果你全部答对了,那么恭喜你大神,本篇可能已经满足不了你了。如果结果不理想也不要气馁。读完本篇后再来一次,相信会收获一个满意的成绩。

答题链接和二维码:https://ks.wjx.top/vj/rlYibac.aspx

视频分享:

【深入理解Java常量池-合集】 https://www.bilibili.com/video/BV1DM4y1Q7GK/?share_source=copy_web&vd_source=536bcea8ab177f9af7fe25ff07c3b483

引子

小试身手

首先我们来看一道题

 Integer i1 = 127;  
 Integer i2 = 127;
 System.out.println(i1 == i2); 
 //这种调用底层实际是执行的Integer.valueOf(127),里面用到了IntegerCache对象池

//值大于127时,不会从对象池中取对象  
Integer i3 = 128;
Integer i4 = 128;
System.out.println(i3 == i4);

这道题是笔试题中常见的一道题。答案相信大部分人都知道,第3行输出true,第9行输出false。

本着知其然,知其所以然的精神我们进一步探究得知:第1,2,7,8行实际执行的是Integer.valueOf()。这个方法出于减少对象创建次数和节省内存的考虑,会对数值为-128~127之间的Integer对象进行缓存,如果valueOf()方法传入的参数在这个范围之内,就直接返回缓存中的对象。

乘胜追击

上面的理论大家可能都知道,但是这个理论是不是和“鬼”一样,大家只听过,没见过呢?下面我来和大家一起,揭开它的神秘面纱。

1. 首先可能大家会问,第1,2,7,8行实际执行的是Integer.valueOf(),这个你是怎么知道的呢?是不是也是从书上看来的。能不能证明给我们看看?

javap -v 命令

当然可以,我们都知道java文件在运行的时候会被编译为字节码文件,要想解答上面疑惑我们只需要查看字节码就可以了。找到class文件,一个简单的 javap -v 命令就可以搞定。

为了降低理解难度我将代码进行了简化,来看下图,是不是瞬间清晰了。

jclasslib bytecode viewer

当然对于字节码的阅读是有一定技术门槛的,这里给大家安利一个神器。

安装好了以后在查看代码时,点击“view - Show Bytecode With Jclasslib”就可以查看字节码了。并且右侧的字节码指令可以直接点击查看指令的详细解释。再也不用担心记不住字节码指令的意思了。

同样的我们可以看到Integer i1 = 127编译成自节码后的样子。

2.字节码我们看过了,但是还是没有看到缓存。下一步我们在来看下源码。

上面这段代码就不用多解释了,在来看下以下片段。这个一个static方法,在项目启动的时候就从low到high依次加入到Integer数组中也就是所谓的缓存中。

经过上面的事例,大家对常量池有了基本的认识。下面我们进入主题。

基本类型的包装类的常量池(对象池)

Java中有6种基本类型的包装类型实现了常量池技术,分别是:Byte,Short,Integer,Long,Character,Boolean,其中Byte,Short,Integer,Long,Character这5种整型的包装类只是在对应值小于等于127时才可使用对象池。 另外两种浮点数类型的包装类型没有实现。之所以这样设计是基于使用频率的考虑。

Byte a1 = 1;
Byte a2 = 1;
System.out.println(a1 == a2);

Short b1 = 2;
Short b2 = 2;
System.out.println(b1 == b2);

 Character c1 = 'a';
Character c2 = 'a';
System.out.println(c1 == c2);

Long d1 = 11L;
Long d2 = 11L;
System.out.println(d1 == d2);

Boolean e1 = false;
Boolean e2 = false;
System.out.println(e1 == e2);

Float f1 = 1.0f;
Float f2 = 1.0f;
System.out.println(f1 == f2);//false

Double g1 = 1.0;
Double g2 = 1.0;
System.out.println(g1 == g2);//false

上面这段代码,除了最后两个为false,其余均为true。需要注意使用new关键词生成的对象不会使用常量池。这里就不需要做过多解释了。下面进入今天的重点内容。

example-3:

Integer i1 = 40;
Integer i2 = 40;
Integer i3 = 0;
Integer i4 = new Integer(40);
Integer i5 = new Integer(40);
Integer i6 = new Integer(0);

System.out.println(i1 == i2);    //true
System.out.println(i1 == i4);   //false
System.out.println(i4 == i5);   //false
//自动拆箱:
// 在进行“+”运算时,Integer类型自动拆箱为int,
// “==”运算时Integer无法与int,所以也拆箱为int。
//所以最终变成了int 与int 比较
System.out.println(i1 == i2 + i3);  //true
System.out.println(i4 == i5 + i6);  //true
System.out.println(40 == i5 + i6);  //true

分析:自动拆箱在进行“+”运算时,Integer类型自动拆箱为int, “==”运算时Integer无法与int,所以也拆箱为int。所以最终变成了int 与int 比较。在字节码中我们可以看到Integer.intValue。

常量池

常量池的概念

很多同学都知道常亮池的概念,但是你是否对class文件常量池,运行时常量池,字符串常量池傻傻分不清楚呢?我们通过下面这张图来直观感受一下。

Class文件常量池

首先我们来看下class文件常量池。Class文件中除了有类的版本、 字段、 方法、 接口等描述信息外, 还有一项信息是常量池表(Constant Pool Table) , 用于存放编译期生成的各种字面量符号引用, 这部分内容将在类加载后存放到方法区的运行时常量池中。

这里的常量池表就是Class文件常量池。

常量池表(Constant Pool Table)

1.我们使用javap命令查看Test1的class文件。

Classfile /D:/PPT/constant-pool/target/classes/com/pool/Test1.class
  Last modified 2021-12-26; size 384 bytes
  MD5 checksum 5a9a4b4f205a38c85fa7634109358b46
  Compiled from "Test1.java"
public class com.pool.Test1
  minor version: 0
  major version: 52
  flags: ACC_PUBLIC, ACC_SUPER
Constant pool:
   #1 = Methodref          #5.#17         // java/lang/Object."<init>":()V
   #2 = Methodref          #18.#19        // java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
   #3 = Fieldref           #4.#20         // com/pool/Test1.i1:Ljava/lang/Integer;
   #4 = Class              #21            // com/pool/Test1
   #5 = Class              #22            // java/lang/Object
   #6 = Utf8               i1
   #7 = Utf8               Ljava/lang/Integer;
   #8 = Utf8               <init>
   #9 = Utf8               ()V
  #10 = Utf8               Code
  #11 = Utf8               LineNumberTable
  #12 = Utf8               LocalVariableTable
  #13 = Utf8               this
  #14 = Utf8               Lcom/pool/Test1;
  #15 = Utf8               SourceFile
  #16 = Utf8               Test1.java
  #17 = NameAndType        #8:#9          // "<init>":()V
  #18 = Class              #23            // java/lang/Integer
  #19 = NameAndType        #24:#25        // valueOf:(I)Ljava/lang/Integer;
  #20 = NameAndType        #6:#7          // i1:Ljava/lang/Integer;
  #21 = Utf8               com/pool/Test1
  #22 = Utf8               java/lang/Object
  #23 = Utf8               java/lang/Integer
  #24 = Utf8               valueOf
  #25 = Utf8               (I)Ljava/lang/Integer;
{
  java.lang.Integer i1;
    descriptor: Ljava/lang/Integer;
    flags:

  public com.pool.Test1();
    descriptor: ()V
    flags: ACC_PUBLIC
    Code:
      stack=2, locals=1, args_size=1
         0: aload_0
         1: invokespecial #1                  // Method java/lang/Object."<init>":()V
         4: aload_0
         5: bipush        127
         7: invokestatic  #2                  // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
        10: putfield      #3                  // Field i1:Ljava/lang/Integer;
        13: return
      LineNumberTable:
        line 11: 0
        line 12: 4
      LocalVariableTable:
        Start  Length  Slot  Name   Signature
            0      14     0  this   Lcom/pool/Test1;
}

我们再来理解下这句话:Class文件中除了有类的版本、 字段、 方法、 接口等描述信息外, 还有一项信息是常量池表(Constant Pool Table)。

字节码中第6,7行即为类的版本。 第35至58行为字段、方法、接口等描述。第9行Constant pool至34行,即为常量池表。

2.我们也可以换一种"非人类视角"来查看class文件。使用文本编辑器打开class文件,调整为16进制查看。如果文本编辑器默认不支持,需要自己安装一下插件。(此部分仅作了解,可以跳过)

第一眼看上去是一堆乱码,但是如果你知道了规律就会发现有章可循。通过对照下图我们就可以阅读class文件了。

  • 魔数:cafe babe。每个Class文件的头4个字节被称为魔数(Magic Number) , 它的唯一作用是确定这个文件是否为一个能被虚拟机接受的Class文件。

  • 次版本号(MinorVersion):0 。 第5和第6个字节是次版本号(MinorVersion)。

  • 主版本号(Major Version):0034 转为10进制为52,即为JDK8 。 第7和第8个字节是主版本号(Major Version)

  • 常量池容量计数值(constant_pool_count)

  • 常量池(constant_pool)

要想阅读常量池的内容,就需要使用常量池项目类型表,感兴趣的同学推荐阅读下《深入理解Java虚拟机》“6.3 Class类文件的结构”,这里就不在深入解析了。

通过上面的常量池项目类型我们可以知道,class文件常量池中主要存放两大类常量: 字面量(Literal) 和符号引用(Symbolic References) 。

字面量(Literal)

字面量比较接近于Java语言层面的常量概念, 如文本字符串、 被声明为final的常量值等。

字面量只可以右值出现,所谓右值是指等号右边的值,如:int a=1 这里的a为左值,1为右值。在这个例子中1就是字面量。

符号引用(Symbolic References)

符号引用则属于编译原理方面的概念, 主要包括下面几类常量:

  • 被模块导出或者开放的包(Package)·

  • 类和接口的全限定名(Fully Qualified Name)·

  • 字段的名称和描述符(Descriptor)·

  • 方法的名称和描述符·

  • 方法句柄和方法类型(Method Handle、 Method Type、 Invoke Dynamic)·

  • 动态调用点和动态常量(Dynamically-Computed Call Site、 Dynamically-Computed Constant)

下面我们通过一个实例来帮助大家理解字面量和符号引用。

package com.pool;
public class Test2 {
    public static void main(String[] args) {
        Integer i1 = 127;
        Integer i2 = 127;
        System.out.println(i1 == i2);//输出true
        //这种调用底层实际是执行的Integer.valueOf(127),里面用到了IntegerCache对象池

        //值大于127时,不会从对象池中aaa取对象
        Integer i3 = 128;
        Integer i4 = 128;
        System.out.println(i3 == i4);//输出false

    }
}

字面量: 等号右边的 127,128即为字面量。

符号引用:

  • 类的全限定名 com.pool.Test2

  • 字段的名称 i1,i2,i3,i4

  • 方法的名称 main()

运行时常量池(Runtime Constant Pool)

运行时常量池(Runtime Constant Pool) 是方法区的一部分。 Class文件常量池里的内容将在类加载后存放到方法区的运行时常量池中(实际是字符串常量池?),并将符号引用解析为直接引用。

我们看到类文件的信息存储在class静态文件中,在程序运行时会由类加载器加载到运行时常量池中,并在解析阶段,将符号引用转换为直接引用,指向真正的内存地址。

这里可以理解为 class文件信息为一份超市的购物清单,上面写着苹果,橘子等。 等你到了超市,超市的导购在你的购物清单上加上了货物的地址信息。 苹果 -> A货架5排3列,橘子->B货架3排5列。

字符串常量池(String Table)

字符串常量池里的内容是在类加载、验证、准备阶段之后在堆中生成字符串对象实例,然后将该字符串对象实例的引用值存到string pool中。 在HotSpot VM里实现的string pool功能的是一个StringTable类,它是一个哈希表。这个StringTable在每个HotSpot VM的实例只有一份,被所有的类共享。

字符串常量池

字符串常量池的设计思想

字符串常量池的设计思想和基本类型的包装类型常量池设计思想是一样的。

1.在内存中为字符串开辟一块空间,作为字符串常量池,类似于缓存。

2.创建字符串时,首先查询字符串常量池是否存在该字符串。

3.如果存在返回引用实例,不存在则实例化该字符串并放入常量池中。

字符串常量池位置

JDK1.7及以后

JDK1.6及以前

在JDK 6或更早之前的HotSpot虚拟机中, 常量池都是分配在永久代中, 我们可以通过-XX: PermSize和-XX: MaxPermSize限制永久代的大小, 即可间接限制其中常量池的容量。

/**
 * VM Args: -XX:PermSize=6M -XX:MaxPermSize=6M
 * @author zzm
 */
public class RuntimeConstantPoolOOM {
    public static void main(String[] args) {
// 使用Set保持着常量池引用, 避免Full GC回收常量池行为
        Set<String> set = new HashSet<String>();
// 在short范围内足以让6MB的PermSize产生OOM了
        short i = 0;
        while (true) {
            set.add(String.valueOf(i++).intern());
        }
    }
}

运行结果:

Exception in thread "main" java.lang.OutOfMemoryError: PermGen space

自JDK 7起,原本存放在永久代的字符串常量池被移至Java堆之中。使用-Xmx参数限制最大堆到6MB就能够看到以下异常:

Exception in thread "main" java.lang.OutOfMemoryError: Java heap space
当年使用永久代来实现方法区的决定并不是一个好主意,这种设计导致了Java应用更容易遇到内存溢出的问题(永久代有-XX:MaxPermSize的上限,即使不设置也有默认大小,而J9和JRockit只要没有触碰到进程可用内存的上限,例如32位系统中的4GB限制,就不会出问题),而且有极少数方法(例如String::intern())会因永久代的原因而导致不同虚拟机下有不同的表现。当Oracle收购BEA获得了JRockit的所有权后,准备把JRockit中的优秀功能,譬如Java Mission Control管理工具,移植到HotSpot虚拟机时,但因为两者对方法区实现的差异而面临诸多困难。考虑到HotSpot未来的发展,在JDK 6的时候HotSpot开发团队就有放弃永久代,逐步改为采用本地内存(Native Memory)来实现方法区的计划了[1],到了JDK 7的HotSpot,已经把原本放在永久代的字符串常量池、静态变量等移出,而到了JDK 8,终于完全废弃了永久代的概念,改用与JRockit、J9一样在本地内存中实现的元空间(Metaspace)来代替,把JDK 7中永久代还剩余的内容(主要是类型信息)全部移到元空间中。 --《深入理解Java虚拟机》

后续内容如何没有特别强调都是jdk1.8版本。

字符串常量池的创建

字符串的创建有3种方式:

使用字面量直接赋值

String s="hello";

使用字面量赋值,只会直接分配到字符串常量池中如果字符串常量池中存在则直接返回,如果不存在则先创建,然后返回。

这里需要注意字符串常量池中存储的是引用值而不是实例对象,具体的实例对象存储在堆中。

example-1:

String s0="hello";
String s1="hello";
System.out.println( s0==s1 ); //true

example-2:

String s1="hello";
String s2="he" + "llo";
System.out.println( s1==s2 ); //true

分析:s2=字符串常量(字面量)+字符串常量(字面量),所以s2一定也是字面量。

编译期优化:如果在编译期就能确定为字面量,则编译器在编译时会进行优化。

如下代码编译成字节码是一样的

example-3:

String a = "a1";
String b = "a" + 1;
System.out.println(a == b); // true 

String c = "atrue";
String d = "a" + "true";
System.out.println(a == b); // true 

String e = "a3.4";
String f = "a" + 3.4;
System.out.println(a == b); // true

字节码如下:

example-4:

String a = "hello";
final String bb = "llo";
String b = "he" + bb;
System.out.println(a == b); // true

分析:被声明为final的常量值为字面量。所以可以在编译期优化。

example-5:

public static final String A; // 常量A
public static final String B;    // 常量B

static {
    A = "he";
    B = "llo";
}

private static void example11() {
    String s1 = A + B;
    String s2 = "hello";
    System.out.println(s1 == s2); //false
}

分析:先来先看下字面量的定义,并对比example-4。这里明明也是声明为final的常量为什么结果不一样。原因很简单,因为A,B没有在编译期赋值,只要到了运行时才会正在被创建。编译期无法进行优化

使用new String()创建

String s1 = new String("hello");

这种方式创建字符串可以理解成两步:

1."hello"为字面量,所以首先按照字面量的方式在常量池中创建"hello"。

2.使用new指令,会在堆中开辟一块空间,然后再将堆的地址返回到栈上保存。

example-6:

String s0="hello";
String s1=new String("hello");
String s2="he" + new String("llo");
System.out.println( s0==s1 );  // false
System.out.println( s0==s2 );  // false
System.out.println( s1==s2 );  // false

分析:编译期无法优化:用new String() 创建的字符串不是常量,不能在编译期就确定,不会放入常量池中,会在堆上分配空间。

example-7:

String a = "ab";
final String bb = getBB();
String b = "a" + bb;
System.out.println(a == b); // false

private static String getBB() 
{  
    return "b";  
 }

分析:编译期无法优化

example-8:

String s = "he" + "llo";  //编译时优化为: "hello";
String a = "he";
String b = "llo";
String s1 = a + b;
System.out.println(s == s1);//false

分析:注意这里 s1 = a+b ,a和b都不是字面量,而是符号引用,在编译期无法优化。

对于上面三个例子,我们来观察下字节码

可以看出来JVM指令码中实际是通过StringBuilder.append来实现的“+”操作,然后调用toString()。再来看下StringBuilder类的toString源码,底层还是一个new String操作。

所以对于String s1 = a + b;可以理解为如下代码,等同于new String()的效果。

StringBuilder temp = new StringBuilder();
temp.append(a).append(b);
String s1 = temp.toString();

使用intern方法创建

String::intern()是一个本地方法,它的作用是如果字符串常量池中已经包含一个等于此String对象的字符串,则返回代表池中这个字符串的String对象的引用;否则,会将此String对象包含的字符串添加到常量池中,并且返回此String对象的引用。(jdk1.6版本需要将 s1 复制到字符串常量池里)

1.字符串常量池中已经包含一个等于此String对象的字符串

example-9:

//s0指向常量池
String s0 = "hello";
//s1指向堆中
String s1 = new String("hello");
//s2指向常量池
String s2 = s1.intern();

System.out.println(s0 == s2);   //ture
System.out.println(s1 == s2);  //false

2.字符串常量池中没有包含一个等于此String对象的字符串

example-10:

String s1 = new String("he") + new String("llo");
String s2 = s1.intern();
System.out.println(s1 == s2);

请问上面这段代码的结果是什么,并且创建了多少个String对象? 不管你的答案是什么,我都要很遗憾的告诉你答错了!为什么? 因为题目有问题,没有指出JDK的版本。

1.JDK1.6中,调用 intern() 方法,当字符串常量池中不存在时,会在永久代上创建一个实例,并存入常量池中。所以在JDK1.6中答案为false,创建了6个对象

2.从JDK7开始常量池移入了堆中,因此JDK 7(以及部分其他虚拟机,例如JRockit)的intern()方法实现就不需要再拷贝字符串的实例到永久代了,既然字符串常量池已经移到Java堆中,那只需要在常量池里记录一下首次出现的实例引用即可。

example-11:

String s1 = new String("he") + new String("llo");
String s2 = "hello";
System.out.println(s1 == s2); //false

example-12:

String s1 = new String("he") + new String("llo");
s1.intern();
String s2 = "hello";
System.out.println(s1 == s2);//true

分析:因为常量池中没有“hello”,S1.intern会将堆中的对象放入到常量池

我们在第2行加一句String s3 = new String("hello");

example-13:

String s1 = new String("he") + new String("llo");
String s3 = new String("hello");
s1.intern();
String s2 = "hello";
System.out.println(s1 == s2); //false
System.out.println(s1 == s3); //false
System.out.println(s2 == s3); //false

分析:因为第2行 new String()的原因,所以在常量池中创建了对象。 s1.intern检查到常量池中已有“hello”不再创建,相当于s1.intern()没有任何影响。而s2拿到的是常量池中的对象。所以都不相等。

把上面的第2行,第3行交换下位置,再看看

example-14:

String s1 = new String("he") + new String("llo");
s1.intern();
String s3 = new String("hello");
String s2 = "hello";
System.out.println(s1 == s2);//true
System.out.println(s1 == s3);//false
System.out.println(s2 == s3);//false

为什么?这里就留给大家思考了,自己画下图,有助于理解!

特例:

example-15:

String str1 = new StringBuilder("he").append("llo").toString();
System.out.println(str1 == str1.intern());  //true

String str2 = new StringBuilder("ja").append("va").toString();
System.out.println(str2 == str2.intern());  //false

String str3 = new StringBuilder("in").append("t").toString();
System.out.println(str3 == str3.intern());  //false

String str4 = new StringBuilder("dou").append("ble").toString();
System.out.println(str4 == str4.intern());  //false

分析:发现规律了吗? 部分java关键字在JVM初始化的时候已经放入了常量池。

总结

  1. 基本类型的包装类的常量池:

a.Java中有6种基本类型的包装类型实现了常量池技术,分别是: Byte,Short,Integer,Long,Character,Boolean,其中Byte,Short,Integer,Long,Character这5种整型的包装类只是在对应值小于等于127时才可使用对象池。 另外两种浮点数类型的包装类型没有实现。

b.包装类型在进行运算时可能会自动拆箱

2.三种常量池:

  • Class文件常量池(字面量,符号引用),其中字面量的概念需要重点掌握。

  • 运行时常量池

  • 字符串常量池

3.字符串常量池

字符串常量池位置,jdk不同版本中的变化。

字符串常量池的创建

  • 使用字面量直接赋值

  • 使用new String()创建

  • 使用intern方法创建

感谢各位能够耐心读完,我在附件的ppt中做了动画效果,以方便大家理解对象创建的过程。如果有不清楚的地方欢迎联系我交流探讨,同时本文中的内容也可能存在错误,请各位大牛不吝赐教。谢谢大家!

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

一文精通常量池 的相关文章

  • Java 中等效的并行扩展

    我在 Net 开发中使用并行扩展有一些经验 但我正在考虑在 Java 中做一些工作 这些工作将受益于易于使用的并行库 JVM 是否提供任何与并行扩展类似的工具 您应该熟悉java util concurrent http java sun
  • 如何为最终用户方便地启动Java GUI程序

    用户想要从以下位置启动 Java GUI 应用程序Windows 以及一些额外的 JVM 参数 例如 javaw Djava util logging config file logging properties jar MyGUI jar
  • Java new Date() 打印

    刚刚学习 Java 我知道这可能听起来很愚蠢 但我不得不问 System out print new Date 我知道参数中的任何内容都会转换为字符串 最终值是 new Date 返回对 Date 对象的引用 那么它是如何打印这个的呢 Mo
  • Java - 将节点添加到列表的末尾?

    这是我所拥有的 public class Node Object data Node next Node Object data Node next this data data this next next public Object g
  • 如何找到给定字符串的最长重复子串

    我是java新手 我被分配寻找字符串的最长子字符串 我在网上研究 似乎解决这个问题的好方法是实现后缀树 请告诉我如何做到这一点或者您是否有任何其他解决方案 请记住 这应该是在 Java 知识水平较低的情况下完成的 提前致谢 附 测试仪字符串
  • Android:捕获的图像未显示在图库中(媒体扫描仪意图不起作用)

    我遇到以下问题 我正在开发一个应用程序 用户可以在其中拍照 附加到帖子中 并将图片保存到外部存储中 我希望这张照片也显示在图片库中 并且我正在使用媒体扫描仪意图 但它似乎不起作用 我在编写代码时遵循官方的Android开发人员指南 所以我不
  • 无法展开 RemoteViews - 错误通知

    最近 我收到越来越多的用户收到 RemoteServiceException 错误的报告 我每次给出的堆栈跟踪如下 android app RemoteServiceException Bad notification posted fro
  • Android MediaExtractor seek() 对 MP3 音频文件的准确性

    我在使用 Android 时无法在eek 上获得合理的准确度MediaExtractor 对于某些文件 例如this one http www archive org download emma solo librivox emma 01
  • Mockito when().thenReturn 不必要地调用该方法

    我正在研究继承的代码 我编写了一个应该捕获 NullPointerException 的测试 因为它试图从 null 对象调用方法 Test expected NullPointerException class public void c
  • Java TestNG 与跨多个测试的数据驱动测试

    我正在电子商务平台中测试一系列商店 每个商店都有一系列属性 我正在考虑对其进行自动化测试 是否有可能有一个数据提供者在整个测试套件中提供数据 而不仅仅是 TestNG 中的测试 我尝试不使用 testNG xml 文件作为机制 因为这些属性
  • 在两个活动之间传输数据[重复]

    这个问题在这里已经有答案了 我正在尝试在两个不同的活动之间发送和接收数据 我在这个网站上看到了一些其他问题 但没有任何问题涉及保留头等舱的状态 例如 如果我想从 A 类发送一个整数 X 到 B 类 然后对整数 X 进行一些操作 然后将其发送
  • JRE 系统库 [WebSphere v6.1 JRE](未绑定)

    将项目导入 Eclipse 后 我的构建路径中出现以下错误 JRE System Library WebSphere v6 1 JRE unbound 谁知道怎么修它 右键单击项目 特性 gt Java 构建路径 gt 图书馆 gt JRE
  • 声明的包“”与预期的包不匹配

    我可以编译并运行我的代码 但 VSCode 中始终显示错误 早些时候有一个弹出窗口 我不记得是什么了 我点击了 全局应用 从那以后一直是这样 Output is there but so is the error The declared
  • 静态变量的线程安全

    class ABC implements Runnable private static int a private static int b public void run 我有一个如上所述的 Java 类 我有这个类的多个线程 在里面r
  • 编译器抱怨“缺少返回语句”,即使不可能达到缺少返回语句的条件

    在下面的方法中 编译器抱怨缺少退货声明即使该方法只有一条路径 并且它包含一个return陈述 抑制错误需要另一个return陈述 public int foo if true return 5 鉴于Java编译器可以识别无限循环 https
  • JGit 检查分支是否已签出

    我正在使用 JGit 开发一个项目 我设法删除了一个分支 但我还想检查该分支是否已签出 我发现了一个变量CheckoutCommand但它是私有的 private boolean isCheckoutIndex return startCo
  • java.lang.IllegalStateException:驱动程序可执行文件的路径必须由 webdriver.chrome.driver 系统属性设置 - Similiar 不回答

    尝试学习 Selenium 我打开了类似的问题 但似乎没有任何帮助 我的代码 package seleniumPractice import org openqa selenium WebDriver import org openqa s
  • 如何实现仅当可用内存较低时才将数据交换到磁盘的写缓存

    我想将应用程序生成的数据缓存在内存中 但如果内存变得稀缺 我想将数据交换到磁盘 理想情况下 我希望虚拟机通知它需要内存并将我的数据写入磁盘并以这种方式释放一些内存 但我没有看到任何方法以通知我的方式将自己挂接到虚拟机中before an O
  • 节拍匹配算法

    我最近开始尝试创建一个移动应用程序 iOS Android 它将自动击败比赛 http en wikipedia org wiki Beatmatching http en wikipedia org wiki Beatmatching 两
  • Spring Boot @ConfigurationProperties 不从环境中检索属性

    我正在使用 Spring Boot 1 2 1 并尝试创建一个 ConfigurationProperties带有验证的bean 如下所示 package com sampleapp import java net URL import j

随机推荐

  • OpenCV——多分辨率LBP的计算方法

    目录 一 算法原理 1 原理概述 2 参考文献 二 代码实现 三 结果展示 一 算法原理 1 原理概述 基本LBP算子虽然在早期的实验中取得了一系列成果 但是应用于不同领域的具体问题时 该算子的处理结果并不能达到预期的效果 因此 很多学者对
  • 不同网段共享文件服务器,不同网段ip 如何设置局域网共享?

    具体操作如下 执行 开始 I 控制面板 命令 在打开的窗口中双击 网络和丨nternet连接 选项 打开 网络连接 窗口 在窗口左边的 网络任务 栏中选择 更改此连接设置 选项 弹出 本地连接属性 对话框 单击 安装 按钮 在win7弹出的
  • .NET 6 ‘Unable to configure HTTPS endpoint...

    Mac M1 NET 6 Exception has occurred CLR System InvalidOperationException System InvalidOperationException 类型的未经处理的异常在 Sy
  • 蓝桥杯 c/c++ 算法提高 最长滑雪道

    算法提高 最长滑雪道 资源限制 时间限制 1 0s 内存限制 256 0MB 问题描述 小袁非常喜欢滑雪 因为滑雪很刺激 为了获得速度 滑的区域必须向下倾斜 而且当你滑到坡底 你不得不再次走上坡或者等待升降机来载你 小袁想知道在某个区域中最
  • CSS(非)实用技巧——背景与边框

    参考 CSS揭秘 CSS Secrets 背景 CSS3 尽管 CSS3 这个名词非常流行 但它严格意义上并不是一个规范 因为在CSS2之后 CSS这门语言已经庞大到无法放进单个规范中了 CSS工作组将其分成不同的模块 其中在CSS2 1已
  • 图书馆数据库服务器设备性能分析,高校图书馆数据库利用率统计与绩效的浅析.doc...

    PAGE PAGE 1 高校图书馆数据库利用率统计与绩效的浅析 摘要 现代的社会是一个信息社会 社会经济发展步伐和高科技信息技术的发展已经超过了我们想象的能力范围 随着越来越多的高校图书馆的建立 为了更好的服务学生和学校教师的教学 科研工作
  • 线程的优先级

    package com kuang Demo05 测试线程的优先级 public class TestPriority public static void main String args System out println Threa
  • Eclipse 从Debug模式中退出

    如果您尚未处于Java透视图中 请在主菜单中选择Window gt Open Perspective gt Java或单击下面的 Click to Perform 链接 Eclipse的右侧有新手教学 简单来说就是菜单栏里按顺序点击 就能切
  • tensorflow-gpu版本详细安装教程(Win10,Python3.7.9,cuda11.2,cudnn8.1.0)

    目录 cuda安装 cudnn安装 python安装 tensorflow安装 cuda安装下载 首先要注意自己的显卡支持cuda的版本 可以这样自查 可以看到适合自己的cuda版本 这里我选择了cuda11 2版本 cuda安装包下载链接
  • 虚拟机与物理机的三种连接方式

    引言 vmware为我们提供了三种网络工作模式 它们分别是 Bridged 桥接模式 NAT 网络地址转换模式 Host Only 仅主机模式 我们在刚刚接触它们的时候 常常被搞的晕头转向 今天我就为大家介绍一下这三种连接方式 桥接模式 桥
  • web前台传递时间日期格式转换为java.util.date,initBinder或者@DateTimeFormat方式

    方法1 根据前台传递的日期格式 在后台创建一个参数绑定的方法 将对应的日期字符串 转换为 java util date 从界面传递参数到spring后台controller类中 日期格式默认只能传long类型的时间戳 如果想要传递格式化的日
  • 阿里云ECS部署Nginx配置域名访问

    目录 前言 环境 具体步骤 服务器 域名 SSL证书 Nginx配置 前言 记录下阿里云服务器建站的过程 回回建 回回忘 尴尬 环境 ECS Centos7 6 Nginx 具体步骤 服务器 首先 需要购买一台服务器 域名 需要购买一个域名
  • Python unicode equal comparison failed

    用python进行判断的时候 如果包含中文会报错 name 这里是中文 if i name print right 修改成 name 这里是中文 decode utf 8
  • 聊聊undefined 和 undeclared

    一 undefined 在Js中 有两个表示 空 的值undefined和null 其中比较有用的是 undefined undefined 是一个值为 undefined 的类型 JavaScript语言也定义了一个全局变量 它的值是 u
  • oracle存储过程----异常的写法介绍

    上一篇 oracle存储过程 case条件控制语句的用法 oracle存储过程 异常介绍 参考PL SQL 存储过程中的异常来自于程序本身 也有的来自开发人员自定义的数据 而所有的这些错误我们称之为异常 编译时的错误不能称为异常 esmp
  • kubeadm配置虚拟机k8s集群

    环境 centos7 vm pro windows terminal termius 虚拟机 硬件配置 2核2G 实验用 具体可根据电脑调整 配置3台 master01 node01 node02 通过克隆虚拟机直接复制 配置通一项以后建议
  • spark-submit 报错 Initial job has not accepted any resources

    spark submit 报这样的错误 WARN scheduler TaskSchedulerImpl Initial job has not accepted any resources check your cluster UI to
  • [pytest源码4]-pluggy之Plugin注册逻辑分析

    前言 本篇将详细对plugin的注册逻辑进行分析 个人拙见 有错请各位指出 如果的我的文章对您有帮助 不符动动您的金手指给个Star 予人玫瑰 手有余香 不胜感激 GitHub pluggy注册逻辑分析性 我们来详细分析一下plugin的注
  • 有道无术,术尚可求,有术无道,止于术

    有道无术 术尚可求 有术无道 止于术 老子 道德经 道和术在一直是一个引起人们广泛讨论的话题 古今中外许多人对此皆有见解 道和术放在道德和能力上来说 到底哪个更重要许多名人名言中都有阐述 1 因为道德是做人的根本 根本一坏 纵然使你有一些学
  • 一文精通常量池

    大家好 今天来和大家一起探索下Java的常量池 在阅读本篇之前 我为大家准备了一个测试 共15道判断题 每题1分 满分15分 大约花费1 2分钟时间 如果你全部答对了 那么恭喜你大神 本篇可能已经满足不了你了 如果结果不理想也不要气馁 读完