19常用类(包装类、字符串相关类、正则表达式( PM)、日期时间类、Math类、 Random类、System类、Runtime类、大数值运算类( BigInteger,BigDecemal))

day19

字符串相关的类

参考常用类.doc–见文件资料

分类:

1.String

2.StringBuffer

3.StringBuilder

String

1.概念

​ String是不可变类, 即一旦一个String对象被创建, 包含在这个对象中的字符序列是不可改变的, 直至该对象被销毁。

​ String类是final类,不能有子类。

2.使用

String str = “123abc”;//(下标)字符串底层:new char[]{‘1’,‘2’,‘3’,‘a’,‘b’,‘c’};

拼接: str = str.concat(“DEf123”);//拼接字符串,并返回新的字符串

截取:substring(2)/substring(1, 7);从开始下标截取到末尾,并返回新的/从开始下标除(包含)截取到结束下标处(排他),并返回新的字符串

转大/小写:toUpperCase()/toLowerCase();//转大写,并返回新的字符串

去除首尾空格:trim();//去除首尾空格,并返回新的字符串

​ replaceAll(" ", “”);//去除空格(将空格字符串替换成空内容的字符串)

替换字符/字符串:replace(‘a’, ‘A’);//替换字符,并返回新的字符串

​ replaceAll(“ABC”, “abc”);//(支持正则表达式)替换字符串,并返回新的字符串

​ replaceFirst(“23”, “66”);//替换第一次出现的字符串,(replaceAll()替换所有出现的字符串),并返回新的字符串

获取字符串的字符个数:length()

判断两个字符串的内容是否相同(区分大小写):equals

判断两个字符串的内容是否相同(不区分大小写):equalsIgnoreCase(做验证码适用)

判断字符串的内容是否以某个字符串开头/结尾:startsWith/endsWith

查找子字符串在此字符串第一次/最后一次出现的下标indexOf(“1”)/lastIndexOf(“1”)

获取字符串中指定下标的字符:charAt(6)

把其他类型转换为String类型:valueOf()/用拼接也可以10 + “”

   * String练习题:
   		练习:完成一个邮箱格式的校验 hhy@qq.com
  		(1),“@”不能在第一位
  		(2),“.”不能在最后一位
  		(3),“@”和“.”中间应该有字符
  		(4),***@***.***
  		当然还有更严格的校验规则,我们此处考虑到这即可
   * */
  String email = "hhy@qq.com";
  
  int indexOf01 = email.indexOf("@");
  int indexOf02 = email.indexOf(".");
  if (indexOf01==0 || indexOf02==email.length()-1 || indexOf02-indexOf01<=1) {
  	System.out.println("邮箱格式错误");
  }else{
  	System.out.println("邮箱格式正确");
  }

StringBuffer/StringBuilder

1.概念

StringBuffer代表可变的字符序列。

StringBuffer称为字符串缓冲区,它的工作原理是:预先申请一块内存,存放字符序列,如果字符序列满了,会重新改变缓存区的大小,以容纳更多的字符序列。StringBuffer是可变对象,这个是String最大的不同

StringBuilder与StringBuffer的用法完全一致,唯一的区别是StringBuffer是线程安全的,而StringBuilder不是线程安全的。所以StringBuilder的性能要比StringBuffer要好。单线程推荐使用StringBuilder,多线程使用StringBuffer。

2.两者和String比较

StringBuilder/StringBuffer是可变对象:因为char[] value = new char[];

String是不可变的对象,因为final char[] value = new char[];

3.使用
  StringBuffer sb = new StringBuffer();//new出来的对象没有内容的	
  sb.append("123abcDEF123");//在末尾追加字符串
  
  sb.insert(6, "xyz");//将字符串插入到此字符串指定下标的位置
  
  sb.setCharAt(6, 'X');//替换指定下标上的字符
  sb.replace(3, 9, "ABCDEFG");//从开始下标(包含)替换到结束下标(排他)的字符串
  
  sb.deleteCharAt(6);//删除指定下标上的字符
  sb.delete(3, 11);//从开始下标(包含)删除到结束下标(排他)的字符串
  
  sb.reverse();//反转字符串
  
  int len = sb.length();
  System.out.println("字符串长度为:" + len);
  
  System.out.println(sb.toString());//底层重写了toString()

