String、StringBuffer与StringBuilder之间区别

2023-11-05

 

String     StringBuffer     StringBuilder
String的值是不可变的,这就导致每次对String的操作都会生成新的String对象,不仅效率低下,而且浪费大量优先的内存空间  StringBuffer是可变类,和线程安全的字符串操作类,任何对它指向的字符串的操作都不会产生新的对象。每个StringBuffer对象都有一定的缓冲区容量,当字符串大小没有超过容量时,不会分配新的容量,当字符串大小超过容量时,会自动增加容量  可变类,速度更快
不可变     可变    可变
   线程安全     线程不安全
   多线程操作字符串    单线程操作字符串

一、Java String 类——String字符串常量

    简要的说, String 类型和 StringBuffer 类型的主要性能区别其实在于 String 是不可变的对象, 因此在每次对 String 类型进行改变的时候其实都等同于生成了一个新的 String 对象,然后将指针指向新的 String 对象,这样不仅效率低下,而且大量浪费有限的内存空间,所以经常改变内容的字符串最好不要用 String 。因为每次生成对象都会对系统性能产生影响,特别当内存中无引用对象多了以后, JVM 的 GC 就会开始工作,那速度是一定会相当慢的。

我们来看一下这张对String操作时内存变化的图:

      我们可以看到,初始String值为“hello”,然后在这个字符串后面加上新的字符串“world”,这个过程是需要重新在栈堆内存中开辟内存空间的,最终得到了“hello world”字符串也相应的需要开辟内存空间,这样短短的两个字符串,却需要开辟三次内存空间,不得不说这是对内存空间的极大浪费。为了应对经常性的字符串相关的操作,就需要使用Java提供的其他两个操作字符串的类——StringBuffer类和StringBuild类来对此种变化字符串进行处理。

二、StringBuffer 和 StringBuilder 类——StringBuffer、StringBuilder字符串变量

