JAVA基础深化提高(三) | 常用类

1.包装类

1.1 基本数据类型的包装类

在这里插入图片描述

1.2 Number类

在这里插入图片描述
Number 类是抽象类,因此它的抽象方法,所有子类都需要提供实现。Number 类提供了抽象方法:intValue()、longValue()、floatValue()、doubleValue(),意味着所有的“数字型”包装类都可以互相转型。
【示例】初识包装类

public class WrapperClassTest {
	public static void main(String[ ] args) {
		Integer i = new Integer(10); //从 java9 开始被废弃
		Integer j = Integer.valueOf(50); //官方推荐
	}
}

示例内存分析如图所示:
在这里插入图片描述

1.3 自动拆箱和装箱

自动装箱(autoboxing)和拆箱(unboxing):将基本数据类型和包装类自动转换。
【示例】自动装箱

Integer i = 100;//自动装箱
//相当于编译器自动为您作以下的语法编译:
Integer i = Integer.valueOf(100);//调用的是 valueOf(100),而不是 new Integer(100)

【示例】自动拆箱

Integer i = 100;
int j = i;//自动拆箱
//相当于编译器自动为您作以下的语法编译:
int j = i.intValue();

1.4 包装类的缓存问题

  整型、char类型所对应的包装类,在自动装箱时,对于-128~127之间的值会进行缓存处理,其目的是提高效率。
  缓存原理为:如果数据在-128~127这个区间,那么在类加载时就已经为该区间的每个数值创建了对象,并将这256个对象存放到一个名为cache的数组中。每当自动装箱过程发生时(或者手动调用valueOf()时),就会先判断数据是否在该区间,如果在则直接获取数组中对应的包装类对象的引用,如果不在该区间,则会通过new调用包装类的构造方法来创建对象。
【示例】Integer 类相关源码

public static Integer valueOf(int i) {
	 if (i >= IntegerCache.low && i <= IntegerCache.high)
	 		return IntegerCache.cache[i + (-IntegerCache.low)];
	 return new Integer(i);
}
  1. IntegerCache类为Integer类的一个静态内部类,仅供Integer类使用。
  2. 一般情况下 IntegerCache.low为-128,IntegerCache.high为127

【示例】IntegerCache 类相关源码

 private static class IntegerCache {
        static final int low = -128;
        static final int high;
        static final Integer cache[];

        static {
            // high value may be configured by property
            int h = 127;
            String integerCacheHighPropValue =
                sun.misc.VM.getSavedProperty("java.lang.Integer.IntegerCache.high");
            if (integerCacheHighPropValue != null) {
                try {
                    int i = parseInt(integerCacheHighPropValue);
                    i = Math.max(i, 127);
                    // Maximum array size is Integer.MAX_VALUE
                    h = Math.min(i, Integer.MAX_VALUE - (-low) -1);
                } catch( NumberFormatException nfe) {
                    // If the property cannot be parsed into an int, ignore it.
                }
            }
            high = h;

            cache = new Integer[(high - low) + 1];
            int j = low;
            for(int k = 0; k < cache.length; k++)
                cache[k] = new Integer(j++);

            // range [-128, 127] must be interned (JLS7 5.1.7)
            assert IntegerCache.high >= 127;
        }

        private IntegerCache() {}
    }

由上面的源码我们可以看到,静态代码块的目的就是初始化数组cache的,这个过程会在类加载时完成。

总结

  • 自动装箱调用的是 valueOf()方法,而不是 new Integer()方法。
  • 自动拆箱调用的 xxxValue()方法。
  • 包装类在自动装箱时为了提高效率,对于-128~127 之间的值会进行缓存处理。超过范围后,对象之间不能再使用==进行数值的比较,而是使用 equals 方法。

2.字符串相关类

String 类代表不可变的字符序列
StringBuilder 类和 StringBuffer 类代表可变字符序列。

2.1 String 类源码分析

  String 类对象代表不可变的 Unicode 字符序列,因此我们可以将 String 对象称为“不可变对象”。 那什么叫做“不可变对象”呢?指的是对象内部的成员变量的值无法再改变。
我们打开 String 类的源码,如图所示:
在这里插入图片描述
  我们发现字符串内容全部存储到 value[ ]数组中,而变量 value 是 final 类型的,也就是常量(即只能被赋值一次)。 这就是“不可变对象”的典型定义方式。

在遇到字符串常量之间的拼接时,编译器会做出优化,即在编译期间就会完成字符串的拼接。因此,在使用==进行 String 对象之间的比较时,我们要特别注意,如示例所示。

【示例】字符串常量拼接时的优化

public class TestString2 {
	public static void main(String[ ] args) {
		//编译器做了优化,直接在编译的时候将字符串进行拼接
		String str1 = "hello" + " java";//相当于 str1 = "hello java";
		String str2 = "hellojava";
		System.out.println(str1 == str2);//true
		String str3 = "hello";
		String str4 = " java";
		//编译的时候不知道变量中存储的是什么,所以没办法在编译的时候优化
		String str5 = str3 + str4;
		System.out.println(str2 == str5);//false
	}
}

2.2 StringBuffer 和 StringBuilder 可变字符序列

StringBuffer 和 StringBuilder 都是可变的字符序列。

  • StringBuffer 线程安全,做线程同步检查, 效率较低。
  • StringBuilder 线程不安全,不做线程同步检查,因此效率较高。建议采用该类。

