11. 常用类
11.1 基本数据类型包装类
含义:基本数据类型对应的类
出现的原因:Java为纯面向对象语言(万物皆对象),而8种基本数据类型不能创建对象,破坏了Java为纯面向对象语言的特征,所以Java又给这8种基本数据类型分别匹配了对应的类,这种叫做包装类/封装类。
继承关系:
基本数据类型 引用数据类型 继承关系 byte Byte extends Number extends Object short Short extends Number extends Object int Integer extends Number extends Object long Long extends Number extends Object float Float extends Number extends Object double Double extends Number extends Object char Character extends Object boolean Boolean extends Object 重点记忆:
- 数值型都继承Number。
- int的包装类Integer。
- char的包装类Character。
11.1.1 装箱
基本数据类型 -> 包装类
示例 int --> Integer
int i=100; Integer integer = Integer.valueOf(i); System.out.println(integer);//100 //能够直接输出integer,因为在Integer类中,toString方法已经被重写。
自动装箱:(在JDK1.5及之后,能够实现自动装箱和自动拆箱,但底层原理依旧是与装箱和拆箱相同)
示例:
int i = 100; Integer integer = i; //自动装箱(底层实现:Integer.valueOf(i);) System.out.println(integer);//100
11.1.2 拆箱
包装类 -> 基本数据类型
示例 Integer --> int
Integer integer = new Integer(100); int i = integer.intValue(); //拆箱 System.out.println(i); //100
自动拆箱:(与自动装箱相同)
Integer integer = new Integer(100); int i = integer;//拆箱 System.out.println(i); //100
11.1.3 包装类底层源码
示例:
Integer integer1 = Integer.valueOf(100); Integer integer2 = Integer.valueOf(100); System.out.println(integer1 == integer2); //true Integer integer3 = Integer.valueOf(200); Integer integer4 = Integer.valueOf(200); System.out.println(integer3 == integer4); //false Character character1 = Character.valueOf('a'); Character character2 = Character.valueOf('a'); System.out.println(character1==character2); //true Character character3 = Character.valueOf('男'); Character character4 = Character.valueOf('男'); System.out.println(character3==character4); //false
解释:
结果分析:
“==”符号用于引用数据类型时,比较的是对象所在的地址,证明integer1和integer2两个引用指向的是一个相同的地址,而character1和character2也是如此,但是剩下的integer3和integer4、character3和character4却截然相反,返回的false表面了他们的地址并不一样。
原因: 这是因为在Integer和Character两个类中,存在一个静态内部类(缓存类),在这个静态内部类中定义有一个类的数组,存储了-128127的Integer对象(0127的Character对象),当调用valueOf()方法时,会首先判断数据是否在已经在数组中定义,如果已经定义,则会直接返回数组中对应的地址,这导致他们的地址是一样的。如果不在其中,才会new一个新的Integer(Character)对象。
底层源码展示(以Integer为例):
public static Integer valueOf(int i) { if (i >= IntegerCache.low && i <= IntegerCache.high) return IntegerCache.cache[i + (-IntegerCache.low)]; return new Integer(i); } //静态内部类 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() {} }
11.2 字符串类
11.2.1 String类
String是一个不可变的类, 即一旦一个String对象被创建, 包含在这个对象中的字符序列是不可改变的, 直至该对象被销毁。
示例:将其他类型转换为字符串类型
int i = 100; System.out.println(String.valueOf(i));//100 boolean bool = true; System.out.println(String.valueOf(bool));//true
注:虽然看起来输出没有变化,但类型已经改变。
String类的一些常用方法:
-
在字符串末尾追加字符串,并返回新的字符串
String str1="adcde"; str1 = str1.concat("12345");// adcde12345
-
传入的下标处(包括)截取到字符串末尾,并返回新的字符串
String str1="adcde"; str1 = str1.substring(2); //cde
-
截取开始下标(包括)和结束下标(不包括)之间的字符串
String str1="adcdefgh"; str1 = str1.substring(2,6); //cdef
-
字符串中的字母转大小写
String str1="adcdefgh"; str1 = str1.toUpperCase();//转大写,ADCDEFGH str1 = str1.toLowerCase();//转小写,adcdefgh
-
去除字符串首尾空格
String str1=" ad c de fg h "; str1 = str1.trim(); //ad c de fg h
-
替换字符
String str=" ad cc aade fgc h "; str = str.replace('c', '-'); // ad -- aade fg- h
-
替换字符串
String str=" ad cc aade fgc h "; str = str.replaceFirst("a", "#");//替换第一个出现的字符串,并返回新的字符串 System.out.println(str); // #d cc aade fgc h str = str.replaceAll("c", "@");//替换字符串,并返回新的字符串 System.out.println(str); // #d @@ aade fg@ h str = str.replaceAll(" ", "");//替换字符串,并返回新的字符串 System.out.println(str); //#d@@aadefg@h
-
判断两个字符串内容是否相同
String str="abcDefG"; //equals区分大小写 System.out.println(str.equals("abcDefG")); //true System.out.println(str.equals("abcdefg")); //false //equalsIgnoreCase不区分大小写 (使用场景:验证码) System.out.println(str.equalsIgnoreCase("abcdefg")); //true
-
判断此字符串是否以某个字符串开头/结尾
String str="abcDefG"; //判断开头字符串 System.out.println(str.startsWith("a"));//true System.out.println(str.startsWith("A"));//false //判断结尾字符串 System.out.println(str.endsWith("G")); //true
-
查询此字符串第一次在目标字符串中的下标:
String str="afaffgfgajjkfds"; System.out.println(str.indexOf("f"));//1
-
查询此字符串最后一次在目标字符串中的下标
String str="afaffgfgajjkfds"; System.out.println(str.lastIndexOf("a"));//8
-
获取指定下标上的字符
String str="afaffgfgajjkfds"; System.out.println(str.charAt(8)); //a
11.2.2 StringBuilder类
StringBuilder代表可变的字符序列。又称为字符串缓冲区.
工作原理:
预先申请一块内存,存放字符序列,
如果字符序列满了,会重新改变缓存区的大小,以容纳更多的字符序列。
StringBuilder是可变对象,这个是String最大的不同。继承关系:StringBuilder extends AbstractStringBuilder
创建示例:
//调用无参构造,默认创建的大小为16个字符 StringBuilder sb = new StringBuilder(); //自定义字符串缓冲区:100个字符 StringBuilder sb1 = new StringBuilder(100); //自定义字符串缓冲区:"abcdef".length() + 16 : 22个字符 StringBuilder sb2 = new StringBuilder("abcdef");
底层源码展示:
//无参构造 public StringBuilder() { super(16); } //有参构造(int类型) public StringBuilder(int capacity) { super(capacity); } //有参构造(String类型) public StringBuilder(String str) { super(str.length() + 16); append(str); }
StringBuilder类常用的一些方法
-
在末尾追加字符串
StringBuilder sb2 = new StringBuilder("abcdef"); sb2.append("#####"); System.out.println(sb2); //abcdef#####
-
在指定下标处插入字符串
StringBuilder sb2 = new StringBuilder("abcdef"); sb2.insert(2, "###"); System.out.println(sb2); //ab###cdef
-
替换指定下标上的字符
StringBuilder sb2 = new StringBuilder("abcdef"); sb2.setCharAt(3, '&'); System.out.println(sb2); //abc&f
-
从开始下标处(包含)替换到结束下标处(不包含)的字符串
StringBuilder sb2 = new StringBuilder("abcdef"); sb2.replace(2, 4, "$$$$$"); System.out.println(sb2); //ab$$$$$ef
-
删除指定下标上的字符
StringBuilder sb2 = new StringBuilder("abcdef"); sb2.deleteCharAt(1); System.out.println(sb2); //acdef
-
从开始下标处(包含)删除到结束下标处(不包含)的字符串
StringBuilder sb2 = new StringBuilder("abcdef"); sb2.delete(2,4); System.out.println(sb2); //abef
-
反转字符串
StringBuilder sb2 = new StringBuilder("abcdef"); sb2.reverse(); System.out.println(sb2); //fedcba
注:StringBuilder是可变的对象,因此只需要在原对象基础上操作,并不会向String一样需要new新的对象,因此,使用StringBuilder对象进行字符串的各种频繁操作时,执行效率比String更加高。
示例:
// 获取自1970.1.1 0:0:0到现在的毫秒数 long startTime = System.currentTimeMillis(); String str = "abc"; for (int i = 0; i < 50000; i++) { str += "aaa"; // str = str + "abc" // str = new StringBuilder(str).append("abc").toString(); } long endTime = System.currentTimeMillis(); System.out.println("消耗时长:" + (endTime - startTime));// 5746 // 获取自1970.1.1 0:0:0到现在的毫秒数 long startTime1 = System.currentTimeMillis(); StringBuilder sb = new StringBuilder("abc"); for (int i = 0; i < 50000; i++) { sb.append("bbb"); } long endTime1 = System.currentTimeMillis(); System.out.println("消耗时长:" + (endTime1 - startTime1));// 5
效率提升近千倍。
11.2.3 StringBuffer类
StringBuffer与StringBuilder基本类似, AbstractStringBuilder是StringBuilder与StringBuffer的公共父类,其中方法调用也一模一样,但唯一不同之处在于是否多线程安全
StringBuffer 类中,对方法加了同步锁或者对调用的方法加了同步锁,所以是线程安全的。而StringBuilder则没有,所以在使用多线程的情况下,为保证安全,使用StringBuffer类,如果是单线程,使用StringBuilder效率则要高于StringBuffer。
11.3 正则表达式
含义:用来描述或者匹配一系列符合某个语句规则的字符串。
Pattern:代表正则表达式的匹配模式
Matcher:提供了对正则表达式的分组支持,以及对正则表达式的多次匹配支持
示例1:(隐藏电话号中间四位)
String str="小红:13333335950,小明:1355551082"; //正则表达式的字符串 String regex = "(\\d{3})(\\d{4})(\\d{4})"; String replaceAll = str.replaceAll(regex, "$1****$3"); System.out.println(replaceAll); //小红:133****5950,小明:1355551082
示例2:(校验QQ邮箱)
String str = "1445584980@qq.com"; //正则表达式的字符串 String regex = "\\d{5,10}@qq.com"; //5~10位数字开头 boolean matches = str.matches(regex); System.out.println(matches);
示例3:(分隔路径)
String str="C:\\相册\\图片\\1.png"; String regex =":?\\\\"; //String[] split = str.split(regex); //底层原理 Pattern pattern = Pattern.compile(regex);//获取正则表达式的对象 String[] split = pattern.split(str);//分隔 for (String string : split) { System.out.println(string); } /* C 相册 图片 1.png */
示例4:(找到前端代码中的图片路径)
String str = "<img src='hhy/aaa.jpg'/><div><div/> <input type='image' src='submit.gif' /><img src='bbb.jpg'/>"; //正则表达式的字符串 String regex = "<img\\b[^>]*\\bsrc\\b\\s*=\\s*('|\")?([^'\"\n\r\f>]+(\\.jpg)\\b)[^>]*>"; //获取正则表达式对象 Pattern pattern = Pattern.compile(regex); //获取匹配结果的对象 Matcher matcher = pattern.matcher(str); //遍历查找 while(matcher.find()){ String group = matcher.group(2);//获取匹配结果 System.out.println(group); }
常用的正则表达式:
验证手机号:
/^(13[0-9]|14[01456879]|15[0-35-9]|16[2567]|17[0-8]|18[0-9]|19[0-35-9])\d{8}$/
验证身份证号
/^[1-9]\d{5}(19|20)\d{2}((0[1-9])|(1[0-2]))(([0-2][1-9])|10|20|30|31)\d{3}[0-9Xx]$/
验证邮政编码
/^[1-9]\d{5}$/
11.4 关于日期的类
11.4.1 Date类
Date–日期类
使用示例:
Date date = new Date(); //星期 月份 日期 时:分:秒 时区 年份 //Thu Aug 05 19:37:06 CST 2021 System.out.println(date); //自1970.1.1 0:0:0 往后推1000毫秒的时间 Date date = new Date(1000); //Thu Jan 01 08:00:01 CST 1970 System.out.println(date);
11.4.2 SimpleDateFormat类
SimpleDateFormat --格式化日期的类,配合Date类使用
使用示例:
SimpleDateFormat sdf = new SimpleDateFormat("yyyy年MM月dd日 HH:mm:ss"); //将Date 转 字符串 String format = sdf.format(new Date()); System.out.println(format); //2021年08月05日 19:41:42 ///将字符串 转 Date Date date = sdf.parse("2021年08月05日 19:41:42"); System.out.println(date); //Thu Aug 05 19:41:42 CST 2021
11.4.3 Calendar类
Calendar—日历类
使用示例:
//获取日历类的对象 Calendar c = Calendar.getInstance(); //获取单个的日历信息 int year = c.get(Calendar.YEAR); int month = c.get(Calendar.MONTH)+1;//月份0~11 int day = c.get(Calendar.DAY_OF_MONTH); int hour = c.get(Calendar.HOUR); int minute = c.get(Calendar.MINUTE); int second = c.get(Calendar.SECOND); System.out.println(year); System.out.println(month); System.out.println(day); System.out.println(hour); System.out.println(minute); System.out.println(second);
注:在只需要使用单个日期或时间信息时,Calendar更加方便,需要获取详细日期时间信息时,使用Date类和SimpleDateFormat类更加方便。
11.5 Math类
Math类为final类,不可被继承,并且他的所有的成员变量和方法都是static的,可通过类名调用,Math类中包含执行基本数字运算和几何函数的方法
常用方法:
取出一个0~1的随机值(包括0,不包括1)
System.out.println(Math.random()); //求一个1~100的随机数 int rand =(int)(Math.random()*100)+1; System.out.println(rand);
求数的平方根
System.out.println(Math.sqrt(9)); //3.0
求数的平方
System.out.println(Math.pow(2, 4)); //16.0
向上取整数
System.out.println(Math.ceil(1.32)); //2.0
向下取整数
System.out.println(Math.floor(1.32)); //1.0
求最大值 最小值
System.out.println(Math.max(3, 6)); //6 System.out.println(Math.min(3, 6)); //3
四舍五入(只针对小数点后一位)
System.out.println(Math.round(1.49)); //1.0
求绝对值
System.out.println(Math.abs(-4)); //4 //注意:abs也可能返回一个负数,当值超越int范围时。 System.out.println(Math.abs(Integer.MAX_VALUE+1)); //-2147483648 Integer.MAX_VALUE=2147483647
拓展:静态导入
示例:导入Math类
/* 将Math类中所有的静态属性和静态方法都导入Test04这个类中; 把导入的静态属性和静态方法都认为是当前类自己的内容。 */ import static java.lang.Math.*;
使用Math的方法时,不在需要使用类名调用,可以直接使用方法名,编译时会首先就近查找本类,再查找Math类。
注:
如果本类中有和静态导入类相同的方法,会就近调用本类中的方法。
11.6 Random类
随机类,随机获取数值(int,byte[],double,long,float)
简单使用示例:
//创建随机类 Random ran = new Random(); //取出一个随机数 System.out.println(ran.nextInt()); //取出一个0~指定数(不包括此数)之间的随机数 int i =10; System.out.println(ran.nextInt(10)); //0~9 //取出一个随机的Boolean值 System.out.println(ran.nextBoolean()); //取出一个随机的byte数组 byte[] bytes =new byte[5]; ran.nextBytes(bytes); for (byte b : bytes) { System.out.println(b); }
实例:(点名器)
public static void main(String[] args) { //创建随机雷的对象 Random ran= new Random(); //设置点名字符数组 String [] names=new String[]{"小强","小花","小刚","小红","小明"}; //获取0~人数之间的随机数 int index = ran.nextInt(names.length); System.out.println("随机选出的人是:"+names[index]); }
深入Random类源码:
//Random的无参构造 public Random() { this(seedUniquifier() ^ System.nanoTime()); } //Random的有参构造 public Random(long seed) { if (getClass() == Random.class) this.seed = new AtomicLong(initialScramble(seed)); else { // subclass might have overriden setSeed this.seed = new AtomicLong(); setSeed(seed); } }
在Random类中,生成的伪随机数,依赖于种子数,无参构造方法中种子数由seedUniquifier() ^ System.nanoTime()得到,再传递给有参构造函数。
当调用有参构造时,如果种子数固定,产生的随机数也将固定。
Random ran= new Random(10);
11.7 Runtime类
Runtime类为运行环境类,能够获取运行环境对象
基本使用示例:
//获取运行环境对象 Runtime run = Runtime.getRuntime(); System.out.println("获取最大内存数(字节):" + run.maxMemory()); System.out.println("获取闲置内存数(字节):" + run.freeMemory()); System.out.println("获取处理数:" + run.availableProcessors());
使用实例:(测试程序效率 时间+内存)
Runtime run = Runtime.getRuntime(); long startTime = System.currentTimeMillis(); long startMemory = run.freeMemory(); /* 测试的程序代码块 */ long endMemory = run.freeMemory(); long endTime = System.currentTimeMillis(); System.out.println("运行程序消耗的时长:" + (endTime-startTime)); System.out.println("运行程序消耗的内存:" + (startMemory-endMemory));
注:
如果程序代码消耗的内存过多,导致jvm回收掉垃圾的内存,会让最终计算的内存增多。
11.8 System类
System类为系统类,最常使用的是系统标准的输入输出流。
系统标准的输入流
//系统标准的输入流(方向:控制台 -> 程序) InputStream in =System.in; Scanner scan = new Scanner(in); String next = scan.next(); //关闭资源 scan.close();
系统标准的输出流
//系统标准的输出流(方向:程序 -> 控制台) PrintStream out =System.out; out.println(next); //系统标准的错误输出流(方向:程序 -> 控制台) PrintStream err = System.err; err.println(next);
获取系统参数的对象
//获取系统参数的对象 Properties properties = System.getProperties(); System.out.println(properties);
通过键获取值
//通过键获取值 String value = System.getProperty("os.name"); System.out.println(value); //Windows 10(电脑操作系统)
退出当前虚拟机
System.exit(0); //其后的任何代码将不会被执行。
注:
错误输出流采用的字体颜色为红色。
虽然System的out和err都为输出流,但是却是两个不同的线程,这两个线程共同争夺CPU资源,输出顺序与代码顺序无关。
System.out.println("1"); System.err.println("2"); System.out.println("3"); /* 输出顺序随机,但“1”和“3”是在同一个线程,所以“1”始终在“3”之前输出。 “2”的位置随机。 */
11.9 大数值运算类
含义:用于大数值的运算。
11.9.1 BigInteger类
整数类型的大数值运算类
常用方法:
相加
//整数类型的大数值运算 BigInteger big1 = new BigInteger("123456789987654321"); BigInteger big2 = new BigInteger("123456789987654321"); //相加 BigInteger add = big1.add(big2); System.out.println(add);//246913579975308642
相减
//相减 BigInteger subtract = big1.subtract(big2); System.out.println(subtract); //0
相乘
//相乘 BigInteger multiply = big1.multiply(big2); System.out.println(multiply);//15241578994055784200731595789971041
相除
//相除 BigInteger divide = big1.divide(big2);//1 System.out.println(divide);
11.9.2 BigDecemal类
小数类型的大数值运算类(精确)
常用方法:
相加
BigDecimal big1 = new BigDecimal("1.5"); BigDecimal big2 = new BigDecimal("0.4"); BigDecimal big3 = new BigDecimal("0.3"); //相加 BigDecimal add = big1.add(big2); System.out.println(add); //1.9
相减
//相减 BigDecimal subtract = big1.subtract(big2); System.out.println(subtract); //1.1
相乘
//相乘 BigDecimal multiply = big1.multiply(big2); System.out.println(multiply); //0.60
相除
//相除 BigDecimal divide = big1.divide(big2); System.out.println(divide);//3.75 //设置保留的小数位和保留方式。 BigDecimal divide2 = big2.divide(big3, 3, BigDecimal.ROUND_HALF_UP); System.out.println(divide2);//1.333
注:在进行小数类型的大数值除法时,如果除不尽,将会出现运行报错, java.lang.ArithmeticException,这时必须使用第二种相除方式。
常见的保留方式:
BigDecimal.ROUND_HALF_UP:四舍五入
BigDecimal.ROUND_CEILING: 舍去小数位,往正无穷方向移动 1.1->2 1.8->2 -1.1->-1 -1.8->-1
BigDecimal.ROUND_DOWN: 舍去小数位 ,向0的方向移动1.1->1 1.5->1 1.8->1 -1.1->-1 -1.5->-1 -1.8>-1
BigDecimal.ROUND_FLOOR: 舍去小数位,往负无穷 1.1->1 1.5->1 1.8->1 -1.1->-2 -1.5->-2 -1.8->-2