StringBuffer 字符串变量(线程安全)
StringBuilder 字符串变量(非线程安
 

对字符串进行修改的时候,特别是字符串对象经常改变的情况下,需要使用 StringBuffer 和 StringBuilder 类。

和 String 类不同的是,StringBuffer 和 StringBuilder 类的对象能够被多次的修改,并且不产生新的未使用对象

StringBuilder 类在 Java 5 中被提出,它和 StringBuffer 之间的最大不同在于 StringBuilder 的方法不是线程安全的(不能同步访问)。

由于 StringBuilder 相较于 StringBuffer 有速度优势,所以多数情况下建议使用 StringBuilder 类。然而在应用程序要求线程安全的情况下,则必须使用 StringBuffer 类。

三者的继承结构

三者的区别

(1)字符修改上的区别(主要,见上面分析)

(2)初始化上的区别,String可以空赋值,后者不行,报错

①String

String s = null;   

String s = “abc”;   

②StringBuffer

StringBuffer s = null; //结果警告:Null pointer access: The variable result can only be null at this location

StringBuffer s = new StringBuffer();//StringBuffer对象是一个空的对象

StringBuffer s = new StringBuffer(“abc”);//创建带有内容的StringBuffer对象,对象的内容就是字符串”

小结:(1)如果要操作少量的数据用 String;

(2)多线程操作字符串缓冲区下操作大量数据 StringBuffer;

(3)单线程操作字符串缓冲区下操作大量数据 StringBuilder

 

    而在某些特别情况下, String 对象的字符串拼接其实是被 JVM 解释成了 StringBuffer 对象的拼接,所以这些时候 String 对象的速度并不会比 StringBuffer 对象慢,而特别是以下的字符串对象生成中, String 效率是远要比 StringBuffer 快的:
 String S1 = "This is only a" + " simple" + " test";
 StringBuffer Sb = new StringBuffer("This is only a").append(" simple").append(" test");
 你会很惊讶的发现,生成 String S1 对象的速度简直太快了,而这个时候 StringBuffer 居然速度上根本一点都不占优势。其实这是 JVM 的一个把戏,在 JVM 眼里,这个
 String S1 = “This is only a” + “ simple” + “test”; 其实就是:
 String S1 = “This is only a simple test”;  

所以当然不需要太多的时间了。但大家这里要注意的是,如果你的字符串是来自另外的 String 对象的话,速度就没那么快了,譬如:
String S2 = “This is only a”;
String S3 = “ simple”;
String S4 = “ test”;
String S1 = S2 +S3 + S4;
这时候 JVM 会规规矩矩的按照原来的方式去做


在大部分情况下 StringBuffer > String
StringBuffer
Java.lang.StringBuffer线程安全的可变字符序列。一个类似于 String 的字符串缓冲区,但不能修改。虽然在任意时间点上它都包含某种特定的字符序列,但通过某些方法调用可以改变该序列的长度和内容。
可将字符串缓冲区安全地用于多个线程。可以在必要时对这些方法进行同步,因此任意特定实例上的所有操作就好像是以串行顺序发生的,该顺序与所涉及的每个线程进行的方法调用顺序一致。
StringBuffer 上的主要操作是 append 和 insert 方法,可重载这些方法,以接受任意类型的数据。每个方法都能有效地将给定的数据转换成字符串,然后将该字符串的字符追加或插入到字符串缓冲区中。append 方法始终将这些字符添加到缓冲区的末端;而 insert 方法则在指定的点添加字符。
例如,如果 z 引用一个当前内容是“start”的字符串缓冲区对象,则此方法调用 z.append("le") 会使字符串缓冲区包含“startle”,而 z.insert(4, "le") 将更改字符串缓冲区,使之包含“starlet”。
在大部分情况下 StringBuilder > StringBuffer

java.lang.StringBuilder
java.lang.StringBuilder一个可变的字符序列是5.0新增的。此类提供一个与 StringBuffer 兼容的 API,但不保证同步。该类被设计用作 StringBuffer 的一个简易替换,用在字符串缓冲区被单个线程使用的时候(这种情况很普遍)。如果可能,建议优先采用该类,因为在大多数实现中,它比 StringBuffer 要快。两者的方法基本相同。

作者:每次上网冲杯Java时,都能看到关于String无休无止的争论。还是觉得有必要让这个讨厌又很可爱的String美眉,赤裸裸的站在我们这些Java色狼面前了。嘿嘿....

众所周知,String是由字符组成的串,在程序中使用频率很高。Java中的String是一个类,而并非基本数据类型。 不过她却不是普通的类哦!!!

 

【镜头1】 String对象的创建 
      1、关于类对象的创建,很普通的一种方式就是利用构造器,String类也不例外:String s=new String("Hello world"); 问题是参数"Hello world"是什么东西,也是字符串对象吗?莫非用字符串对象创建一个字符串对象?

      2、当然,String类对象还有一种大家都很喜欢的创建方式:String s="Hello world"; 但是有点怪呀,怎么与基本数据类型的赋值操作(int i=1)很像呀?

      在开始解释这些问题之前,我们先引入一些必要的知识:

★ Java class文件结构 和常量池 
      我们都知道,Java程序要运行,首先需要编译器将源代码文件编译成字节码文件(也就是.class文件)。然后在由JVM解释执行。
      class文件是8位字节的二进制流 。这些二进制流的涵义由一些紧凑的有意义的项组成。比如class字节流中最开始的4个字节组成的项叫做魔数 (magic),其意义在于分辨class文件(值为0xCAFEBABE)与非class文件。class字节流大致结构如下图左侧。

                                

      其中,在class文件中有一个非常重要的项——常量池 。这个常量池专门放置源代码中的符号信息(并且不同的符号信息放置在不同标志的常量表中)。如上图右侧是HelloWorld代码中的常量表(HelloWorld代码如下),其中有四个不同类型的常量表(四个不同的常量池入口)。关于常量池的具体细节,请参照我的博客《Class文件内容及常量池 》

Java代码  

public class HelloWorld{  
    void hello(){  
        System.out.println("Hello world");  
    }  
}  

      通过上图可见,代码中的"Hello world"字符串字面值被编译之后,可以清楚的看到存放在了class常量池中的字符串常量表中(上图右侧红框区域)。

 

★ JVM运行class文件

      源代码编译成class文件之后,JVM就要运行这个class文件。它首先会用类装载器加载进class文件。然后需要创建许多内存数据结构来存放class文件中的字节数据。比如class文件对应的类信息数据、常量池结构、方法中的二进制指令序列、类方法与字段的描述信息等等。当然,在运行的时候,还需要为方法创建栈帧等。这么多的内存结构当然需要管理,JVM会把这些东西都组织到几个“运行时数据区 ”中。这里面就有我们经常说的“方法区 ”、“堆 ”、“Java栈 ”等。详细请参见我的博客《Java 虚拟机体系结构 》 。

      上面我们提到了,在Java源代码中的每一个字面值字符串,都会在编译成class文件阶段,形成标志号 为8(CONSTANT_String_info)的常量表 。 当JVM加载 class文件的时候,会为对应的常量池建立一个内存数据结构,并存放在方法区中。同时JVM会自动为CONSTANT_String_info常量表中 的字符串常量字面值 在堆中 创建 新的String对象(intern字符串 对象,又叫拘留字符串对象)。然后把CONSTANT_String_info常量表的入口地址转变成这个堆中String对象的直接地址(常量池解 析)。 

      这里很关键的就是这个拘留字符串对象 。源代码中所有相同字面值的字符串常量只可能建立唯一一个拘留字符串对象。 实际上JVM是通过一个记录了拘留字符串引用的内部数据结构来维持这一特性的。在Java程序中,可以调用String的intern()方法来使得一个常规字符串对象成为拘留字符串对象。我们会在后面介绍这个方法的。

 

★ 操作码助忆符指令 
      有了上面阐述的两个知识前提,下面我们将根据二进制指令来区别两种字符串对象的创建方式:  

      (1) String s=new String("Hello world");编译成class文件后的指令(在myeclipse中查看):

Class字节码指令集代码

 

0  new java.lang.String [15]  //在堆中分配一个String类对象的空间,并将该对象的地址堆入操作数栈。  
3  dup //复制操作数栈顶数据,并压入操作数栈。该指令使得操作数栈中有两个String对象的引用值。  
4  ldc <String "Hello world"> [17] //将常量池中的字符串常量"Hello world"指向的堆中拘留String对象的地址压入操作数栈  
6  invokespecial java.lang.String(java.lang.String) [19] //调用String的初始化方法,弹出操作数栈栈顶的两个对象地址,用拘留String对象的值初始化new指令创建的String对象,然后将这个对象的引用压入操作数栈  
9  astore_1 [s] // 弹出操作数栈顶数据存放在局部变量区的第一个位置上。此时存放的是new指令创建出的,已经被初始化的String对象的地址 (此时的栈顶值弹出存入局部变量中去)。  

注意:
【这里有个dup指令。其作用就是复制之前分配的Java.lang.String空间的引用并压入栈顶。那么这里为什么需要这样么做呢?因为invokespecial指令通过[15]这个常量池入口寻找到了java.lang.String()构造方法,构造方法虽然找到了。但是必须还得知道是谁的构造方法,所以要将之前分配的空间的应用压入栈顶让invokespecial命令应用才知道原来这个构造方法是刚才创建的那个引用的,调用完成之后将栈顶的值弹出。之后调用astore_1将此时的栈顶值弹出存入局部变量中去。】     


 事实上,在运行这段指令之前,JVM就已经为"Hello world"在堆中创建了一个拘留字符串( 值得注意的是:如果源程序中还有一个"Hello world"字符串常量,那么他们都对应了同一个堆中的拘留字符串)。然后用这个拘留字符串的值来初始化堆中用new指令创建出来的新的String对象,局部变量s实际上存储的是new出来的堆对象地址。 大家注意了,此时在JVM管理的堆中,有两个相同字符串值的String对象:一个是拘留字符串对象,一个是new新建的字符串对象。如果还有一条创建语句String s1=new String("Hello world");堆中有几个值为"Hello world"的字符串呢? 答案是3个,大家好好想想为什么吧!

 

      (2)将String s="Hello world";编译成class文件后的指令:

Class字节码指令集代码  

0  ldc <String "Hello world"> [15]//将常量池中的字符串常量"Hello world"指向的堆中拘留String对象的地址压入操作数栈  
2  astore_1 [str] // 弹出操作数栈顶数据存放在局部变量区的第一个位置上。此时存放的是拘留字符串对象在堆中的地址  

     和上面的创建指令有很大的不同,局部变量s存储的是早已创建好的拘留字符串的堆地址(没有new 的对象了)。 大家好好想想,如果还有一条穿件语句String s1="Hello word";此时堆中有几个值为"Hello world"的字符串呢?答案是1个。那么局部变量s与s1存储的地址是否相同呢?  呵呵, 这个你应该知道了吧。

 

★ 镜头总结: String类型脱光了其实也很普通。真正让她神秘的原因就在于CONSTANT_String_info常量表 拘留字符串对象 的存在。现在我们可以解决江湖上的许多纷争了。

   纷争1】关于字符串相等关系的争论

Java代码 

//代码1  
String sa=new String("Hello world");            
String sb=new String("Hello world");      
System.out.println(sa==sb);  // false       
//代码2    
String sc="Hello world";    
String sd="Hello world";  
System.out.println(sc==sd);  // true   

       代码1中局部变量sa,sb中存储的是JVM在堆中new出来的两个String对象的内存地址。虽然这两个String对象的值(char[]存放的字符序列)都是"Hello world"。 因此"=="比较的是两个不同的堆地址。代码2中局部变量sc,sd中存储的也是地址,但却都是常量池中"Hello world"指向的堆的唯一的那个拘留字符串对象的地址 。自然相等了。

  【纷争2】 字符串“+”操作的内幕

Java代码  

//代码1  
String sa = "ab";                                          
String sb = "cd";                                       
String sab=sa+sb;                                      
String s="abcd";  
System.out.println(sab==s); // false  
//代码2  
String sc="ab"+"cd";  
String sd="abcd";  
System.out.println(sc==sd); //true  

    代码1中局部变量sa,sb存储的是堆中两个拘留字符串对象的地址。而当执行sa+sb时,JVM首先会在堆中创建一个StringBuilder类,同时用sa指向的拘留字符串对象完成初始化,然后调用append方法完成对sb所指向的拘留字符串的合并操作,接着调用StringBuilder的toString()方法在堆中创建一个String对象,最后将刚生成的String对象的堆地址存放在局部变量sab中。而局部变量s存储的是常量池中"abcd"所对应的拘留字符串对象的地址。 sab与s地址当然不一样了。这里要注意了,代码1的堆中实际上有五个字符串对象:三个拘留字符串对象、一个String对象和一个StringBuilder对象。
      代码2中"ab"+"cd"会直接在编译期就合并成常量"abcd", 因此相同字面值常量"abcd"所对应的是同一个拘留字符串对象,自然地址也就相同。

 

【镜头二】  String三姐妹(String,StringBuffer,StringBuilder) 
        String扒的差不多了。但他还有两个妹妹StringBuffer,StringBuilder长的也不错哦!我们也要下手了:
                           String(大姐,出生于JDK1.0时代)          不可变字符序列
                           StringBuffer(二姐,出生于JDK1.0时代)    线程安全的可变字符序列
                           StringBuilder(小妹,出生于JDK1.5时代)   非线程安全的可变字符序列 

 

★StringBuffer与String的可变性问题。 
         我们先看看这两个类的部分源代码:

Java代码  

//String   
public final class String  
{  
        private final char value[];  
  
         public String(String original) {  
              // 把原字符串original切分成字符数组并赋给value[];  
         }  
}  
  
//StringBuffer   
public final class StringBuffer extends AbstractStringBuilder  
{  
         char value[]; //继承了父类AbstractStringBuilder中的value[]  
         public StringBuffer(String str) {  
                 super(str.length() + 16); //继承父类的构造器,并创建一个大小为str.length()+16的value[]数组  
                 append(str); //将str切分成字符序列并加入到value[]中  
        }  
}  

     很显然,String和StringBuffer中的value[]都用于存储字符序列。但是,
      (1) String中的是常量(final)数组,只能被赋值一次。 
      比如:new String("abc")使得value[]={'a','b','c'}(查看jdk String 就是这么实现的),之后这个String对象中的value[]再也不能改变了。这也正是大家常说的,String是不可变的原因 。    
      注意:这个对初学者来说有个误区,有人说String str1=new String("abc"); str1=new String("cba");不是改变了字符串str1吗?那么你有必要先搞懂对象引用和对象本身的区别。这里我简单的说明一下,对象本身指的是存放在堆空间中的该对象的实例数据(非静态非常量字段)。而对象引用指的是堆中对象本身所存放的地址,一般方法区和Java栈中存储的都是对象引用,而非对象本身的数据。


      (2) StringBuffer中的value[]就是一个很普通的数组,而且可以通过append()方法将新字符串加入value[]末尾。这样也就改变了value[]的内容和大小了。

      比如:new StringBuffer("abc")使得value[]={'a','b','c','',''...}(注意构造的长度是str.length()+16)。如果再将这个对象append("abc"),那么这个对象中的value[]={'a','b','c','a','b','c',''....}。这也就是为什么大家说 StringBuffer是可变字符串 的涵义了。从这一点也可以看出,StringBuffer中的value[]完全可以作为字符串的缓冲区功能。其累加性能是很不错的,在后面我们会进行比较。

     总结,讨论String和StringBuffer可不可变。本质上是指对象中的value[]字符数组可不可变,而不是对象引用可不可变。 

 

★StringBuffer与StringBuilder的线程安全性问题 
      StringBuffer和StringBuilder可以算是双胞胎了,这两者的方法没有很大区别。但在线程安全性方面,StringBuffer允许多线程进行字符操作。这是因为在源代码中StringBuffer的很多方法都被关键字synchronized 修饰了,而StringBuilder没有。
      有多线程编程经验的程序员应该知道synchronized。这个关键字是为线程同步机制 设定的。我简要阐述一下synchronized的含义:
      每一个类对象都对应一把锁,当某个线程A调用类对象O中的synchronized方法M时,必须获得对象O的锁才能够执行M方法,否则线程A阻塞。一旦线程A开始执行M方法,将独占对象O的锁。使得其它需要调用O对象的M方法的线程阻塞。只有线程A执行完毕,释放锁后。那些阻塞线程才有机会重新调用M方法。这就是解决线程同步问题的锁机制。 
      了解了synchronized的含义以后,大家可能都会有这个感觉。多线程编程中StringBuffer比StringBuilder要安全多了 ,事实确实如此。如果有多个线程需要对同一个字符串缓冲区进行操作的时候,StringBuffer应该是不二选择。
      注意:是不是String也不安全呢?事实上不存在这个问题,String是不可变的。线程对于堆中指定的一个String对象只能读取,无法修改。试问:还有什么不安全的呢? 

 

★String和StringBuffer的效率问题(这可是个热门话题呀!) 
      首先说明一点:StringBuffer和StringBuilder可谓双胞胎,StringBuilder是1.5新引入的,其前身就是StringBuffer。StringBuilder的效率比StringBuffer稍高,如果不考虑线程安全,StringBuilder应该是首选。另外,JVM运行程序主要的时间耗费是在创建对象和回收对象上。
      我们用下面的代码运行1W次字符串的连接操作,测试String,StringBuffer所运行的时间。

Java代码  

//测试代码  
public class RunTime{  
    public static void main(String[] args){  
           ● 测试代码位置1  
          long beginTime=System.currentTimeMillis();  
          for(int i=0;i<10000;i++){  
                 ● 测试代码位置2  
          }  
          long endTime=System.currentTimeMillis();  
          System.out.println(endTime-beginTime);     
    }  
}  

(1) String常量与String变量的"+"操作比较 
        ▲测试①代码:     (测试代码位置1)  String str="";
                                  (测试代码位置2)  str="Heart"+"Raid";
            [耗时:  0ms]
             
       ▲测试②代码        (测试代码位置1)  String s1="Heart";
                                                           String s2="Raid";
                                                           String str="";
                                  (测试代码位置2)  str=s1+s2;
            [耗时:  15—16ms]
      结论:String常量的“+连接”  稍优于  String变量的“+连接”。 
      原因:测试①的"Heart"+"Raid"在编译阶段就已经连接起来,形成了一个字符串常量"HeartRaid",并指向堆中的拘留字符串对象。运行时只需要将"HeartRaid"指向的拘留字符串对象地址取出1W次,存放在局部变量str中。这确实不需要什么时间。 
               测试②中局部变量s1和s2存放的是两个不同的拘留字符串对象的地址。然后会通过下面三个步骤完成“+连接”:
                                1、StringBuilder temp=new StringBuilder(s1),
                                2、temp.append(s2);
                                3、str=temp.toString();
               我们发现,虽然在中间的时候也用到了append()方法,但是在开始和结束的时候分别创建了StringBuilder和String对象。可想而知:调用1W次,是不是就创建了1W次这两种对象呢?不划算。

     但是,String变量的"+连接"操作比String常量的"+连接"操作使用的更加广泛。 这一点是不言而喻的。
    

(2)String对象的"累+"连接操作与StringBuffer对象的append()累和连接操作比较。 
          ▲测试①代码:     (代码位置1)  String s1="Heart";
                                                       String s="";
                                    (代码位置2)  s=s+s1;
             [耗时:  4200—4500ms]
             
          ▲测试②代码        (代码位置1)  String s1="Heart";
                                                       StringBuffer sb=new StringBuffer();
                                    (代码位置2) sb.append(s1);
             [耗时:  0ms(当循环100000次的时候,耗时大概16—31ms)]
         结论:大量字符串累加时,StringBuffer的append()效率远好于String对象的"累+"连接 
         原因:测试① 中的s=s+s1,JVM会利用首先创建一个StringBuilder,并利用append方法完成s和s1所指向的字符串对象值的合并操作,接着调用StringBuilder的 toString()方法在堆中创建一个新的String对象,其值为刚才字符串的合并结果。而局部变量s指向了新创建的String对象。

                  因为String对象中的value[]是不能改变的,每一次合并后字符串值都需要创建一个新的String对象来存放。循环1W次自然需要创建1W个String对象和1W个StringBuilder对象,效率低就可想而知了。


                  测试②中sb.append(s1);只需要将自己的value[]数组不停的扩大来存放s1即可。循环过程中无需在堆中创建任何新的对象。效率高就不足为奇了。        

 

★ 镜头总结:

    (1) 在编译阶段就能够确定的字符串常量,完全没有必要创建String或StringBuffer对象。直接使用字符串常量的"+"连接操作效率最高。

    (2) StringBuffer对象的append效率要高于String对象的"+"连接操作。

    (3) 不停的创建对象是程序低效的一个重要原因。那么相同的字符串值能否在堆中只创建一个String对象那。显然拘留字符串能够做到这一点,除了程序中的字符串常量会被JVM自动创建拘留字符串之外,调用String的intern()方法也能做到这一点。当调用intern()时,如果常量池中已经有了当前String的值,那么返回这个常量指向拘留对象的地址。如果没有,则将String值加入常量池中,并创建一个新的拘留字符串对象。

全)

 