注意:在调用方法层面上StringBuilder和StringBuffer是一样的

3.功能

​ StringBuffer sb = new StringBuffer();
​ sb.append(“xxx”);

4.构造方法

构造字符串缓冲区

StringBuilder/StringBuffer代表可变的字符序列,

StringBuilder/StringBuffer称为字符串缓冲区,

它的工作原理是:预先申请一块内存(char[] value = new char[]),存放字符序列,如果字符序列满了,会重新改变缓存区的大小,以容纳更多的字符序列(扩容机制:原来数组长度的两倍+2)。

	//缓冲区默认长度:16个字符

		StringBuffer sb = new StringBuffer();
		
	//自定义缓冲长度:99个字符

		StringBuffer sb = new StringBuffer(99);

	//自定义缓冲长度:"abc".length() + 16

		StringBuffer sb = new StringBuffer("abc");
5.应用场景

频繁拼接字符串,使用StringBuilder/StringBuffer

(1)应用原因

字符串的不变性:一个String对象的长度是固定的,不能改变它的内容,或者是附加新的字符到String对象中。

如果程序对这种附加字符串的需求很频繁,系统会频繁在内存中创建String对象,造成性能下降。所以并不建议使用+来进行频繁的字符串串联。应该使用java.lang.StringBuffer类。

(2)案例

​ //获取自1970年1月1日0:0:0:到现在的毫秒数(1000毫秒 = 1秒)

​ long currentTimeMillis = System.currentTimeMillis();

//		long startTime = System.currentTimeMillis();
//		String str = "奇男子";
//		for (int i = 1; i < 50000; i++) {
//			str += "欲戴其冠必乘其重"; 
///*		底层实现:
//			str = str + "欲戴其冠必乘其重";
//			str = new StringBuilder(str).append("欲戴其冠必乘其重");//变量参与多次new StringBuilder对象*/
//		}
//		long endTime = System.currentTimeMillis();
//		System.out.println("消耗时长" + (endTime - startTime));//消耗时长5303

​ System.out.println(“-----------------------------------”);
​ //优化

//		StringBuilder sb = new StringBuilder("奇男子");//只new一个StringBuilder对象
//		for (int i = 1; i < 500000; i++) {
//			sb.append("欲戴其冠必乘其重"); 
//		}

​ System.out.println(“-----------------------------------”);
​ //再优化

	StringBuilder sb = new StringBuilder(560000);//优化方案:减少底层扩容次数
	sb.append("奇男子");
	for (int i = 1; i < 500000; i++) {
		sb.append("欲戴其冠必乘其重"); 
	}

字符串类的深入

常量池概念:

Java运行时会维护一个常量池, 常量池用来存放运行时中产生的各种字符串,并且池中的字符串的内容不重复。

1.面试题

面试题1:

描述下列代码会创建几个String对象

		String str1 = "abc";
		String str2 = "abc";

答案:1个(常量池中的数据不允许重复)

面试题2:

描述下列代码会创建几个String对象

		String str1 = new String("abc");
		String str2 = new String("abc");

答案:3个(new了两个String对象 + “abc”)

2.深入String创建对象
String str1 = "abc";
String str2 = "abc";
System.out.println(str1 == str2);//true

//注意两个常量在编译时直接拼接
String str3 = "ab" + "c";//String str3 = "abc";
System.out.println(str1==str3);//true
//注意两个常量在编译时直接拼接
final String s1 = "ab";
final String s2 = "c";
String str4 = s1 + s2;//String str4 = "abc";
System.out.println(str1 == str4);//true