【示例】StringBuffer/StringBuilder 基本用法

        public class TestStringBufferAndBuilder{
            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,下面的方法同样适用 StringBuilder*/
                StringBuffer sb2 = new StringBuffer("Java");
                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());//字符串逆序
            }
        }

2.3 不可变和可变字符序列使用陷阱

  String 一经初始化后,就不会再改变其内容了。对 String 字符串的操作实际上是对其副本(原始拷贝)的操作,原来的字符串一点都没有改变。比如:

	String s ="a"; 创建了一个字符串

  s = s+“b”; 实际上原来的"a"字符串对象已经丢弃了,现在又产生了另一个字符串s+“b”(也就是"ab")。 如果多次执行这些改变串内容的操作,会导致大量副本字符串对象存留在内存中,降低效率。如果这样的操作放到循环中,会极大影响程序的时间和空间性能,甚至会造成服务器的崩溃。
  相反,StringBuilder 和 StringBuffer 类是对原字符串本身操作的,可以对字符串进行修改而不产生副本拷贝或者产生少量的副本。因此可以在循环中使用。
【示例】String 和 StringBuilder 在字符串频繁修改时的效率测试

public class Test {
    public static void main(String[ ] args) {
/**使用 String 进行字符串的拼接*/
        String str8 = "";
        long num1 = Runtime.getRuntime().freeMemory();//获取系统剩余内存空间
        long time1 = System.currentTimeMillis();//获取系统的当前时间
        for (int i = 0; i < 5000; i++) {
            str8 = str8 + i;//相当于产生了 5000 个对象
        }
        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));
    }
}

执行结果如图所示:
在这里插入图片描述

3.时间处理相关类

  “时间如流水,一去不复返”,时间是一维的。所以,我们需要一把刻度尺来表达和度量时间。在计算机世界,我们把 1970 年 1 月 1 日 00:00:00 定为基准时间,每个度量单位是毫秒(1 秒的千分之一),如图所示。
在这里插入图片描述
  我们用 long 类型的变量来表示时间,从基准时间前后几亿年都能表示。
  这个“时刻数值”是所有时间类的核心值,年月日都是根据这个“数值”计算出来的。

3.1 Date 时间类(java.util.Date)

【示例】Date 类的使用

System.currentTimeMillis():时间戳是指格林威治时间1970年01月01日00时00分00秒(北京时间1970年01月01日08时00分00秒)起至现在的总毫秒数

long nowNum = System.currentTimeMillis(); //当前时刻对应的毫秒数
Date d = new Date(); //当前时刻的对象
System.out.println(d.getTime()); //返回时间对应的毫秒数
Date d2 = new Date(1000L * 3600 * 24 * 365 * 150); //距离 1970年 150 年
System.out.println(d2);

3.2 DateFormat 类和 SimpleDateFormat 类

DateFormat 类的作用

  把时间对象转化成指定格式的字符串。反之,把指定格式的字符串转化成时间对象。
  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 = "2049-10-1";
        Date date = s2.parse(time);
        System.out.println("date1: " + date);
        time = "2049-10-1 20:15:30";
        date = s1.parse(time);
        System.out.println("date2: " + date);
    }
}

字母日期或时间元素表示示例
GEra 标志符TextAD
yYear1996; 96
M年中的月份MonthJuly; Jul; 07
w年中的周数Number27
W月份中的周数Number2
D年中的天数Number189
d月份中的天数Number10
F月份中的星期Number2
E星期中的天数TextTuesday; Tue
aAm/pm 标记TextPM
H一天中的小时数(0-23)Number0
k一天中的小时数(1-24)Number24
Kam/pm中的小时数(0-11)Number
ham/pm 中的小时数(1-12)Number12
m小时中的分钟数Number30
s分钟中的秒数Number55
S毫秒数Number978
z时区General time zonePacific Standard Time; PST; GMT-08:00
Z时区RFC 822 time zone0800

【示例】获取今天时本年度第几天

import java.text.SimpleDateFormat;
import java.util.Date;
public class TestDateFormat2 {
	public static void main(String[ ] args) {
		SimpleDateFormat s1 = new SimpleDateFormat("D");
		String daytime = s1.format(new Date());
		System.out.println(daytime);
	}
}

3.3 Calendar 日历类

Calendar 类是一个抽象类,为我们提供了关于日期计算的功能,比如:年、月、日、时、分、秒的展示和计算。

获取Calendar实例的方法

  • 使用Calendar.getInstance()方法
  • 调用它的子类GregorianCalendar的构造器。

注意月份的表示,一月是 0,二月是 1,以此类推,12 月是 11。 因为大多数人习惯于使用单词而不是使用数字来表示月份,这样程序也许更易读,父类 Calendar 使用常量来表示月份:JANUARY、FEBRUARY 等等。

【示例】GregorianCalendar 类和 Calendar 类的使用

import java.util.*;
public class TestCalendar {
    public static void main(String[ ] args) {
		// 得到相关日期元素
        GregorianCalendar calendar = new GregorianCalendar(2049, 9, 1, 22, 10, 50);
        int year = calendar.get(Calendar.YEAR); // 打印:2049
        int month = calendar.get(Calendar.MONTH); // 打印:9
        int day = calendar.get(Calendar.DAY_OF_MONTH); // 打印:1
        int day2 = calendar.get(Calendar.DATE); // 打印:1
		// 日:Calendar.DATE 和 Calendar.DAY_OF_MONTH 同义
        int date = calendar.get(Calendar.DAY_OF_WEEK); // 打印:1
		// 星期几 这里是: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, 2049);
        calendar2.set(Calendar.MONTH, Calendar.OCTOBER); // 月份数:0-11
        calendar2.set(Calendar.DATE, 1);
        calendar2.set(Calendar.HOUR_OF_DAY, 10);
        calendar2.set(Calendar.MINUTE, 20);
        calendar2.set(Calendar.SECOND, 23);
        printCalendar(calendar2);
		// 日期计算
        GregorianCalendar calendar3 = new GregorianCalendar(2049, 9, 1, 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);
    }
}