参照:

https://www.cnblogs.com/goody9807/p/6516374.html

https://blog.csdn.net/u011702479/article/details/82262823

https://blog.csdn.net/weixin_41101173/article/details/79677982

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

String、StringBuffer与StringBuilder之间区别 的相关文章

  • 在 Java 中有效地对图像进行颜色循环

    我正在编写一个曼德尔布罗分形查看器 我想以智能的方式实现颜色循环 给定一个图像 我想修改它的 IndexColorModel 据我所知 没有办法修改 IndexColorModel 也没有办法为图像提供新的 IndexColorModel
  • Spring boot 404错误自定义错误响应ReST

    我正在使用 Spring boot 来托管 REST API 即使浏览器正在访问 URL 以及自定义数据结构 我也希望始终发送 JSON 响应 而不是使用标准错误响应 我可以使用 ControllerAdvice 和 ExceptionHa
  • ORMLite - join where 子句中的括号

    我想使用连接三个表QueryBuilder join and QueryBuilder joinor但我想在 where 子句中添加括号 如下所示 WHERE first table where AND second table where
  • 使用用户名进行 Java LDAP 身份验证

    好吧 这让我发疯 我正在尝试使用 Java 创建 LDAP 身份验证 如果我在 SECURITY PRINCIPAL 中使用我的名字和姓氏 一切都很好 这是我的代码 try Hashtable
  • java模拟自定义对象

    public class MainClass public void makeCall CustomObject obj new CustomObject obj testMethod 我想进行单元测试makeCall 所以我必须嘲笑Cus
  • JSF 错误 - IllegalStateException:PWC3999:提交响应后无法创建会话[重复]

    这个问题在这里已经有答案了 我是 JSF 新手 正在构建一个使用 Facelet 创建的应用程序 这是我的模板master xhtml
  • 使用 Thymeleaf 时我们应该删除 HTML 属性吗?

    我正在研究 Thymeleaf 发现几乎所有示例中都有 Thymeleaf 的标签值以及标准 HTML 值 例如 这些
  • 读取 Nashorn JO4 和 NativeArray

    Java调用代码 import jdk nashorn api scripting myCustomHashMap dataStore new myCustomHashMap ScriptEngineManager sem new Scri
  • Android 上的自定义视图和窗口属性

    我想要做的是在我的应用程序顶部添加一个视图 该视图类似于过滤器视图 我想操纵屏幕的颜色 并且我还希望能够同时更改屏幕的亮度时间 这两件事似乎是分开起作用的 但不能一起起作用 这是我的代码 添加视图 colourView new Layer
  • 添加和完成 PHP 源代码文档的工具 [关闭]

    Closed 此问题正在寻求书籍 工具 软件库等的推荐 不满足堆栈溢出指南 help closed questions 目前不接受答案 我有几个已完成的较旧的 PHP 项目 其中有很多内容 我想以 javadoc phpDocumentor
  • 在 Java/GWT 中解析用户时间输入

    解析用户在 GWT 中的文本字段中键入的时间的最佳方法是什么 默认时间格式要求用户完全按照区域设置指定的时间格式输入时间 我想要更加灵活 因为用户可以通过多种不同的方式输入时间 例如 8 8p 8pm 8 15pm 13 15 1315 1
  • 基于Java模式分割字符串

    您好 我有以下模式的日志文件 2014 03 06 03 21 45 432 ERROR mfs pool 3 thread 19 dispatcher StatusNotification Error processing notific
  • 使用 Lint 和 SonarQube 分析 Android 项目

    我真的 溢出 了试图让这些东西一起工作 我按照这里的指示进行操作 http docs sonarqube org display PLUG Android Lint Plugin http docs sonarqube org displa
  • JSF“总”变量类似于 JSTL 中的 c:set

    我不喜欢 JSF 但我需要用它来解决这个问题 我正在 纯 JSF 中工作 所以这就是我基本上需要的 但我不知道如何用 JSF 来实现它
  • 飞碟 - html 实体未呈现

    我正在使用 Flying saucer lib 生成 pdf 但我对一些 html 实体有问题 我已经在寻找解决方案 我在这个论坛和其他地方找到了很多提示 但仍然存在问题 我尝试过这种方法 http sdtidbits blogspot c
  • 需要同步仅增量计数器吗?

    我使用整数作为计数器 该整数只会增加 并且肯定有多个线程会同时增加它 当没有其他线程尝试访问其值时 在程序执行结束时读取该计数器的值 我假设我不必为这种仅增量计数器使用锁或任何类型的同步 这是正确的吗 如果这有什么区别的话 我用 Java
  • 从 IntelliJ 运行 JavaFX 应用程序

    Versions openjdk版本 11 0 11 2021 04 20 OpenJDK 运行时环境 build 11 0 11 9 Ubuntu 0ubuntu2 20 10 OpenJDK 64 位服务器虚拟机 内部版本 11 0 1
  • Hibernate 命名查询使用 Like 和 % % 运算符?

    在我的 Hibernate JPA 示例代码中 public List
  • Java分数计算器

    我对 Java 编程还很陌生 我的 AP 计算机编程课程有作业要完成 所以请耐心等待 我必须弄清楚如何将两个分数相乘 我想知道是否有任何方法可以在方法内部声明变量并在该方法外部使用它 我在介绍方法中的 while 循环 谢谢您 希望这不会令
  • 如何获取 res.drawable 文件夹的路径来复制文件?

    我正在编写我的应用程序AndroidStudio 我的里面有gif文件drawable gifs文件夹 我希望将该文件复制到MediaStore Images Media单击按钮后的文件夹 目前 即使使用发布的一些答案 我也无法获取我的 g

