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


目录
打赏
0
0
0
0
0
分享
相关文章
# 【Java全栈学习笔记-U1-day02】变量+数据类型+运算符
本篇笔记主要围绕Java全栈学习的第二天内容展开,涵盖了变量、数据类型、运算符以及Scanner类的应用。首先介绍了变量的概念与命名规范,以及如何定义和使用变量;接着详细讲解了Java中的基本数据类型,包括整型、浮点型、字符型、布尔型等,并通过实例演示了数据类型的运用。随后,深入探讨了各类运算符(赋值、算术、关系、逻辑)及其优先级,帮助理解表达式的构成。最后,介绍了如何利用Scanner类实现用户输入功能,并通过多个综合示例(如计算圆面积、购物打折、变量交换及银行利息计算)巩固所学知识。完成相关作业将进一步加深对这些基础概念的理解与实践能力。
27 12
|
23天前
|
《从头开始学java,一天一个知识点》之:字符串处理:String类的核心API
🌱 **《字符串处理:String类的核心API》一分钟速通!** 本文快速介绍Java中String类的3个高频API:`substring`、`indexOf`和`split`,并通过代码示例展示其用法。重点提示:`substring`的结束索引不包含该位置,`split`支持正则表达式。进一步探讨了String不可变性的高效设计原理及企业级编码规范,如避免使用`new String()`、拼接时使用`StringBuilder`等。最后通过互动解密游戏帮助读者巩固知识。 (上一篇:《多维数组与常见操作》 | 下一篇预告:《输入与输出:Scanner与System类》)
50 11
|
29天前
|
java变量与数据类型:整型、浮点型与字符类型
### Java数据类型全景表简介 本文详细介绍了Java的基本数据类型和引用数据类型,涵盖每种类型的存储空间、默认值、取值范围及使用场景。特别强调了`byte`、`int`、`long`、`float`、`double`等基本类型在不同应用场景中的选择与优化,如文件流处理、金融计算等。引用数据类型部分则解析了`String`、数组、类对象、接口和枚举的内存分配机制。
60 15
|
29天前
|
课时14:Java数据类型划分(初见String类)
课时14介绍Java数据类型,重点初见String类。通过三个范例讲解:观察String型变量、&quot;+&quot;操作符的使用问题及转义字符的应用。String不是基本数据类型而是引用类型,但使用方式类似基本类型。课程涵盖字符串连接、数学运算与字符串混合使用时的注意事项以及常用转义字符的用法。
如何配置 Java 环境变量:设置 JAVA_HOME 和 PATH
本文详细介绍如何在Windows和Linux/macOS系统上配置Java环境变量。
2548 12
Java 中的 String Pool 简介
本文介绍了 Java 中 String 对象及其存储机制 String Pool 的基本概念,包括字符串引用、构造方法中的内存分配、字符串文字与对象的区别、手工引用、垃圾清理、性能优化,以及 Java 9 中的压缩字符串特性。文章详细解析了 String 对象的初始化、内存使用及优化方法,帮助开发者更好地理解和使用 Java 中的字符串。
Java 中的 String Pool 简介
java 为什么 String 在 java 中是不可变的?
本文探讨了Java中String为何设计为不可变类型,从字符串池的高效利用、哈希码缓存、支持其他对象的安全使用、增强安全性以及线程安全等方面阐述了不可变性的优势。文中还通过具体代码示例解释了这些优点的实际应用。
java 为什么 String 在 java 中是不可变的?
Java 11 的String是如何优化存储的?
本文介绍了Java中字符串存储优化的原理和实现。通过判断字符串是否全为拉丁字符,使用`byte`代替`char`存储,以节省空间。具体实现涉及`compress`和`toBytes`方法,前者用于尝试压缩字符串,后者则按常规方式存储。代码示例展示了如何根据配置决定使用哪种存储方式。
100 1
|
5月前
|
在Java中如何将基本数据类型转换为String
在Java中,可使用多种方法将基本数据类型(如int、char等)转换为String:1. 使用String.valueOf()方法;2. 利用+运算符与空字符串连接;3. 对于数字类型,也可使用Integer.toString()等特定类型的方法。这些方法简单高效,适用于不同场景。
198 7
课时44:String类对象两种实例化方式比较
本次课程的主要讨论了两种处理模式在Java程序中的应用,直接赋值和构造方法实例化。此外,还讨论了字符串池的概念,指出在Java程序的底层,DOM提供了专门的字符串池,用于存储和查找字符串。 1.直接赋值的对象化模式 2.字符串池的概念 3.构造方法实例化
AI助理

你好,我是AI助理

可以解答问题、推荐解决方案等