【示例】Calendar.getInstance()

    @Test
    public void test3() throws ParseException {
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS");

        //产生
        Calendar c = Calendar.getInstance(); //当前时间new Date()

        //得到field
        System.out.println(c.get(Calendar.YEAR)); //得到年
        System.out.println(c.get(Calendar.MONTH)); //得到月 传统日期月从0开始,周从周日=1开始
        System.out.println(c.get(Calendar.DAY_OF_MONTH));
        System.out.println(c.get(Calendar.HOUR_OF_DAY));

        //设置field
        c.set(Calendar.MONTH, 0); //传统日期月从0开始
        System.out.println(sdf.format(c.getTime()));//得到date

        //减3个月
        c.add(Calendar.MONTH, -3);
        System.out.println(sdf.format(c.getTime()));//得到date


        //创建1970-1-1 8:0:0.0时间
        //方式1:
        String dateStr = "1970-01-1 08:0:0.0";
        //把字符串解析成日期,string->date
        Date date1 = sdf.parse(dateStr);
        System.out.println(date1.getTime());

        //方式2
        Calendar c2 = Calendar.getInstance();
        c2.set(1970, 0, 1,8,0,0);
        c2.set(Calendar.MILLISECOND, 0);
        System.out.println(sdf.format(c2.getTime()));


        //当前时间的4周后
        Calendar c3 = Calendar.getInstance(); //当前时间
        c3.add(Calendar.WEEK_OF_YEAR, 5);
        System.out.println(sdf.format(c3.getTime()));

    }

3.4 JDK8新日期API

Java 8中引入的java.time API 已经纠正了过去的缺陷,将来很长一段时间内它都会为我们服务。
Java 8 吸收了 Joda-Time 的精华,以一个新的开始为 Java 创建优秀的 API。新的 java.time 中包含了所有关于本地日期(LocalDate)、本地时间(LocalTime)、本地日期时间(LocalDateTime)、时区(ZonedDateTime)和持续时间(Duration)的类。历史悠久的 Date 类新增了 toInstant() 方法,用于把 Date 转换成新的表示形式。这些新增的本地化时间日期 API 大大简化了日期时间和本地化的管理。

  • java.time – 包含值对象的基础包
  • java.time.chrono – 提供对不同的日历系统的访问
  • java.time.format – 格式化和解析时间和日期
  • java.time.temporal – 包括底层框架和扩展特性
  • java.time.zone – 包含时区支持的类

3.4.1 LocalDateTime

LocalDate、 LocalTime、 LocalDateTime 类是其中较重要的几个类,它们的实例是不可变的对象,分别表示使用 ISO-8601日历系统的日期、时间、日期和时间。它们提供了简单的本地日期或时间,并不包含当前的时间信息,也不包含与时区相关的信息。

  • LocalDate代表IOS格式(yyyy-MM-dd)的日期,可以存储 生日、纪念日等日期。
  • LocalTime表示一个时间,而不是日期。
  • LocalDateTime是用来表示日期和时间的, 这是一个最常用的类之一。
    注: ISO-8601日历系统是国际标准化组织制定的现代公民的日期和时间的表示法,也就是公历。
方法描述
now() / * now(ZoneId zone)静态方法, 根据当前时间创建对象/指定时区的对象
of()静态方法, 根据指定日期/时间创建对象
getDayOfMonth()/getDayOfYear()获得月份天数(1-31) /获得年份天数(1-366)
getDayOfWeek()获得星期几(返回一个 DayOfWeek 枚举值)
getMonth()获得月份, 返回一个 Month 枚举值
getMonthValue() / getYear()获得月份(1-12) /获得年份
getHour()/getMinute()/getSecond()获得当前对象对应的小时、 分钟、 秒
withDayOfMonth()/withDayOfYear()/ withMonth()/withYear()将月份天数、 年份天数、 月份、 年份修改为指定的值并返回新的对象
plusDays(), plusWeeks(), plusMonths(), plusYears(),plusHours()向当前对象添加几天、 几周、 几个月、 几年、 几小时
minusMonths() / minusWeeks()/ minusDays()/minusYears()/minusHours()从当前对象减去几月、 几周、 几天、 几年、 几小时

3.4.2 Instant

  • Instant:时间线上的一个瞬时点。 这可能被用来记录应用程序中的事件时间戳。
  • 在处理时间和日期的时候,我们通常会想到年,月,日,时,分,秒。然而,这只是时间的一个模型,是面向人类的。第二种通用模型是面向机器的,或者说是连续的。在此模型中,时间线中的一个点表示为一个很大的数,这有利于计算机处理。 在UNIX中,这个数从1970年开始,以秒为的单位;同样的,在Java中,也是从1970年开始,但以毫秒为单位。
  • java.time包通过值类型Instant提供机器视图,不提供处理人类意义上的时间单位。 Instant表示时间线上的一点,而不需要任何上下文信息,例如,时区。概念上讲, 它只是简单的表示自1970年1月1日0时0分0秒( UTC)开始的秒数。 因为java.time包是基于纳秒计算的,所以Instant的精度可以达到纳秒级。
  • (1 ns = 10-9 s) 1秒 = 1000毫秒 =106微秒=109纳秒
方法描述
now()静态方法, 返回默认UTC时区的Instant类的对象
ofEpochMilli(long epochMilli)静态方法 数之后的,Instant 返回在类的对象 1970-01-01 00:00:00基础上加上指定毫秒
atOffset(ZoneOffset offset)结合即时的偏移来创建一个 OffsetDateTime
toEpochMilli()返回1970-01-01 00:00:00到当前时间的毫秒数, 即为时间戳

**注意:**时间戳是指格林威治时间1970年01月01日00时00分00秒(北京时间1970年01月01日08时00分00秒)起至现在的总毫秒数

3.4.3 DateTimeFormatter

java.time.format.DateTimeFormatter 类:该类提供了三种格式化方法:

  • 预定义的标准格式。如:ISO_LOCAL_DATE_TIME;ISO_LOCAL_DATE;ISO_LOCAL_TIME
  • 本地化相关的格式。如: ofLocalizedDateTime(FormatStyle.LONG)
  • 自定义的格式。如: ofPattern(“yyyy-MM-dd hh:mm:ss”)
方 法描 述
ofPattern(String pattern)静 态 方 法 , 返 回 一 个 指 定 字 符 串 格 式 的 DateTimeFormatter
format(TemporalAccessor t)格式化一个日期、 时间, 返回字符串
parse(CharSequence text)将指定格式的字符序列解析为一个日期、 时间
    @Test
    public void test5() throws ParseException {
        //得到当前时间
        //LocalDateTime:(UTC)日期时间,理解成Date + Calander
        //LocalDate:日期
        //LocalTime:时间
        LocalDateTime l1 = LocalDateTime.now();
        System.out.println("l1 = " + l1);

        //得到field
        System.out.println(l1.getMonth().getValue()); //新时间api,月从1开始
        System.out.println(l1.getYear());
        System.out.println(l1.get(ChronoField.HOUR_OF_DAY)); //时

        //设置field,支持chain方法链,设置1月1日
        LocalDateTime l2 = l1.withMonth(1).withDayOfMonth(1);
        System.out.println(l2);

        //加3个月,加3周
//        l2.plusMonths(3).plus(3, ChronoUnit.WEEKS)
        LocalDateTime l3 = l2.plusMonths(3).plusWeeks(3);
        System.out.println(l3);

        //减3月
        LocalDateTime l4 = l3.minusMonths(3);
        System.out.println(l4);

        //创建1970-1-1 8:0:0.0时间
        LocalDateTime l5 = LocalDateTime.of(1970, 1, 1, 0, 0, 0, 0);
        System.out.println(l5);

        //时间戳操作 Instant
        Instant i1 = l5.toInstant(ZoneOffset.UTC); //得到utc时间的Instant
        System.out.println(i1.toEpochMilli());

//        ZoneOffset.getAvailableZoneIds().forEach(s -> System.out.println(s));

        LocalDateTime l6 = LocalDateTime.of(1970, 1, 1, 8, 0, 0, 0);
        Instant i2 = l6.toInstant(ZoneOffset.ofHours(8)); //得到东8区的Instant
        System.out.println(i2.toEpochMilli()); //utc时间的1970.1.1.0点,北京时间的8点,是时间戳的0

        //格式化
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy年MM月dd日HH时mm分ss秒.SSS");
        System.out.println(formatter.format(LocalDateTime.now()));
//        formatter.parse() //解析一个时间

    }

4.其他常用类

4.1 Math 类

【示例】Math 类的常用方法

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)
	}
}

执行结果如图所示:
在这里插入图片描述

4.2 System和Random 类

System
  • System类代表系统,系统级的很多属性和控制方法都放置在该类的内部。该类位于java.lang包。
  • 由于该类的构造器是private的,所以无法创建该类的对象,也就是无法实例化该类。其内部的成员变量和成员方法都是static的, 所以也可以很方便的进行调用。
  • 成员变量
    • System类内部包含in、 out和err三个成员变量,分别代表标准输入流(键盘输入),标准输出流(显示器)和标准错误输出流(显示器)。
  • 成员方法
    • native long currentTimeMillis():该方法的作用是返回当前的计算机时间,时间的表达格式为当前计算机时间和GMT时间(格林威治时间)1970年1月1号0时0分0秒所差的毫秒数。
    • void exit(int status):该方法的作用是退出程序。其中status的值为0代表正常退出,非零代表异常退出。 使用该方法可以在图形界面编程中实现程序的退出功能等。
    • void gc():该方法的作用是请求系统进行垃圾回收。至于系统是否立刻回收,则取决于系统中垃圾回收算法的实现以及系统执行时的情况。
    • String getProperty(String key):该方法的作用是获得系统中属性名为key的属性对应的值。系统中常见的属性名以及属性的作用如下表所示:
public class SystemDemo1 {

    public static void main(String[] args) {
        Scanner in = new Scanner(System.in); //得到用户控制台输入
        System.out.println("请输入i,输入0退出");
        int i = in.nextInt();

        if (i == 0) {
            System.exit(0);
        }

        System.out.println("i=" + i);

    }

    @Test
    public void test1() {
        Scanner in = new Scanner(System.in); //得到用户控制台输入
        System.out.println("请输入i,输入0退出");
        int i = in.nextInt();

        if (i == 0) {
            System.exit(0);
        }

        System.out.println("i=" + i);
    }

    @Test
    public void test2() {
        System.out.println(System.currentTimeMillis());
    }

    @Test
    public void test3() {
        String javaVersion = System.getProperty("java.version");
        System.out.println("java的version:" + javaVersion);
        String javaHome = System.getProperty("java.home");
        System.out.println("java的home:" + javaHome);
        String osName = System.getProperty("os.name");
        System.out.println("os的name:" + osName);
        String osVersion = System.getProperty("os.version");
        System.out.println("os的version:" + osVersion);
        String userName = System.getProperty("user.name");
        System.out.println("user的name:" + userName);
        String userHome = System.getProperty("user.home");
        System.out.println("user的home:" + userHome);
        String userDir = System.getProperty("user.dir");
        System.out.println("user的dir:" + userDir);
    }
}
Random

public void addShutdownHook(Thread hook):捕获jvm退出时间

import java.util.Random;
public class TestRandom {
	public static void main(String[ ] args) {
		Runtime.getRuntime().addShutdownHook(new Thread(new Runnable() {
            @Override
            public void run() {
                System.out.println("捕获了jvm退出--释放资源");
            }
        }));

		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));
	}
}

4.3 File 类

File 类的基本用法

  java.io.File 类:代表文件和目录,用于:读取文件、创建文件、删除文件、修改文件。
【示例】使用 File 类创建文件
File 类的常见构造方法:public File(String pathname)
  以 pathname 为路径创建 File 对象,如果 pathname 是相对路径,则默认的当前路径在系统属性 user.dir 中存储。

import java.io.File;
public class TestFile1 {
	public static void main(String[ ] args) throws Exception {
		System.out.println(System.getProperty("user.dir"));
		File f = new File("a.txt"); //相对路径:默认放到 user.dir 目录下面
		f.createNewFile();//创建文件
		File f2 = new File("d:/b.txt");//绝对路径
		f2.createNewFile();
	}
}

user.dir 就是本项目的目录。上面代码执行后,在本项目和 D 盘下都生成了新的文件。

1.通过 File 对象可以访问文件的属性:
在这里插入图片描述
2.通过 File 对象创建空文件或目录(在该对象所指的文件或目录不存在的情况下)
在这里插入图片描述

4.4 BigInteger和BigDecimal

BigInteger
  • Integer类作为int的包装类,能存储的最大整型值为231-1, Long类也是有限的,最大为263-1。 如果要表示再大的整数,不管是基本数据类型还是他们的包装类都无能为力,更不用说进行运算了。
  • java.math包的BigInteger可以表示不可变的任意精度的整数。 BigInteger 提供所有 Java 的基本整数操作符的对应物,并提供java.lang.Math 的所有相关方法。另外, BigInteger 还提供以下运算:模算术、 GCD 计算、质数测试、素数生成、位操作以及一些其他操作。
  • 构造器 BigInteger(String val): 根据字符串构建BigInteger对象
  • 常用方法
    • public BigInteger abs():返回此 BigInteger 的绝对值的 BigInteger。
    • BigInteger add(BigInteger val) :返回其值为 (this + val) 的 BigInteger
    • BigInteger subtract(BigInteger val) :返回其值为 (this - val) 的 BigInteger
    • BigInteger multiply(BigInteger val) :返回其值为 (this * val) 的 BigInteger
    • BigInteger divide(BigInteger val) :返回其值为 (this / val) 的 BigInteger。整数相除只保留整数部分。
    • BigInteger remainder(BigInteger val) :返回其值为 (this % val) 的 BigInteger。
    • BigInteger[] divideAndRemainder(BigInteger val):返回包含 (this / val) 后跟(this % val) 的两个 BigInteger 的数组。
    • BigInteger pow(int exponent) :返回其值为 (thisexponent) 的 BigInteger。
BigDecimal
  • 一般的Float类和Double类可以用来做科学计算或工程计算,但在商业计算中,要求数字精度比较高,故用到java.math.BigDecimal类。
  • BigDecimal类支持不可变的、任意精度的有符号十进制定点数。
  • 构造器
    • public BigDecimal(double val)
    • public BigDecimal(String val)
  • 常用方法
    • public BigDecimal add(BigDecimal augend)
    • public BigDecimal subtract(BigDecimal subtrahend)
    • public BigDecimal multiply(BigDecimal multiplicand)
    • public BigDecimal divide(BigDecimal divisor, int scale, int roundingMode)
public class BigIntegerDemo {

    @Test
    public void test1() {
        System.out.println(Integer.MAX_VALUE);

        Integer i1 = 2147483647;

//        Integer i2 = 2147483648;

        BigInteger i3= new BigInteger("10");
        System.out.println(i3);

        BigInteger i4 = new BigInteger("15");



        BigInteger i5 = i3.add(i4);
        System.out.println(i5);

        BigInteger[] arrs = i3.divideAndRemainder(new BigInteger("3"));
        System.out.println(Arrays.toString(arrs));

    }
}

4.5 正则表达式

正则表达式,又称规则表达式,(Regular Expression,在代码中常简写为regex、regexp或RE),是一种文本模式,包括普通字符(例如,a 到 z 之间的字母)和特殊字符(称为"元字符"),是计算机科学的一个概念。正则表达式使用单个字符串来描述、匹配一系列匹配某个句法规则的字符串,通常被用来检索、替换那些符合某个模式(规则)的文本。
简单来说,正则表达式就是一个很牛逼的字符串处理工具。

正则在线工具 : https://c.runoob.com/front-end/854/?optionGlobl=global

4.5.1 String类中的正则表达式
public class StringRegexDemo1 {

    public static void main(String[] args) {
        Scanner in = new Scanner(System.in);
        while (true) {
            System.out.println("请输入qq");
            String s1 = in.nextLine();
            //匹配s1中是否是6-12位数字
            System.out.println(s1.matches("^[0-9]{6,12}$"));
        }
    }

    @Test
    public void test1() {
        String s = "Java 是由 Sun Microsystems 公司于 1995 年 5 月推出的高级程序设计语言Java 可运行于多个平台,如 windows,Mac OS 及其他多种 UNIX 版本的系统";
//        s = s.replaceAll("[a-zA-Z]{1,}", "hello");
        s = s.replaceAll("[a-zA-Z]+", "hello");
        s = s.replaceAll("\\d+", "world");
        System.out.println(s);
    }


    @Test
    public void test2() {
        String s1 = "aaa,bbb,123,456,hello,word";
        String[] arrs = s1.split(",");
        for (int i = 0; i < arrs.length; i++) {
            System.out.println(arrs[i]);
        }
    }

    @Test
    public void test3() {
        String s2 = "hello12333world4567welcome34to4beijing";
        String[] arrs2 = s2.split("\\d+");
        for (int i = 0; i < arrs2.length; i++) {
            System.out.println(arrs2[i]);
        }
    }
}
4.5.2 正则表达式常用类
(1) Pattern类

pattern 对象是一个正则表达式的编译表示。Pattern 类没有公共构造方法。要创建一个 Pattern 对象,你必须首先调用其公共静态编译方法,它返回一个 Pattern 对象。该方法接受一个正则表达式作为它的第一个参数。

  • compile():通过正则得到一个Pattern
  • matchers():方便正则表达式只是用一次,进行匹配
  • matcher():产生Matcher对象,多次正则匹配推荐使用
(2) Matcher类

Matcher 对象是对输入字符串进行解释和匹配操作的引擎。与Pattern 类一样,Matcher 也没有公共构造方法。你需要调用 Pattern 对象的 matcher 方法来获得一个 Matcher 对象。

  1. 索引方法

索引方法提供了有用的索引值,精确表明输入字符串中在哪能找到匹配:

  • public int start()返回以前匹配的初始索引。
  • public int start(int group) 返回在以前的匹配操作期间,由给定组所捕获的子序列的初始索引
  • public int end()返回最后匹配字符之后的偏移量。
  • public int end(int group)返回在以前的匹配操作期间,由给定组所捕获子序列的最后字符之后的偏移量。
  1. 查找方法:

查找方法用来检查输入字符串并返回一个布尔值,表示是否找到该模式:

  • public boolean lookingAt() 尝试将从区域开头开始的输入序列与该模式匹配。
  • public boolean find()尝试查找与该模式匹配的输入序列的下一个子序列。
  • public boolean find(int start)重置此匹配器,然后尝试查找匹配该模式、从指定索引开始的输入序列的下一个子序列。
  • public boolean matches()尝试将整个区域与模式匹配。
  • group()返回上一个匹配项匹配的输入子序列。
  • group(int group)返回上一个匹配操作期间给定组捕获的输入子序列。
  1. 替换方法

替换方法是替换输入字符串里文本的方法:

  • public Matcher appendReplacement(StringBuffer sb, String replacement)实现非终端添加和替换步骤。
  • public StringBuffer appendTail(StringBuffer sb)实现终端添加和替换步骤。
  • public String replaceAll(String replacement)替换模式与给定替换字符串相匹配的输入序列的每个子序列。
  • public String replaceFirst(String replacement) 替换模式与给定替换字符串匹配的输入序列的第一个子序列。
  • public static String quoteReplacement(String s)返回指定字符串的字面替换字符串。这个方法返回一个字符串,就像传递给Matcher类的appendReplacement 方法一个字面字符串一样工作。
public class RegexDemo1 {

    public static void main(String[] args) {
        Scanner in = new Scanner(System.in);
        //
        Pattern pattern = Pattern.compile("^[0-9]{5,12}$"); //正则的编译对象

        while (true) {
            System.out.println("请输入qq");
            String s1 = in.nextLine();
            Matcher matcher = pattern.matcher(s1);
            System.out.println(matcher.matches()); //全部匹配
//            System.out.println(s1.matches("^[0-9]{5,12}$"));
        }
    }

    @Test
    public void test1() {
        //正则编译对象,只匹配一次可以使用matches方法
        System.out.println(Pattern.matches("^[0-9]{5,12}$", "77546313")); //正则是否全部匹配
        System.out.println(Pattern.matches("^[0-9]{5,12}$", "123456")); //正则是否全部匹配
        System.out.println(Pattern.matches("^[0-9]{5,12}$", "333333")); //正则是否全部匹配

        Pattern pattern = Pattern.compile("^[0-9]{5,12}$");
        pattern.matcher("77546313").matches();
        pattern.matcher("123456").matches();
        pattern.matcher("333333").matches();
    }

