Java从入门到精通六(java中的字符串变量String,StringBuilder,StringBuffer)

简介: 一: String1:String的数据类型首先我们认识到java中的数据类型分为基本数据类型和引用数据类型。基本数据类型分为数值,字符,布尔,而引用数据类型分为类,接口,数组。String是属于引用数据类型的。因为String本身就是一个类需要了解基本数据类型和引用数据类型的区别。基本数据类型是直接存储在内存的栈上的,引用数据类型继承自Object类,按照对象的内存模式进行存储。我们的引用存放在内存的栈上,而对于对象本身的值存放在内存的堆上。我们java中通过new出来的对象就会存放在堆中。

一: String


1:String的数据类型


首先我们认识到java中的数据类型分为基本数据类型和引用数据类型。基本数据类型分为数值,字符,布尔,而引用数据类型分为类,接口,数组。


String是属于引用数据类型的。因为String本身就是一个类


需要了解基本数据类型和引用数据类型的区别。基本数据类型是直接存储在内存的栈上的,引用数据类型继承自Object类,按照对象的内存模式进行存储。我们的引用存放在内存的栈上,而对于对象本身的值存放在内存的堆上。我们java中通过new出来的对象就会存放在堆中。


关于堆栈的一点点普及,可以参考java中的堆与栈


2:String 在静态数据区和堆区(动态存储区之一)创建对象的区别

String 在创建对象如果是在静态存储区,如果两次创建的对象的值是一样的,那么地址是一样的,如果是通过new的话,地址绝对是不一样的。String的一个特点就是如果静态数据区存在,那么不会创建新的对象,而是指向这个对象。在比较的时候==是比较的地址,而提供的equals()方法,比较的是内容。

在代码中举例


package java_practice;
public class StringDemo_1 {
    public static void main(String args[])
    {
        String str1 = "jgdabc";
        String str2 = "jgdabc";
        System.out.println(str1 == str2);
        String str3 = new String("jgdabc");
        String str4 = new String("jgdabc");
        System.out.println(str2==str3);
        System.out.println(str3 == str4);
        System.out.println(str1.equals(str2));
        System.out.println(str3.equals(str4));
    }
}


3:String 的相关方法

下面展示一些 内联代码片。


package java_practice;
import java.io.UnsupportedEncodingException;
public class StringDemo2 {
    public static void main(String args[]) throws UnsupportedEncodingException{
        System.out.println("Java String 类方法");
        String s = "abc";
        //1:截取字符(按照索引)
        char c = s.charAt(1);
        System.out.println("截取到的字符:"+c);
        String s1 = "def";
        //2:进行字符串大小比较
        int s2 = s1.compareTo(s);
        System.out.println("比较结果为:"+s2);
        ;//3:将字符串进行连接
        String s3 = s1.concat(s);
        System.out.println("连接后的字符串;"+s3);
        //4判断是否以某字符串开始
        boolean b =s.startsWith("c"); 
        System.out.println("输出判断结果;"+b); 
        //5:判断是否以某字符串结尾
        boolean b1 = s.endsWith("a");
        System.out.println("输出判断结果;"+b1);
        //6:比较字符串的内容
        boolean b2 = s.equals(s1);
        System.out.println("输出内容比较结果:"+b2);
        //7:将字符串转换为byte数组
        byte[] b3 = s.getBytes("utf-8"); 
        System.out.println("转换结果为:"+b3);
        //8:找出字符或者字符串在当前字符串中的起始位置
        int index = s.indexOf("a");
        System.out.println("起始位置为;"+index);   
         //9:从后向前查找指定字符或者字符串在字符串中第一次出现的位置 
        int last_index = s.lastIndexOf('a');
        System.out.println("从后向前查找到字符首次出现的位置为:"+last_index);
        //10:返回字符串的长度
        int length = s.length();
        System.out.println("找到字符串的长度为:"+length);
        //11:替换指定的字符,生成新的字符串
        String ss = s.replace('a','1');
        System.out.println("替换后的字符串为:"+ss);
        //12:根据指针的正则表达式拆分字符
        String s_1 = "jgdabc";
        String[] s_2 = s_1.split("a");//从a处分割
        System.out.println("内部含分割出的字符串长度为:"+s_2.length);
        System.out.println(s_2[0]);
        System.out.println(s_2[1]);
        //13:截取指定索引后的索引字符串
        String ss_3 = ss.substring(2);
        System.out.println("截取到的字符串为:"+ss_3);
    }
}



