GVKun编程网logo

JAVA 面试题 StringBuffer 和 StringBuilder 的区别,从源码角度分析?(java中stringbuilder和stringbuffer的区别)

2

对于JAVA面试题StringBuffer和StringBuilder的区别,从源码角度分析?感兴趣的读者,本文将会是一篇不错的选择,我们将详细介绍java中stringbuilder和stringb

对于JAVA 面试题 StringBuffer 和 StringBuilder 的区别,从源码角度分析?感兴趣的读者,本文将会是一篇不错的选择,我们将详细介绍java中stringbuilder和stringbuffer的区别,并为您提供关于java - day009 - 基础API,object,String, StringBuilder/StringBuffer, 正则表达式、java - 工具类 - StringBuffer,StringBuilder、java --StringBuffer/StringBuilder、Java Review (二十、基础类库----常用类:Object、String、StringBuffer、StringBuilder、Math)的有用信息。

本文目录一览:

JAVA 面试题 StringBuffer 和 StringBuilder 的区别,从源码角度分析?(java中stringbuilder和stringbuffer的区别)

JAVA 面试题 StringBuffer 和 StringBuilder 的区别,从源码角度分析?(java中stringbuilder和stringbuffer的区别)

面试官 Q1:请问 StringBuffer 和 StringBuilder 有什么区别?

这是一个老生常谈的话题,笔者前几年每次面试都会被问到,作为基础面试题,被问到的概率百分之八九十。下面我们从面试需要答到的几个知识点来总结一下两者的区别有哪些?

  • 继承关系?

  • 如何实现的扩容?

  • 线程安全性?

 

继承关系

从源码上看看类 StringBuffer 和 StringBuilder 的继承结构:

 

从结构图上可以直到,StringBuffer 和 StringBuiler 都继承自 AbstractStringBuilder 类

 

如何实现扩容

StringBuffer 和 StringBuiler 的扩容的机制在抽象类 AbstractStringBuilder 中实现,当发现长度不够的时候 (默认长度是 16),会自动进行扩容工作,扩展为原数组长度的 2 倍加 2,创建一个新的数组,并将数组的数据复制到新数组。

public void ensureCapacity(int minimumCapacity) {
    if (minimumCapacity > 0)
        ensureCapacityInternal(minimumCapacity);
}

/**
* 确保value字符数组不会越界.重新new一个数组,引用指向value
*/    
private void ensureCapacityInternal(int minimumCapacity) {
    // overflow-conscious code
    if (minimumCapacity - value.length > 0) {
        value = Arrays.copyOf(value,
                newCapacity(minimumCapacity));
    }
}

/**
* 扩容:将长度扩展到之前大小的2倍+2
*/    
private int newCapacity(int minCapacity) {
    // overflow-conscious code   扩大2倍+2
    //这里可能会溢出,溢出后是负数哈,注意
    int newCapacity = (value.length << 1) + 2;
    if (newCapacity - minCapacity < 0) {
        newCapacity = minCapacity;
    }
    //MAX_ARRAY_SIZE的值是Integer.MAX_VALUE - 8,先判断一下预期容量(newCapacity)是否在0<x<MAX_ARRAY_SIZE之间,在这区间内就直接将数值返回,不在这区间就去判断一下是否溢出
    return (newCapacity <= 0 || MAX_ARRAY_SIZE - newCapacity < 0)
        ? hugeCapacity(minCapacity)
        : newCapacity;
}

/**
* 判断大小,是否溢出
*/
private int hugeCapacity(int minCapacity) {
    if (Integer.MAX_VALUE - minCapacity < 0) { // overflow
        throw new OutOfMemoryError();
    }
    return (minCapacity > MAX_ARRAY_SIZE)
        ? minCapacity : MAX_ARRAY_SIZE;
}

 

线程安全性

我们先来看看 StringBuffer 的相关方法:

@Override
public synchronized StringBuffer append(long lng) {
    toStringCache = null;
    super.append(lng);
    return this;
}

/**
 * @throws StringIndexOutOfBoundsException {@inheritDoc}
 * @since      1.2
 */
@Override
public synchronized StringBuffer replace(int start, int end, String str) {
    toStringCache = null;
    super.replace(start, end, str);
    return this;
}

/**
 * @throws StringIndexOutOfBoundsException {@inheritDoc}
 * @since      1.2
 */
@Override
public synchronized String substring(int start) {
    return substring(start, count);
}

@Override
public synchronized String toString() {
    if (toStringCache == null) {
        toStringCache = Arrays.copyOfRange(value, 0, count);
    }
    return new String(toStringCache, true);
}

从上面的源码中我们看到几乎都是所有方法都加了 synchronized, 几乎都是调用的父类的方法.,用 synchronized 关键字修饰意味着什么?加锁,资源同步串行化处理,所以是线程安全的。

 

我们再来看看 StringBuilder 的相关源码:

@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;
}

