文章目录
- 前言
- 1.包装类
- 1.1.包装类基本知识
- 1.2.包装类的用途
- 1.3.装箱和拆箱
- 1.3.1.装箱:
- 1.3.2.拆箱
- 1.4 包装类的缓存问题
- 2.时间处理类
- 2.1.Date 时间类(java.util.Date)
- 2.2.DateFormat 类和 SimpleDateFormat 类
- 2.3.Calendar 日历类
- 3.其他常用类
- 3.1.Math类
- 3.2.Random 类
- 3.3. File 类
- 3.4 递归遍历目录结构和树状展现
- 3.5.枚举
前言
上一节课我们学习时间复杂度和空间复杂度。今天我们学习常用类
这个就是我们要学习的内容
1.包装类
1.1.包装类基本知识
Java 是面向对象的语言,但并不是“纯面向对象”的,因为我们经常用到的基本数据类型就不是对象。但是我们在实际应用中经常需要将基本数据转化成对象,以便于操作。比如:将基本数据类型存储到 Object[ ]数组或集合中的操作等等。为了解决这个不足, Java 在设计类时为每个基本数据类型设计了一个对应的类进行代表,这样八个和基本数据类型对应的类统称为包装类(Wrapper Class)。
包装类位于 java.lang 包,八种包装类和基本数据类型的对应关系:
在这八个类名中,除了 Integer 和 Character 类以外,其它六个类的类名和基本数
据类型一致,只是类名的第一个字母大写而已
Number 类是抽象类,因此它的抽象方法,所有子类都需要提供实现。 Number 类提供了
抽象方法: intValue()、 longValue()、 floatValue()、 doubleValue(),意味着所有的“数
字型”包装类都可以互相转型。
1.2.包装类的用途
对于包装类来说,这些类的用途主要包含两种:
- 作为和基本数据类型对应的类型存在,方便涉及到对象的操作,如 Object[ ]、集合等
的操作。 - 包含每种基本数据类型的相关属性如最大值、最小值等,以及相关的操作方法(这些操
作方法的作用是在基本数据类型、包装类对象、字符串之间提供相互之间的转化!)。
1.3.装箱和拆箱
装箱(autoboxing)和拆箱(unboxing):将基本数据类型和包装类自动转换。
1.3.1.装箱:
public static void main(String[] args) {
int a=10;
Integer b=new Integer(a);//这个方法在JDK9之后就不再使用了,但是为了兼用之前的版本,但是也可以使用
Integer c=Integer.valueOf(a);
Integer d=a;
}
这个是装箱操作,其中
Integer c=Integer.valueOf(a);是显示装箱
Integer b=new Integer(a);或者Integer d=a;是自动转型
他的底层仍是使用的是Integer.valueOf()方法
可以看反汇编
1.3.2.拆箱
public static void main(String[] args) {
Integer a=10;
int b= a.intValue();
int c=a;
}
这个就是拆箱操作。
自动装箱/拆箱的本质是:
自动装箱与拆箱的功能是编译器来帮忙,编译器在编译时依据您所编写的语法,决定是否进行装箱或拆箱动作。
自动装箱与拆箱的功能是所谓的“编译器蜜糖(Compiler Sugar)”,虽然使用这个功能很方
便,但在程序运行阶段您得了解 Java 的语义。 如下所示的程序是可以通过编译的:
public static void main(String[] args) {
Integer a=null;
int i=a;
System.out.println(i);
}
我们会发现报错了,空指针异常,为什么?
因为包装类是属于引用类型,会在栈和堆上开辟内存,a的值可以是null,但是在进行拆箱的时候,i是一个基本数据类型,不可能是null,因而报错。
1.4 包装类的缓存问题
我们看一个例子
public static void main(String[] args) {
Integer a=100;
Integer b=100;
System.out.println(a==b);
Integer c=1000;
Integer d=1000;
System.out.println(c==d);
}
大家觉得分别输出什么?
为什么呢?
整型、 char类型所对应的包装类,在自动装箱时,对于-128~127之间的值会进行缓
存处理,其目的是提高效率。
缓存原理为:如果数据在-128~127这个区间,那么在类加载时就已经为该区间的每
个数值创建了对象,并将这256个对象存放到一个名为cache的数组中。每当自动装箱过程
发生时(或者手动调用valueOf()时),就会先判断数据是否在该区间,如果在则直接获取
数组中对应的包装类对象的引用,如果不在该区间,则会通过new调用包装类的构造方法
来创建对象。
我们再看看Integer的部分源码
这段代码中我们需要解释下面几个问题:
- IntegerCache类为Integer类的一个静态内部类,仅供Integer类使用。
- 一般情况下 IntegerCache.low为-128, IntegerCache.high为127。
我们可以发现,如果-128<=i<127的话,会存放在IntegerCache.cache数组当中,那么在上面的代码中,100指的是同一个对象,但是如果不在这个范围的话,就是new Ineger()一个对象,会在栈和堆上开辟内存,那么用两个1000所在地址不一样,那么就不能使用==,而要使用equals方法了。
总结
1.自动装箱调用的是 valueOf()方法,而不是 new Integer()方法。
2.自动拆箱调用的 xxxValue()方法。
3.包装类在自动装箱时为了提高效率,对于-128~127 之间的值会进行缓存处理。超过范
围后,对象之间不能再使用==进行数值的比较,而是使用 equals 方法。
下面我们模拟复现一个Integer类,叫做MyInteget类
public class MyInteger {
private int value;
private static MyInteger[]cache=new MyInteger[256];
public static final int LOW=-128;
public static final int HIGH=127;
private MyInteger(int i){
this.value=i;
}
//静态代码块先被执行
static {
for(int i=MyInteger.LOW;i<=HIGH;i++){
cache[i+128]=new MyInteger(i);
}
}
public int intValue(){
return this.value;
}
public static MyInteger ValueOf(int i){
if(i>=LOW&&i<=HIGH){
return cache[i+128];
}
return new MyInteger(i);
}
@Override
public String toString() {
return this.value+"";
}
public static void main(String[] args) {
MyInteger i=MyInteger.ValueOf(10);
MyInteger a=MyInteger.ValueOf(1000);
System.out.println(i);
System.out.println(a);
}
}
String类型咱们在Java(十一)—String类型中已经讲过了,因此在这就不在进行赘述了。
2.时间处理类
时间如流水,一去不复返”,时间是一维的。所以,我们需要一把刻度尺来表达和度
量时间。在计算机世界,我们把 1970 年 1 月 1 日 00:00:00 定为基准时间,每个度量单
位是毫秒(1 秒的千分之一),如图所示。
我们用 long 类型的变量来表示时间,从基准时间前后几亿年都能表示。
这个“时刻数值” 是所有时间类的核心值,年月日都是根据这个“数值” 计算出来的。
我们工作学习涉及的时间相关类有如下这些
2.1.Date 时间类(java.util.Date)
在标准 Java 类库中包含一个 Date 类。它的对象表示一个特定的瞬间,精确到毫秒。
- Date() 分配一个 Date 对象,并初始化此对象为系统当前的日期和时间,可以精确到毫秒)。
- Date(long date) 分配 Date 对象并初始化此对象,以表示自从标准基准时间以来的毫秒数。
- boolean equals(Object obj) 比较两个日期的相等性。
- long getTime() 返回毫秒数。
- String toString() 把此 Date 对象转换为以下形式的 String:
dow mon dd hh:mm:ss zzz yyyy 其中: dow 是一周中的某一天
public static void main(String[] args) {
long nowNum=System.currentTimeMillis();
System.out.println(nowNum);
Date date1=new Date(10000020323L);
Date date2=new Date();
System.out.println(date1);
System.out.println(date1.getTime());
System.out.println(date2);
System.out.println(date2.getTime());
Date date3=new Date(-21L*365*24*3600*1000);//1949 年
System.out.println(date3);
System.out.println(date3.equals(date1));
System.out.println(date3.before(date1));
System.out.println(date3.after(date1));
}
2.2.DateFormat 类和 SimpleDateFormat 类
DateFormat 类的作用:
把时间对象转化成指定格式的字符串。反之,把指定格式的字符串转化成时间对象。
DateFormat 是一个抽象类,一般使用它的的子类SimpleDateFormat 类来实现。
public static void main(String[] args)throws ParseException {
DateFormat format = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");
String str="2024-6-8 12:25:00";
Date date=format.parse(str);//从给定字符串的开头解析文本以生成日期。
System.out.println(date.getTime());
System.out.println(date);
System.out.println("=========");
DateFormat dateFormat=new SimpleDateFormat("yyyy年MM月dd日 hh时mm分ss秒");
Date date1=new Date(2342342342334L);
String date1Str=format.format(date1);//将 Date 格式化为日期时间字符串。
System.out.println(date1Str);
//小妙招
Date now = new Date();
DateFormat f1 = new SimpleDateFormat("今年的第D天,第w周");
String str3 = f1.format(now);
System.out.println(str3);
}
2.3.Calendar 日历类
Calendar 类是一个抽象类,为我们提供了关于日期计算的功能,比如:年、月、日、时、分、秒的展示和计算。
GregorianCalendar 是 Calendar 的子类, 表示公历。
注意:
月份的表示,一月是 0,二月是 1,以此类推, 12 月是 11。 因为大多数人习惯于使用单词而不是使用数字来表示月份,这样程序也许更易读,父类 Calendar 使用常量来表示月份:
JANUARY、 FEBRUARY 等等
import java.util.GregorianCalendar;
import java.util.*;
public class TestCalendar {
public static void main(String[] args) {
GregorianCalendar calendar=new GregorianCalendar
(2024,6,8,12,40,00);
System.out.println(calendar);
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);
// 日:Calendar.DATE和Calendar.DAY_OF_MONTH同义
int date = calendar.get(Calendar.DAY_OF_WEEK);
// 星期几 这里是: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 calendar1=new GregorianCalendar();
calendar1.set(Calendar.YEAR,2000);
calendar1.set(Calendar.MONTH,1);
calendar1.set(Calendar.DATE,25);
calendar1.set(Calendar.HOUR_OF_DAY,8);
calendar1.set(Calendar.MINUTE,10);
calendar1.set(Calendar.SECOND,10);
//日期的计算
GregorianCalendar calendar2=new GregorianCalendar
(2024,6,8,12,40,00);
calendar2.add(Calendar.MONTH,-7);
calendar2.add(Calendar.DATE,7);
printCalendar(calendar2);
// 日历对象和时间对象转化
Date d = calendar2.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);
}
}
3.其他常用类
3.1.Math类
java.lang.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 的随机数
long round(double a) double 型的数据 a 转换为 long 型(四舍五入)
toDegrees(double angrad) 弧度->角度
toRadians(double angdeg) 角度->弧
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(2,5));
System.out.println(Math.pow(5,2));
//Math类中常用的常量
System.out.println(Math.PI);
System.out.println(Math.E);
//随机值
System.out.println(Math.random());//[0,1)
}
3.2.Random 类
Random 类: 专门用来生成随机数
public static void main(String[] args) {
Random random=new Random();
//随机产生[0,1)的double的数据
System.out.println(random.nextDouble());
//随机生成int范围内的数据
System.out.println(random.nextInt());
//随机生成一个[0,1)范围内的数据
System.out.println(random.nextFloat());
//随机生成false或true
System.out.println(random.nextBoolean());
//随机生成一个[0,10)int类型的数据
System.out.println(random.nextInt(10));
//随机生成一个[20,30)的数字
System.out.println(20+random.nextInt(10));
System.out.println(20+(int)(random.nextDouble()*10));
}
注意
Random 类位于 java.util 包下。
3.3. File 类
File 类的基本用法:
java.io.File 类: 代表文件和目录, 用于: 读取文件、 创建文件、删除文件、修改文件。
【示例】使用 File 类创建文件
File 类的常见构造方法: public File(String pathname)
以 pathname 为路径创建 File 对象,如果 pathname 是相对路径,则默认的当前路径在系统属性 user.dir 中存储
public static void main(String[] args)throws IOException {
System.out.println(System.getProperty("user.dir"));//当前文件所在的位置
File f=new File("a.txt");//相对路径,默认放在uesr.dir目录下
f.createNewFile();//创建文件
}
user.dir 就是本项目的目录。 上面代码执行后,在本项目和 D 盘下都生成了新的文件。
这个是绝对路径
通过 File 对象可以访问文件的属性:
public static void main(String[] args) throws IOException {
File f=new File("a.txt");//相对路径,默认放在uesr.dir目录下
f.createNewFile();//创建文件
System.out.println("File f是否存在:"+f.exists());
System.out.println("File f是否是目录:"+f.isDirectory());
System.out.println("File f是否是文件:"+f.isFile());
System.out.println("File f的最后修改时间"+f.lastModified());
System.out.println("FIle f的大小:"+f.length());
System.out.println("File f的文件名:"+f.getName());
System.out.println("File f的文件目录路径"+f.getPath());
}
通过 File 对象创建空文件或目录(在该对象所指的文件或目录不存在的情况下)
使用 mkdir 创建目录
public static void main(String[] args)throws IOException {
//使用 mkdir 创建目录
File f=new File("d:/c.txt");
f.createNewFile();
f.delete();
File f2=new File("d:/电影/华语/大陆");
boolean flag=f2.mkdir();//目录结构中有一个不存在,则不会创建整个目录树
System.out.println(flag);//创建失败
}
使用 mkdirs 创建目录
public static void main(String[] args) {
File f3=new File("d:/电影/华语/大陆");
boolean flag=f3.mkdirs();//目录结构中有一个不存在也没关系;创建整个目录树
System.out.println(flag);//创建成功
}
3.4 递归遍历目录结构和树状展现
本节结合前面给大家讲的递归算法,展示目录结构。大家可以先建立一个目录,下面增加几个子文件夹或者文件,用于测试。
public static void PrintFile(File file,int level){
for(int i=0;i<level;i++){
System.out.print('-');
}
//输出文件名
System.out.println(file.getName());
if(file.isDirectory()){
File[]files=file.listFiles();
for (File temp:files){
PrintFile(temp,level+1);
}
}
}
public static void main(String[] args) throws IOException {
File f1=new File("d:/电影/华语/大陆/哪吒传奇.mp4");
File f2=new File("d:/电影/华语/大陆/战狼.mp4");
File f3=new File("d:/电影/华语/大陆/战狼2.mp4");
f1.createNewFile();
f2.createNewFile();
f3.createNewFile();
File f4=new File("d:/电影/好莱坞/速度与激情8.mp4");
boolean flag=f4.mkdirs();
System.out.println(flag);
File f=new File("d:/电影");
PrintFile(f,0);
}
3.5.枚举
JDK1.5 引入了枚举类型。枚举类型的定义包括枚举声明和枚举体
格式如下:
enum 枚举名 {
枚举体(常量列表)
}
枚举体就是放置一些常量。我们可以写出我们的第一个枚举类型,如示例所示:
import java.util.Random;
/**
* @Author: Lenovo
* @Date: 2024/6/8 15:19
* @description:
*/
enum Season{
SPRING,SUMMER,AUTUMN,WINTRE
}
class Jijie{
public static final int SPRING=0;
public static final int SUMMER=1;
public static final int AUTUMN=2;
public static final int WINTER=3;
}
public class TestEnum {
public static void main(String[] args) {
/*System.out.println(Jijie.SPRING);
System.out.println(Season.SPRING);*/
for(Season s:Season.values()){
System.out.println(s);
}
int a=new Random().nextInt(4);
switch (Season.values()[a]){
case SPRING:
System.out.println("春天");
break;
case SUMMER:
System.out.println("夏天");
break;
case AUTUMN:
System.out.println("秋天");
break;
case WINTRE:
System.out.println("冬天");
break;
}
}
}