4:String基本类型的替换操作


我们可以通过调用包装类的静态方法进行转换。比如parseIInt()转换字符String类型为Integer包装类型。以及String.valueof()转换为String类型。


//String-->基本数据类型、包装类
        String s1 = "123";
        int i = Integer.parseInt(s1);
        System.out.println(i + 123);//123
        //基本数据类型、包装类-->String
        String s2 = 222 + "";
        System.out.println(s2 + 111);//222111
        String s3 = String.valueOf(12345);
        System.out.println(s3 + 222);//12345222


5:String与char[]之间的转换


既然是转换为数组,那就是toCharArray()


//String --> char[]
        String str1 = "abc123";
        char[] charArray = str1.toCharArray();
        for (int i = 0; i < charArray.length; i++) {
            System.out.println(charArray[i]);//abc123
        }
        //char[] --> String
        char[] arr = new char[]{
    'h', 'e', 'l', 'l', 'o'};
        String str2 = new String(arr);
        System.out.println(str2);//hello


二:StringBuilder


StringBuilder是类,固然也是引用数据类型。


1:有关StringBuilder的一些说明


通过在帮助文档中查看,我们可以了解到一些简要的说明。



2:StringBuilder的常用方法


StringBuilder sb = new StringBuilder();
        // 1:对象名.length() 序列长度
        System.out.println(sb.length());  // 0
        // 2:对象名.append() 追加到序列
        sb.append("hello");
        System.out.println(sb);  // hello
        //3:97代表的是是'a'
        sb.appendCodePoint(97);
        System.out.println(sb);  // helloa
        // 4:链式编程
        sb.append(1).append("world").append(2);
        System.out.println(sb);  // helloa1world2
        // 5:索引是5的位置替换成空格
        sb.setCharAt(5, ' ');
        System.out.println(sb);  // hello 1world2
        // 6:指定位置0前插入0
        sb.insert(0, 0);
        System.out.println(sb);  // 0hello 1world2
        // 7:删除索引6(包含)至索引14(不包含)的字符串
        sb.delete(6, 14);
        System.out.println(sb);  // 0hello
        // 8:StringBuilder类型转换成String类型
        String s__ = sb.toString();
        System.out.println(s__);  // 0hello
        // 9:进行反转
        StringBuilder sb__ = sb.reverse();
        System.out.println(sb__);


三: StringBuffer


1:有关StringBuffer的一些说明



2:有关StringBuffer的常用方法