//注意:有变量参与字符串拼接的情况,底层会创建StingBuilder进行拼接
String s3 = "ab";
String s4 = "c";
String str5 = s3 + s4;//newStringBuilder(String.value(s3)).append(s4).toString();
System.out.println(str1 == str5);//false

注意:可以用将代码的class文件反编译查看底层拼接情况

3.StringBuilder和StringBuffer的底层原理

注意:

​ 1.StringBuffer和StringBuilder都是继承的AbstractStringBuilder

​ 2.StringBuffer和StringBuilder的核心功能都是由父类实现

​ 3.StringBuffer在方法中上锁、解锁 – 在多线程下使用

​ 4.StringBuffer和StringBuilder相比,因为有了上锁和解锁的步骤,所以效率没有StringBuilder高

public class MyAbstractStringBuilder {

//缓存数组
char[] value;

//储存字符个数
int count;

public MyAbstractStringBuilder() {
	// TODO Auto-generated constructor stub
}

MyAbstractStringBuilder(int capacity){
	value = new char[capacity];
}

//获取字符个数
public int length() {
	return count;
}

public MyAbstractStringBuilder append(String str) {
	
	//如果添加的字符串为null
    if (str == null)
        return appendNull();
    
    int len = str.length();
    ensureCapacityInternal(count + len);
    str.getChars(0, len, value, count);
    count += len;
    return this;
}

//添加字符串为null的情况
private MyAbstractStringBuilder appendNull(){
	int c = count;
	
	//判断是否扩容的方法
	ensureCapacityInternal(c + 4);//4  - "null".length()
	
	final char[] value = this.value;
	value[c++] = 'n';
	value[c++] = 'u';
	value[c++] = 'l';
	value[c++] = 'l';
	count = c;
	return this;
}

//判断是否扩容
private void ensureCapacityInternal(int minimumCapacity) {
	//有溢出的代码(容量必须大于缓存数组的长度才扩容)
	if (minimumCapacity - value.length >0) {
		value = Arrays.copyOf(value, newCapacity(minimumCapacity));
	}
}

//计算新的长度
private int newCapacity(int minimumCapacity) {
	//扩容机制:原来的长度*2 + 2
	int newCapacity = (value.length << 1) + 2;//+2的原因:怕用户设置初始化数组长度为0,0<<1还是0,就得不到扩容
	return newCapacity;
}

}

ps:MyStringBuffer(StringBuilder不同之处,没有synchronized)

public class MyStringBuffer extends MyAbstractStringBuilder{

public MyStringBuffer(){
	super(16);//默认缓冲数组的长度
}

public MyStringBuffer(int capacity){
	super(capacity);//自定义缓冲数组的
}

public MyStringBuffer(String str){
	super(str.length() + 16);//自定义缓存数组的长度:字符串长度+16
	append(str);//追加字符串
}
//synchronized -- 线程安全的方法
@Override
public synchronized MyAbstractStringBuilder append(String str) {//上锁
	super.append(str);//依赖于父类的append
	return this;
}//解锁

}

正则表达式

参考正则表达式常用文档

见文件资料

概念:

含义:用来描述或者匹配一系列符合某个语句规则的字符串

Pattern类 及 Matcher

Pattern:代表正则表达式的匹配模式

Matcher:提供了对正则表达式的分组支持,以及对正则表达式的多次匹配支持

总结:Pattern与Matcher一起合作.Matcher类提供了对正则表达式的分组支持,以及对正则表达式的多次匹配支持. 单独用Pattern只能使用Pattern.matches(String regex,CharSequence input)一种最基础最简单的匹配。

正则表达式作用

1.做替换

案例:把一个字符串中带电话号码替换成138****1234

	String str = "小陈12345678912小红12343565646小黄12122142154";
	
	String regex = "(1\\d{2})(\\d{4})(\\d{4})";//两个\\表示一个\,d表示数字D表示非数字
	str = str.replaceAll(regex, "$1****$3");//$n保留第几组正则表达式里的数据
2.做验证

