一、String类
1.字符串的分类:
不可变的字符串String:当对象创建完毕之后,其内容不能改变。一旦内容改变,便是一个新的对象。
可变的字符串StringBuilder/StringBuffer:当对象创建完毕之后,对象的内容可以改变,且当内容改变的时候,对象保持不变。
字符串其底层就是char[]数组,比如:
String str = "ABCD";//等价于↓
char[] str = {'A','B','C','D'};
2.字符串的创建问题
String对象的空值:
String str1 = null;//没有初始化,没有分配内存空间
String str2 = "";//初始化完毕,分配内存,无内容
因此我们在判断字符串是否为空的时候,要注意以上问题:具体是内存不空还是内容不空。另外,在使用字符串比较的时候。因此,单单比较内容的时候,我们往往使用equals方法。
另外,对于字符串常规的两种创建方法,如:
//以下两种方法有何区别
String str1 = "ABC"; //法一
String str2 = new String("ABC"); //法二
从对内存的使用来看,对于法一创建出来的“ABCD”,最多创建一个String对象,最少不创建String对象。因为,如果常量池中已经存在了“ABCD”,那么str1直接引用即可,此时不创建String对象,否则现在常量池中创建“ABCD”内存空间,再引用。
对于法二,最多创建两个String对象,至少创建一个String对象。如果常量池中不存在了“ABCD”那就先在其中创建一个,再在堆空间中创建一个对常量池进行引用。如果存在,直接开辟内存后引用。
那么此时也就会出现下面的现象:
System.out.println(str1 == str2); //false
System.out.println(str1.equals(str2)); //true
当然,将这个问题引申一步之后:
public class Demo_02 {
public static void main(String[] args) {
//注释为编译前
String str1 = "ABCD"; //String str1 = "ABCD";
String str2 = "A"+"B"+"C"+"D"; //String str2 = "ABCD";
String str3 = "AB"+"CD"; //String str3 = "ABCD";
String str4 = new String("ABCD"); //String str4 = new String("ABCD");
String str5 = "AB"; //String str5 = "AB";
String str6 = str5+"CD"; //(new StringBuilder(String.valueOf(str5))).append("CD").toString();
String str7 = getAB()+"CD"; //(new StringBuilder(String.valueOf(getAB()))).append("CD").toString();
//输出结果
System.out.println(str1 == str2);//true
System.out.println(str1 == str3);//true
System.out.println(str1 == str4);//false
System.out.println(str1 == str6);//false
System.out.println(str1 == str7);//false
}
private static String getAB()
{
return "AB";
}
}
为什么会产生这种状况?对于str1到str3,涉及到了编译的优化问题。在编译的时候,就对其进行了优化,使其成为一个字符串常量。对于str5和str1的关系,是因为在编译时期,我们无法确定其值为多少,我们只检查了语法不存在错误。因此,编译器无法对其进行优化。str7同理,只有在运行时期才知道其值,编译器无法对其进行优化。
总结:
①.单独使用引号创建的字符串都是直接量 ,编译期就已确定存储到常量池中。
②.使用new方法创建的对象会存储都堆内存中,是运行时期才创建的。
③.使用只包含直接量的字符串连接符,比如像“+”,创建的也是直接编译期就能确定,已经确定的存储到常量池中(如上面的str2和str3)
④.使用包含String的直接量的字符都是只有在运行时期才能确定变量的值和方法的返回值,不存在编译优化操作。
3.StringBuilder/StringBuffer
对于二者的解释,根据JDK API 1.6可以查到:
StringBuffer:
StingBuilder:
//字符串的拼接
public class Demo_01 {
public static void main(String[] args) {
StringTest(); //205
StringBufferTest(); //3
StringBuilderTest(); //1
}
public static void StringTest()
{
long begin = System.currentTimeMillis();
String str = "";
for(int i = 0 ; i < 5000 ; i++)
{
str += i;
}
long end = System.currentTimeMillis();
System.out.println(end - begin);
}
public static void StringBuilderTest()
{
long begin = System.currentTimeMillis();
StringBuilder sb = new StringBuilder("");
for(int i = 0 ; i < 5000 ; i++)
{
sb.append(i);
}
long end = System.currentTimeMillis();
System.out.println(end - begin);
}
public static void StringBufferTest()
{
long begin = System.currentTimeMillis();
StringBuffer sb = new StringBuffer("");
for(int i = 0 ; i < 5000 ; i++)
{
sb.append(i);
}
long end = System.currentTimeMillis();
System.out.println(end - begin);
}
}
StringBuffer和StringBuilder在功能上是一样的,都表示可变的字符串。
唯一的区别就是:StringBuffer中的方法都是用了synchronized修饰符,表示同步,在多线程并发的时候保证线程安全,性能会有所下降。但是StringBuilder中都没有使用synchronized修饰符,不安全,但是性能相对较高。因此,我们一般使用StringBuilder。
对于使用StringBuilder的时候,如果需要创建一初始容量的char[]数组,我们需要注意到以下问题。
例如:char[] value = new char[30];此时数组只能存储16个字符,一旦超过就需要自动扩容(此时性能将降低)。一般的,我们事先知道需要储存多少内容。
二 、随机数类
1.Random类
十分常用但是也十分简单的一个类,用于产生一个随机数(伪随机)。
int num = new Random().nextInt(150) + 50;//产生一个int型的,[50,150)的随机数。
2.TheadRandom类
Java7新增类,是Random的子类,再多线程并发情况下,可以相对于Random减少线程资源的竞争,保证了线程的安全性。整体来说,它比Random更为强大。
另外,因为构造器是默认访问权限只能在java.util中创建对象,因此提供了一个静态方法ThreadLocalRandom.current()用于返回当前类的对象。
ThreadLocalRandom random=THreadLocalRandom.current();//返回了一个ThreadLocalRandom对象
int num = random.nextInt(50,105)//返回一个int型的[50,105)的随机数。
3.UUID类
UUID在一台机器上生成的数字,它保证对在同一时空的机器都是唯一的。是一个128位长的数字,一般用16进制表示。核心算法思想是通过结合机器网卡、当地时间、一个伪随机数来生成UUID,我们一般用来表示随机的字符串。
String uuid = UUID.randomUUID().toString();
System.out.println(uuid);
三、 日期类
1.Date类
位于java.util.Date包中,表示特定的瞬间精确到毫秒。但是其中大量的方法都已过时(不代表不能用,只是不建议使用)。
2.DateFormat类
DateFormat可以完成日期的格式化操作。包括格式化(Date类型---->String类型)和解析(String类型—>Date类型)。
对于DateFormat的使用,
Date date = new Date();
DateFormat df = DateFormat.getDateInstance();//static修饰的,返回类型为DateFormat
String time =df.format(date);
System.out.println(time);
需要注意的是,DateFormat是经过abstract修饰过的,不能进行实例化操作。
3.SimpleDateFormat类
自定义日期类,可以根据自己需要定制任意格式的时间格式。具体使用情况如下:
String pattern = "yyyy-mm-dd hh:mm:ss a";
SimpleDateFormat mode_01 = new SimpleDateFormat();
mode_01.applyPattern(pattern);
String time = mode_01.format(new Date());
System.out.println(time);
其模式以字符串形式构成,具体内容如下:
4.Calendar类
是一个抽象类,方法多为静态方法。多数情况下,我们使用calendar类的时候,使用getInstance()方法来创建对象。
Calendar date = Calendar.getInstance();
当然,此时创建出来date并不直观,简洁。因此我们通常需要再使用date.get(Calendar.YEAR)来使得提取出需要的信息(此处提取了年份)。
多数情况下,我们使用Calendar表示时间。