/**
 * @throws StringIndexOutOfBoundsException {@inheritDoc}
 */
@Override
public StringBuilder delete(int start, int end) {
    super.delete(start, end);
    return this;
}

StringBuilder 的源码里面,基本上所有方法都没有用 synchronized 关键字修饰,当多线程访问时,就会出现线程安全性问题。

 

为了证明 StringBuffer 线程安全,StringBuilder 线程不安全,我们通过一段代码进行验证:

测试思想

  • 分别用 1000 个线程写 StringBuffer 和 StringBuilder,

  • 使用 CountDownLatch 保证在各自 1000 个线程执行完之后才打印 StringBuffer 和 StringBuilder 长度,

  • 观察结果。

测试代码

import java.util.concurrent.CountDownLatch;

public class TestStringBuilderAndStringBuffer {
    public static void main(String[] args) {
        //证明StringBuffer线程安全,StringBuilder线程不安全
        StringBuffer stringBuffer = new StringBuffer();
        StringBuilder stringBuilder = new StringBuilder();
        CountDownLatch latch1 = new CountDownLatch(1000);
        CountDownLatch latch2 = new CountDownLatch(1000);
        for (int i = 0; i < 1000; i++) {
            new Thread(new Runnable() {
                @Override
                public void run() {
                    try {
                        stringBuilder.append(1);
                    } catch (Exception e) {
                        e.printStackTrace();
                    } finally {
                        latch1.countDown();
                    }
                }
            }).start();
        }
        for (int i = 0; i < 1000; i++) {
            new Thread(new Runnable() {
                @Override
                public void run() {
                    try {
                        stringBuffer.append(1);
                    } catch (Exception e) {
                        e.printStackTrace();
                    } finally {
                        latch2.countDown();
                    }

                }
            }).start();
        }
        try {
            latch1.await();
            System.out.println(stringBuilder.length());
            latch2.await();
            System.out.println(stringBuffer.length());
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

测试结果

  • StringBuffer 不论运行多少次都是 1000 长度。

  • StringBuilder 绝大多数情况长度都会小于 1000。

  • StringBuffer 线程安全,StringBuilder 线程不安全得到证明。

总结一下

  • StringBuffer 和 StringBuilder 都继承自抽象类 AbstractStringBuilder。

  • 存储数据的字符数组也没有被 final 修饰,说明值可以改变,且构造出来的字符串还有空余位置拼接字符串,但是拼接下去肯定也有不够用的时候,这时候它们内部都提供了一个自动扩容机制,当发现长度不够的时候 (默认长度是 16),会自动进行扩容工作,扩展为原数组长度的 2 倍加 2,创建一个新的数组,并将数组的数据复制到新数组,所以对于拼接字符串效率要比 String 要高。自动扩容机制是在抽象类中实现的。

  • 线程安全性:StringBuffer 效率低,线程安全,因为 StringBuffer 中很多方法都被 synchronized 修饰了,多线程访问时,线程安全,但是效率低下,因为它有加锁和释放锁的过程。StringBuilder 效率高,但是线程是不安全的。

 

各位老铁如果还有别的答案,可以评论留言哈!

 

原文出处:https://www.cnblogs.com/marsitman/p/11204313.html

java - day009 - 基础API,object,String, StringBuilder/StringBuffer, 正则表达式

java - day009 - 基础API,object,String, StringBuilder/StringBuffer, 正则表达式

API

java.lang.object

object

所有类的顶层父类

一个类如果不继承其他类,默认继承object.

   toString() 获得一个对象的字符串表示 

   可以重写

   equals()

   当前对象与参数对象比较是否相等

   object 中默认实现是比较两个对象的内存地址.

   可以重写

 

java.lang.String

String 

   封装一个char[] 数组

   创建字符串对象

   char[] a = {''a'', ''b'',''c''};

   String s = new String(a);

 

  简化上面的语法

  String s = "abc";

 

  字符串的常量池

  第一次用到一个字符串的字面值 "abc"

  在 ''字符串常量池''中新建对象

  再次用到相同字面值时,访问''常量池''中已经存在的对象

 

  String s2 = new String("abc");

  // 这句代码创建了两个对象,第一个"abc"会在''常量池''中创建一个,new 

      也会在堆内存创建一个 s2 对象

 

 

   字符串长度不可变

   String s1 = "aaa";

   String s2 = "bbb";

   String s3 = "ccc";

   String  s4 = s1+s2+s3;

   字符串+链接会新建对象

   链接对此效率会低

   String s5 = "aaa"+"bbb"+"ccc";

   会进行编译器优化 String s5 = "aaabbbccc";

 

  字符串方法

 

  charAt(i); 获取指定位置的字符

 

  indexOf(子串); 查找子串的起始位置,

  String s1 = "abc abc";

  String s2 = "bc";

  s1.indexOf(s2) = 1;

 

  indexOf(子串,指定位置);从指定位置向后查找子串的起始位置

 

  lastIndexOf(子串);从后向前找

  

  查找位置找不到会返回 -1

 

  subString(start);截取从start 位置到末尾的子串

 

  subString(start,end);截取[start,end)

 

  trim();去除两端的空白字符,中间的不去除,返回一个新的字符串

 

  length();获取字符串长度

 

 

 

 

   

StringBuilder/StringBuffer

可变的字符序列,封装char[]

一般用来代替String ,做高效率的字符串链接

  append();

  用来做字符串内容的追加

  向内部数组放入新字符

  数组放满,会创建容量翻倍的新数组,内容拷贝

 

  String 和 StringBuilder 区别,不可变字符串和可变字符串的区别

 

  StringBuilder 和 StringBuffer 区别

  StringBuffer 是 旧版本的类,(jdk1.0),线程安全,效率低

  StringBuilder 是 jdk1.5才有的类, 线程不安全,效率高

  

 

正则表达式   Regex(Regular Expression)

   正确的字符串格式规则

   一般用来判断用户输入是否符合格式要求

   正则表达式是独立语法

 

正则表达式 匹配的字符串 k k abc abc [abc] a,b,c, 只能匹配单个字符 [abc][123] a1,a2,a3,b1,b2,b3,c1,c2,c3 [a-z] 匹配a~z [a-zA-Z_0-9] a,A,8,_ [^a-zA-Z] 排除a~z,A~Z,   7,%,$,_ [\u4e00-\u9fa5] 匹配中文 \d 数组 \D 排除数字 \w 单词字符[a-zA-Z_0-9] \W 排除单词字符 \s 空白字符 \S 排除空白字符   .  (点) 任意字符 [abc]? ?   0或者一个   a,b,不写  , c [abc]?[123] a1,b2,c3,1,2,3 [abc]* *   0到多个   ,a,  ,  abc,abbcc [abc]+ +  1到多个, a,abc,abbcc [abc]{3} 指定三个, abc,aab,bbb [abc]{3,5} 3到5个  abc,abbc,abbbb [abc]{3, } 至少三个  abc,acccccccc   |   或  (  )  \(   \)  括号转译

 

  

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

  Java 字符串的正则表达式匹配方法

  matches(正则表达式) ; 返回 bool

 

  replaceAll(正则表达式,子串);如果符合正则表达式,就替换成子串

 

  split(正则表达式); 用匹配的分隔字符,拆分字符串

  String s = "sdfsdfds,fsf,fdfsdf,ffs";

  String[] StrArr = s.split(",");  ["ffsfsf","fdsff","dsfds"]

 

  注意:

         输入反斜杠  "\"  输入  "\\" 

 

  

 

 

BigDecimal/BigInteger

 

Date

 

SimpleDateFormat

 

java - 工具类 - StringBuffer,StringBuilder

java - 工具类 - StringBuffer,StringBuilder

String可以像基本类型一样直接赋值,而且有不可变特性(长度内容不变),每次修改会重新生成新对象然后赋值,多次修改效率很低。

StringBuffer,StringBuilder,继承接口:Serializable,CharSequence,Appendable

String,继承了接口:Serializable,CharSequence,Comparable

 

所以StringBuffer比String少了 compareto方法,多了append方法。

compareto: 用来比较

append:用来拼接

 

StringBuffer: StringBuilder是他的进化版,和他用法区别不大更安全一些,相对的效率低一些。

本质也是char[],但是没有final修饰,所以可以动态扩容。

package stringtest;

public class StringBufferTest {
    public static void main(String[] args){

        //String中没有的方法:
        StringBuffer sb = new StringBuffer("abc");
        System.out.println(sb.append(1==1));//拼接,很多类型都可以包括boolean
        //abctrue
        System.out.println(sb.insert(2,"def"));//插入位置char[2],字段def,//abdefctrue   第二个字母后插入
        System.out.println(sb.delete(2,4));//删除范围[2-4)
        //abfctrue   ab|de|fctrue 删除了char[2],char[3]
        System.out.println(sb.deleteCharat(2));//删除char[2]
        //abctrue
        System.out.println(sb.reverse());//反转
        //eurtcba

        System.out.println(sb.capacity());//当前使用的容量:3 + 16 = 19 最开始定义时长度是3,只要不超过19就不会改变
        //StringBuffer 初始容量为定义字符串长度+16,用无参数构造函数则为16.
        sb.ensureCapacity(20);
        //确保能满足多大的空间,不够则扩容= =基本用不到。因为会自动扩容,不过可以用提前扩容来提高效率
        //每次扩容
        // 如果new > old * 2 + 2 则新容量为new
        // 如果new < old * 2 + 2 则新容量为  old * 2 + 2
        System.out.println(sb.capacity());//返回当前容量:19 * 2 + 2 = 40;

        sb.trimToSize();//去掉多余空间,只保留当前长度
        System.out.println(sb.capacity());
        //7  现在sb里是eurtcba,长度为7,所以只保留7
        sb.setLength(6);
        System.out.println(sb);
        System.out.println(sb.capacity());
        //eurtcb    长度变为6所以最后一个被删了
        //7         长度改变后,不超过容量就不会改变
        sb.setLength(8);
        System.out.println(sb + "!");
        System.out.println(sb.capacity());
        //eurtcb  !    长度变为8,后面的用空格补充了
        //16           长度>7,所以自动增长了7 * 2 + 2

        StringBuffer sbEfficiency1 = new StringBuffer("abc");
        StringBuffer sbEfficiency2 = new StringBuffer("abc");
        sbEfficiency2.ensureCapacity(200000000);//提前增加2000万
        System.out.println(sbEfficiency1.capacity());  //19
        System.out.println(sbEfficiency2.capacity()); // 50 > (3+16) * 2 + 2 所以新容量为50

        Long time1 = System.currentTimeMillis();//显示系统当前时间,进行运行效率比较。
        for(int i = 0; i < 1000000; i++) { //100万次
            sbEfficiency1.append("12345678901234567890");//添加了20个字符
        }
        Long time2 = System.currentTimeMillis();
        for(int i = 0; i < 1000000; i++) { //100万次
            sbEfficiency2.append("12345678901234567890");//添加了20个字符
        }
        Long time3 = System.currentTimeMillis();

        System.out.println(time2 - time1);
        System.out.println(time3 - time2);
        //第一次:
        //71
        //26
        //第二次:
        //61
        //26
        //第三次:
        //78
        //21
        //提前扩容速度明显要快一些


        //String中也有但是效果不同
        String a = "abcde";
        StringBuffer b = new StringBuffer("abcde");

        String s1 = a.substring(1,3);
        System.out.println(s1);
        String s2 = b.substring(1,3);//StringBuffer结束后返回的是String,效果一样
        System.out.println(s2);
        //bc
        //bc

    }
}

java --StringBuffer/StringBuilder

java --StringBuffer/StringBuilder

#1.StringBuffer
StringBuffer是一个字符串容器,它允许字符串改变长度。它是线程安全的

		StringBuffer sb = new StringBuffer();
		//1.字符串增改
		sb.append("panda").append("&").append("laoli");
		//2.指定索引位置插入元素
		sb.insert(5, "like");
		//3.反转
		StringBuffer sb2 = sb.reverse();

#2.StringBuilder
StringBuilder也是一个字符串容器,可以改变字符串的长度,它是线程不安全,但是效率比StringBuffer高。
#3.应用场景
String:在字符串不经常变化的场景中可以使用String类,例如变量的声明、少量运算等。
StringBuffer:需要频繁的进行字符串运算(例如:拼接、替换、删除等),并且运行在多线程环境中,可以考虑使用StringBuffer,例如xml解析、HTTP参数解析与封装等。
StringBuilder:需要频繁的进行字符串运算(例如:拼接、替换、删除等),并且运行在单线程环境中,可以考虑使用StringBuilder,例如SQL语句拼接、json封装等。

Java Review (二十、基础类库----常用类:Object、String、StringBuffer、StringBuilder、Math)

Java Review (二十、基础类库----常用类:Object、String、StringBuffer、StringBuilder、Math)

@

目录
  • Object 类
  • String 、 StringBuffer 和 StringBuilder 类
    • String类
    • StringBuilder、StringBuffer
  • Math 类


Object 类

Object 类是所有类、数组、枚举类的父类 ,也就是说, Java 允许把任何类型的对象赋给 Object 类型的变量 。 当定义一个类时没有使用 extends 关键字为它显式指定父类,则该类默认继承 Object 父类。

因为所有的 Java 类都是 Object 类的子类 , 所以任何 Java 对象都可以调用 Object 类的方法 。 Object类提供了如下几个常用方法 :

  • boolean equals(Object obj): 判断指定对象与该对象是否相等 。 此处相等的标准是 , 两个对象是同一个对象,因此该 equalsO方法通常没有太大的实用价值 。
  • protected void fmalize(): 当系统中没有引用变量引用到该对象时,垃圾回收器调用 此方法来清理该对象的资源 。
  • Class<?> getClass(): 返回该对象的运行时类。
  • int hashCode(): 返回该对象的 hashCode 值。在默认情况下, Object 类的 hashCode()方法根据该对象的地址来计算 但很多类都 重写了 Object 类的 hashCode()方法,不再根据地址来计算其 hashCode()方法值 。
  • String toString(): 返回 该对象 的 字符串表示 , 当程序用System.out.println()方法输出一个对象,或者把某个对象和字符串进行连接运算时,系统会自动调用该对象的 toString()方法返回该对象的字符串表示 。 Object 类的 toString()方法返回"运行时类名@十六进制 hashCode 值"格式的字符串 ,但很多类都重写了 Object 类 的 toString()方法,用于返回可以表述该对象信息的字符串。

除此之外 , Object 类还提供了 wai() 、 notify() 、 notifyAll()几个方法,通过这几个方法可以控制线程的暂停和运行。

Java 还提供了一个 protected 修饰的 clone()方法 , 该方法用于帮助其他对 象来实现"自我克隆",所谓"自我克隆"就是得到一个当前对象的副本,而且二者之间完全隔离。由于 Object 类提供的 clone()方法使用了 protected 修饰,因此该方法只能被子类重写或调用。


CloneTest.java

class Address {
	String detail;

	public Address(String detai1) {
		this.detail = detai1;
	}
}

// 实现 C1oneab1e 接口
class User implements Cloneable {
	int age;
	Address address;

	public User(int age) {
		this.age = age;
		address = new Address("广州天河 ");
	}

	// 通过调用 super.c1one ()来实现 c1one ()方法
	public User clone() throws CloneNotSupportedException {
		return (User) super.clone();
	}

}

public class CloneTest {
	public static void main(String[] args) throws CloneNotSupportedException {
		User u1 = new User(29);
		// clone 得到 u1对象的副本
		User u2 = u1.clone();
		// 判断 u1 、 u2 是否相同
		System.out.println(u1 == u2); // ①
		// 判断 u1 、 u2 的 address 是否相同
		System.out.println(u1.address == u2.address); // ②
	}

}

Object 类提供的 Clone机制只对对象里各实例变量进行"简单复制",如果实例变量的类型是引用类型, Object 的 Clone 机制也只是简单地复制这个引用变量,这样原有对象的引用类型的实例变量与克隆对象的引用类型的实例变量依然指向内存中的同一个实例,所以上面程序在②号代码处输出 true。上面程序"克隆 "出来的u1、u2 所指向的对 象在内存中的存储示意图如图所示 。


Object 类提供的克隆机制

在这里插入图片描述



API:java.lang.Object


String 、 StringBuffer 和 StringBuilder 类

字符串就是一连串的字符序 列, Java 提供 了 String 、 StringBuffer 和 StringBuilder 三个类来封装宇符串,并提供了 一系列方法来操作字符串对象 。

  • String 类是不可变类 ,即 一旦一个 String 对象被创建以后,包含在这个对象中的字符序列是不可改变的 , 直至这个对象被销毁。
  • StringBuffer 对 象 则代 表一个字符序列可变的 字符串 ,当 一个 StringBuffer 被创建以后,通过StringBuffer 提供的 append() 、 insert() 、 reverse() 、 setCharat() 、 setLength()等方法可以改变这个字符串对象的宇符序列。一旦通过 StringBuffer 生成了 最终想要的字符串,就可以调用它的 toStringO方法将其转换为一个 String 对象 。
  • StringBuilder 类是 JDK 1.5 新增的类 ,它也代表可变宇符串对象 。 实际上, StringBuilder 和 StringBuffer基本相似,两个类的构造器和方法也基本相同。不同的是 , StringBuffer 是线程安全的,而 StringBuilder则没有实现线程安全功能 ,所以性能略高。因此在通常情况下,如果需要创建一个内容可变的字符串对象, 则应该优先考虑使用 StringBuilder 类。

String类

String类提供了大量构造器来创建String对象,其中如下几个有特殊用途:

  • String():创建一个包含0个字符串序列的String对象(并不是返回null)。
  • String(byte[] bytes,Charset charset):使用指定的字符集将指定的byte[擞组解码成一个新的String 对象。
  • String(byte[] bytes,int offset,int length):使用平台的默认字符集将指定byte[]数组从ofifeet开始、长度为length的子数组解码成一个新的String对象。
  • String(byte[] bytes,int length,String charsetName):使用指定的字符集将指定的 byte[]数 组从offset开始、长度为length的子数组解码成一个新的String对象。
  • String(byte[] bytes,String charsetName):使用指定的字符集将指定的byte[]数组解码成一个新的 String 对象。
  • String(char[] value,int count):将指定的字符数组从offset开始、长度为count的字符元 素连缀成字符串。
  • String(String original):根据字符串直接量来创建一个String对象。也就是说,新创建的String 对象是该参数字符串的副本。
  • String(StringBuffer buffer):根据 StringBuffer 对象来创建对应的 String 对象。
  • String(StringBuilder builder):根据 StringBuilder 对象来创建对应的 String 对象。

String 类也提供了大量方法来操作字符串对象:
  • char charat(int index): 获取字符串中指定位置的字符。其中 , 参数 index 指 的是字符串的序数,字符串的序数从 0 开始到 length()-l 。 如下代码所示:
String s = new String("fkit.org");
System .out. println("s.charat(5): "+ s.charat(5) );

结果为:

s . charat(5) : 0
  • int compareto(String anotherString): 比较两个宇符串的大小 。 如果两个字符串的字符序列相等,则返回 0; 不相等时,从两个字符串第 0 个字符开始比较,返回第一个不相等的字符差。另一种情况,较长字符串的前面部分恰巧是较短的字符串,则返回它们的长度差。
String s1 = new String( "abcdefghijklmn");
String s2 = new String( "abcdefghij ");
String s3 = new String( "abcdefghijalmn") ;
System.out .println( "sl. compareto(s2) : " + sl. compareto(s2) ) ; //返回长度差
System.out.println( "sl. compareto (s3): " + sl. compareto(s3) ) ; //返回 'k'-'a' 的差

结果为 :

s1.compareto(s2): 4
s1.compareto(s3) : 10
  • String concat(String s):将该 String 对象与调用对象连接在一起。与 Java 提供的字符串连接运算符" +"的功能相同。
  • boolean contentEquals(StringBuffer sb): 将该 String 对象与 StringBuffer 对象 sb 进行比较,当它们包含的字符序列相同时返回 true 。
  • static String copyValueOf(char[] data): 将字符数组连缀成字符串,与 String(char[] content)构造器的功能相同 。
  • static String copyValueOf(char[] data,int count): 将 char 数组的子数组中的元素连缀成字符串,与 String(char[] value,int count)构造器的功能相同 。
  • boolean endsWith(String suffix): 返回该 String 对象是否以 suffix 结尾 。
String s1 = "fkit. org"; String s2 = ". org";
System.out .println("s1 .endsWith(s2): " + s1.endsWith(s2) );

结果为:

s1 .endsWith(s2): true
  • boolean equals(Object anObject): 将该字符串与指定对象比较,如果二者包含的字符序列相等,则返回 true; 否则返回 false 。
  • boolean equalsIgnoreCase(String s):与前 一个方法基本相似,只是忽略字符的大小写 。
  • byte[] getBytes(): 将 该 String 对象转换成 byte 数组 。
  • void getChars(int srcBegin,int srcEnd,char[] dst,int dstBegin): 该方法将字符串中从 srcBegin 开始,到 srcEnd 结束的字符复制到 dst 字符数组中,其中 dstBegin 为目标字符数组的起始复制位置。
char[] s1 = {'I',' ',' l',' o',' v',' e ','j',' a',' v ',' a'); // s1=1 love_java
String s2 = new String( "ejb");
s2 .getChars(0,3,s1,7); // s1=I love java
System.out . println ( s1 );

结果为:

I love java
  • int indexOf(int ch): 找出 ch 字符在该字符串中第一次 出现的位置 。
  • int indexOf(int ch,int fromIndex): 找出 ch 字符在该字符串中从企fromIndex 开始后第一 次出现的位置。
  • int indexOf(String s):找出 str 子字符串在该宇符串中第 一次出现的位置 。
  • int indexOf(String s, int fromIndex): 找出 s位子字符串在该字符串中从 fromIndex 开始后第一次出现的位置。
String s = "www.fkit .org"; String ss = "it ";
System. out .print1n( "s.indexOf( ' r ' ): " + s .indexOf( ' r ') );
System .out.print1n( "s . indexOf( ' r ',2) : " + s.indexOf('r ',2) );
System.out.print1n( " s . indexOf(ss): " + s.indexOf(ss)) ;

结果为:

s .indexOf( 'r'): 10
s . indexOf (' r ',2) : 10
s . indexOf (ss) : 6
  • int lastIndexOf(int ch): 找出 ch 字符在该字符串中最后一次出现的位置。
  • int lastIndexOf(int ch,int fromIndex): 找出 ch 字符在该字符串 中从 fromIndex 开始后最后一次出现的位置 。
  • int lastIndexOf(String str):找出 str子字符串在该字符串中最后 一次 出现的位置 。
  • int lastIndexOf(String str, int fromIndex): 找出 str 子字符串在该字符串中从 台fromlndex 开始后最后一次出现的位置 。
  • int length(): 返回当前字符串长度。
  • String replace(char oldChar,char newChar): 将字符串中的第一个 oldChar 替换成 newChar 。
  • boolean startsWith(String prefix): 该 String 对象是否以 prefix 开始。
  • boolean startsWith(String prefix , int toffset): 该 String 对象从 toffset 位置算起,是否以 prefix 开始。
String s = "www . fki t .org"; String ss = "www"; String sss = "fkit ";
System.out .print1n("s.startsWith (ss): " + s.startsWith(ss) );
System.out .print1n( "s.startsWith(sss,4): " + s.startsWith (sss,4));

结果为 :

s .startsWith(ss) : true
s.startsWith(sss,4): true
  • String substring(int beginlndex): 获取从 beginlndex 位置开始到结束的子字符串。
  • String substring(int beginlndex,int endindex): 获取从 beginIndex 位置开始到 endlndex 位置的子字符串。
  • char[] tochararray(): 将该 String 对象转换成 char 数组。
  • String toLowerCase(): 将字符串转换成小写。
  • String toupperCase(): 将字符串转换成大写。
String s = "fkjava.org ";
System.out.print1n( "s.toupperCase() : " + s . toupperCase()) ;
System.out.print1n( "s.toLowerCase(): " + s.toLowerCase()) ;

结果为 :

s . toupperCase() : FKJAVA .ORG
s.toLowerCase() : fkjava .org
  • static String valueOf(X x): 一系列用于将基本类型值转换为 String 对象的方法 。

String 类是不可变的, String类的实例一旦生成就不会再改变了。

例如如下代码:

String str1 = "java";
str1 = str1 + "struts ";
str1 = str1 + " spring";

上面程序除使用了 3 个字符串直接量之外,还会额外生成 2 个字符串直接量一一 "java"和 "struts"连接生成的 "javastruts" , 接着 "javastruts"与 "spring"连接生成 的 "javastrutsspring" , 程序中 的 strl 依次指向 3个不同的字符串对象。

字符串存储

对于不同版本的JDK,String类在内存中有不同的优化方式。具体来说,早期JDK版本的String总是以char[]存储,它的定义如下:

public final class String {
    private final char[] value;
    private final int offset;
    private final int count;
}

而较新的JDK版本的String则以byte[]存储:如果String仅包含ASCII字符,则每个byte存储一个字符,否则,每两个byte存储一个字符,这样做的目的是为了节省内存,因为大量的长度较短的String通常仅包含ASCII字符:

public final class String {
    private final byte[] value;
    private final byte coder; // 0 = latin1,1 = UTF16
}

API:java.lang.String

StringBuilder、StringBuffer

为了能高效拼接字符串,Java标准库提供了StringBuilder,它是一个可变对象,可以预分配缓冲区,这样,往StringBuilder中新增字符时,不会创建新的临时对象:

StringBuilder sb = new StringBuilder(1024);
for (int i = 0; i < 1000; i++) {
    sb.append(',');
    sb.append(i);
}
String s = sb.toString();

StringBuilder 提供了一系列插入、追加、改变该字符串里包含 的 字符序 列的方法 。 而 StringBuffer与其用法完全相同,只是 StringBuffer 是线程安全 的 。

StringBuilder 、 StringBuffer 有两个属性 : length 和 capacity , 其中 length 属性表示其包含的字符序列的长度。与 String 对象的 length 不同的 是:StringBuilder、 StringBuffer 的 length 是可以改变的,可以通过 length()、 setLength(int len)方法来访 问和修改其字符序列的长度。 capacity 属性表示 StringBuilder的容量, capacity 通常比 length 大,程序通常无须关心 capacity 属性。 如下程序示范了 StringBuilder 类的用法:

StringBuilderTest.java

public class StringBuilderTest {
	public static void main(String[] args) {
		StringBuilder sb = new StringBuilder(); 
	    // 追加字符串 
	    sb.append("java");//sb = "java" 
	    // 插入 
	    sb.insert(0,"hello "); // sb="hello java" 
	    // 替换 
	    sb.replace(5,6,","); // sb="hello,java" 
	    System.out.println(sb); 
	    // 删除 
	    sb.delete(5,6); // sb="hellojava" 
	    System.out.println(sb); 
	    // 反转 
	    sb.reverse(); // sb="avajolleh" 
	    System.out.println(sb); 
	    System.out.println(sb.length()); // 输出9 
	    System.out.println(sb.capacity()); // 输出16 
	    // 改变StringBuilder的长度,将只保留前面部分 
	    sb.setLength(5); // sb="avajo" 
	    System.out.println(sb); 
	  
	}
}

API:java.lang.StringBuilder

API:java.lang.StringBuffer


Math 类

Java 提供了基本的+、一、 *、 /、%等基本算术运算的运算符,但对于更复杂的数学运算 ,例如,三角函数、对数运算、指数运算等则无能为力 。 Java 提供了 Math 工具类来完成这些复杂的运算, Math类是一个工具类,它的构造器被定义成 private 的, 因此无法创建 Math 类的对象 ; Math 类中的所有方法都是类方法,可以直接通过类名来调用它 们 。 Math 类除提供 了大量静态方法之外,还提供了两个类变量 : PI 和 E , 正如它们名 字所暗示的,它们的值分别等于π平日 e 。

下面程序示范了 Math 类 的用法 。


MathTes.java

public class MathTest {
	public static void main(String[] args) {
		/* ------下面是三角运算-------- */
		// 将弧度转换成角度
		System.out.println(" Math.todegrees(1.57): " + Math.todegrees(1.57));
		// 将角 度转换为弧度
		System.out.println(" Math.toradians (90): " + Math.toradians(90));
		// 计算反余弦,返回的角度范围在 0 . 0 到 pi 之间
		System.out.println(" Math . acos(1 . 2): " + Math.acos(1.2));
		// 计算反正弦,返回的角度范围在 -p工 /2 到 pi/2 之间
		System.out.println(" Math.as 工 n(0.8 ): " + Math.asin(0.8));
		// 计算反正切,返回的角度范围在 -pi/2 到 pi /2 之间
		System.out.println("Math . atan(2.3): " + Math.atan(2.3));
		// 计算三角余弦
		System.out.println("Math . cos(1 . 57): " + Math.cos(1.57));
		// 计算双 曲余弦
		System.out.println(" Math . cosh(1 . 2 ): " + Math.cosh(1.2));
		// 计算正弦
		System.out.println(" Math.sin(1.57 ): " + Math.sin(1.57));
		// 计算双曲正弦
		System.out.println(" Math . sinh(1 . 2 ): " + Math.sinh(1.2));
		// 计算三角正切
		System.out.println("Math . tan(0 . 8 ): " + Math.tan(0.8));
		// 计算双曲正切
		System.out.println("Math . tanh(2 . 1 ): " + Math.tanh(2.1));

		// 将矩形坐标 (x , y) 转换成极坐标 (r , thet))
		System.out.println("Math . atan2(0.1,0 . 2): " + Math.atan2(0.1,0.2));

		/* -----下面是取整运算 -------- */
		// 取整 ,返回小于目标数的最大整数
		System.out.println("Math.floor( - 1 . 2 ): " + Math.floor(-1.2));
		// 取整 ,返回大于目标数的最小整数
		System.out.println("Math.ceil(I.2) : " + Math.ceil(1.2));
		// 四舍五入取整
		System.out.println("Math . round(2.3 ) : " + Math.round(2.3));
		/*------下面是乘方、开方、指数运算-----*/
		// 计算平方根
		System.out.println("Math . sqrt(2.3 ): " + Math.sqrt(2.3));
		// 计算立方根
		System.out.println("Math . cbrt(9 ): " + Math.cbrt(9));
		// 返回欧拉数 e 的 n 次幕
		System.out.println("Math .exp(2 ): " + Math.exp(2));
		// 返回 sqrt(x2 +y2) ,没有中间溢出或下溢
		System.out.println("Math.hypot (4,4 ): " + Math.hypot(4,4));
		// 按照 IEEE 754 标准的规定,对两个参数进行余数运算
		System.out.println("Math . IEEEremainder(5,2): " + Math.IEEEremainder(5,2));
		// 计算乘方
		System.out.println("Math .pow (3,2 ): " + Math.pow(3,2));
		// 计算自然对数
		System.out.println(" Math.log(12 ): " + Math.log(12));
		// 计算底数为 10 的对数
		System.out.println("Math . logl0 ( 9) : " + Math.log10(9));
		// 返回参数与 1 之和的自然对数
		System.out.println("Math.loglp ( 9) : " + Math.log10(9));
		/*------下面是符号相关的运算 ----------*/
		// 计算绝对值
		System.out.println(" Math . abs(-4.5): " + Math.abs(-4.5));
		// 符号赋值 ,返回带有第二个浮点数符号的第一个浮点参数
		System.out.println("Math . copySign(I.2,-1 . 0) : " + Math.copySign(1.2,-1.0));
		// 符号 函数,如果参数为 0 ,则返回 0: 如果参数大于 0
		// 则返回1. 0 ; 如果参数小于 0 ,则返回 - 1. 0
		System.out.println(" Math . sig口 um (2. 3): " + Math.signum(2.3));
		/*-----下面是大小相关的运算----- */
		// 找出最大值
		System.out.println("Math.max(2 . 3,4.5) : " + Math.max(2.3,4.5));
		// 计算最小值
		System.out.println("Math . min(I . 2,3 . 4) : " + Math.min(1.2,3.4));

		// 返回第 一个参数和第二个参数之间与第一个参数相邻的浮点数
		System.out.println("Math.nextAfter(l . 2,1.0) :" + Math.nextAfter(1.2,1.0));
		// 返回比目标数略大的浮点数
		System.out.println("Math . nextUp(l . 2 ): " + Math.nextUp(1.2));
		// 返回 一个伪随机数,该值大于等于 0 . 0 且小于1. 0
		System.out.println("Math. randorn (): " + Math.random());
	}

}

API:java.lang.Math





参考:

【1】:《疯狂Java讲义》
【2】:https://www.liaoxuefeng.com/wiki/1252599548343744/1260469698963456

今天关于JAVA 面试题 StringBuffer 和 StringBuilder 的区别,从源码角度分析?java中stringbuilder和stringbuffer的区别的讲解已经结束,谢谢您的阅读,如果想了解更多关于java - day009 - 基础API,object,String, StringBuilder/StringBuffer, 正则表达式、java - 工具类 - StringBuffer,StringBuilder、java --StringBuffer/StringBuilder、Java Review (二十、基础类库----常用类:Object、String、StringBuffer、StringBuilder、Math)的相关知识,请在本站搜索。

本文标签: