常用类
String类
-
String是引用数据类型,不属于基本数据类型,"hello world"不是基本类型,而是一个String对象。通过String源码中public final char[] value,这个value属性是一个char数组,所以字符串底层实际上是一个字符数组,通过final说明,字符串一旦被创建是不可变的。
-
以下程序创建了几个String对象:
public class Test{ String s1 = "hello"; String s2 = "hello"; String s3 = new String("hello"); String s4 = new String("hello"); }
双引号括起来的“hello”一定会在字符串常量池中创建并保存一个。一旦使用new关键字必然会在堆内存中开辟新的存储空间,以上程序new了两次。以上程序一共有三个对象,堆内存中两个,字符串常量池中一个(实际上三个对象都在堆内存中,因为Java8之后字符串常量池挪到了堆内存中)。
-
字符串拼接:
public class Test{ String s1 = "hello"; String s2 = "world"; String s3 = s1 + s2; String s4 = "abc" + "def"; }
通过加号可以进行字符串的拼接,字符串一旦被创建不可变,以上程序一共6个对象都保存在字符串常量池中。
接下来通过一个程序看看有多少对象:
public class Test { public static void main(String[] args) { String s = ""; for (int i=0;i<10000;i++){ s += i; } } }
如果加号两边都是字符串常量的话,可以使用加号进行拼接,因为它们会在编译阶段拼接。但如果加号两个有变量的话,必然会在底层new一共StringBuilder对象进行字符串的拼接,如果循环拼接的话,每次循环都会new一共StringBuilder对象,所以效率较低。通过上面程序的循环可以猜到nwe了一万个对象StringBuilder对象,效率较低。怎么解决呢?在for循环外面创建一个StringBuilder对象,在for循环中调用StringBuilder的append方法进行字符串的拼接,这样只创建了一共StringBuilder对象,效率较高。如果字符串需要进行频繁拼接,建议使用StringBuilder对象。
-
字符串的比较
public class Test{ public static void main(String[] args) { String s1 = new String("hello"); String s2 = new String("hello"); System.out.println(s1 == s2); } } 运行结果: false
双等号判断的是内存的地址,以上程序new了两次,所以是两个不同的内存地址,所以双等号判断结果是false。
在String类中有一共方法可以进行字符串的比较:equals()方法。
public class Test{ public static void main(String[] args) { String s1 = new String("hello"); String s2 = new String("hello"); System.out.println(s1.equals(s2)); } } 运行结果: true
通过以上程序可以得出,进行字符串比较使用equals()方法,equals()方法底层实际上也是双等号比较地址,但String类进行了重写比较的是内容。
-
String的构造方法:
String(String original); String(byte[] bytes); // 将byte数组转成字符串 String(byte[] bytes , int offset , int length); // 将byte数组的一部分转成字符串 String(char[] value); // 将char数组转成字符串 String(char[] value , int offset , int length); // 将char数组的一部分转成字符串
以下代码进行测试:
public class Test { public static void main(String[] args) { // 1 String s1 = "hello"; // 2 String s2 = new String("world"); //3 byte[] bytes = {97,98,99,100}; String s3 = new String(bytes); String s4 = new String(bytes,0,2); // 4 char[] chars = {'你','好','呀'}; String s5 = new String(chars); String s6 = new String(chars,0,2); System.out.println(s1); System.out.println(s2); System.out.println(s3); System.out.println(s4); System.out.println(s5); System.out.println(s6); } } 运行结果: hello world abcd ab 你好呀 你好
-
String类的常用方法
char charAt(int index); // 返回指定索引index的字符 int compareTo(String anotherString); // 比较两个字符串大小,a.compareTo(b),结果0表示a和b相等,结果<0表示a<b,结果>0表示a>b String concat(String str); // 拼接字符串,参数只能是String类型,如果参数是null,会出现空指针异常 boolean contains(CharSequence s); // 判断当前字符串是否包含某个字符串s boolean endsWith(String sufffix); // 判断当前字符串是否以某个字符串结尾 boolean equals(Object anObject); // 判断两个字符串是否相等 boolean equalslgnoreCase(String anotherString); // 判断两个字符串是否相等,忽略大小写 byte[] getBytes(); // 将字符串转成byte数组 int indexOf(String str); // 获取str字符串在当前字符串中第一次出现的索引 int indexOf(String str , int frimlndex); // 从下标frimlndex开始,获取str字符串在当前字符串中第一次出现的索引 int lastlndexOf(String str); // 获取str在当前字符串中最后一次出现的索引 int lastlndexOf(String str , int frimlndex); // 从下标frimlndex开始,获取str在当前字符串中最后一次出现的索引 String intern(); // 从字符串常量池中获取当前字符串对象,获取则返回,如果获取不到,则新建一共字符串常量存储常量池中,并返回此字符串的引用 int length(); // 获取字符串的长度 String replaceAll(String str,String newStr); // 将字符串str替换成newStr String[] split(String regex); // 将当前字符串对象是否以某个特定的符号进行拆分,返回String数组 boolean startsWith(String prefix); // 判断当前字符串对象是否以某个子字符串开头 String substring(int beginlndex); // 从beginlndex下标开始截取字符串,返回截取后的子字符串 String substring(int beginlndex , itn endlndex); // 从beginlndex下标开始,到endlndex结束(不包括),截取字符串 char[] toCharArray(); // 将字符串转成char数组 String toLowerCase(); // 转成小写 String toUpperCase(); // 转成大写 String trim(); // 去除字符串前后空白 String strip(); // 去除字符串前后空白,并且支持unicode编码的空白 static String valueOf(任意类型的参数); // 将任意类型的参数转成字符串
StringBuilder与StringBuffer
-
StringBuilder和StringBuffer是对String的一个补充,String称为不可变长字符串,而StringBuilder和StringBuffer称为可边长字符串,它们的区别是:StringBuffer在多线程并发的环境下,它是安全的。而StringBuilder是非线程安全的。其他方面基本相同。
-
StringBuilder主要是进行字符串的拼接,因为String做字符串的拼接使用+号,会在字符串常量池中生成多个String对象,效率较低,而StringBuilder不会。
-
通过源码解析,StringBuilder底层是一个char[]数组,StringBuilder的默认初始化容量是16,通过构造方法也可以指定初始容量,StringBuilder和StringBuffer称为可边长字符串,那他们是怎么扩容的呢?扩容规则:原数组容量*2+2。
-
在StringBuilder和StringBuffer中都有一个拼接字符串的方法,append()方法,通过以下程序进行测试:
public class Test { public static void main(String[] args) { // 创建一个指定初始化容量的StringBuilder对象 StringBuilder s = new StringBuilder(30); // 拼接(追加)字符串 s.append("public class Test{\n"); s.append("int a = 10"); s.append("\n}"); System.out.println(s); } } 运行结果: public class Test{ int a = 10 }
包装类
-
Java语言中提供了8中基本类型,为了编程方便,对这8中基本类型又分别提供了它们的包装类。
-
基本数据类型 包装类型(java.lang包下) byte Byte short Short int Integer long Long float Float double Double boolean Boolean char Character -
其中Byte,Short,Integer,Long,Float,Double它们6个的父类是Number,而Boolean和Charcater它们两个的父类是Object。
-
以下程序测试包装类的拆箱和装箱:
public class Test { public static void main(String[] args) { // 手动装箱,Integer提供了两个构造方法,可传入数字和字符串(这个字符串必须是一个数字) Integer x1 = Integer.valueOf(100); Integer x2 = Integer.valueOf("200"); // 手动拆箱 int y1 = x1.intValue(); int y2 = x2.intValue(); // 自动装箱 Integer a = 500; // 自动拆箱 int b = a; } }
-
这里有一个经典的题,大家可以猜测一下结果是什么:
public class Test { public static void main(String[] args) { Integer x = 127; Integer y = 127; System.out.println( x == y); Integer a = 128; Integer b = 128; System.out.println(a == b); } } 运行结果: true false
第一个结果是true,第二结果是false,这是为什么呢?
因为在Integer类中有一个特殊的机制,在Integer类进行加载之后,会在堆(Java7之前在方法区)中生成一个整数常量池,这个常量池的范围-128~127,
也就是说当数字没有超过这个范围的时候,会直接从整数常量池中拿这个Integer对象,如果超出了这个范围才会new对象。x和y没有超出这个范围,它们拿的是同一个对象,而a和b超出了这个范围,它们是new的对象,双等号判断的是内存地址,所以a和b是false。
日期类
-
日期在实际的开发中应用非常广泛,主要涉及到的类有:java.utilDate , java,text,SimpleDateFormat , java.util.Calendar。
-
如何获取系统当前时间:
public class Test { public static void main(String[] args) { // 获取系统当前时间 Date date = new Date(); // 这里输出date会自动调用toString方法 System.out.println(date); } } 运行结果: Wed Aug 17 10:13:41 CST 2022
-
通过以上的程序输出当前系统时间,但这个时间格式对于我们来说不太习惯,接下来将日期格式化:
public class Test { public static void main(String[] args) { // 获取系统当前时间 Date date = new Date(); /* 创建格式化日期对象 y 年 M 月 d 日 H 时 m 分 s 秒 S 毫秒 */ SimpleDateFormat sdf = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss SSS"); // 调用format方法进行格式化,返回一个字符串 String time = sdf.format(date); System.out.println(time); } } 运行结果: 2022/08/17 10:17:31 238
-
以上代码将日期类型转成String类型,怎么将String类型转成日期类型呢?
public class Test { public static void main(String[] args) { // 创建一个格式化对象 SimpleDateFormat sdf = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss"); // 创建一个字符串日期,这个字符串日期格式必须和日期格式化对象格式匹配 String date = "2008/1/1 19:30:00"; try { // 将String类型转成Date类型,使用parse方法,这个方法需要处理异常 Date newDate = sdf.parse(date); System.out.println(newDate); } catch (ParseException e) { throw new RuntimeException(e); } } } 运行结果:; Tue Jan 01 19:30:00 CST 2008
-
如果我们想获取一个时间对于的星期几,这时候需要借助日历类,例如:
public class Test { public static void main(String[] args) { // 获取系统当前时间 Date date = new Date(); // 获取日历对象 Calendar c = Calendar.getInstance(); // 让日历对象关联时间 c.setTime(date); System.out.println("系统当前时间:" + date); System.out.println("一周的第几天:" + c.get(Calendar.DAY_OF_WEEK)); System.out.println("一个月的第几天:" + c.get(Calendar.DAY_OF_MONTH)); } } 运行结果:; 系统当前时间:Wed Aug 17 10:34:50 CST 2022 一周的第几天:4 一个月的第几天:17
这个为什么是第四天呢?因为国外的一周第一天是星期日。
数学类
public class Test {
public static void main(String[] args) {
// java.util.Math 数学工具类
// 计算平方根
System.out.println("9的平方根:" + Math.sqrt(9));
// 计算立方根
System.out.println("8的立方根:" + Math.cbrt(8));
// 计算x的y次方
System.out.println("2的3次方:" + Math.pow(2,3));
// 计算最大值
System.out.println("1和2的最大值:" + Math.max(1,2));
// 计算最小值
System.out.println("1和2的最小值:" + Math.min(1,2));
// 计算绝对值
System.out.println("-1的绝对值:" + Math.abs(-1));
// 向上取整
System.out.println("10.2向上取整:" + Math.ceil(10.2));
// 向下取整
System.out.println("10.99向下取整:" + Math.floor(10.99));
// 四舍五入返回double类型
System.out.println("10.4四舍五入返回double类型:" + Math.rint(10.4));
System.out.println("10.5四舍五入返回double类型:" + Math.rint(10.5));
// 四舍五入返回int类型
System.out.println("10.4四舍五入返回int类型:" + Math.round(10.4));
System.out.println("10.5四舍五入返回int类型:" + Math.round(10.5));
}
}
运行结果:
9的平方根:3.0
8的立方根:2.0
2的3次方:8.0
1和2的最大值:2
1和2的最小值:1
-1的绝对值:1
10.2向上取整:11.0
10.99向下取整:10.0
10.4四舍五入返回double类型:10.0
10.5四舍五入返回double类型:10.0
10.4四舍五入返回int类型:10
10.5四舍五入返回int类型:11
数字类
-
这里主要掌握两个类:java.text.DecimalFormat (数字格式化显示方面)和java.math.BigDecimal(财务数据处理方面)。
public class Test { public static void main(String[] args) { // 创建数字格式化对象 // ###,###.## 表示数字加入千分位,保留两位小数 DecimalFormat df = new DecimalFormat("###,###.##"); String str = df.format(123456.789); System.out.println(str); // 小数部分保留两位,四舍五入 DecimalFormat df2 = new DecimalFormat(".00"); String str2 = df2.format(123.5489); System.out.println(str2); } } 运行结果:; 123,456.79 123.55
public class Test { public static void main(String[] args) { // 创建两个个精度较高的对象 BigDecimal v1 = new BigDecimal(100); BigDecimal v2 = new BigDecimal(200); // 求和方法 BigDecimal x1 = v1.add(v2); System.out.println(x1); // 乘积方法 BigDecimal x2 = v1.multiply(v2); System.out.println(x2); // 这里只说了求和与乘积的方法,当然还有其他的方法,大家可以去查文档进行学习 } } 运行结果: 300 20000
随机数
public class Test {
public static void main(String[] args) {
// 在Java中可以专门生成随机数,java.util.Random
// 创建一个随机生成器对象
Random r = new Random();
System.out.println("返回一个int类型随机数:" + r.nextInt());
// 生成五个int类型的随机数,范围在0~100之间
for (int i=0;i<5;i++){
int v = r.nextInt(100);
System.out.print(v + " ");
}
System.out.println();
// 生成五个int类型的随机数,范围在0~10之间
for (int i=0;i<5;i++){
int v = r.nextInt(6);
System.out.print(v + " ");
}
}
}
运行结果:;
返回一个int类型随机数:-178658592
40 1 65 55 75
2 2 5 2 1
-
通过以上程序发现,区间越小,重复也高。假设现在有一个需求,在0~4之间生成5个不同的随机数,这应该怎么去实现呢?
public class Test { public static void main(String[] args) { // 创建随机生成器对象 Random random = new Random(); // 准备一个容量为5的int类型的数组 // 元素初始值为-1,如果为0的话,随机数中可以能有0,可能程序出错 int[] arr = new int[]{-1,-1,-1,-1,-1}; // 从数组的第一个下标开始放元素 int index = 0; while (index < arr.length){ // 生成随机数 int value = random.nextInt(5); // 如果数组中不包含随机数,放进数组中 if (!(query(arr,value))){ arr[index++] = value; } } // 输出结果 System.out.println(Arrays.toString(arr)); } /** * 查询数组中是否包含value随机数 * @param arr 数组 * @param value 查询元素 * @return true包含 , false不包含 */ public static boolean query(int[] arr , int value){ for (int i=0;i<arr.length;i++){ if (arr[i] == value){ return true; } } return false; } } 运行第一次结果: [0, 4, 3, 2, 1] 运行第二次结果: [4, 0, 1, 2, 3] 运行第三次结果: [1, 0, 3, 2, 4]