《疯狂java讲义》第7章 java基础类库

第7章 java基础类库

7.1 与用户互动

  • 运行java程序的参数:java程序入口main()方法的方法签名:
    public static void main (Strign[] args) { ..... }
  • Scanner获取键盘输入:Scanner是一个基于正则表达式的文本扫描器。
    两个扫描输入方法:hasNextXxx()nextXxx()。(Xxx代表Int,Long等基本类型)
    逐行读取:boolean hasNextLine()String nextLine()
    Scanner还可以读取文件输入,在创建Scanner对象时传入一个File对象作为参数Scanner sc = new Scanner(new File("Test.java"));

7.2 系统相关

System类:代表当前java程序的运行平台,程序不能创建System类的对象,(提供一些方法访问环境变量、系统属性、垃圾回收)。

  • 提供两个获取系统当前时间的方法:currentTimeMillis()毫秒、nanoTime()纳秒。
  • in(标准输入,通常键盘);out(标准输出,通常显示器);err(错误输出流)。
  • identityHashCode(Object x)方法,返回指定对象的精确hashCode值。(如果两个对象的identityHashCode值相同,这两个对象绝对是同一个对象)。

Runtime类:代表java程序的运行时环境,每个java程序都有一个与之对应的Runtime实例,应用程序不能创建自己的Runtime实例,可以通过getRuntime()方法获取与之关联的Runtime对象。

  • 提供垃圾回收的方法;load(String filename)loadLibrary(String libname)加载文件和动态链接库。
  • 可以访问JVM的相关信息(处理器数量、内存信息等)。
  • 可以直接单独启动一个进程来运行操作系统的命令。
  • java使用Process代表进程,新增ProcessHandle接口,课获取进程的ID、父进程、后代进程,通过该接口 的onExit()方法可在进程结束时完成某些行为。
  • ProcessHandle.Info类,用于获取进程的命令、参数、启动时间、累计运行时间、累计、运行时间、用户等信息。

7.3 常用类

7.3.1 Object类

  • Object类是所有类、数组、枚举类的父类。所有的java类都是Object类的子类,所以任何java对象都可以调用Object类的方法。
    常用方法:
  • boolean equals(Object obj):判断两个对象是否相等(此处为是否为同一对象)
  • protected void finalize():垃圾回收器调用此方法清理该对象的资源。
  • Class getClass():返回对象的运行时类。
  • int hashCode():返回对象的hashCode值。
  • String toString():返回对象的字符串表示。
  • java还提供了一个protected修饰的clone()方法(该方法只能被子类重写或调用),来实现“自我克隆”,得到一个当前对象的副本,二者之间完全隔离。
    步骤:自定义类实现Cloneable接口;自定义类实现自己的clone()方法;实现clone()方法时通过super.clone();
  • Objects工具类:Objects类提供的toString( )方法不会引发空指针异常(java为工具类命名习惯是加s,数组的工具类Arrays,集合的工具类Collections)

7.3.3 String、StringBuffer、StringBuilder类

  • String类是不可变类,一旦创建不可改变,直至对象被销毁。
  • StringBuffer代表一个字符序列可变的字符串,提供一些方法(append()、insert()、reverse()、setCharAt()、setLength()等方法),通过StringBuffer生成了最终想要的字符串,就可调用它的toString()方法将其转换为一个String对象。
  • StringBuilder类也代表可变字符串对象,区别是,StringBuffer是线程安全的,StringBuilder线程不安全,但性能略高,优先考虑。
  • java 9 字符串的每个字符只占一个字节。
    String类的构造器:

String(); 构造一个空字符串对象
String(byte[] bytes); 通过byte数组构造字符串对象
String(byte[] bytes,int offset,int length)通过byte数组,从offset开始,长度为length的子数组解码成新的String对象
String(char[] value);通过char数组构造字符串对象
String(char[] char,int offset,int length);通过char数组,从offset开始,长度为length的子数组解码成新的String对象
String(String original) 创建一个original的副本
String(StringBuffer buffer);通过StringBuffer数组创建对应String对象
String(StringBuilder builder);通过StringBuilder数组创建对应String对象

String类的方法:

StringBuffer类的常用方法:
《疯狂java讲义》第7章 java基础类库_第1张图片