随机推荐

  • FPGA实现电机转速PID控制

    通过纯RTL实现电机转速PID控制 包括电机编码器值读取 电机速度 正反转控制 PID算法 卡尔曼滤波 最终实现对电机速度进行控制 使其能够渐近设定的编码器目标值 一 设计思路 前面通过SOPC之NIOS 实现电机转速PID控制 调用中断函
  • Android数据库升级解决方案

    方案一 第三方库ActiveAndroid数据库 在对应继承model的实体类中添加的字段 并且对应的数据库版本升级 1 在assert资源文件添加一个migrations文件夹 里面创建文件 版本号 sql 文件中添加数据库脚本 即 AL
  • 最容易理解的JavaScript解决约瑟夫环问题的方式之一

    这种方式虽然效率不是最高的 但绝对是最容易理解的思路之一 function ysf flag stayNum allNum let arr let start 1 for let i 1 i lt allNum i arr push i 当
  • 做爱做的事,做有快感的事

    还是不发首页了 最近没规划 需要缓一缓 因为发首页还是要符合几点要求的 所以就先停停 不过文章还是得写 本来十一点多就写好了 没想到洗个澡就过了十二点 今天就更像聊天了 上一篇说到拖延症 最后留下了一个尾巴 就是怎么找到不会发生拖延症的事去
  • 【Git】(四)子模块

    1 增加子模块 进入准备添加子模块所在的目录 例如library git submodule add b 1 0 0 0 git gitee com sunriver2000 SubModule git 参数 b用于指定子模块分支 2 更新
  • 刷脸支付每个人的脸都具有唯一性无法复制

    移动支付时代 手机成为承载资金的介质 人人手机里有支付宝或者微信支付 但如果手机一旦丢失 不法分子破解了用户密码 那么资金安全也面临威胁 而刷脸支付的第一大优势就在于保证用户资金安全 因为在整个支付过程中 用户完全不用打开手机和自己的资金账
  • [游戏开发][Shader]GLSLSandBox转Unity-CG语言

    官网 GLSL Sandbox Galleryhttps glslsandbox com 屏幕坐标计算 fragCoord与 ScreenParams mat2矩阵转换 vec2向量 在GLSL里mat2 a b c d 函数返回vec2
  • yolov3之数据集预处理

    目录 txt标签文件的说明 将jpg与txt文件分开 txt生成xml标签文件 xml标签详解 xml标签生成txt txt标签文件的说明 获取到的数据集是这样的 需要转换为VOC格式 其实就是将txt转换为xml文件 打开txt文件可以看
  • 在线代码编辑器:Monaco Editor

    monaco editor是微软开源的一款web版代码编辑器 它支持智能提示 代码高亮 代码格式化 Monaco Editor是为VS Code提供支持的代码编辑器 运行在浏览器环境中 编辑器提供代码提示 智能建议等功能 供开发人员远程更方
  • 2013年9月10日星期二(DEMO8_6矩阵)

    首先设置了2个矩阵 1 把所有的点存储为1 2矩阵 typedef struct MATRIX1X2 TYP float M 2 MATRIX1X2 MATRIX1X2 PTR M X Y 2把所有变换矩阵采用3 2矩阵 typedef s
  • 带你玩转kubernetes-k8s(第21篇:k8s-深入掌握Pod-初始化容器、Pod滚动升级)

    上节内容的错误 还请大家不要太在意 后面我们会解决的 理解Job的作用 概念就可以了 下面我们进入正题 Init Container 初始化容器 在很多应用场景中 应用在启动之前都需要进行如下初始化操作 等待其他关联组件正确运行 例如数据库
  • Gitbash 无法显示中文

    GitBash gt 右键 gt options gt 左侧text 设置locale zh cn 设置Character set GBK save gt apply GitBash输入 systeminfo看能否正常显示
  • 几种C/C++语言安全检测工具介绍

    转自新浪微博http www vckbase com index php wv 1635 针对C C 语言安全漏洞的分析检测也出现了大量的工具 按照不同的机理主要分为以下几类 如表所示 分析类型 机理 分析工具 备注 静态分析 预处理 Fo
  • ## Hive分区、桶、与倾斜

    Hive的分区 1 在Hive Select 查询中一般会扫描整个表内容 会消耗很多时间做没必要的工作 有时候查询 只需要扫描表中关心的一部分数据 因此建表时引入partition概念 2 分区表指的是在创建表时指定的partition的分
  • 数据库查询最近N天数据

    查询最近7天数据 1 查询最近7天订单金额 用到了虚表和UNION ALL的知识 其中 price是要查询的数据 orders是表名 IFNULL b price 0 是指b price如果值为空 则将空值设置为0 SELECT a cli
  • Java版手写数字(0~9)BP神经网络识别

    MNIST的样本集太无趣 连图片都看不到 也无法用人手进行输入 所以 基于BP神经网络的理论知识 参见数据挖掘黑书212页起 讲得甚好 纯手写了一版带训练和测试的小玩具 Java语言 效果如下 代码已上传github https githu
  • 多项式回归(非线性回归)的python代码实现

    1 概述 在解决回归问题中 很多数据集中输入空间与输出空间并非完全呈线性关系 使用线性回归无法解决此类问题 为了解决存在非线性关系的数据集的回归问题 需要进行多项式回归 但sklearn并未提供多项式回归模型的类 多项式回归使用的还是线性回
  • 字节的对齐方式

    VC对结构的存储的特殊处理确实提高CPU存储变量的速度 但是有时候也带来了一些麻烦 我们也屏蔽掉变量默认的对齐方式 自己可以设定变量的对齐方式 重要规则 1 复杂类型中各个成员按照它们被声明的顺序在内存中顺序存储 第一个成员的地址和整个类型
  • 【k8s】k8s部署网络插件Calico、创建网络策略

    一 简介 01 calico简介 calico官网 flannel实现的是网络通信 calico的特性是在pod之间的隔离 通过BGP路由 但大规模端点的拓扑计算和收敛往往需要一定的时间和计算资源 纯三层的转发 中间没有任何的NAT和ove
  • String、StringBuffer与StringBuilder之间区别

    String StringBuffer StringBuilder String的值是不可变的 这就导致每次对String的操作都会生成新的String对象 不仅效率低下 而且浪费大量优先的内存空间 StringBuffer是可变类 和线程