StringBuffer append(boolean b)
将boolean参数的字符串表示形式追加到序列中。
StringBuffer append(char c)
将char参数的字符串表示形式追加到此序列。
StringBuffer append(char[] str)
将char数组参数的字符串表示形式追加到此序列。
StringBuffer append(char[] str, int offset, int len)
将char数组参数的子数组的字符串表示形式追加到此序列。
StringBuffer append(CharSequence s)
将指定的内容附加CharSequence到此序列。
StringBuffer append(CharSequence s, int start, int end)
将指定的子CharSequence序列追加到此序列。
StringBuffer append(double d)
将double 参数的字符串表示形式追加到此序列。
StringBuffer append(float f)
将float 参数的字符串表示形式追加到此序列。
StringBuffer append(int i)
将int 参数的字符串表示形式追加到此序列。
StringBuffer append(long lng)
将long 参数的字符串表示形式追加到此序列。
StringBuffer append(Object obj)
附加Object参数的字符串表示形式。
StringBuffer append(String str)
将指定的字符串追加到此字符序列。
StringBuffer append(StringBuffer sb)
将指定的内容附加StringBuffer到此序列。
StringBuffer appendCodePoint(int codePoint)
将codePoint参数的字符串表示形式追加到此序列。
int capacity()
返回当前容量。
char charAt(int index)
返回char指定索引处的此序列中的值。
int codePointAt(int index)
返回指定索引处的字符(Unicode代码点)。
int codePointBefore(int index)
返回指定索引之前的字符(Unicode代码点)。
int codePointCount(int beginIndex, int endIndex)
返回此序列的指定文本范围内的Unicode代码点数。
StringBuffer delete(int start, int end)
删除此序列的子字符串中的字符。
StringBuffer deleteCharAt(int index)
char按此顺序删除指定位置。
void ensureCapacity(int minimumCapacity)
确保容量至少等于指定的最小值。
void getChars(int srcBegin, int srcEnd, char[] dst, int dstBegin)
字符从此序列复制到目标字符数组中dst。
int indexOf(String str)
返回指定子字符串第一次出现的字符串中的索引。
int indexOf(String str, int fromIndex)
从指定的索引处开始,返回指定子字符串第一次出现的字符串中的索引。
StringBuffer insert(int offset, boolean b)
将boolea参数的字符串表示形式插入此序列中。
StringBuffer insert(int offset, char c)
将char参数的字符串表示形式插入此序列中。
StringBuffer insert(int offset, char[] str)
将char数组参数的字符串表示形式插入此序列中。
StringBuffer insert(int index, char[] str, int offset, int len)
将str数组参数的子数组的字符串表示形式插入到此序列中。
StringBuffer insert(int dstOffset, CharSequence s)
将指定的内容CharSequence插入此序列中。
StringBuffer insert(int dstOffset, CharSequence s, int start, int end)
将指定的子CharSequence序列插入此序列中。
StringBuffer insert(int offset, double d)
将double参数的字符串表示形式插入此序列中。
StringBuffer insert(int offset, float f)
将float参数的字符串表示形式插入此序列中。
StringBuffer insert(int offset, int i)
将第二个int 参数的字符串表示形式插入到此序列中。
StringBuffer insert(int offset, long l)
将long参数的字符串表示形式插入此序列中。
StringBuffer insert(int offset, Object obj)
将Object 参数的字符串表示形式插入此字符序列。
StringBuffer insert(int offset, String str)
将字符串插入此字符序列。
int lastIndexOf(String str)
返回指定子字符串最后一次出现在字符串中的索引。
int lastIndexOf(String str, int fromIndex)
返回指定子字符串最后一次出现在字符串中的索引。
int length()
返回该字符串的长度(字符数)。
int offsetByCodePoints(int index, int codePointOffset)
返回此序列中与代码点给定index的偏移量的索引codePointOffset。
StringBuffer replace(int start, int end, String str)
用指定的字符替换此序列的子字符串中的字符String。
StringBuffer reverse()
返回此字符序列的反向替换。
void setCharAt(int index, char ch)
指定索引处的字符设置为ch。
void setLength(int newLength)
设置字符序列的长度。
CharSequence subSequence(int start, int end)
返回一个新的字符序列,它是该序列的子序列。
String substring(int start)
返回一个新的String,包含此字符序列中当前包含的字符的子序列。
String substring(int start, int end)
返回一个新的String,包含此序列中当前包含的字符的子序列。
String toString()
返回表示此序列中数据的字符串。
void trimToSize()


四:String,StringBuilder,StringBuffer三者的区别(重点 )


1:定义声明上的区别


我们从定义上看



可以看到,只有String类型才可以直接声明创建,在静态数据存储区,而StringBuffer与StringBuilder只能通过new对象。


下面是一个继承关系图



2:结构上的区别

String是不可变字符串,而StringBuilder和StringBuffer是可变的。

去稍微看一下Stringl类的源码



摘录部分



public final class String
    implements java.io.Serializable, Comparable, CharSequence {
    /** The value is used for character storage. */
    private final char value[];}


类整体是被final关键字修饰的,这在一定程度上说明了该类是不可变的,是最终类,final修饰的方法同样是不可以改变的。private修饰的value更说明了value是不可以被访问到的。value只会在构造方法初始化,但是也没有提供可供修改value的方法,所以String类在结构上是不可变字符串。


在者,我们查看StringBuilder的相关源代码方法,StringBuilder可以动态变化的理由。