7.3.4 Math类

Math工具类,定义为private,无法创建Math类的对象,所有方法都是类方法,两个类变量:PI 和 E(π,e)
《疯狂java讲义》第7章 java基础类库_第2张图片

ThreadLocalRandom与Random

Random类的基本用法:

1.random.nextInt();作用是随机生成一个int类型
2.random.nextInt(int bound)方法的作用是生成一个0-参数bound范围内的随机数
3.random.nextLong()会随机生成一个Long类型
4.random.nextDouble()会生成一个0-1的double类型
5.random.nextFloat()会生成一个随机的0-1之间的浮点型
6.random.nextBoolean()会生成一个true或false
7.random.nextBytes()会为一个byte类型的数组随机赋值
8.random.nextGaussian()的作用是随机生成一个高斯分布的浮点数

  • 只要两个Random对象的种子相同,且方法的调用顺序也相同,他们就会产生相同的数字序列,是一种伪随机
  • 推荐使用当前时间作为Random对象的种子:
    Random rand = new Random(System.currentTimeMikkis());
  • ThreadLocalRandom:是java7新增类,是Random的增强版(用法基本相似)。在多线程并发情况下,THreadLocalRandom相对于Random可以减少多线程资源竞争,保证了线程的安全性。

7.3.6 BigDecimal类

  • BigDecimal类:为了精确表示、计算浮点数。
  • BigInteger类:是针对大整数的处理类。
  • BigDecimal(double val),不可预知性,近似等于val的数。
  • BigDecimal(String val),可预知,正好等于val的数。
  • BigDecimal.valueOf(double value)静态方法创建对象。
  • BigDecimal类提供了add()、subtract()、multiply()、divide()、pow()等方法对精确浮点数进行常规算术运算。
  • 构造BigDecimal 对象常用方法
    BigDecimal BigDecimal(double d); //不允许使用
    BigDecimal BigDecimal(String s); //常用,推荐使用
    static BigDecimal valueOf(double d); //常用,推荐使用
  • 创建BigDecimal对象时,不要直接使用double浮点数作为构造器的参数,会发生精度丢失的问题,一定要使用String对象作为构造器的参数。
  • 可以以BigDecimal为基础定义一个xxx工具类,对double浮点数进行加减乘除运算。

7.4 日期、时间类

7.4.1 Date类

  • Date类来处理日期、时间(java.util包下的),但大多构造器和方法已经不再使用了
  • 两个构造器的使用:
    Date():创建一个当前时间的Date对象
    Date(long date):创建指定long型毫秒数的Date对象
  • 方法:
    boolean after(Date when):是否在when日期之后
    boolean before(Date when):是否在when日期之前
    long getTime(): 获取当前Date对象对应的毫秒数。(时间戳)
    void setTime(long time):设置Date对象的时间

7.4.2 Calendar类

  • Calendar类:来更好的处理日期和时间。是一个抽象类,表示日历。
  • 它本身不能被实例化,程序只能创建Calendar自类的实例,java提供了一个GregorianCalendar类。
  • 也可以创建自己的Calendar子类。
  • 提供几个静态getInstance()方法获取Calendar对象,这些方法根据TimeZone,Locale类来获取特定的Calendar。
  • Calendar与Date类可以直接自由转换
Calendar calendar = Calendar.getInstance();//创建一个Calendar对象
Date date = calendar.getTime();//从Calendar对象中取出Date对象

//通过Date对象获得对应的Calendar对象
Calendar calendar2 = Calendar.getInstance();//必须先创建一个实例
calendar2.setTime(date);//然后在调用setTime()方法
  • Calendar类的常用方法:
    void add(int field, int amount) 根据日历的规则,为给定的日历字段添加或减去指定的时间量。
    int get(int field) 返回给定日历字段的值。
    int getActualMaximum(int field) 给定此 Calendar 的时间值,返回指定日历字段可能拥有的最大值。
    int getActualMinimum(int field) 给定此 Calendar 的时间值,返回指定日历字段可能拥有的最小值。
    static Calendar getInstance() 使用默认时区和语言环境获得一个日历。
    void roll(int field, int amount) 向指定日历字段添加指定(有符号的)时间量,不更改更大的字段。
    void set(int field, int value) 将给定的日历字段设置为给定值。
    void set(int year, int month, int date) 设置日历字段 YEAR、MONTH 和 DAY_OF_MONTH 的值。
    void set(int year, int month, int date, int hourOfDay, int minute, int second) 设置字段 YEAR、MONTH、DAY_OF_MONTH、HOUR、MINUTE 和 SECOND 的值。
  • 注意点:add(上一级增大)与roll(上一级不增大)的区别;设置Calendar的容错性(setLenient(false));set()方法的延迟修改。
public class CalendarTest{
	public static void main(String[] args){
		Calendar c = Calendar.getInstance();
		System.out.println(c.get(YEAR));
		System.out.println(c.get(MONTH));
		System.out.println(c.get(DATE));
		c.set(2003, 11, 23, 12, 32, 36);//2003-11-23 12:32:36
		System.out.println(c.getTime());//输出设置的时间
		c.add(YEAR, -1);//时间往前推1年
		c.roll(MONTH, -8);//时间往前推8个月
	}
}

7.4.3 java 8 新增的日期、时间包

Java 8专门新增了一个java.time包,该包下包含了以下经常使用类:
Clock、Duration、LocalDate、LocalTime、LocalDateTime、MonthDay、Year、YearMonth、DayOfWeek、Month。

public class NewDatePackageTest {
    public static void main(String[] args){
        /*
         * Clock的用法
         */
        //获取当前Clock
        Clock clock = Clock.systemUTC();
        //通过Clock获取当前时间
        System.out.println("当前时刻为:"+clock.instant());
        //获取clock对应毫秒数,与System.currentTimeMills()输出相同
        System.out.println(clock.millis());
        System.out.println(System.currentTimeMillis());
        /*
         * Duration的用法
         */
        Duration d = Duration.ofSeconds(6000);
        System.out.println("6000秒相当于"+d.toMinutes()+"分");
        System.out.println("600秒相当于"+d.toHours()+"小时");
        System.out.println("6000秒相当于"+d.toDays()+"天");
        //在clock基础上增加6000秒。返回新得Clock
        Clock clock2 = Clock.offset(clock,d);
        //可以看到clock2与Clock相差1小时40分
        System.out.println("当前时间加6000秒为:"+clock2.instant());
        /*
         * Instant的用法
         */
        //获取当前时间
        Instant instant = Instant.now();
        System.out.println(instant);
        //instant添加6000秒(即100分钟),返回新的Instant
        Instant instant2 = instant.plusSeconds(6000);
        System.out.println(instant2);
        //根据字符串解析Instant对象
        Instant instant3 = Instant.parse("2014-02-23T10:12:35.342Z");
                System.out.println(instant3);
        //在instant3的基础上添加5小时4分钟
        Instant instant4 = instant3.plus(Duration.ofHours(5).plusMinutes(4));
        System.out.println(instant4);
        //获取instant4的5天以前的时刻
        Instant instant5 = instant4.minus(Duration.ofDays(5));
        System.out.println(instant5);
        /*
         * LocalDate的用法
         */
        LocalDate localdate = LocalDate.now();
        System.out.println(localdate);
        //获取2014年的第146天
        localdate = LocalDate.ofYearDay(2017, 146);
        System.out.println(localdate);
        //设置2017年5月21日
        localdate = LocalDate.of(2017, 05, 21);
        System.out.println(localdate);
        /*
         * LocalTime的用法
         */
        //获取当前时间
        LocalTime localtime = LocalTime.now();
        //设置为22点33分
        localtime = LocalTime.of(22, 33);
        System.out.println(localtime);
        //返回一天中的第5503秒
        localtime = LocalTime.ofSecondOfDay(5503);
        System.out.println(localtime);
        /*
         * localDateTime的用法
         */
        //获取当前时间,日期
        LocalDateTime localdatetime = LocalDateTime.now();
        //当前日期时间加上25小时3分钟
        LocalDateTime future = localdatetime.plusHours(25).plusMinutes(3);
        System.out.println("当前日期,时间的25小时3分钟后:"+future);
        /*
         * Year,YearMonth,MonthDay的用法
         */
        //获取当前年份
        Year year = Year.now();
        //输出当前年份
        System.out.println("当前年份:"+year);
        //当前年份在加5年
        year = year.plusYears(5);
        System.out.println("当前年份在加5年:"+year);
        //根据指定月份获取YearMonth
        YearMonth ym = year.atMonth(10);
        System.out.println(year+"年10月"+ym);
        //当前年月再加5年,减3个月
        ym = ym.plusYears(5).minusMonths(3);
        System.out.println(year+"年再加5年,减3个月:"+ym);
        //获取当前月日
        MonthDay md = MonthDay.now();
        System.out.println("当前月日"+md);
        //设置为5月23日
        MonthDay md2 = md.with(Month.MAY).withDayOfMonth(23);
        System.out.println("5月23日为:"+md2);
   }
}

7.5 正则表达式

是一个强大的字符串处理工具,可以对字符串进行查找、提取、分割、替换等操作。是一个用于匹配字符串的模板。
正则表达式是一组由字母和符号组成的特殊文本,它可以用来从文本中找出满足你想要的格式的句子。
部分参考自:https://www.runoob.com/regexp/regexp-syntax.html

7.5.1 创建正则表达式

简单例子:
在这里插入图片描述

^ 为匹配输入字符串的开始位置。
[0-9]+匹配多个数字, [0-9] 匹配单个数字,+ 匹配一个或者多个。
abc 匹 配 字 母 a b c 并 以 a b c 结 尾 , 匹配字母 abc 并以 abc 结尾, abcabc 为匹配输入字符串的结束位置。

《疯狂java讲义》第7章 java基础类库_第3张图片
非打印字符的转义序列:
《疯狂java讲义》第7章 java基础类库_第4张图片
正则表达式中的特殊字符(一般使用反斜线 \ 转义字符):
《疯狂java讲义》第7章 java基础类库_第5张图片
正则表达式的限定符:
《疯狂java讲义》第7章 java基础类库_第6张图片
正则表达式的定位符:
《疯狂java讲义》第7章 java基础类库_第7张图片
正则表达式预定义字符:
《疯狂java讲义》第7章 java基础类库_第8张图片
方括号表达式:
《疯狂java讲义》第7章 java基础类库_第9张图片
边界匹配符:
《疯狂java讲义》第7章 java基础类库_第10张图片

  • Greedy(贪婪模式):数量表示符默认采用贪婪模式,除非另有表示。贪婪模式的表达式会一直匹配下去,直到无法匹配为止。
  • Reluctant(勉强模式):用问号后缀()表示,它只会匹配最少的字符。也称为最小匹配模式。
  • Possessive(占有模式):用加号后缀(+)表示,目前只有Java支持占有模式,通常比较少用。
    《疯狂java讲义》第7章 java基础类库_第11张图片
String str = "hello , java!";
//贪婪模式的正则表达式
str.replaceFirst("\\w*"," ");
//勉强模式的正则表达式
str.replaceFirst("\\w*?"," ");

7.5.2 使用正则表达式

使用Pattern(样式)和Matcher(匹配)来使用正则表达式。

  • Pattern对象是正则表达式编译后内存中的表示形式。正则表达式字符串必须先被编译为Pattern对象,然后再利用该Pattern对象创建对应的Matcher对象。执行匹配所涉及的状态保留在Matcher对象中,多个Matcher对象可共享同一个Pattern对象。
//字符串编译为Pattern对象
Pattern p = Pattern.compile("a*b");
//利用Pattern对象创建对应的Matcher对象
Matcher m = p.matcher("aaaaab");
boolean b = m.matches();//返回true
  • 上面定义的Pattern对象可以多次重复使用。Pattern是不可变类,可供多个并发线程安全使用。
  • Matcher类提供几个常用方法:

find():返回目标字符串中是否包含与Pattern匹配的子串。
group():返回上一次与Pattern匹配的子串
start():返回上一次与Pattern匹配的子串在目标字符串中的开始位置
end():返回上一次与Patterm匹配的子串在目标字符串中的结束位置加1
lookingAt():返回目标字符串前面部分与Pattern是否匹配
matches():返回整个目标字符串与Pattern是否匹配
reset():将现有的Matcher对象应用于一个新的字符序列

  • 在Pattern、Matcher类的介绍中经常会看到一个CharSequence接口。简单地说,CharSequence代表一个各种表示形式的字符串。
  • 程序示例找电话号码:
