常用类
一、包装类
1.包装类概念
Java是面向对象的语言,但并不是“纯面向对象”的,因为我们经常用到的基本数据类型就不是对象。但是我们在实际应用中经常需要将基本数据转化成对象,以便于操作。比如:将基本数据类型存储到Object[]数组或集合中的操作等等。
为了解决这个不足,Java在设计类时为每个基本数据类型设计了一个对应的类进行代表,这样八个和基本数据类型对应的类统称为包装类(Wrapper Class)。
包装类均位于java.lang包,八种包装类和基本数据类型的对应关系如表8-1所示:
基本数据类型 | 包装类 |
---|---|
byte | Byte |
boolean | Boolean |
short | Short |
char | Character |
int | Integer |
long | Long |
float | Float |
double | Double |
在这八个类名中,除了Integer和Character类以外,其它六个类的类名和基本数据类型一致,只是类名的第一个字母大写而已
2.包装类的使用
对于包装类来说,这些类的用途主要包含两种:
1. 作为和基本数据类型对应的类型存在,方便涉及到对象的操作,如Object[]、集合等的操作。
2. 包含每种基本数据类型的相关属性如最大值、最小值等,以及相关的操作方法(这些操作方法的作用是在基本数据类型、包装类对象、字符串之间提供相互之间的转化!)。

执行结果为:

3.自动装箱和拆箱
自动装箱和拆箱就是将基本数据类型和包装类之间进行自动的互相转换。JDK1.5后,Java引入了自动装箱(autoboxing)/拆箱(unboxing)。
自动装箱:基本类型的数据处于需要对象的环境中时,会自动转为“对象”。
自动拆箱:每当需要一个值时,对象会自动转成基本数据类型,没必要再去显式调用intValue()、doubleValue()等转型方法。
Integer a = 234;//自动装箱。 Integer a = Integer.valueOf(234);
int b = a; //自动拆箱。 编译器会修改成: int b = a.intValue();
Integer c = null;
//if(c!=null) {//会出现空指针异常
int d = c; //自动拆箱:调用了:c.intVaule();
//}
4.包装类的缓存问题
整型、char类型所对应的包装类,在自动装箱时,对于-128~127之间的值会进行缓存处理,其目的是提高效率。
缓存处理的原理为:如果数据在-128~127这个区间,那么在类加载时就已经为该区间的每个数值创建了对象,并将这256个对象存放到一个名为cache的数组中。每当自动装箱过程发生时(或者手动调用valueOf()时),就会先判断数据是否在该区间,如果在则直接获取数组中对应的包装类对象的引用,如果不在该区间,则会通过new调用包装类的构造方法来创建对象。
//缓存[-128,127]之间的数字//实际就是系统初始的时候创建了[-128,127]之间的一个cache数组,在
//范围内时直接从cache数组中取已经创好的对象,所以是同一个对象
Integer.valueOf(-128);
Integer in1 = -128;
Integer in2 = -128;
System.out.println(in1 == in2);//true 因为128在缓存范围内
System.out.println(in1.equals(in2));//true
System.out.println("---------------------");
Integer in3 = 1234;
Integer in4 = 1234;
System.out.println(in3 == in4);//false 因为1234不在缓存范围内
System.out.println(in3.equals(in4));//true
二、String、StringBuilder和StringBuffer
1.String类
根据原码,字符串内容全部被存入value字符数组中,并用final修饰,即常量(只能被赋值一次),所以称String类是”不可变的字符序列”。
String类是不可变的!!

public class TestString02 {
public static void main(String[] args) {
String s1 = new String("abcdef");
String s2 = s1.substring(2, 4);
// 打印:ab199863
System.out.println(Integer.toHexString(s1.hashCode()));
// 打印:c61, 显然s1和s2不是同一个对象
System.out.println(Integer.toHexString(s2.hashCode()));
}
}
String类的常用方法:
public class TestString01 {
public static void main(String[] args) {
String s1 = "core Java";
String s2 = "Core Java";
System.out.println(s1.charAt(3));//提取下标为3的字符
System.out.println(s2.length());//字符串的长度
System.out.println(s1.equals(s2));//比较两个字符串是否相等
System.out.println(s1.equalsIgnoreCase(s2));//比较两个字符串(忽略大小写)
System.out.println(s1.indexOf("Java"));//字符串s1中是否包含Java
System.out.println(s1.indexOf("sea"));//字符串s1中是否包含sea
String str = s1.replace(' ', '&');//将s1中的空格替换成&
System.out.println("result is : " + str);
System.out.println("s1 : "+s1);
System.out.println("-----------------------------------------");
String s = "";
System.out.println("s的地址"+Integer.toHexString(s.hashCode()));
String s3 = "How are you?";
System.out.println(s3.startsWith("How"));//是否以How开头
System.out.println(s3.endsWith("you"));//是否以you结尾
s = s3.substring(4);//提取子字符串:从下标为4的开始到字符串结尾为止
System.out.println(s);
System.out.println("s的地址"+Integer.toHexString(s.hashCode()));
s = s3.substring(4, 7);//提取子字符串:下标[4, 7) 不包括7
System.out.println(s);
System.out.println("s的地址"+Integer.toHexString(s.hashCode()));//地址不同,不是同一个对象了
s = s3.toLowerCase();//转小写
System.out.println(s);
s = s3.toUpperCase();//转大写
System.out.println(s);
String s4 = " How old are you!! ";
s = s4.trim();//去除字符串首尾的空格。注意:中间的空格不能去除
System.out.println(s);
System.out.println(s4);//因为String是不可变字符串,所以s4不变
}
}