@Override
    public StringBuilder append(Object obj) {
        return append(String.valueOf(obj));
    }
    @Override
    @HotSpotIntrinsicCandidate
    public StringBuilder append(String str) {
        super.append(str);
        return this;
    }
    /**
     * Appends the specified {@code StringBuffer} to this sequence.
     * <p>
     * The characters of the {@code StringBuffer} argument are appended,
     * in order, to this sequence, increasing the
     * length of this sequence by the length of the argument.
     * If {@code sb} is {@code null}, then the four characters
     * {@code "null"} are appended to this sequence.
     * <p>
     * Let <i>n</i> be the length of this character sequence just prior to
     * execution of the {@code append} method. Then the character at index
     * <i>k</i> in the new character sequence is equal to the character at
     * index <i>k</i> in the old character sequence, if <i>k</i> is less than
     * <i>n</i>; otherwise, it is equal to the character at index <i>k-n</i>
     * in the argument {@code sb}.
     *
     * @param   sb   the {@code StringBuffer} to append.
     * @return  a reference to this object.
     */
    public StringBuilder append(StringBuffer sb) {
        super.append(sb);
        return this;
    }
    @Override
    public StringBuilder append(CharSequence s) {
        super.append(s);
        return this;
    }
    /**
     * @throws     IndexOutOfBoundsException {@inheritDoc}
     */
    @Override
    public StringBuilder append(CharSequence s, int start, int end) {
        super.append(s, start, end);
        return this;
    }
    @Override
    public StringBuilder append(char[] str) {
        super.append(str);
        return this;
    }
    /**
     * @throws IndexOutOfBoundsException {@inheritDoc}
     */
    @Override
    public StringBuilder append(char[] str, int offset, int len) {
        super.append(str, offset, len);
        return this;
    }
    @Override
    public StringBuilder append(boolean b) {
        super.append(b);
        return this;
    }
    @Override
    @HotSpotIntrinsicCandidate
    public StringBuilder append(char c) {
        super.append(c);
        return this;
    }
    @Override
    @HotSpotIntrinsicCandidate
    public StringBuilder append(int i) {
        super.append(i);
        return this;
    }
    @Override
    public StringBuilder append(long lng) {
        super.append(lng);
        return this;
    }
    @Override
    public StringBuilder append(float f) {
        super.append(f);
        return this;
    }
    @Override
    public StringBuilder append(double d) {
        super.append(d);
        return this;
    }
    /**
     * @since 1.5
     */
    @Override
    public StringBuilder appendCodePoint(int codePoint) {
        super.appendCodePoint(codePoint);
        return this;
    }
    /**


同理啊,我们也可以去研究查看StringBuffer的源代码


@Override
    public synchronized int codePointCount(int beginIndex, int endIndex) {
        return super.codePointCount(beginIndex, endIndex);
    }
    /**
     * @throws IndexOutOfBoundsException {@inheritDoc}
     * @since     1.5
     */
    @Override
    public synchronized int offsetByCodePoints(int index, int codePointOffset) {
        return super.offsetByCodePoints(index, codePointOffset);
    }
    /**
     * @throws IndexOutOfBoundsException {@inheritDoc}
     */
    @Override
    public synchronized void getChars(int srcBegin, int srcEnd, char[] dst,
                                      int dstBegin)
    {
        super.getChars(srcBegin, srcEnd, dst, dstBegin);
    }
    /**
     * @throws IndexOutOfBoundsException {@inheritDoc}
     * @see        #length()
     */
    @Override
    public synchronized void setCharAt(int index, char ch) {
        toStringCache = null;
        super.setCharAt(index, ch);
    }
    @Override
    public synchronized StringBuffer append(Object obj) {
        toStringCache = null;
        super.append(String.valueOf(obj));
        return this;
    }
    @Override
    @HotSpotIntrinsicCandidate
    public synchronized StringBuffer append(String str) {
        toStringCache = null;
        super.append(str);
        return this;
    }
    /**
     * Appends the specified {@code StringBuffer} to this sequence.
     * <p>
     * The characters of the {@code StringBuffer} argument are appended,
     * in order, to the contents of this {@code StringBuffer}, increasing the
     * length of this {@code StringBuffer} by the length of the argument.
     * If {@code sb} is {@code null}, then the four characters
     * {@code "null"} are appended to this {@code StringBuffer}.
     * <p>
     * Let <i>n</i> be the length of the old character sequence, the one
     * contained in the {@code StringBuffer} just prior to execution of the
     * {@code append} method. Then the character at index <i>k</i> in
     * the new character sequence is equal to the character at index <i>k</i>
     * in the old character sequence, if <i>k</i> is less than <i>n</i>;
     * otherwise, it is equal to the character at index <i>k-n</i> in the
     * argument {@code sb}.
     * <p>
     * This method synchronizes on {@code this}, the destination
     * object, but does not synchronize on the source ({@code sb}).
     *
     * @param   sb   the {@code StringBuffer} to append.
     * @return  a reference to this object.
     * @since 1.4
     */
    public synchronized StringBuffer append(StringBuffer sb) {
        toStringCache = null;
        super.append(sb);
        return this;
    }


synchronized 是锁我们后文继续研究。


3:线程安全上和性能上的区别

String是不可变的,char[]数组被final修饰,是不可变的。所以也就不存在线程不安全的问题。因为其不可变,所以当我们需要添加或者进行一系列相关的操作的时候就会显得很不方便