public class FindGroup{
	public static void main(String[] args){
		//使用字符串模拟从网络上得到的网页源码
		String str = "我想求购一本《疯狂Java讲义》,尽快联系我13500006666"
		+"交朋友,电话号码是13611125565"
		+"出售二手电脑,联系方式15899903312"//创建一个Pattern对象,并用它建立一个Matcher对象
		//该正则表达式只抓取13x和15X段的手机号
		//实际要抓取哪些电话号码,只要修改正则表达式即可
		Matcher m = Pattern.compile("( (13\\d) | (15\\d) ) \\ d(8)").matcher(str);
		//将所有符合正则表达式的子串(电话号码)全部输出
		while(m.find()){	
			System.out.println(m.group());
		}
	}
}
  • 一旦找到对应子串,下次调用find()方法接着向下查找;带int参数find()方法将从该int索引处向下搜索。
  • start()end() 方法用于确定子串在目标中的位置。
  • matcher()lookingAt() 方法有点像:matcher() 要求整个字符串和Pattern完全匹配才返回true;lookingAt() 只要以Pattern开头就会返回true;
  • reset() 方法可将现有的Matcher对象应用于新的字符序列。
  • Matcher类提供的replaceAll() 方法把字符串中所有与正则表达式匹配的子串替换成“xxx”;Matcher类还提供一个replaceFirst() 方法,只替换第一个匹配子串。
  • String类中也提供了replaceAll()、replaceFirst() 、split()等方法。

7.6 变量处理和方法处理

java 9 引入一个新的CarHandle类,并增强了MethodHandle类。通过这两个类,允许java像动态语言一样应用变量引用方法,并调用它们。

7.6.1 增强的MethodHandle类

  • MethodHandle为java增加了方法引用的功能(有点类似C的“函数指针”),是一种轻量级的引用方式。
  • 使用MethodHandle,还涉及如下几个类:
    MethodHandles:MethodHandle的工厂类,提供一系列静态方法。
    MethodHandles.Lookup:用于获取MethodHandle和VarHandle。
    MethodType:代表一个方法类型。
//定义一个返回值为void、不带形参的方法类型
MethodType type = MethodType.methodType(void.class);
//使用MethodHandles.Lookup的findStatic获取类(findVirtual获取实例方法)
MethodHandle mtd = MethodHandles.lookup().
				findStatic(MethodHandleTest.class, "xxx", type);
//通过MethodHandle执行方法
mtd.invoke();

7.6.2 增加的VarHandle

  • VarHandle主要用于动态操作数组的元素对象的成员变量
  • 它也需要通过MethodHandles来获取实例,然后调用VarHandle的方法即可操作。
//获取一个String[]数组的VarHandle对象
VarHandle avh = MethodHandles.arrayElementVatHandle(String[].class);
//比较并设置:若第三个元素为Go,设为Lua
boolean r = avh.compareAndSet(arr, 2, "Go", "Lua");

//用findVarHandle方法获取User类中的名为name,类型为String的实例变量
VarHandle vh1 = MethodHandles.lookup().findVarHandle(User.class, 
				"name", String.clas);
User user = new User();
//通过VarHandle获取实例变量的值(需要传入对象作为调用者)
vh1.get(user);
//通过VarHandle设置指定实例变量的值
vh1.set(user,"xxx");
  • 使用VarHandle操作类变量与操作实例变量差别不大,区别只是类变量不需要对象,因此使用VarHandle操作类变量时无须传入对象作为参数。
  • VarHandle与MethodHandle一样,它也是一种动态调用机制

7.7 改进的国际化与格式化

国际化,自适应、更友好,I18N;本地化,L10N。java 9 升级到Unicode 8.0字符集。

  • 国际化的思路:将程序中的标签、提示等信息放在资源文件中,程序需要支持哪些国家、语言环境,就对应提供相应的资源文件。
  • 资源文件是key-value对,每个资源文件中的key是不变的,但value则随不同的国家、语言而改变(key是程序使用的部分,而value则是程序界面的显示字符串。)。
  • Java程序的国际化主要通过如下三个类完成

