文章目录
8.1.1包装类基本知识
对于包装类来说,这些类的用途主要包含两种:
- 作为和基本数据类型对应的类型存在,方便涉及到对象的操作,如Object[]、集合等的操作。
- 包含每种基本数据类型的相关属性如最大值、最小值等,以及相关的操作方法(这些操作方法的作用是在基本数据类型、包装类对象、字符串之间提供相互之间的转化!)。
8.1.3自动装箱和拆箱
自动装箱和拆箱就是将基本数据类型和包装类之间进行自动的互相转换。JDK1.5后,Java引入了自动装箱(autoboxing)/拆箱(unboxing)。
我们以Integer为例:在JDK1.5以前,这样的代码** Integer i = 5 是错误的**,必须要通过Integer i = new Integer(5) 这样的语句来实现基本数据类型转换成包装类的过程;而在JDK1.5以后,Java提供了自动装箱的功能,因此只需Integer i = 5这样的语句就能实现基本数据类型转换成包装类,这是因为JVM为我们执行了**Integer i = Integer.valueOf(5)**这样的操作,这就是Java的自动装箱。
自动拆箱:
每当需要一个值时,对象会自动转成基本数据类型,没必要再去显式调用intValue()、doubleValue()等转型方法。
如 Integer i = 5;int j = i; 这样的过程就是自动拆箱。
我们可以用一句话总结自动装箱/拆箱:
自动装箱过程是通过调用包装类的valueOf()方法实现的,而自动拆箱过程是通过调用包装类的 xxxValue()方法实现的(xxx代表对应的基本数据类型,如intValue()、doubleValue()等)。
八种包装类和基本数据类型的对应关系
8.1.4包装类的缓存问题
- 整型、char类型所对应的包装类,在自动装箱时,对于-128~127之间的值会进行缓存处理,其目的是提高效率。
- JDK1.5以后,增加了自动装箱与拆箱功能,如:
Integer i = 100; int j = new Integer(100);
- 自动装箱调用的是valueOf()方法,而不是new Integer()方法。
- 自动拆箱调用的xxxValue()方法。
- 包装类在自动装箱时为了提高效率,对于-128~127之间的值会进行缓存处理。超过范围后,对象之间不能再使用==进行数值的比较,而是使用equals方法。
String类
String 类对象代表不可变的Unicode字符序列
字符串 拼接 截取等操作本质是生成一个新的串(耗费空间时间)
String s ="a"; 创建了一个字符串
s = s+"b"; 实际上原来的"a"字符串对象已经丢弃了,
现在又产生了另一个字符串s+"b"(也就是"ab")。
如果多次执行这些改变串内容的操作,
会导致大量副本字符串对象存留在内存中,降低效率。如果这样的操作放到循环中,
会极大影响程序的时间和空间性能,甚至会造成服务器的崩溃。
可变的字符序列 :StringBuffer和StringBuilder
区别
- StringBuffer JDK1.0版本提供的类,线程安全,做线程同步检查, 效率较低。
- StringBuilder JDK1.5版本提供的类,线程不安全,不做线程同步检查,因此效率较高。 建议采用该类
常用方法
-
重载的public StringBuilder append(…)方法
可以为该StringBuilder 对象添加字符序列,仍然返回自身对象。
- 方法 public StringBuilder delete(int start,int end)
可以删除从start开始到end-1为止的一段字符序列,仍然返回自身对象。
- 方法 public StringBuilder deleteCharAt(int index)
移除此序列指定位置上的 char,仍然返回自身对象。
- 重载的public StringBuilder insert(…)方法
可以为该StringBuilder 对象在指定位置插入字符序列,仍然返回自身对象。
- 方法 public StringBuilder reverse()
用于将字符序列逆序,仍然返回自身对象。
- 方法 public String toString()
返回此序列中数据的字符串表示形式。
- 和 String 类含义类似的方法:
public int indexOf(String str)
public int indexOf(String str,int fromIndex)
public String substring(int start)
public String substring(int start,int end)
public int length()
char charAt(int index)
实例
public class TestStringBufferAndBuilder 1{
public static void main(String[] args) {
/**StringBuilder*/
StringBuilder sb = new StringBuilder();
for (int i = 0; i < 7; i++) {
sb.append((char) ('a' + i));//追加单个字符
}
System.out.println(sb.toString());//转换成String输出
sb.append(", I can sing my abc!");//追加字符串
System.out.println(sb.toString());
/**StringBuffer*/
StringBuffer sb2 = new StringBuffer("中华人民共和国");
sb2.insert(0, "爱").insert(0, "我");//插入字符串
System.out.println(sb2);
sb2.delete(0, 2);//删除子字符串
System.out.println(sb2);
sb2.deleteCharAt(0).deleteCharAt(0);//删除某个字符
System.out.println(sb2.charAt(0));//获取某个字符
System.out.println(sb2.reverse());//字符串逆序
}
}
String 与StringBuilder 比较
public class Test {
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));
}
}
8.3.1 Date时间类(java.util.Date)
- 1970 年 1 月 1 日 00:00:00定为基准时间,每个度量单位是毫秒
我们用long类型的变量来表示时间,从基准时间往前几亿年,往后几亿年都能表示。 如果想获得现在时刻的“时刻数值”,可以使用:
long now = System.currentTimeMillis();
常用方法
-
Date() 分配一个Date对象,并初始化此对象为系统当前的日期和时间,可以精确到毫秒)。
-
Date(long date) 分配 Date 对象并初始化此对象,以表示自从标准基准时间(称为“历元(epoch)”,即 1970 年 1 月 1 日 00:00:00 GMT)以来的指定毫秒数。
-
boolean after(Date when) 测试此日期是否在指定日期之后。
-
booleanbefore(Date when) 测试此日期是否在指定日期之前。
-
boolean equals(Object obj) 比较两个日期的相等性。
-
long getTime() 返回自 1970 年 1 月 1 日 00:00:00 GMT 以来此 Date 对象表示的毫秒数。
-
String toString() 把此 Date 对象转换为以下形式的
String:dow mon dd hh:mm:ss zzz yyyy 其中:(月:0~ 11)
dow 是一周中的某一天 (Sun、 Mon、Tue、Wed、 Thu、 Fri、 Sat)。
import java.util.Date;
public class TestDate {
public static void main(String[] args) {
Date date1 = new Date();
System.out.println(date1.toString());
long i = date1.getTime();
Date date2 = new Date(i - 1000);
Date date3 = new Date(i + 1000);
System.out.println(date1.after(date2));
System.out.println(date1.before(date2));
System.out.println(date1.equals(date2));
System.out.println(date1.after(date3));
System.out.println(date1.before(date3));
System.out.println(date1.equals(date3));
System.out.println(new Date(1000L * 60 * 60 * 24 * 365 * 39L).toString());
}
}
8.3.2 DateFormat类和SimpleDateFormat类
把时间对象转化成指定格式的字符串。反之,把指定格式的字符串转化成时间对象。
DateFormat是一个抽象类,一般使用它的的子类SimpleDateFormat类来实现。
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
public class TestDateFormat {
public static void main(String[] args) throws ParseException {
// new出SimpleDateFormat对象
SimpleDateFormat s1 = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");
SimpleDateFormat s2 = new SimpleDateFormat("yyyy-MM-dd");
// 将时间对象转换成字符串
String daytime = s1.format(new Date());
System.out.println(daytime);
System.out.println(s2.format(new Date()));
System.out.println(new SimpleDateFormat("hh:mm:ss").format(new Date()));
// 将符合指定格式的字符串转成成时间对象.字符串格式需要和指定格式一致。
String time = "2007-10-7";
Date date = s2.parse(time);
System.out.println("date1: " + date);
time = "2007-10-7 20:15:30";
date = s1.parse(time);
System.out.println("date2: " + date);
}
}
代码中的格式化字符的具体含义
8.3.3 Calendar日历类
Calendar 类是一个抽象类,为我们提供了关于日期计算的相关功能,比如:年、月、日、时、分、秒的展示和计算。
GregorianCalendar 是 Calendar 的一个具体子类,提供了世界上大多数国家/地区使用的标准日历系统。
注意
- 月份 : 0—11;
- 星期:1-7(星期日、 星期一。。。。。、星期六);
实例
import java.util.*;
public class TestCalendar {
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);
}
}
8.4 Math类(常用方法)
- abs 绝对值
- acos,asin,atan,cos,sin,tan 三角函数
- sqrt 平方根
- pow(double a, double b) a的b次幂
- max(double a, double b) 取大值
- min(double a, double b) 取小值
- ceil(double a) 大于a的最小整数
- floor(double a) 小于a的最大整数
- random() 返回 0.0 到 1.0 的随机数 [0,1)
- long round(double a) double型的数据a转换为long型(四舍五入)
- toDegrees(double angrad) 弧度->角度
- toRadians(double angdeg) 角度->弧度
常用方法
public class TestMath {
public static void main(String[] args) {
//取整相关操作
System.out.println(Math.ceil(3.2));
System.out.println(Math.floor(3.2));
System.out.println(Math.round(3.2));
System.out.println(Math.round(3.8));
//绝对值、开方、a的b次幂等操作
System.out.println(Math.abs(-45));
System.out.println(Math.sqrt(64));
System.out.println(Math.pow(5, 2));
System.out.println(Math.pow(2, 5));
//Math类中常用的常量**
System.out.println(Math.PI);
System.out.println(Math.E);
//随机数
System.out.println(Math.random());// [0,1)
}
}
Random类
Math类中虽然为我们提供了产生随机数的方法Math.random(),但是通常我们需要的随机数范围并不是[0, 1)之间的double类型的数据,这就需要对其进行一些复杂的运算。如果使用Math.random()计算过于复杂的话,我们可以使用例外一种方式得到随机数,即Random类,这个类是专门用来生成随机数的,并且Math.random()底层调用的就是Random的nextDouble()方法。
Random类的常用方法
import java.util.Random;
public class TestRandom {
public static void main(String[] args) {
Random rand = new Random();
//随机生成[0,1)之间的double类型的数据
System.out.println(rand.nextDouble());
//随机生成int类型允许范围之内的整型数据
System.out.println(rand.nextInt());
//随机生成[0,1)之间的float类型的数据
System.out.println(rand.nextFloat());
//随机生成false或者true
System.out.println(rand.nextBoolean());
//随机生成[0,10)之间的int类型的数据
System.out.print(rand.nextInt(10));
//随机生成[20,30)之间的int类型的数据
System.out.print(20 + rand.nextInt(10));
//随机生成[20,30)之间的int类型的数据(此种方法计算较为复杂)
System.out.print(20 + (int) (rand.nextDouble() * 10));
}
}
8.5.1 File类的基本用法
import java.io.File;
public class TestFile3 {
public static void main(String[] args) throws Exception {
File f = new File("d:/c.txt");
f.createNewFile(); // 会在d盘下面生成c.txt文件
f.delete(); // 将该文件或目录从硬盘上删除
File f2 = new File("d:/电影/华语/大陆");
boolean flag = f2.mkdir(); //目录结构中有一个不存在,则不会创建整个目录树
//boolean flag = f2.mkdirs();//目录结构中有一个不存在也没关系;创建整个目录树
System.out.println(flag);//创建失败
}
}
import java.io.File;
import java.util.Date;
public class TestFile2 {
public static void main(String[] args) throws Exception {
File f = new File("d:/b.txt");
System.out.println("File是否存在:"+f.exists());
System.out.println("File是否是目录:"+f.isDirectory());
System.out.println("File是否是文件:"+f.isFile());
System.out.println("File最后修改时间:"+new Date(f.lastModified()));
System.out.println("File的大小:"+f.length());
System.out.println("File的文件名:"+f.getName());
System.out.println("File的目录路径:"+f.getPath());
}
}
8.5.2 递归遍历目录结构和树状展现
import java.io.File;
public class TestFile6 {
public static void main(String[] args) {
File f = new File("d:/电影");
printFile(f, 0);
}
/**
* 打印文件信息
* @param file 文件名称
* @param level 层次数(实际就是:第几次递归调用)
*/
static void printFile(File file, int level) {
//输出层次数
for (int i = 0; i < level; i++) {
System.out.print("-");
}
//输出文件名
System.out.println(file.getName());
//如果file是目录,则获取子文件列表,并对每个子文件进行相同的操作
if (file.isDirectory()) {
File[] files = file.listFiles();
for (File temp : files) {
//递归调用该方法:注意等+1
printFile(temp, level + 1);
}
}
}
}
8.6 枚举
enum 枚举名 {
枚举体(常量列表)
}
import java.util.Random;
public class TestEnum {
public static void main(String[] args) {
// 枚举遍历
for (Week k : Week.values()) {
System.out.println(k);
}
// switch语句中使用枚举
int a = new Random().nextInt(4); // 生成0,1,2,3的随机数
switch (Season.values()[a]) {
case SPRING:
System.out.println("春天");
break;
case SUMMER:
System.out.println("夏天");
break;
case AUTUMN:
System.out.println("秋天");
break;
case WINDTER:
System.out.println("冬天");
break;
}
}
}
/**季节*/
enum Season {
SPRING, SUMMER, AUTUMN, WINDTER
}
/**星期*/
enum Week {
星期一, 星期二, 星期三, 星期四, 星期五, 星期六, 星期日
}
课后 部分 练习题
1. 以下选项中关于int和Integer的说法错误的是( )。(选择二项)
A.int是基本数据类型,Integer是int的包装类,是引用数据类型
B.int的默认值是0,Integer的默认值也是0 // 0,null
C.Integer可以封装了属性和方法提供更多的功能
D.Integer i=5;该语句在JDK1.5之后可以正确执行,使用了自动拆箱功能
2. 分析如下Java代码,该程序编译后的运行结果是( )。(选择一项)
public static void main(String[ ] args) {
String str=””;
str.concat(“abc”);
str.concat(“def”);
System.out.println(str);
}
A.null//String 为不可变字符串
B.abcdef
C.编译错误
D.运行时出现NullPointerException异常
5. 分析下面代码的结果( )。(选择一项)
public static void main(String args[]) {
String s = "abc";
String ss = "abc";
String s3 = "abc" + "def";
String s4 = "abcdef";
String s5 = ss + "def";
String s2 = new String("abc");
System.out.println(s == ss);
System.out.println(s3 == s4);
System.out.println(s4 == s5);
System.out.println(s4.equals(s5));
}
A.true true false true
B.true true true false
C.true false true true
D.false true false true