目录
2.2 StringBuffer和StringBuilder
3.2 DateFormat类和SimpleDateFormat类的使用
一、常用类
1、包装类
Java是面向对象的语言,但并不是“纯面向对象”的,因为我们经常用到的基本数据类型就不是对象。但是我们在实际应用中经常需要将基本数据转化成对象,以便于操作。比如:将基本数据类型存储到Object[]数组或集合中的操作等。为了解决这个不足,Java在设计类时为每个基本数据类型设计了一个对应的类进行代表,这样八个和基本数据类型对应的类类统称为包装(WrapperClass)。
1.1 初识包装类
package studyweek4;
//包装类
public class study1 {
public static void main(String[] args) {
Integer i=new Integer(100);//java9以后被废弃
}
}
1.2 包装类的用途
对于包装类来说,这些类的用途主要包含两种:
1.作为和基本数据类型对应的类型存在,方便涉及到对象的操作,如Object[]、集合等的操作。
2.包含每种基本数据类型的相关属性如最大值、最小值等,以及相关的操作方法(这些操作方法的作用是在基本数据类型、包装类对象、字符串之间提供相互之间的转化!)。
1.3 包装类的使用
package studyweek4;
//包装类
public class study1 {
public static void main(String[] args) {
//基本数据类型转换为包装类对象
Integer int1 = new Integer(100);//java9以后被废弃
Integer int2 = Integer.valueOf(20);//官方推荐使用这种方法
//包装类对象转换为基本数据类型
int a = int1.intValue();
double d = int2.doubleValue();
//字符串类型转化为包装类对象(两种方法都可以)
Integer int3=Integer.valueOf("234");//valueof的重载
Integer int4=Integer.parseInt("999");
//包装类对象转换为字符串
String str=int3.toString();//包装类的toString方法String str = Integer.toString(10);
//一些常用的常量
System.out.println(Integer.MAX_VALUE);//返回int类型能表示的最大整数
System.out.println(Integer.MIN_VALUE);//返回int类型能表示的最小整数
}
}
1.4 自动装箱和自动拆箱
自动装箱和拆箱就是将基本数据类型和包装类之间进行自动的互相转换。JDK1.5后,Java引入了自动装箱(autoboxing)/拆箱(unboxing)。
自动装箱:
基本类型的数据处于需要对象的环境中时,会自动转为“对象”。我们以Integer为例:在JDK1.5以前,这样的代码Integeri=5是错误的,必须要通过Integeri=newInteger(5)这样的语句来实现基本数据类型转换成包装类的过程;而在JDK1.5以后,Java提供了自动装箱的功能,因此只需Integeri=5这样的语句就能实现基本数据类型转换成包装类,这是因为JVM为我们执行了Integeri=Integer.valueOf(5)这样的操作,这就是Java的自动装箱。
自动拆箱:
每当需要一个值时,对象会自动转成基本数据类型,不必再去显式调用intValue()、doubleValue()等转型方法。如Integeri=5;intj=i;这样的过程就是自动拆箱。
我们可以用一句话总结自动装箱/拆箱:自动装箱过程是通过调用包装类的valueOf()方法实现的,而自动拆箱过程是通过调用包装类的xxxValue()方法实现的(xxx代表对应的基本数据类型,如intValue()、doubleValue()等)。
//自动装箱和拆箱
public class study1{
public static void main(String[] args) {
//自动装箱
Integer a=200;//编译器帮你改成了Integer a=Integer.valueOf(200);
//自动拆箱
int b=a;//编译器改成了a.intValue();
//报错代码
Integer c=null;//空对象是不能调用方法的!!
int c2=c;//编译器改成了c.intValue();//" java.lang.NullPointerException:对象为null,我们调用了它的属性或方法
}
}
1.5 包装类的缓存问题
整型、char类型所对应的包装类,在自动装箱时,对于-128~127之间的值会进行缓存处理,其目的是提高效率。
缓存处理的原理为:如果数据在-128~127这个区间,那么在类加载时就已经为该区间的每个数值创建了对象,并将这256个对象存放到一个名为cache的数组中。每当自动装箱过程发生时(或者手动调用valueOf()时),就会先判断数据是否在该区间,如果在则直接获取数组中对应的包装类对象的引用,如果不在该区间,则会通过new调用包装类的构造方法来创建对象。
//包装的缓存问题
Integer d1=4000;
Integer d2=4000;
Integer d3=123;//当数据在-128~127之间的时候,编译器会从数组里面拿对象,因此返回缓存数组中的某个元素
Integer d4=123;//还是从缓存数组中取,并且与之前取的对象一致。
System.out.println(d1==d2);//false
System.out.println(d3==d4);//true
System.out.println(d1.equals(d2));//true;
2、字符串相关类
String类、StringBuilder类、StringBuffer类是三个字符串相关类。String类是的对象代表不可变的字符序列,StringBuilder类和StringBuffer类代表可变字符序列。关于这三个类详细的用法,在笔试面试以及实际开发中经常用到,我们必须掌握好它们。
2.1 String类源码分析
String类对象代表不可变的Unicode字符序列,因此我们可以将String对象称为“不可变对象”。那什么叫做“不可变对象”呢?指的是对象内部的成员变量的值无法再改变。我们打开String类的源码,
我们发现字符串内容全部存储到value[]数组中,而变量value是final类型的,也就是常量(即只能被赋值一次)。这就是“不可变对象”的典型定义方式。
我们发现在前面学习String的某些方法,比如:substring()是对字符串的截取操作,但本质是读取原字符串内容生成了新的字符串。
补充:字符串常量拼接的优化
String类常用的方法有(之前已经讲过,此处不赘述):
String类的下述方法能创建并返回一个新的String对象:concat()、replace()、substring()、toLowerCase()、toUpperCase()、trim()。
提供查找功能的有关方法:endsWith()、startsWith()、indexOf()、lastIndexOf()。
提供比较功能的方法:equals()、equalsIgnoreCase()、compareTo()。
其它方法:charAt()、length()。
2.2 StringBuffer和StringBuilder
StringBuffer和StringBuilder非常类似,均代表可变的字符序列。这两个类都是抽象类AbstractStringBuilder的子类,方法几乎一模一样。
显然,内部也是一个字符数组,但这个字符数组没有用final修饰,随时可以修改。因此,StringBuilder和StringBuffer称之为“可变字符序列”。那两者有什么区别呢?
StringBufferJDK1.0版本提供的类,线程安全,做线程同步检查,效率较低。
StringBuilderJDK1.5版本提供的类,线程不安全,不做线程同步检查,因此效率较高。建议采用该类。
2.3 StringBuilder常用方法(重点)
目前主要学好append方法!
package studyweek4;
public class study2 {
public static void main(String[] args) {
String s1=new String("abcdef");
String s2=s1.substring(2,4);
System.out.println(Integer.toHexString(s1.hashCode()));
String str="aabb";//不可变字符序列
//StringBuilder sb=null;//可变字符序列
//StringBuffer sb2=null;//可变字符序列
//StringBuilder和StringBuffer常用方法
//append;
StringBuilder sb=new StringBuilder("ji");
sb.append(123);
sb.append(456);
System.out.println(sb);//ji123456
sb.append("aa").append("bb").append("cc");//因为每一个.append之后返回的都是sb,因此每一次结束又重新变成sb.append
System.out.println(sb);//ji123456aabbcc
//以下方法StringBuilder同样适用
//insert插入
StringBuffer sb2=new StringBuffer("java");
sb2.insert(0,"爱").insert(0,"我");
System.out.println(sb2);
//delete删除子字符串
sb2.delete(0,2);
System.out.println(sb2);
//deleteCharAt(x)删除某个字符
sb2.deleteCharAt(0).deleteCharAt(0);
System.out.println(sb2.charAt(0));//获取某一个字符
//字符串逆序
System.out.println(sb2.reverse());
}
}
新增反思:StringBuilder s=new StringBuilder(1);那么定义s容量为1再以后进行append还是否能够添加进去呢?
StringBuilder s=new StringBuilder(0);
s.append("a" );
s.append("b");
s.append(5);
System.out.println(s);
可见:append方法会自动对StringBuilder进行扩容
对StringBulider自动扩容的理解https://blog.csdn.net/qq_40911298/article/details/104943304
注意:如果需要字符串拼接的时候尽量使用StringBuilder而不是String,由下面的代码可以看出StringBuilder的占用内存和占用时间都明显更少。
package studyweek4;
public class study3 {
public static void main(String[] args) {
/**使用String进行字符串的拼接*/
String str="";
//本质上使用StringBuilder拼接,但是每次循环都会生成一个StringBuilder对象
long num1=Runtime.getRuntime().freeMemory();//获取系统剩余内存空间
long time1=System.currentTimeMillis();//获取系统的当时时间
for(int i=0;i<5000;i++){
str=str+i;
}
long num2=Runtime.getRuntime().freeMemory();
long time2=System.currentTimeMillis();
System.out.println("String占用内存"+(num2-num1));
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占用内存"+(num4-num3));
System.out.println("StringBuilder占用时间"+(time4-time3));
}
}
3、时间处理相关类
3.1 Date类
//都是以毫秒数来计算
long a=Long.MAX_VALUE/(1000L*365*3600*24);
System.out.println(a);//大约能表示到2.9亿年之后
long now=System.currentTimeMillis();//代表当前时刻的毫秒数
System.out.println(now);
Date d1=new Date(); //没有传参,代表当前的时刻
System.out.println(d1);
System.out.println(d1.getTime());
Date d2=new Date(1000L*3600*24*365*250); //1970年后的250年
System.out.println(d2);
3.2 DateFormat类和SimpleDateFormat类的使用
//DateFormat和SimpleDateFormat
//格式化对象
SimpleDateFormat df=new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");//格式也可以加yyyy年等
//将字符串转换为Date对象
Date d11= df.parse("2022-2-4 15:00:20");
System.out.println(d11.getTime());
//将Date对象转换为字符串
Date d22=new Date(1000L*3600*23);
String str11=df.format(d22);
System.out.println(str11);
DateFormat df2=new SimpleDateFormat("今年第w周");
System.out.println(df2.format(d11));
代码中可能出现的格式化字符:
3.3 Calendar类的使用
//Calendar计算日期
package studyweek4;
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;//Date类的导入
import java.util.GregorianCalendar;
public class study3 {
public static void main(String[] args) throws ParseException {//处理异常,后面会学
GregorianCalendar calendar=new GregorianCalendar(2022,1,5,0,5);//1指的是2月,这里的月份从0-11代表1-12月。
int year=calendar.get(Calendar.YEAR);
int month=calendar.get(Calendar.MONTH);
int day=calendar.get(Calendar.DAY_OF_MONTH);
int day2=calendar.get(Calendar.DATE);
int date=calendar.get(Calendar.DAY_OF_WEEK);//周几
//=calendar.get(Calendar.DAY_OF_YEAR); //计算该天是在该年的第几天
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,1999);
calendar2.set(Calendar.MONTH,Calendar.SATURDAY);//月份数: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(1999,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());
}
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);
}
}
4、Math类
5、Random类
6、File类
File类用来代表文件
File类的基本用法:
java.io.File类:代表文件和目录。在开发中,读取文件、生成文件、删除文件、修改文件的属性时经常会用到本类。
6.1 使用File类创建文件
package studyweek4;
//File类使用
import java.io.File;
import java.io.IOException;
public class FIle类 {
public static void main(String[] args) throws IOException {
File f1=new File("D:/java.txt");//创建文件
File f2=new File("D:\\java.txt");//创建文件,反斜杠是转义字符,因此要两条
f1.createNewFile();
System.out.println(System.getProperty("user.dir"));//获得项目路径
File f3=new File(System.getProperty("user.dir"));//f3代表这个项目
}
}
6.2 使用File类访问文件或者目录属性
public class FIle类 {
public static void main(String[] args) throws IOException {
System.out.println("File是否存在:"+f1.exists());
System.out.println("File是否是目录:"+f1.isDirectory());
System.out.println("File是否是文件:"+f1.isFile());
System.out.println("File最后修改时间:"+new Date(f1.lastModified()));
System.out.println("File的大小:"+f1.length());
System.out.println("File的文件名:"+f1.getName());
System.out.println("File的目录路径:"+f1.getPath());
}
}
6.3 通过File对象创建空文件或目录
delete是删除指定目录,不会删除父目录
7、枚举
JDK1.5引入了枚举类型。枚举类型的定义包括枚举声明和枚举体。格式如下:
enum 枚举名{
枚举体(常量列表)
}
枚举本质上还是类,枚举体就是放置一些常量。
7.1 创建枚举类型
enum Season{
SPRING,SUMMER,AUTUMN,WINTER
}
7.2 枚举的使用
package studyweek4;
import java.util.Random;
public class 枚举 {
public static void main(String[] args){
//枚举遍历
for(Week k:Week.values()){
System.out.println(k);
}
Week[] ws=Week.values();
System.out.println(ws[0]);
//switch语句中使用枚举
int a=new Random().nextInt(4);//生成0,1,2,3的随机数
switch (Season.values()[a]){ //values()返回的是:Week[],里面包含了所有的枚举元素
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{星期一,星期二,星期三,星期四,星期五,星期六,星期日}
8、递归打印目录树结构
public class 递归 {
public static void main(String[] args) {
File f=new File("D:/c++ study");
printFile(f,0);
}
static void printFile(File file, int level){//level用来加-
//输出层次数
for(int i=0;i<level;i++){
System.out.println("-");
}
//输出文件名
System.out.println(file.getName());
//如果file是目录,则获取子文件列表,并对每个子文件进行相同操作。
if(file.isDirectory()) {
File files[] = file.listFiles();//树状展示
for (File temp : files) {
//递归调用该方法:注意level+1。
printFile(temp, level + 1);
}
}
}
}
file.listFiles()是获取file这个对象也就是file这个目录下面的文件和文件夹的集合