String,StringBuilder,StringBuffer三者的区别
1.首先说运行速度,或者说是执行速度
在这方面运行速度快慢为:StringBuilder > StringBuffer > String
String最慢的原因:
String的值是不可变的,这就导致每次对String的操作都会生成新的String对象,这样不仅效率低下,而且大量浪费有限的内存空间。
String为字符串常量,而StringBuilder和StringBuffer均为字符串变量,即String对象一旦创建之后该对象是不可更改的,但后两者的对象是变量,是可以更改的。
2. 再来说线程安全
StringBuilder 类在 Java 5 中被提出,它和 StringBuffer 之间的最大不同在于 StringBuilder 的方法不是线程安全的(不能同步访问)。
由于 StringBuilder 相较于 StringBuffer 有速度优势,所以多数情况下建议使用 StringBuilder 类。然而在应用程序要求线程安全的情况下,则必须使用 StringBuffer 类。
3. 总结一下
String:适用于少量的字符串操作的情况
StringBuilder:适用于单线程下在字符缓冲区进行大量操作的情况
StringBuffer:适用多线程下在字符缓冲区进行大量操作的情况
一、String
String类的常见操作
特别要注意的是,String类的所有方法都没有改变字符串本身的值,都是返回了一个新的对象。
字符串常量池
String cmower = "沉默王二"; String cmower1 = "沉默王二"; System.out.println(cmower == cmower1); // 输出true String cmowsan = new String("沉默王三"); String cmowsan1 = new String("沉默王三"); System.out.println(cmowsan == cmowsan1); // 输出false
双引号创建的相同字符串使用==
判断时结果为true,而new关键字创建的相同字符串使用==
判断时结果为false。
这是为什么呢?
String在Java中使用过于频繁,为了避免在系统中产生大量的String对象,Java的设计者引入了“字符串常量池”的概念。
当使用双引号创建一个字符串时,首先会检查字符串常量池中是否有相同的字符串对象,如果有,则直接从常量池中取出对象引用;如果没有,则新建字符串对象,并将其放入字符串常量池中,并返回对象引用。
这也就是说,"沉默王二"是放在字符串常量池中的,cmower和cmower1两个字符串对象引用是相同的。
而new关键字创建的字符串对象是不涉及字符串常量池的,直接放在堆中,也就是说,虽然cmowsan和cmowsan1都叫沉默王三,但不一个人。
强烈建议:不要使用new关键字的形式创建字符串对象。
二、StringBuffer
三、StringBuilder
由于字符串是不可变的,因此字符串在进行拼接的时候会创建新的字符串对象。大家都知道,内存是一定的,因此对象创建多了就会影响系统性能。
StringBuilder正是为了解决字符串拼接产生太多中间对象的问题而提供的一个类,可以通过append()方法把字符串添加到已有序列的末尾,非常高效。
强烈建议:如果只是三四个字符串的拼接,尽管使用+号操作符,别想什么性能优化(举个例子,你离目的地只有100米,你是打算打个出租车,还是自己步行走过去?);如果遇到多于四个字符串的拼接,或者需要用到循环来拼接,那就选择StringBuilder。
关于StringUtils
字符串的操作往往需要用到一个工具类,那就是org.apache.commons.lang3.StringUtils
(null安全的,也就是说,StringUtils类的方法可以接受为null的字符串,但不会抛出NullPointerException)。
System类
Runtime
Math
Random
包装类
可以将基本数据类型的值包装为引用数据类型的对象。
Date、Calendar、DateFormat
Date类
import java.util.Date ; public class DateDemo01{ public static void main(String args[]){ Date date = new Date() ; // 直接实例化Date对象 System.out.println("当前日期为:" + date) ; } };
Calendar(弥补Date类的设计缺陷)
import java.util.* ; public class DateDemo02{ public static void main(String args[]){ Calendar calendar = new GregorianCalendar(); // 实例化Calendar类对象 System.out.println("YEAR: " + calendar.get(Calendar.YEAR)); System.out.println("MONTH: " + (calendar.get(Calendar.MONTH) + 1)); System.out.println("DAY_OF_MONTH: " + calendar.get(Calendar.DAY_OF_MONTH)); System.out.println("HOUR_OF_DAY: " + calendar.get(Calendar.HOUR_OF_DAY)); System.out.println("MINUTE: " + calendar.get(Calendar.MINUTE)); System.out.println("SECOND: " + calendar.get(Calendar.SECOND)); System.out.println("MILLISECOND: " + calendar.get(Calendar.MILLISECOND)); } };
DateFormat类
import java.text.DateFormat ; import java.util.Date ; public class DateDemo03{ public static void main(String args[]){ DateFormat df1 = null ; // 声明一个DateFormat DateFormat df2 = null ; // 声明一个DateFormat df1 = DateFormat.getDateInstance() ; // 得到日期的DateFormat对象 df2 = DateFormat.getDateTimeInstance() ; // 得到日期时间的DateFormat对象 System.out.println("DATE:" + df1.format(new Date())) ; // 按照日期格式化 System.out.println("DATETIME:" + df2.format(new Date())) ; // 按照日期时间格式化 } }
import java.text.DateFormat ; import java.util.Date ; import java.util.Locale ; public class DateDemo04{ public static void main(String args[]){ DateFormat df1 = null ; // 声明一个DateFormat DateFormat df2 = null ; // 声明一个DateFormat df1 = DateFormat.getDateInstance(DateFormat.YEAR_FIELD,new Locale("zh","CN")) ; // 得到日期的DateFormat对象 df2 = DateFormat.getDateTimeInstance(DateFormat.YEAR_FIELD,DateFormat.ERA_FIELD,new Locale("zh","CN")) ; // 得到日期时间的DateFormat对象 System.out.println("DATE:" + df1.format(new Date())) ; // 按照日期格式化 System.out.println("DATETIME:" + df2.format(new Date())) ; // 按照日期时间格式化 } };
SimpleDateFormat类
import java.text.* ; import java.util.* ; public class DateDemo05{ public static void main(String args[]){ String strDate = "2008-10-19 10:11:30.345" ; // 准备第一个模板,从字符串中提取出日期数字 String pat1 = "yyyy-MM-dd HH:mm:ss.SSS" ; // 准备第二个模板,将提取后的日期数字变为指定的格式 String pat2 = "yyyy年MM月dd日 HH时mm分ss秒SSS毫秒" ; SimpleDateFormat sdf1 = new SimpleDateFormat(pat1) ; // 实例化模板对象 SimpleDateFormat sdf2 = new SimpleDateFormat(pat2) ; // 实例化模板对象 Date d = null ; try{ d = sdf1.parse(strDate) ; // 将给定的字符串中的日期提取出来 }catch(Exception e){ // 如果提供的字符串格式有错误,则进行异常处理 e.printStackTrace() ; // 打印异常信息 } System.out.println(sdf2.format(d)) ; // 将日期变为新的格式 } };
Equals和==的区别
关于变量之间的比较,可以分为基础类型变量的比较和对象之间的比较。
对于基本类型来说,他们存储在jvm的栈中,因此比较的是变量的内容,也就是比较的变量的值。
对于引用类型来说,因为对象内容存储在jvm的堆中,栈中只是存储对象的引用(地址),无论是==还是equals比较的都是栈中的内容,即对象的引用,也就是比较的是两个对象的地址。
但根据创建对象的方式不同可以分为两种情况:
1. 使用表达式创建对象:
2.使用new方法创建对象:
这里会引入两个新的问题:
1.为什么表达式创建和new创建,会让==比较产生不同的结果。
这是因为jvm在程序运行的时候会创建一个缓冲池,当使用表达式创建的时候,程序会在缓冲池中寻找相同值的对象,如果找到,就把这个对象的地址赋给当前创 建的对象,因此,c和d实际上都指向了c的引用。因此在使用==时会返回true。
当用new创建对象时,是在堆中重新分配内存,因此栈中的引用是不相同的,所以,a和b引用的是值相同的不同对象。所以a==b返回false
2.既然equals比较的是引用,那么a.equals(b)为什么返回true。这是因为在Integer里,重写了equals方法!
资料
https://mp.weixin.qq.com/s/hiIBQu6mAPzYa7QgTNacUA
https://www.cnblogs.com/wupeixuan/p/8908524.html
http://www.cnblogs.com/guoyaohua/category/1149306.html
http://www.cnblogs.com/wtzbk/p/8591559.html