    @Test
    public void test2() {
        //全部匹配
        Pattern pattern = Pattern.compile("\\d{5,12}");
        Matcher matcher = pattern.matcher("12345a34343434");
        System.out.println(matcher.matches()); //全部匹配
    }

    @Test
    public void test3() {
        //全部匹配
        Pattern pattern = Pattern.compile("\\d{5,12}");
        Matcher matcher = pattern.matcher("12345a34343434abc9878989");

        while (matcher.find()) {//查找匹配,如果匹配返回ture
            String target = matcher.group();//得到上一次匹配的子序列
            System.out.println(target + "-" + matcher.start() + "-" + matcher.end()); //start得到上一个匹配的索引开始
        }
    }

    @Test
    public void test4() {
        String content =
                "Java 是由 Sun Microsystems 公司于 1995 年 5 月推出的高级程序设计语言。\n"
                        + "Java 可运行于多个平台,如 windows,Mac OS 及其他多种 UNIX 版本的系统。\n"
                        + "本教程通过简单的实例将让大家更好的了解 Java 编程语言。\n"
                        + "移动操作系统 Android 大部分的代码采用 Java 编程语言编程。";
        Pattern pattern = Pattern.compile("([a-zA-Z]+) | (\\d+)");
        Matcher matcher = pattern.matcher(content);

        while (matcher.find()) {
            String target = matcher.group(2); //0:全部的正则捕获组,1:的一个小括号的正则补货组
            System.out.println(target);
        }

    }


    @Test
    public void test6() {
        String content =
                "Java 是由 Sun Microsystems 公司于 1995 年 5 月推出的高级程序设计语言。\n"
                        + "Java 可运行于多个平台,如 windows,Mac OS 及其他多种 UNIX 版本的系统。\n"
                        + "本教程通过简单的实例将让大家更好的了解 Java 编程语言。\n"
                        + "移动操作系统 Android 大部分的代码采用 Java 编程语言编程。";

        //创建一个Pattern对象
        Pattern pattern = Pattern.compile("Java");
        //创建一个匹配对象
        Matcher matcher = pattern.matcher(content);

        StringBuffer sb = new StringBuffer();
        while (matcher.find()) {
            //将Java替换为java后,将最后匹配到之前的子串都添加到sb对象中
            matcher.appendReplacement(sb, "java");
            System.out.println("sb:" + sb);
            System.out.println("---------分割线-----------");
        }
        //将最后匹配到的子串添加到sb中
        matcher.appendTail(sb);
        System.out.println("sb: " + sb);
    }

}

4.6 正则表达式的语法

4.6.1 正则转义符

元符号-转义号\
\符号说明:在我们使用正则表达式去检索某些特殊字符的时候,需要用到转义字符,否则检测不到结果,甚至会报错。
需要用到转义符的字符有:. * + ( )$ / \ ? [ ] ^ { }
注意:在Java的正则表达式中,两个\代表其他语言中的一个\

4.6.2 正则表达式支持字符

正则表达式所支持的合法字符

字符解释
X字符x(x 可代表任何合法的字符)
\0mnn八进制数 0mnn 所表示的字符
\xhh十六进制值 0xhh 所表示的字符
\uhhhh十六进制值 0xhhhh 所表示的 Unicode 字符
\t制表符(“\u0009”)
\n新行(换行)符(‘\u000A’)
\r回车符(‘\u000D’)
\f换页符(‘\u000C’)
\a报警(bell)符(‘\u0007’)
\eEscape 符(‘\u001B’)
\cxx 对应的的控制符。例如,\cM匹配 Ctrl-M。x 值必须为 A~Z 或 a~z 之一。

正则表达式中的特殊字符

特殊字符说明
$匹配一行的结尾。要匹配 $ 字符本身,请使用$
^匹配一行的开头。要匹配 ^ 字符本身,请使用^
()标记子表达式的开始和结束位置。要匹配这些字符,请使用(和)
[]用于确定中括号表达式的开始和结束位置。要匹配这些字符,请使用[和]
{}用于标记前面子表达式的出现频度。要匹配这些字符,请使用{和}
*指定前面子表达式可以出现零次或多次。要匹配 * 字符本身,请使用*
+指定前面子表达式可以出现一次或多次。要匹配 + 字符本身,请使用+
?指定前面子表达式可以出现零次或一次。要匹配 ?字符本身,请使用?
.匹配除换行符\n之外的任何单字符。要匹配.字符本身,请使用.
\用于转义下一个字符,或指定八进制、十六进制字符。如果需匹配\字符,请用\
|指定两项之间任选一项。如果要匹配丨字符本身,请使用|

预定义字符

预定义字符说明
.可以匹配任何字符
\d匹配 0~9 的所有数字
\D匹配非数字
\s匹配所有的空白字符,包括空格、制表符、回车符、换页符、换行符等
\S匹配所有的非空白字符
\w匹配所有的单词字符,包括 0~9 所有数字、26 个英文字母和下画线_
\W匹配所有的非单词字符

方括号表达式
方括号表达式 说明 表示枚举 例如 [abc]表示 a、b、c 其中任意一个字符; [gz]表示 g、z 其中任意一个字符 表示范围:- 例如 [a-f]表示 a~f 范围内的任意字符; [\u0041-\u0056]表示十六进制字符 \u0041 到 \u0056 范围的字符。范围可以和枚举结合使用,如 [a-cx-z],表示 ac、xz 范围内的任意字符 表示求否:^ 例如 [^abc]表示非 a、b、c 的任意字符; [^a-f]表示不是 a~f 范围内的任意字符 表示“与”运算:&& 例如 [a-z&&[def]]是 a~z 和 [def] 的交集,表示 d、ef[a-z&&^bc]]是 a~z 范围内的所有字符,除 b 和 c 之外[ad-z] [a-z&&[m-p]]是 a~z 范围内的所有字符,除 m~p 范围之外的字符 表示“并”运算 并运算与前面的枚举类似。例如 [a-d[m-p]]表示 [a-dm-p]