案例:验证QQ邮箱

	String email = "183666918@qq.com";
	String regex = "\\d{4,11}@qq.com";//数字在什么区间的限定,后缀固定
	
	boolean matches = email.matches(regex);//获取验证结果
3.做字符串的分割

案例:分割路径

	String str = "C:\\资源\\中国\\春秋";

//		String regex = "\\\\";//分割:\\
		//:?表示冒号出现1次或0次
		String regex = ":?\\\\";//分割::\\ 或  \\
		String[] split = str.split(regex);
		for (String string : split) {
			System.out.println(string);
		}
4.利用正则表达式做字符串的爬数据的工作

案例:Pattern和Matcher找到前端代码中的图片路径

	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()){

//			System.out.println("x");//验证匹配几个
			//获取匹配结果
			String group = matcher.group(3);//3表示第3组
			System.out.println(group);

日期时间类

分类:

  1. Date类
  2. SimpleDateFormat类
  3. Calendar类

Date(java.util)

日期类

	Date date = new Date();
	System.out.println(date);
	//Sun Jan 28 21:11:46 CST 2024
	//星期    月份  日期  时:分:秒      区        年份

SimpleDateFormat

格式化日期类

	SimpleDateFormat sdf = new SimpleDateFormat("yyyy年MM月dd日HH时mm分ss秒");
	
	//Date转String
	String datetime = sdf.format(new Date());
	System.out.println(datetime);
	
	//String转Date
	Date date = sdf.parse("2024年01月28日21时20分09秒");
	System.out.println(date);

Calendar

日历类

	//获取当前系统的日历对象
	Calendar c = Calendar.getInstance();
	//简单工厂模式
	int year = c.get(Calendar.YEAR);
	int moth = c.get(Calendar.MONTH)+1;//注意:月份0~11,0表示1月,所以加1
	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(moth);
	System.out.println(day);
	System.out.println(hour);
	System.out.println(minute);
	System.out.println(second);

小结:

Date + SimpleDateFormat一起使用,获取我们想要的日期格式

获取当日历信息,考虑使用Calenda

Math类

理解:

Math类提供了一系列基本数学运算和几何函数的方法

Math类是final类,并且它的所有成员变量和成员方法都是静态的

方法:

	System.out.println("求次方:" + Math.pow(2, 3));//求次方:8.0
	System.out.println("求平方根:" + Math.sqrt(9));//求平方根:3.0
	System.out.println("求绝对值:" + Math.abs(-100));//求绝对值:100
	System.out.println("求最小值:" + Math.min(10, 20));//求最小值:10
	System.out.println("求最大值:" + Math.max(10, 20));//求最大值:20
	System.out.println("向上取整:" + Math.ceil(1.1));//向上取整:2.0
	System.out.println("向下取整:" + Math.floor(1.9));//向下取整:1.0
	System.out.println("四舍五入:" + Math.round(1.53));//四舍五入:2(取决于小数点后一位)
	System.out.println("取随机值:" + Math.random());//取随机值:0.8459309625873379(注意:随机出0~1的数字,包含0,1排他)
	
	//需求:随机出1~100的数字
	int num = (int)(Math.random()*100)+1;
	System.out.println("获取随机值:" + num);
	//获取int类型的最大值 -> 2147483647 -- 2的31次方-1
	System.out.println(Integer.MAX_VALUE);
	//获取int类型的最小值 -> -2147483648 -- 负的2的31次方
	System.out.println(Integer.MIN_VALUE);
	
	//面试题:Math.abs会出现负数吗?
	//答案:会出现负数 --> -2147483648
	System.out.println(Math.abs(-2147483648));//超过int类型的最大取值范围

静态导入:

将类中所有的静态属性和方法都导入到本类来,作为本类自己的静态属性和方法
import static java.lang.Math.*;

缺点:如果类中的方法和静态导入类中的方法重名了,会调用本类自己的静态方法,所有可读性差,不建议使用

public static void main(String[] args) {
	System.out.println("求次方:" + pow(2, 3));//求次方:8.0
	System.out.println("求平方根:" + sqrt(9));//求平方根:3.0
	
}
public static int sqrt(int i){
	return 123456;
}

Random类

理解

随机类,此类用于生成随机数

方法

Random ran = new Random();

System.out.println("随机出int取值范围里的数值" + ran.nextInt());
System.out.println("随机出0~9的int数值" + ran.nextInt(10));
System.out.println("随机出double取值范围里的数值" + ran.nextDouble());
System.out.println("随机出boolean取值范围里的数值" + ran.nextBoolean());

种子数

是初始化时产生的一个long类型的变量,Random会根据改变了生成伪随机数流,种子数固定,随机出的数据就是固定的

MyRandom

  注意:seed叫做种子数,种子数一旦固定随机出的数字就是固定的!

测试类:验证

	Random ran = new Random(1000);
	System.out.println("随机出int取值范围里的数值" + ran.nextInt());
	System.out.println("随机出0~9的int数值" + ran.nextInt(10));
	
	System.out.println("-----------------------");
	
	MyRandom myRandom = new MyRandom(4);
	System.out.println("随机出int取值范围里的数值" + myRandom.nextInt());
	System.out.println("随机出0~9的int数值" + myRandom.nextInt(10));

Random底层原理

public class MyRandom {

//种子数
private long seed;

public MyRandom(){
	this(seedUniquifier() ^ System.nanoTime());//伪随机数流
}

//获取相对随机的值
private static long seedUniquifier() {
	for (;;) {//死循环
		long cunrrent = System.currentTimeMillis();//获取一个long值
		long next = cunrrent * 181783497276652981L;
		if (next%3==0 || next%12==0 || next%17==0) {
			return next;
		}
	}
}

public MyRandom(long seed) {
	super();
	this.seed = seed;//随机种子数
}

public int nextInt(){
	return (int)seed;//返回种子数
}

public int nextInt(int bound){
	return Math.abs((int)seed)%bound;//随机出0~9的int数值
}

}

System类

理解:

Java程序的运行平台

1.System类提供了一些静态属性和方法,允许通过类名直接调用

2.System类提供了代表标准输入、标注输出、错误输出的类属性

3.System类提供了一些静态方法用于访问环境变量、系统属性的方法

属性:

static PrintStreamerr “标准”错误输出流。
static InputStreamin “标准”输入流。
static PrintStreamout “标准”输出流。
	//获取系统的标准输入流 - 方向:控制台 -> 程序
	InputStream in = System.in;
	
	Scanner scan = new Scanner(in);
	System.out.println("请输入int值:");
	int num = scan.nextInt();
	
	//获取系统的标准输出流 - 方向:程序 -> 控制台 
	PrintStream out = System.out;
	out.println(num);//黑色
	
	//获取系统的标准错误输出流 - 方向:程序 -> 控制台 
	PrintStream err = System.err;
	err.println(num);//红色
	
	scan.close();

​ 注意:理解System.out和System.err多线程抢资源

out和err先抢到资源先输出一个字符串结束一个,之后换行也会争抢,不一定在字符串输出就立即执行;再重复操作;直到所有都输出完结束。

由于上述条件就会出现多种情况

小陈
小明
小红
小红
小陈
小明
小陈
小红
小明
小陈
小明
小红
小陈
小红小明
小陈小红
小明
小红小陈

小明
  System.out.println("小陈");
  System.err.println("小红");
  System.out.println("小明");

方法

	long currentTimeMillis = System.currentTimeMillis();
	System.out.println("获取自1970年1月1日到现在的毫秒数:" + currentTimeMillis);
	
	//获取系统参数
	Properties properties = System.getProperties();
	System.out.println(properties);
	
	System.out.println("---------------------");
	
	//通过具体Key获取相应的Value
	String property = System.getProperty("os.name");
	System.out.println(property);
	
	//拷贝数组
	int[] arr = {1,2,3,4,5,6,7,8,9,10};
	int[] newArr = new int[4];
	System.arraycopy(arr, 3, newArr, 0, 4);//(原数组,开始下标,目标数组,开始下标,拷贝长度)
	for (int num : newArr) {
		System.out.println(num);
	}
	
	System.out.println("----------------");
	
	//利用System.arraycopy做数组的删除功能
	String[] names = {"aaa","bbb","ccc","ddd","eee","fff",null,null,null};
	System.arraycopy(names, 2, names, 1, 4);
	names[5] = null;
	for (String str : names) {
		System.out.println(str);
	}
	
	//退出当前虚拟机,0表示正常退出
	System.exit(0);

Runtime类

理解

Runtime表示运行时系统(JVM)

Runtime代表Java程序的运行时环境,可以通过 getRuntime 方法获取当前运行时。

应用程序不能自己创建Runtime对象,可以通过Runtime的静态方法getRuntime()获得Runtime对象。

Runtime类可以访问jvm的相关信息,如处理器数量,内存信息等

方法

  ```
  //获取运行时系统对象
  	Runtime run = Runtime.getRuntime();
  
  	System.out.println("获取最大操作数" + run.availableProcessors());//获取最大操作数12
  	System.out.println("获取最大内存数(byte)" + run.maxMemory());//获取最大内存数
  	System.out.println("获取空闲内存数(byte)" + run.freeMemory());//获取空闲内存数
  ```

程序的效率(时间、内存)消耗相对越少越好

频繁拼接字符串,StringBuilder/StringBuffer应用场景案例,加上Runtime的方法测试其消耗内存

  //再优化
  Runtime run = Runtime.getRuntime();
  long startTime = System.currentTimeMillis();
  long startmemory = run.freeMemory();
  StringBuilder sb = new StringBuilder(560000);//优化方案:减少底层扩容次数
  sb.append("奇男子");
  for (int i = 1; i < 500000; i++) {
  	sb.append("欲戴其冠必乘其重"); 
  }
  long endTime = System.currentTimeMillis();
  long endmemory = run.freeMemory();
  System.out.println("消耗时长" + (endTime - startTime));//消耗时长9
  System.out.println("消耗内存" + (endmemory - startmemory));//消耗内存-16800120

大数值运算类

分类:

BigInteger

BigDecimal

BigInteger

整数大数值运算类

方法(API查找)ps:

	BigInteger big1 = new BigInteger("1700000000000000");
	BigInteger big2 = new BigInteger("1700000000000000");
	
	BigInteger add = big1.add(big2);
	System.out.println("加法" + add);
	
	BigInteger subtract = big1.subtract(big2);
	System.out.println("减法" + subtract);
	
	BigInteger multiply = big1.multiply(big2);
	System.out.println("乘法" + multiply);

	BigInteger divide = big1.divide(big2);
	System.out.println("除法" + divide);

BigDecimal

小数大数值运算类
注意:

​ 1.小数做运算会失去精度,所以小数做运算都要生成大数值的运算类(用这个解决)

​ 2.构造方法里的值使用字符串,否则会失去精度

方法(API查找)ps:

	System.out.println(0.5 - 0.4);//0.09999999999999998
	
	BigDecimal big1 = new BigDecimal("0.5");
	BigDecimal big2 = new BigDecimal("0.4");

	BigDecimal add = big1.add(big2);
	System.out.println("加法" + add);

	BigDecimal subtract = big1.subtract(big2);
	System.out.println("减法" + subtract);

	BigDecimal multiply = big1.multiply(big2);
	System.out.println("乘法" + multiply);

	BigDecimal divide = big1.divide(big2);
	System.out.println("除法" + divide);

整数相除有小数情况:

	BigDecimal big1 = new BigDecimal("10");
	BigDecimal big2 = new BigDecimal("3");
	
	BigDecimal divide = big1.divide(big2, 3, BigDecimal.ROUND_HALF_UP);//(执行数,保留小数位数,保留小数形成限定情况)
	System.out.println("除法:" + divide);	
  • 23
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值