2.字符串相等判断
public class TestStringEquals {
public static void main(String[] args) {
String s1 = "长安十二时辰";
String s2 = "长安十二时辰";
String s3 = new String("长安十二时辰");
System.out.println(s1 == s2);//true 指向同一个字符串常量对象
System.out.println(s1 == s3);//false s3是新创建的对象
System.out.println(s1.equals(s3));//true 值内容相同
}
}

3.StringBuilder和StringBuffer
两者的内部也是字符数组,但没有被final修饰,可以随时修改因此,StringBuilder和StringBuffer称之为”可变字符序列”。
- StringBuffer 线程安全,做线程同步检查, 效率较低。
- StringBuilder 线程不安全,不做线程同步检查,因此效率较高。 建议采用该类。
两者用法基本相同:
public class TestStringBuilder {
public static void main(String[] args) {
StringBuilder sb = new StringBuilder();
for (int i = 0; i < 26; i++) {
sb.append((char)('a'+i));//追加单个字符
}
System.out.println(sb.toString());//转换成String输出
sb.append(", helloworld!");//追加字符串
System.out.println(sb.toString());
System.out.println("-----------------------------");
StringBuilder sb2 = new StringBuilder("拂衣去,深藏功与名");
sb2.insert(0, "了").insert(0, "事");//插入字符串 //return的是this对象可链式调用
System.out.println(sb2);
sb2.delete(0, 2);//删除字符串[0,2)
System.out.println(sb2);
sb2.deleteCharAt(2);//删除某个字符串
System.out.println(sb2);
System.out.println(sb2.charAt(7));//获取某个字符
System.out.println(sb2.reverse());//字符串逆序
}
}

4.可变与不可变字符串的使用
String一旦经过初始化后就不可变了。对String字符串的操作实际上是拷贝副本的操作,会导致大量副本字符串对象存留在内存中,降低效率,甚至造成服务器崩溃。相反,StringBuilder和StringBuffer类是对原字符串本身操作的,可以对字符串进行修改而不产生副本拷贝或者产生少量的副本。因此可以在循环中使用。
public class TestStringBuilder02 {
public static void main(String[] args) {
/**使用String进行字符串的拼接*/
String str8 = "";
//本质上使用StringBuilder拼接, 但是每次循环都会生成一个StringBuilder对象
long num1 = Runtime.getRuntime().freeMemory();//获取系统剩余内存空间
long time1 = System.currentTimeMillis();//获取系统的当前时间
for (int i = 0; i < 5000; i++) {
str8 = str8 + i;//相当于产生了10000个对象
}
long num2 = Runtime.getRuntime().freeMemory();
long time2 = System.currentTimeMillis();
System.out.println("String占用内存 : " + (num1 - num2));
System.out.println("String占用时间 : " + (time2 - time1));
/**使用StringBuilder进行字符串的拼接*/
StringBuilder sb1 = new StringBuilder("");
long num3 = Runtime.getRuntime().freeMemory();
long time3 = System.currentTimeMillis();
for (int i = 0; i < 5000; i++) {
sb1.append(i);
}
long num4 = Runtime.getRuntime().freeMemory();
long time4 = System.currentTimeMillis();
System.out.println("StringBuilder占用内存 : " + (num3 - num4));
System.out.println("StringBuilder占用时间 : " + (time4 - time3));
}
}

