Java 字符串处理的一些小细节

转载请注明出处:王亟亟的大牛之路

讲今天的内容之前温故一些理论知识?(部分理论知识来源于网上,谢谢开源大家庭)

1.什么是指针?
—指针是指向内存中的地址,该地址就是存储变量的值。

2.Java中没有了指针,那以什么东西来替代指针相应的功能?
—java中我们所谓的对象引用就是指针,只是没有像C/C++中给出了一个明确的定义。java是为了避免指针带来的使用上的麻烦,所以就使用对象的引用来代替了指针。

3.那么这些对象的引用又存放在哪?
—java中的内存分为堆内存(heap)和栈内存(stack)。堆就是用来存放对象的,而栈则是存放一些数据基本类型的值。


一.引用

平时字面量创建就是简单的

String wjj = "Hello";

JVM检测这个字面量,这里我们认为没有内容为Hello的对象存在。JVM通过字符串常量池查找不到内容为Hello的字符串对象存在,那么会创建这个字符串对象,然后将刚创建的对象的引用放入到字符串常量池中,并且将引用返回给变量wjj。

然后又给第二个对象赋值,如:

String wjj1 = "Hello";

因为在我们的常量池中已经有了hello这个对象,所以把已经存在的字符串对象的引用返回给变量wjj1。

测试下这两个对象指向同一个Hello:

 String Wjj= "Hello";
 String Wjj2="Hello";
 System.out.println(Wjj==Wjj2);
 System.out.println(Wjj.equals(Wjj2));
 结果:
 true
 true

那除了直接 String Wjj= “Hello”;我们还用 new String的 方式,像这样:

  String Wjj2=new String("Hello");

结果还是一样的给我们的Wjj2这个对象赋值了Hello,那么打印的结果会有区别么?

  String Wjj= "Hello";
  String Wjj2=new String("Hello");
  System.out.println(Wjj==Wjj2);
  System.out.println(Wjj.equals(Wjj2));

  结果:
  false
  true

“==”和equals的区别只后会再加解释,基础还是很重要的哈哈!

我们可以看到当我们使用了new来构造字符串对象的时候,这两个变量指向的为不同的对象,不管字符串常量池中有没有相同内容的对象的引用,新的字符串对象都会创建


二.修改值相同但地址不同的引用

对于上面使用new创建的字符串对象,如果想将这个对象的引用加入到字符串常量池,可以使用intern方法。

调用intern后,首先检查字符串常量池中是否有该对象的引用,如果存在,则将这个引用返回给变量,否则将引用加入并返回给变量。

String Wjj1=Wjj.intern();
System.out.println(Wjj1==Wjj);

结果:
true

-概念:
1.字符串常量池中存放的时引用还是对象,这个问题是最常见的。字符串常量池存放的是对象引用,不是对象。在Java中,对象都创建在堆内存中。

2.因为字符串常量池中持有了共享的字符串对象的引用,这就是说是不是会导致这些对象无法回收?
首先问题中共享的对象一般情况下都比较小。据我查证了解,在早期的版本中确实存在这样的问题,但是随着弱引用的引入,目前这个问题应该没有了。



那么String Wjj3="a"+"b"+"c";又等于"abc"么?

   String Wjj= "abc";
   String Wjj2="a"+"b"+"c";
   System.out.println(Wjj==Wjj2);
   System.out.println(Wjj.equals(Wjj2));
   结果:
   true
   true

其实是在编译之前就已经进行了优化所以他们指向了同一个对象


三.String对象

在Java中,String对象是不可变的(Immutable)。在代码中,可以创建多个某一个String对象的别名。但是这些别名都是的引用是相同的。
比如wjj2和wjj都是”hello”对象的别名,别名保存着到真实对象的引用。所以wjj2 = wjj

 String Wjj= "hello";
 String Wjj2=Wjj;
 System.out.println(Wjj==Wjj2);
 System.out.println(Wjj.equals(Wjj2));
 结果:
 true
 true

在Java中,唯一被重载的运算符就是字符串的拼接相关的。+,+=。除此之外,Java设计者不允许重载其他的运算符。

字符串操作的性能问题

  String s1="a" ;
  String s2="b";
  String s3="c";
  String s4=s1+s2+s3;
  System.out.println(s4);
  结果:
  abc

要得到上面的S4,就会S1和S2拼接生成临时一个String对象t1,内容为ab,然后有t1和s3拼接生成最终我们需要的s4对象,这其中,产生了一个中间的t1,而且t1创建之后,没有主动回收,势必会占一定的空间。如果是一个很多(假设上百个,多见于对对象的toString的调用)字符串的拼接,那么代价就更大了,性能一下会降低很多。

编译器的优化处理

真的会有上面的性能代价么,字符串拼接这么常用,没有特殊的处理优化么,答案是有的,这个优化进行在编译器编译.java到bytecode时。

一个Java程序如果想运行起来,需要经过两个时期,编译时和运行时。在编译时,Java 编译器(Compiler)将java文件转换成字节码。在运行时,Java虚拟机(JVM)运行编译时生成的字节码。通过这样两个时期,Java做到了所谓的一处编译,处处运行。

Java编译器做的优化,当Java编译器遇到字符串拼接的时候,会创建一个StringBuilder对象,后面的拼接,实际上是调用StringBuilder对象的append方法。这样就不会有我们上面担心的问题了。