StringBuffer也是线程安全的,我们参考上述源码可以了解到,虽然SringBuffer是可以动态改变的,但是其内部添加了synchronized 。这就为其加了锁,这个锁的作用就是当一个线程在对StringBuffer进行操作的时候,另外一个线程是没有权力去操作的。一直到锁被释放掉才可以被使用。所以这个StringBuffer比较适合在多线程下使用。

所以



总结一下,String执行速度是最慢的,因为操作不是很方便,常常需要多次定义,但是线程比较安全,所以对于字符串比较少的,变化改动不是很大的进行操作。


StringBuffer执行速度比String要快,但是加了锁,加锁不可同时被多个线程操作,所以是比较安全,在多线程下操作比较适用。


StringBuilder是不安全的,没有加锁,对字符串的操作比较灵活。但是在多线程下是必定不安全的,所以适合在单线程下进行大量操作。


4:equals()方法上实现以及hashcode()的区别


String是实现了equals()和hashcode()方法的,StringBuilder和StringBuffer并没有实现。


equals()方法本来是用来比较地址的,但是String重写来该方法,使得可以进行对内容进行比较。


所以如果想要比较StringBuffer(),StringBuilder()的内容,可以先转换为String类型。

比如StringBuffer可以使用toString()方法进行转换为字符串String类型。


相关文章
|
11天前
|
Java 测试技术 开发者
Java零基础-indexOf(String str)详解!
【10月更文挑战第14天】Java零基础教学篇,手把手实践教学!
98 65
|
12天前
|
Java 测试技术 开发者
Java零基础-indexOf(String str)详解!
【10月更文挑战第13天】Java零基础教学篇,手把手实践教学!
33 1
|
16天前
|
安全 Java 测试技术
Java零基础-StringBuffer 类详解
【10月更文挑战第9天】Java零基础教学篇,手把手实践教学!
16 2
|
26天前
|
canal 安全 索引
(StringBuffer和StringBuilder)以及回文串,字符串经典习题
(StringBuffer和StringBuilder)以及回文串,字符串经典习题
33 5
|
26天前
|
存储 安全 Java
【一步一步了解Java系列】:认识String类
【一步一步了解Java系列】:认识String类
23 2
|
10天前
|
存储 安全 Java
String、StringBuffer 和 StringBuilder 的区别
【10月更文挑战第21天】String、StringBuffer 和 StringBuilder 都有各自的特点和适用场景。了解它们之间的区别,可以帮助我们在编程中更合理地选择和使用这些类,从而提高程序的性能和质量。还可以结合具体的代码示例和实际应用场景,进一步深入分析它们的性能差异和使用技巧,使对它们的理解更加全面和深入。
7 0
|
2月前
|
Java 索引
java基础(13)String类
本文介绍了Java中String类的多种操作方法,包括字符串拼接、获取长度、去除空格、替换、截取、分割、比较和查找字符等。
36 0
java基础(13)String类
|
19天前
|
Java
【编程基础知识】(讲解+示例实战)方法参数的传递机制(值传递及地址传递)以及String类的对象的不可变性
本文深入探讨了Java中方法参数的传递机制,包括值传递和引用传递的区别,以及String类对象的不可变性。通过详细讲解和示例代码,帮助读者理解参数传递的内部原理,并掌握在实际编程中正确处理参数传递的方法。关键词:Java, 方法参数传递, 值传递, 引用传递, String不可变性。
39 1
【编程基础知识】(讲解+示例实战)方法参数的传递机制(值传递及地址传递)以及String类的对象的不可变性
|
18天前
|
存储 安全 C++
【C++打怪之路Lv8】-- string类
【C++打怪之路Lv8】-- string类
17 1
|
22天前
|
数据可视化 Java
让星星月亮告诉你,通过反射创建类的实例对象,并通过Unsafe theUnsafe来修改实例对象的私有的String类型的成员属性的值
本文介绍了如何使用 Unsafe 类通过反射机制修改对象的私有属性值。主要包括: 1. 获取 Unsafe 的 theUnsafe 属性:通过反射获取 Unsafe类的私有静态属性theUnsafe,并放开其访问权限,以便后续操作 2. 利用反射创建 User 类的实例对象:通过反射创建User类的实例对象,并定义预期值 3. 利用反射获取实例对象的name属性并修改:通过反射获取 User类实例对象的私有属性name,使用 Unsafe`的compareAndSwapObject方法直接在内存地址上修改属性值 核心代码展示了详细的步骤和逻辑,确保了对私有属性的修改不受 JVM 访问权限的限制
48 4