5.三者区别
- String:不可变字符序列。
- StringBuffer:可变字符序列,并且线程安全,但是效率低。
- StringBuilder:可变字符序列,线程不安全,但是效率高(一般用它)。
三、Date、DateFormat和Calendar
1.Date类
在标准Java类库中包含一个Date类。它的对象表示一个特定的瞬间,精确到毫秒。
public class TestDate {
public static void main(String[] args) {
//Date(long date) 分配 Date 对象并初始化此对象,以表示自从标准基准时间(称为“历元(epoch)”,即 1970 年 1 月 1 日 00:00:00 GMT)以来的指定毫秒数。
Date d = new Date(2000);
System.out.println(d);
System.out.println(d.getTime());
//Date() 分配一个Date对象,并初始化此对象为系统当前的日期和时间,可以精确到毫秒
Date d2 = new Date();
System.out.println(d2.getTime());//转换为毫秒数
System.out.println(d2.after(d));//是否在后
System.out.println(d2.before(d));//是否在前
//已废弃,以后遇到日期处理使用Canlendar日期类
Date d3 = new Date(2020-1900,3,10);//2020/04/10
System.out.println(d3);
}
}
JDK1.1之后,Date类的很多方法都过时了,日期操作一般使用Calendar类,而字符串的转化使用DateFormat类。
2.DateFormat类和SimpleDateFormat类
DateFormat类的作用:时间对象与字符串之间的相互转换。
DateFormat是一个抽象类,一般使用它的的子类SimpleDateFormat类来实现

public class TestDateFormat {
public static void main(String[] args) throws ParseException {
//把时间对象按照"格式字符串指定格式"转成相应的字符串
//DateFormat df = new SimpleDateFormat("yyyy年MM月dd日 hh:mm:ss");
DateFormat df = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");//DateFormat是抽象类
String str = df.format(new Date());//可传毫秒
System.out.println(str);
//把字符串按照"格式字符串指定的格式"转成相应的时间对象
DateFormat df2 = new SimpleDateFormat("yyyy年MM月dd天 hh时mm分ss秒");
Date date = df2.parse("2019年08月27天 20时24分55秒");
System.out.println(date);
//测试其他格式的字符。比如:利用D,获取本时间对象是所处年份的第几天。
DateFormat df3 = new SimpleDateFormat("D");
String str3 = df3.format(new Date());
System.out.println(str3);
}
}
执行结果如下:
3.Calendar类和GregorianCalendar类
Calendar 类是一个抽象类,为我们提供了关于日期计算的相关功能,比如:年、月、日、时、分、秒的展示和计算。
GregorianCalendar 是 Calendar 的一个具体子类,提供了世界上大多数国家/地区使用的标准日历系统。
月份0~11,周日-周六1~7
public class TestCanlendar02 {
public static void main(String[] args) {
// 得到相关日期元素
GregorianCalendar calendar = new GregorianCalendar(2999, 10, 9, 22, 10, 50);
int year = calendar.get(Calendar.YEAR); // 打印:1999
int month = calendar.get(Calendar.MONTH); // 打印:10
int day = calendar.get(Calendar.DAY_OF_MONTH); // 打印:9
int day2 = calendar.get(Calendar.DATE); // 打印:9
// 日:Calendar.DATE和Calendar.DAY_OF_MONTH同义
int date = calendar.get(Calendar.DAY_OF_WEEK); // 打印:3
// 星期几 这里是:1-7.周日是1,周一是2,。。。周六是7
System.out.println(year);
System.out.println(month);
System.out.println(day);
System.out.println(day2);
System.out.println(date);
// 设置日期
GregorianCalendar calendar2 = new GregorianCalendar();
calendar2.set(Calendar.YEAR, 2999);
calendar2.set(Calendar.MONTH, Calendar.FEBRUARY); // 月份数:0-11
calendar2.set(Calendar.DATE, 3);
calendar2.set(Calendar.HOUR_OF_DAY, 10);
calendar2.set(Calendar.MINUTE, 20);
calendar2.set(Calendar.SECOND, 23);
printCalendar(calendar2);
// 日期计算
GregorianCalendar calendar3 = new GregorianCalendar(2999, 10, 9, 22, 10, 50);
calendar3.add(Calendar.MONTH, -7); // 月份减7
calendar3.add(Calendar.DATE, 7); // 增加7天
printCalendar(calendar3);
// 日历对象和时间对象转化
Date d = calendar3.getTime();
GregorianCalendar calendar4 = new GregorianCalendar();
calendar4.setTime(new Date());
long g = System.currentTimeMillis();
}
static void printCalendar(Calendar calendar) {
int year = calendar.get(Calendar.YEAR);
int month = calendar.get(Calendar.MONTH) + 1;
int day = calendar.get(Calendar.DAY_OF_MONTH);
int date = calendar.get(Calendar.DAY_OF_WEEK) - 1; // 星期几
String week = "" + ((date == 0) ? "日" : date);
int hour = calendar.get(Calendar.HOUR);
int minute = calendar.get(Calendar.MINUTE);
int second = calendar.get(Calendar.SECOND);
System.out.printf("%d年%d月%d日,星期%s %d:%d:%d\n", year, month, day, week, hour, minute, second);
}
}
