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类型。


相关文章
|
2月前
|
存储 Oracle Java
java零基础学习者入门课程
本课程为Java零基础入门教程,涵盖环境搭建、变量、运算符、条件循环、数组及面向对象基础,每讲配示例代码与实践建议,助你循序渐进掌握核心知识,轻松迈入Java编程世界。
316 0
|
3月前
|
Java
java入门代码示例
本文介绍Java入门基础,包含Hello World、变量类型、条件判断、循环及方法定义等核心语法示例,帮助初学者快速掌握Java编程基本结构与逻辑。
424 0
|
3月前
|
前端开发 Java 数据库连接
帮助新手快速上手的 JAVA 学习路线最详细版涵盖从入门到进阶的 JAVA 学习路线
本Java学习路线涵盖从基础语法、面向对象、异常处理到高级框架、微服务、JVM调优等内容,适合新手入门到进阶,助力掌握企业级开发技能,快速成为合格Java开发者。
573 3
|
3月前
|
Java API 数据库
2025 年最新 Java 实操学习路线,从入门到高级应用详细指南
2025年Java最新实操学习路线,涵盖从环境搭建到微服务、容器化部署的全流程实战内容,助你掌握Java 21核心特性、Spring Boot 3.2开发、云原生与微服务架构,提升企业级项目开发能力,适合从入门到高级应用的学习需求。
794 0
|
3月前
|
监控 Java API
2025 年全新出炉的 Java 学习路线:从入门起步到实操精通的详细指南
2025年Java学习路线与实操指南,涵盖Java 21核心特性、虚拟线程、Spring Boot 3、微服务、Spring Security、容器化部署等前沿技术,助你从入门到企业级开发进阶。
847 0
|
2月前
|
编解码 Java 开发者
Java String类的关键方法总结
以上总结了Java `String` 类最常见和重要功能性方法。每种操作都对应着日常编程任务,并且理解每种操作如何影响及处理 `Strings` 对于任何使用 Java 的开发者来说都至关重要。
317 5
|
6月前
|
存储 编译器 C语言
关于string的‘\0‘与string,vector构造特点,反迭代器与迭代器类等的讨论
你真的了解string的'\0'么?你知道创建一个string a("abcddddddddddddddddddddddddd", 16);这样的string对象要创建多少个对象么?你知道string与vector进行扩容时进行了怎么的操作么?你知道怎么求Vector 最大 最小值 索引 位置么?
177 0
|
9月前
|
缓存 安全 Java
《从头开始学java,一天一个知识点》之:字符串处理:String类的核心API
🌱 **《字符串处理:String类的核心API》一分钟速通!** 本文快速介绍Java中String类的3个高频API:`substring`、`indexOf`和`split`,并通过代码示例展示其用法。重点提示:`substring`的结束索引不包含该位置,`split`支持正则表达式。进一步探讨了String不可变性的高效设计原理及企业级编码规范,如避免使用`new String()`、拼接时使用`StringBuilder`等。最后通过互动解密游戏帮助读者巩固知识。 (上一篇:《多维数组与常见操作》 | 下一篇预告:《输入与输出:Scanner与System类》)
267 11
|
9月前
|
Java
课时14:Java数据类型划分(初见String类)
课时14介绍Java数据类型,重点初见String类。通过三个范例讲解:观察String型变量、&quot;+&quot;操作符的使用问题及转义字符的应用。String不是基本数据类型而是引用类型,但使用方式类似基本类型。课程涵盖字符串连接、数学运算与字符串混合使用时的注意事项以及常用转义字符的用法。
292 9