补充:
Java正则表达式默认是区分字母大小写的,如要实现不区分大小写
(?i)abc表示abc都不区分大小写
a(?i)bc表示bc不区分大小写
a((?i)b)c表示只有b不区分大小写
Pattern pattern=Pattern.compile(regStr,Pattern.CASE_INSENSITIVE);
//当创建Pattern对象时,指定Pattern.CASE_INSENSITIVE,表示匹配不区分字母大小写
细节:Java匹配默认贪婪匹配,即尽可能匹配多的,比如"a{3,4}“,表示匹配aaa或者aaaa,但是优先匹配aaaa,例如原字符串中包括"aaaaaa”,匹配"a{3,4}“时,会找到"aaaa”

4.6.3 捕获组(capture group)

从正则表达式左侧开始,每出现一个左括号"("记做一个分组,分组编号从 1 开始。0 代表整个表达式。常用分组构造形式(pattern)
对于时间字符串:2017-04-25,表达式如下
(\d{4})-((\d{2})-(\d{2}))
有 4 个左括号,所以有 4 个分组:

编号捕获组匹配
0(\d{4})-((\d{2})-(\d{2}))2017-04-25
1(\d{4})2017
2((\d{2})-(\d{2}))04-25
3(\d{2})04
4(\d{2})25

4.7 正则表达式的常见应用

  1. 验证字符串是否全是汉字
    Pattern pattern=Pattern.compile("^[\u0391-\uffe5]+$");
  2. 验证字符串是否是邮编
    Pattern pattern=Pattern.compile("^\\d{6}$");
  3. 验证字符串是否是QQ号码
    Pattern pattern=Pattern.compile("^[1-9]d{4,9}$");
  4. 验证字符串是否是手机号码(要求:必须以13,14,15,18开头的11位数)
    Pattern pattern=Pattern.compile("^1[3|4|5|8]\\d{9}$");
  5. 验证字符串是否是url
    Pattern pattern=Pattern.compile("^((http|https)://)([\\w-]+\\.)+[\\w-]+(\\/[\\w-?=&/%.#]*)?$");

4.4 枚举

JDK1.5 引入了枚举类型。枚举类型的定义包括枚举声明和枚举体。格式如下:

enum 枚举名 {

	枚举体(常量列表)
	
}
  • 当需要定义一组常量时,强烈建议使用枚举类 使用说明:
    • 使用 enum 定义的枚举类默认继承了 java.lang.Enum类,因此不能再继承其他类
    • 枚举类的构造器只能使用 private 权限修饰符
    • 枚举类的所有实例必须在枚举类中显式列出(, 分隔 ; 结尾)。列出的实例系统会自动添加 public static final 修饰
    • 必须在枚举类的第一行声明枚举类对象
  • Enum类的主要方法:
    • values()方法:返回枚举类型的对象数组。该方法可以很方便地遍历所有的枚举值。
    • valueOf(String str):可以把一个字符串转为对应的枚举类对象。要求字符串必须是枚举类对象的“名字”。如不是,会有运行时异常:IllegalArgumentException。
    • toString():返回当前枚举类对象常量的名称
      枚举体就是放置一些常量。我们可以写出我们的第一个枚举类型,如示例所示:

【示例】创建枚举类型

enum Season {
	SPRING, SUMMER, AUTUMN, WINTER
}

  所有的枚举类型隐性地继承自 java.lang.Enum。枚举实质上还是类!而每个被枚举的
成员实质就是一个枚举类型的实例,他们默认都是 public static final 修饰的。可以直接通
过枚举类型名使用它们。

【示例】枚举的使用

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 WINTER:
                System.out.println("冬天");
                break;
        }
    }
}
/**季节*/
enum Season {
    SPRING, SUMMER, AUTUMN, WINTER
}
/**星期*/
enum Week {
    星期一, 星期二, 星期三, 星期四, 星期五, 星期六, 星期日
}

【示例】订单状态的枚举

package a_enum;

/**
 *   订单状态: Nonpayment(未付款)、 Paid(已付款) 、 Delivered(已发货)、Return(退货)、 Checked(已确认) Fulfilled(已配货)、
 */
public class StateDemo3 {

    public static void main(String[] args) {
        OrderState[] states = OrderState.values();
        for (int i = 0; i < states.length; i++) {
            System.out.println(states[i] + "-" + states[i].getValue() + "-" + states[i].getCode());
        }
    }

    public enum OrderState {
        //static OrderState NON_PAYMENT = new OrderState("未付款")
        NON_PAYMENT(1, "未付款"),
        PAID(2, "已付款"),
        DELIVERED(3, "已发货"),
        RETURN(4, "退货"),
        CHECKED(5, "已确认"),
        FULFILLED(6, "已配货");

        private OrderState(int code, String value) {
            this.code = code;
            this.value = value;
        }

        private int code;
        private String value;

        public String getValue() {
            return value;
        }
        public int getCode() {
            return code;
        }
    }
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值