SO,我们来测试一下:

    public static void main(String[] asa) {
        String value="";
        long a=System.currentTimeMillis();
        for(int k=0;k<9000;k++){
            value=value+k;
        }
        System.out.println("a的时间差= "+(System.currentTimeMillis()-a));

        StringBuilder stringBuilder=new StringBuilder();
        long b=System.currentTimeMillis();
        for(int f=0; f<9000; f++){
            stringBuilder.append(f);
        }
        System.out.println("b的时间差="+(System.currentTimeMillis()-b));
    }

结果:
a的时间差= 1137
b的时间差=4

性能差距明显哦!!!

时间: 2024-08-18 08:24:10

Java 字符串处理的一些小细节的相关文章

关于Java 字符串的一个小问题

问题描述 我在代码里面想实现一个将Object对象打印的功能,具体的代码如下:public class JavaJsonDemo { /** * @param args */ public static void main(String[] args) { Object value = null; String str = "value=" + value; System.out.print(str); }} 这单代码是可以正常执行的. 但是,如果将代码改为  /** * @param

java实现归并排序和树形排序(锦标赛制):java字符串分隔或的形式

String[] b=str.split("query|,");//query分隔或者逗号分隔 归并排序,递归实现 public class MergeSort2 { // 对data数组中的 [a,b) 区间的数据进行归并排序, // 排序结束后,[a,b)间数据处于升序有序状态 static void mergeSort(int[] data, int a,int b) { if (a >= b) return; int mid=(a+b)/2;//拆分排序 mergeSor

JAVA字符串转日期或日期转字符串

文章中,用的API是SimpleDateFormat,它是属于java.text.SimpleDateFormat,所以请记得import进来! 用法: SimpleDateFormat sdf = new SimpleDateFormat( " yyyy-MM-dd HH:mm:ss " ); 这一行最重要,它确立了转换的格式,yyyy是完整的公元年,MM是月份,dd是日期,至于 HH:mm:ss就不需要我再解释了吧! PS:为什么有的格式大写,有的格式小写,那是怕避免混淆,例如MM

Java字符串分割

1. java.lang.String 的 split() 方法, JDK 1.4 or later split public String[] split(String regex, int limit) 根据匹配给定的正则表达式来拆分此字符串. 此方法返回的数组包含此字符串的每个子字符串,这些子字符串由另一个匹配给定的表达式的子字符串终止或由字符串结束来终止.数组中的子字符串按它们在此字符串中的顺序排列.如果表达式不匹配输入的任何部分,则结果数组只具有一个元素,即此字符串. limit 参数

Java字符串排序中文+数字

  思路: 在Java中,排序需要复写的是 equals 方法 和 Comparable<T> 接口 的public int compareTo(T o); 方法 步骤: 1. 使用正则表达式来判断数字,多个连续的数字作为一组, 2. 一次检索出数字组合, 3. 检出下一组数字,如果有,则进入步骤4,否则进入步骤6. 4. 如果两组数字出现的位置相等,并且前面部分的字符串相等,则进入第5步.否则break,跳到第6步. 5. 如果前面部分的字符串完全一致.则比较两个数字的大小,如果大小一致,则

为什么Java字符串是不可变对象?

本文主要来介绍一下Java中的不可变对象,以及Java中String类的不可变性,那么为什么Java的String类是不可变对象?让我们一起来分析一下. 答案一: 最流行的Java面试题之一就是:什么是不可变对象(immutable object),不可变对象有什么好处,在什么情况下应该用,或者更具体一些,Java的String类为什么要设成immutable类型? 不可变对象,顾名思义就是创建后不可以改变的对象,典型的例子就是Java中的String类. String s = "ABC&quo

Java字符串拼接效率分析及最佳实践

本文来源于问题 Java字符串连接最佳实践? java连接字符串有多种方式,比如+操作符,StringBuilder.append方法,这些方法各有什么优劣(可以适当说明各种方式的实现细节)? 按照高效的原则,那么java中字符串连接的最佳实践是什么? 有关字符串处理,都有哪些其他的最佳实践? 废话不多说,直接开始, 环境如下: JDK版本: 1.8.0_65 CPU: i7 4790 内存: 16G 直接使用+拼接 看下面的代码: @Test      public void test() {

JAVA 字符串加密、密码加密实现方法_java

在我们的程序设计中,我们经常要加密一些特殊的内容,今天总结了几个简单的加密方法,分享给大家! 如何用JAVA实现字符串简单加密解密?为保证用户信息安全,系统在保存用户信息的时候,务必要将其密码加密保存到数据库.  需要使用密码的时候,取出数据,解密处理即可.  避免保存明文密码. 方案一: package com.tnt.util; import java.security.MessageDigest; public class StringUtil { private final static

java 字符串分割的三种方法(总结)_java

最近在项目中遇到一个小问题,一个字符串分割成一个数组,类似String str="aaa,bbb,ccc"; 然后以","为分割符,将其分割成一个数组,用什么方法去实现呢? 第一种方法: 可能一下子就会想到使用split()方法,用split()方法实现是最方便的,但是它的效率比较低 第二种方法: 使用效率较高的StringTokenizer类分割字符串,StringTokenizer类是JDK中提供的专门用来处理字符串分割子串的工具类.它的构造函数如下: publ