java.util.ResourceBundle:用于加载国家、语言资源包。
java.util.Locale:用于封装特定的国家/区域、语言环境。
java.text.MessageFormat:用于格式化带占位符的字符串。

  • java 支持的国家和语言:可调用Local类getAvailableLocales() 方法,返回一个Local数组,包含java支持的国家和语言。
  • Java 程序国际化的关键类是ResourceBundleLocale,ResourceBundle根据不同的Locale加载语言资源文件,再根据指定的key取得已加载语言资源文件中的字串。
  • 使用MessageFormat处理包含占位符的字符串:一个静态方法format(String pattern, Object... values):返回后面的多个参数值填充前面的pattern字符串(不是正则表达式,是一个带占位符的字符串)。
  • 使用类文件代替资源文件:即将所有的key-value对存入class文件(而不是属性文件)。
    条件:类名必须是baseName_language_country,这与属性文件的命名相似;必须继承ListResourceBundle,并重写getContents()方法,该方法返回Object数组,该数组的每一项都是key-value对。
  • 新增的日志API
    用法:①调用System 类的getLogger(String name)方法获取System.Logger对象。②调用System.Logger对象的log()方法输出日志。
    日志级别:(调试程序,需要大量输出调试信息;发布软件,希望关掉这些调试信息)
    《疯狂java讲义》第7章 java基础类库_第12张图片
  • 使用NumberFormat格式化数字
    MessageFormat是抽象类Format的子类,是一个抽象基类。
    《疯狂java讲义》第7章 java基础类库_第13张图片

getCurrencyInstance():返回默认Locale的货币格式器。
getlntegerlnstance():返回默认Locale的整数格式器。
getNumberlnstance():返回默认Locale的通用数值格式器。
getPercentInstance(():返回默认Locale的百分数格式器。

一旦取得了NumberFormat对象后,就可以调用它的format()方法来格式化数值,包括整数和浮点数。

  • 使用DateFormat格式化日期和时间
    也是一个抽象类,获取对象的方法:

getDatelnstance():返回一个日期格式器,格式化后的字符串只有日期,没有时间。
getTimelnstance():返回一个时间格式器,格式化后的字符串只有时间,没有日期。
getDate Timelnstance():返回一个日期、时间格式器,它格式化后的字符串既有日期,也有时间。

  • 使用SimpleDateFormat格式化日期:
    “简单”的日期格式器,更加灵活。
    可以非常灵活地格式化Date,也可以解析各种格式的日期字符串
    创建SimpleDateFormat 对象时需要传入一个pattern字符串,这个pattern不是正则表达式,而是一个日期模板字符串。

7.8 java 8 新增日期、时间格式器

java.time.format包下提供了一个DateTimeFormatter格式器类。与DateFormat、SimpleDateFormat类似,DateTimeFormatter不仅可以将日期、时间对象格式化成字符串,也可以将特定格式的字符串解析成日期、时间对象。
获取对象的方法:

1.直接使用静态常量创建DateTimeFormatter 格式器。DateTimeFormatter类中包含了大量形如ISO LOCAL DATE、ISO LOCAL TIME、ISO LOCAL DATE TIME等静态常量,这些静态常量本身就是DateTimeFormatter实例。
2.使用代表不同风格的枚举值来创建 DateTimeFormatter格式器。在FormatStyle枚举类中定义了FULL、LONG、MEDIUM、SHORT四个枚举值,它们代表日期、时间的不同风格。
3.根据模式字符串来创建DateTimeFormatter格式器。类似于SimpleDateFormat,可以采用模式字符串来创建 DateTimeFormatter。

  • 使用DateTimeFormatter完成格式化

1.调用DateTimeFormatter的format(TemporalAccessor temporal)方法执行格式化,其中LocalDate、LocalDate Time、LocalTime 等类都是TemporalAccessor接口的实现类。
调用LocalDate、LocalDateTime、LocalTime等日期、时间对象的format(Date TimeFormatter formatter)方法执行格式化。

Date TimeFormatter的功能完全覆盖了传统的DateFormat、SimpleDateFormate的功能;
DateTimeFormatter则提供了一个toFormat()方法,可以获取Date TimeFormatter对应的Format对象。

  • 使用DateTimeFormatter解析字符串:通过日期、时间对象提供的parse(CharSequence text, DateTimeFormatter formatter)方法进行解析。

你可能感兴趣的:(java基础,java,开发语言,后端)