第十一章、 Java常用类
11.1 包装类
11.1.1 包装类的分类
- 针对八种基本数据类型相应的引用类型-包装类
- 有了类的特点,就可以调用类中的方法。
11.1.2 包装类和基本数据的转换
- Jdk5前的手动装箱和拆箱方式,装箱:基本类型->包装类型(即把基本类型变成包装类型的过程称为装箱);拆箱反之。
- Jdk5以后(含jdk5)的自动装箱和拆箱方式
- 自动装箱底层调用的是valueOf方法,比如Integer.valueOf()
- 其他类型同理,面试题常考
package chapter11.wrapper;
/**
* @aim java基础学习
* @note java笔记
*/
public class Integer01 {
public static void main(String[] args) {
//jdk5前是手动装箱和拆箱
//手动装箱 int->Integer
int n1=100;
Integer integer=new Integer(n1);
Integer integer1=Integer.valueOf(n1);
//手动拆箱 Integer->int
int n2=integer.intValue();
//jdk5后,就可以自动装箱和拆箱
int n3=100;
//自动装箱
Integer integer2=n3;//底层使用的是Integer.valueOf(n2)
//自动拆箱
int n4=integer2;//底层仍然使用的是 intValue()方法
}
}
11.1.3 包装类练习
- 下面代码是否正确,为什么?
- 并判断两个输出语句输出是一样吗,如果不一样各是什么?为什么?
package chapter11.wrapper;
/**
* @aim java基础学习
* @note java笔记
*/
public class WrapperType {
public static void main(String[] args) {
Double d=100d;//对,自动装箱,底层是Double.valueOf(100d);
Float f=1.5f;//对,自动装箱,底层是Float.valueOf(1.5d);
Object obj1=true?new Integer(1):new Double(2.0);
System.out.println(obj1);//1.0,三元运算符是一个整体,会自动转型
Object obj2;
if(true){
obj2=new Integer(1);
}else{
obj2=new Double(2.0);
}
System.out.println(obj2);//1
}
}
11.1.4 包装类型和String类型的相互转换
- 通过代码来理解:包装类型和String类型之间的相互转换
package chapter11.wrapper;
/**
* @aim java基础学习
* @note java笔记
*/
public class WrapperVSString {
public static void main(String[] args) {
//包装类型--->String类型
Integer i=10;//自动装箱
//方式1:
String s1=i.toString();
//方式2:
String s2=String.valueOf(i);
//方式3:这种方式不会改变i本身
String s3=""+i;
//String类型--->包装类类型
String s="100";
//方式1:
Integer j1=new Integer(s1);//构造器
//方式2:
Integer j2=Integer.valueOf(s);
//方式3:
Integer j3=Integer.parseInt(s);//parseInt本身是返回int,但是这个可以进行自动装箱
}
}
11.1.5 Integer类和Character类的常用方法
- Integer类和Character有些常用的方法(会常用方法即可。其他方法太多了,会查即可)。通过下面代码来理解。
package chapter11.wrapper;
/**
* @aim java基础学习
* @note java笔记
*/
public class WrapperMethod {
public static void main(String[] args) {
System.out.println(Integer.MIN_VALUE);//通过访问属性,返回最小值
System.out.println(Integer.MAX_VALUE);//返回最大值
System.out.println(Character.isDigit('a'));//判断是否属于数字
System.out.println(Character.isLetter('a'));//判断是否属于字母
System.out.println(Character.isUpperCase('a'));//判断是否属于大写字母
System.out.println(Character.isLowerCase('a'));//判断是否属于小写字母
System.out.println(Character.isWhitespace('a'));//判断是否属于空格
System.out.println(Character.toUpperCase('a'));//转成大写
System.out.println(Character.toLowerCase('A'));//转成小写
}
}
/*
-2147483648
2147483647
false
true
false
true
false
A
a
*/
11.1.6 Integer创建机制
- 查看下面代码,输出什么结果?为什么?
package chapter11.wrapper;
/**
* @aim java基础学习
* @note java笔记
*/
public class WrapperExercise01 {
public static void main(String[] args) {
}
public void method(){
Integer i = new Integer(1);
Integer j = new Integer(1);
System.out.println(i==j);//false
Integer m=1;
Integer n=1;
System.out.println(m==n);//true
Integer x=128;
Integer y=128;
System.out.println(x==y);//false
}
}
(1). 分析ij为什么是false,因为i和j分别是对象引用,对比的它的地址,所以是false。
(2). 分析mn为什么是true,首先要知道底层代码是Integer.valueOf(1)。查看源码得知,当传入-128~127时,直接返回;否则就返回new Integer(x);
(3). 分析xy为什么是false,由上面解释可得。
部分代码如下:(具体代码自行查看)
2. 查看下面代码,输出什么结果?为什么?
package chapter11.wrapper;
/**
* @aim java基础学习
* @note java笔记
*/
public class WrapperExercise02 {
public static void main(String[] args) {
//1.
Integer i1=new Integer(127);
Integer j1=new Integer(127);
System.out.println(i1==j1);//f
//2.
Integer i2=new Integer(128);
Integer j2=new Integer(128);
System.out.println(i2==j2);//f
//3.
Integer i3=127;
Integer j3=127;
System.out.println(i3==j3);//t
//4.
Integer i4=128;
Integer j4=128;
System.out.println(i4==j4);//f
//5.
Integer i5=127;
Integer j5=new Integer(127);
System.out.println(i5==j5);//f
//6.如果存在基本数据类型,那么判断的是值是否相等
Integer i6=127;
int j6=127;
System.out.println(i6==j6);//t
//7.
Integer i7=128;
int j7=128;
System.out.println(i7==j7);//t
}
}
分析:如果存在基本数据类型,那么判断的是值是否相等
11.2 String
11.2.1 String类的理解和创建对象
- String对象用于保存字符串,也就是一组字符序列String 01.java
- 字符串常量对象是用双引号括起来的字符序列。例如:”你好”,”12.97”,”boy”等
- 字符串的字符使用Unicode字符编码,一个字符(不区分字母还是汉字)占两个字节
- String类较常用构造方法(其他看手册)
(1). String s1=new String();
(2). String s2=new String(String original);
(3). String s3=new String(char[] a);
(4). String s4=new String(char[] a,int startIndex,int count);
(5). String 类实现了接口Serializable【String 可以串行化:可以在网络传输】、Comparable 【String 对象可以比较大小】
(6). String 是final类,即不能被其他类继承
(7). String有属性 private final byte[] value;用于存放字符串内容/,JDK8之前是char[]
(8). 一定要注意:value 是一个final类型,不可以修改(重点):即内容可以修改,但是指向的地址不能修改(即value不能指向新地址)
package chapter11.string_;
/**
* @aim java基础学习
* @note java笔记
*/
public class String01 {
public static void main(String[] args) {
String name="jack";
name="mark";
//1.String 对象用于保存字符串,也就是一组字符序列
//2."jack" 是字符串常量,双引号括起来的字符序列
//3.字符串的字符使用Unicode字符编码,一个字符(不区分字母还是汉字)占两个字节
//4.String类有很多构造器,构造器重载
// 常用的有:
// (1). String s1=new String();
// (2). String s2=new String(String original);
// (3). String s3=new String(char[] a);
// (4). String s4=new String(char[] a,int startIndex,int count);
// (5). String s5=new String(byte[] b)
//5.String 类实现了接口Serializable【String 可以串行化:可以在网络传输】
// 接口Comparable 【String 对象可以比较大小】
//6.String 是final类,即不能被其他类继承
//7.String有属性 private final byte[] value;用于存放字符串内容/,JDK8之前是char[]
//8.一定要注意:value 是一个final类型,不可以修改(重点):
// 即内容可以修改,但是指向的地址不能修改(即value不能指向新地址)
final byte[] value={1,2,3,4};
value[0]=3;//可以修改内容
byte[] v2={1,2,3,4};
// value=v2;//报错,不可以修改value地址
}
}
11.2.2 String结构剖析
-
创建String对象的两种方式
(1). 方式一:直接赋值 String s=”hello”;
(2). 方式二:调用构造器String s2=new String(“hello”); -
两种创建String对象的区别
(1). 方式一:先从常量池查看是否有”hello”的数据空间,如果有,直接指向;如果没有则重新创建,然后指向。s最终指向的是常量池的空间地址。
(2). 方式二:先从堆中创建空间,里面维护了value属性,指向常量池的hello空间。如果常量池没有”hello”,重新创建,如果有,直接通过value指向。最终指向的是堆中的空间地址。
(3). 画出两种方式的内存分布图
11.2.3 练习
- 思考下面代码输出什么?
package chapter11.string_;
/**
* @aim java基础学习
* @note java笔记
*/
public class StringExercise01 {
public static void main(String[] args) {
String a="hello";
String b="hello";
System.out.println(a.equals(b));//true,对比的是值
System.out.println(a==b);//true,对比的是地址
}
}
- 思考下面代码输出什么?
package chapter11.string_;
/**
* @aim java基础学习
* @note java笔记
*/
public class StringExercise02 {
public static void main(String[] args) {
String a=new String("hello");
String b=new String("hello");
System.out.println(a.equals(b));//true
System.out.println(a==b);//false
}
}
- 思考下面代码输出什么?
知识点:
当调用intern方法时,如果池中已经包含有一个等于这个String(用equals(Object)方法确定),则返回池中的字符串。否则,将此String对象添加到池中,并返回此String对象的引用。
package chapter11.string_;
/**
* @aim java基础学习
* @note java笔记
*/
public class StringExercise03 {
public static void main(String[] args) {
String a="hello"; //指向 常量池中 hello的地址
String b =new String("hello"); //指向的是堆中的对象,这个对象有个value指向常量池中 hello的地址
String c = "hi";
System.out.println(a.equals(b));// true
System.out.println(a==b);//false
System.out.println(a==b.intern());//true
System.out.println(b==b.intern());//false
System.out.println(c==b.intern());//false
/*
理解这个intern()的使用:
由前面代码知道"hello",已经在常量池中存在了,那么执行b.intern(),
如果常量池中存在和b对象的字符串一样的话,就将该返回池中的字符串,
也就是b.intern指向的是常量池字符串"hello",否则,就将这个字符串"hello"
添加到常量池中,返回这个b对象的引用,也就是b.intern指向的是堆中的对象
*/
}
}
- 思考下面代码输出什么?
package chapter11.string_;
/**
* @aim java基础学习
* @note java笔记
*/
public class StringExercise04 {
public static void main(String[] args) {
String s1= "hello";
String s2= "hi";
String s3= "hi";
String s4= new String("hi");
System.out.println(s2==s3);//true
System.out.println(s2==s4);//false
System.out.println(s2.equals(s4));//true
System.out.println(s1==s2);//false
}
}
- 思考下面代码输出什么?
package chapter11.string_;
/**
* @aim java基础学习
* @note java笔记
*/
public class StringExercise05 {
public static void main(String[] args) {
Person p1=new Person();
p1.name="hello";
Person p2=new Person();
p2.name="hello";
System.out.println(p1.name.equals(p2.name));//true
System.out.println(p1.name==p2.name);//true
System.out.println(p1.name=="hello");//true
String s1=new String("abc");
String s2=new String("abc");
System.out.println(s1==s2);//false
}
}
class Person{
public String name;
}
11.2.4 字符串的特性(面试题)
- 以下语句创建了几个对象?
String s1="hello";
s1="haha";
/*
2
理解:首先s1会去常量池寻找有没有hello这个字符串常量对象,如果没有就创建。
然后s1="haha",同理它会去常量池中寻找haha这个字符串常量对象,如果没有就创建。
并不会修改hello这个字符串常量对象
*/
总结:
(1). String是final类,代表不可变的字符序列
(2). 字符串是不可变的。一个字符串对象一旦被分配,其内容是不可变的。
- 以下语句创建了几个对象?
String a="hello"+"hi";
/*
创建了1个对象
String a="hello"+"hi";底层优化等价于 String a="hellohi";
*/
总结:
(1). 编译器会做一个优化,判断创建的是不是属于字符串常量,如果是就做优化
(2). String a=“hello”+“hi”;==>底层优化等价于 String a=“hellohi”;
- 以下语句创建了几个对象?
package chapter11.string_;
/**
* @aim java基础学习
* @note java笔记
*/
public class StringExercise3 {
public static void main(String[] args) {
String a="hello";
String b="hi";
String c=a+b;
/*
创建了3个对象,但是对象引用不一样。a和b指向的常量池的字符串常量对象;而c指向的堆中对象的value。
底层实现:
1. 先创建一个StringBuilder sb=StringBuilder();
2. 执行 sb.append("hello");
3. sb.append("hi");
4. String c=sb.toString();
最后 c 指向堆中的对象(String) value[]-->池中"hellohi"
*/
//证明c指向的不是池中的hellohi
String s="hellohi";
String s2="hello"+"hi";
System.out.println(c==s);//false
System.out.println(c==s2);//false
}
}
总结:
(1). 底层是StringBuilder sb=StringBuilder(); sb.append(“hello”); sb.append(“hi”);
(2). String c=sb.toString(); sb在堆中,并且append是在原来字符串的基础上追加的。
(3). 重要规则:String c1=“ab”+“cd”;常量相加,看的是池。String c1=a+b; 变量相加,是在堆中。
- 判断下面代码输出什么?为什么?
package chapter11.string_;
/**
* @aim java基础学习
* @note java笔记
*/
public class StringExercise4 {
public static void main(String[] args) {
String s1="hello";//指向池中的"hello"
String s2="hi";//指向池中的"hi"
String s3="hellohi";//指向池中的"hellohi"
String s4=(s1+s2).intern();//指向池中的"hellohi"
System.out.println(s3==s4);//true
System.out.println(s3.equals(s4));//true
}
}
- 判断下面代码输出什么?为什么?(重点)
package chapter11.string_;
/**
* @aim java基础学习
* @note java笔记
*/
public class Test1 {
public static void main(String[] args) {
Test1 ex = new Test1();
ex.change(ex.str,ex.ch);
System.out.print(ex.str+ " and ");
System.out.println(ex.ch);
//输出:hello and wello
}
String str = new String("hello");
final char[] ch ={'h','e','l','l','o'};
public void change(String str ,char ch[]){
str="hi";
ch[0]='w';
/*
理解:首先在堆中创建了一个Test1对象指向main栈中的ex,在这个Test1对象中,有创建了一个str指向堆另一个String对象
这个String对象有个属性value,value指向池中的"hello",ch就直接在静态区生成数组。
然后ex引用变量调用方法change(),传入了str和ch.这时候在change栈中有一个str的变量指向了Test1对象的str
而ch直接指向栈中静态区的数组。再然后执行str="hi",它是change栈中str的变量就去常量池中寻找或创建。
也就是说这时候change栈的str指向的是池中的"hi"与Test1对象的str就没有关系了。
而ch[0]='w'是栈中数组的引用传递,是可以直接在静态区的数组进行修改。所以最后输出:hello and wello
*/
}
}
11.2.5 String类的常见方法
说明:
String类是保存字符串常量的。每次更新都需要重新开辟空间,效率较低,因此java设计者还提供了StringBuilder和StringBuffer来增强String的功能,并提高开发效率。
- String类的常见方法一览(不用背,用多就会啦)
(1). equals //区分大小写,判断内容是否相等
(2). equalsIgnoreCase //忽略大小写的判断内容是否相等
(3). length //获取字符的个数,字符串长度
(4). indexOf //获取字符或子串在字符串中第一次出现的索引,索引从0开始,如果找不到就返回-1
(5). lastIndexOf //获取字符或子串在字符串中最后一次出现的索引,索引从0开始,如果找不到就返回-1
(6). substring //截取指定范围的子串
(7). trim //去前后空格
(8). charAt //获取某索引处的字符,注意不能使用Str[index]这样的方式
(9). toUpperCase //将小写字母转换成大写
(10). toLowerCase //将大写字母转换成小写字母
(11). concat //拼接字符串
(12). replace //替换字符串中的字符,返回的是新的字符串,本身没有改变
(13). split //分割字符串,对于某些分割字符,需要用到转义 .比如| \等
(14). compareTo // 比较两个字符串的大小,如果前者大则返回正数;否则就返回负数;若相等则返回0
(15). toCharArray //将字符串转换成字符数组
(16). format //格式化字符串,占位符:%s字符串 %c字符 %d整型 %.2f浮点型(四舍五入)
package chapter11.string_;
/**
* @aim java基础学习
* @note java笔记
*/
public class StringMethod01 {
public static void main(String[] args) {
//(1). equals //区分大小写,判断内容是否相等
String s1="hello";
String s2="Hello";
System.out.println(s1.equals(s2));//false
//(2). equalsIgnoreCase //忽略大小写的判断内容是否相等
String a1="hi";
String a2="HI";
System.out.println(s1.equalsIgnoreCase(a2));//false
//(3). length //获取字符的个数,字符串长度
System.out.println("hello".length());//5
//(4). indexOf //获取字符或子串在字符串中第一次出现的索引,索引从0开始,如果找不到就返回-1
String b1="ehi@hi@3@";
System.out.println(b1.indexOf('@'));//3
System.out.println(b1.indexOf("hi"));//1
System.out.println(b1.indexOf('c'));//-1
//(5). lastIndexOf //获取字符或子串在字符串中最后一次出现的索引,索引从0开始,如果找不到就返回-1
String b2="ehi@hi@3@";
System.out.println(b2.lastIndexOf('@'));//8
System.out.println(b1.lastIndexOf("hi"));//4
System.out.println(b2.lastIndexOf('c'));//-1
//(6). substring //截取指定范围的子串
String c="hello,java";
System.out.println(c.substring(1));//从索引开始截取到最后面:ello.java
System.out.println(c.substring(1,3));//截取索引1-2(遵循左闭右开):el
//(7). trim //去前后空格
String d=" hello ";
System.out.println(d.trim());//hello
//(8). charAt //获取某索引处的字符,注意不能使用Str[index]这样的方式
String e="hello";
System.out.println(e.charAt(2));//l
//(9). toUpperCase //将小写字母转换成大写
String f="HEllo";
System.out.println(f.toUpperCase());//HELLO
//(10). toLowerCase //将大写字母转换成小写字母
String g="heLLO";
System.out.println(g.toLowerCase());//hello
//(11). concat //拼接字符串
String h1="你好";
String h2=",mark";
System.out.println(h1.concat(h2));//你好,mark
//(12). replace //替换字符串中的字符,返回的是新的字符串,本身没有改变
String i="hello,jack";
System.out.println(i.replace("jack","mark"));//将所有的jack替换为mark:hello,mark
System.out.println(i);//hello,jack
//(13). split //分割字符串,对于某些分割字符,需要用到转义 \.比如| \\等
String j1="hi,mark";
System.out.println(j1.split(",")[0]);//以,为标准进行分割,返回的是一个数组:hi
String j2="E:\\cd\\ef";
System.out.println(j2.split("\\\\")[0]);//E:
//(14). compareTo //比较两个字符串的大小,如果前者大则返回正数;否则就返回负数;若相等则返回0
// 比较规则:从str1和str2两个字符串的索引0开始按字符逐一比较,若第一个相同,则一直往下比较,
// 直到str1和str2的某个位置的字符不相同,用str1的字符 - str2的字符(按Unicode码来)。
//若 str1 和 str2 直到最后一个字符都相同,则比较长度,返回 str1.length() - str2.length()。
String str1="abff";//a-97,b-98,c-99
String str2="acd";
String str3="acdef";
System.out.println(str1.compareTo(str2));//-1
System.out.println(str2.compareTo(str3));//-2
//(15). toCharArray //将字符串转换成字符数组
String l="hello";
char[] ch=c.toCharArray();
System.out.println(ch[0]);//h
//(16). format //格式化字符串,占位符:%s字符串 %c字符 %d整型 %.2f浮点型(四舍五入)
String n="我的名字是%s 年龄是%d 成绩是%.2f 性别是%c . 很高兴认识大家....";
String info=String.format(n,"mark",22,87.758,'男');
System.out.println(info);//我的名字是mark 年龄是22 成绩是87.76 性别是男 . 很高兴认识大家....
}
}
- 输入商品名称和商品价格,要求打印效果示例,使用String.format的方法来实现:
StringMethod02.java
商品名 商品价格
手机 123,456.79
要求:使用千位分隔符。
package chapter11.string_;
import java.util.InputMismatchException;
import java.util.Scanner;
/**
* @aim java基础学习
* @note java笔记
*/
public class StringMethod02 {
public static void main(String[] args) {
Scanner scanner=new Scanner(System.in);
System.out.print("请输入商品:");
String goods=scanner.next();
double price= 0;
try {
System.out.print("请输入手机价格:");
price = scanner.nextDouble();
} catch (InputMismatchException e) {
System.out.println("你输入的价格不正确(默认0.00)");
}
String ans =String.format("商品名\t商品价格\n%s\t\t%,.2f",goods,price);
System.out.print(ans);
}
}
/*
请输入商品:菠萝手机
请输入手机价格:123
商品名 商品价格
菠萝手机 123.00
*/
11.3 StringBuffer
11.3.1 StringBuffer结构剖析
-
基本介绍
(1). Java.lang.StringBuffer代表可变的字符序列,可以对字符串内容进行增删。
(2). 很多方法和String相同,但StringBuffer是可变长度的。
(3). StringBuffer是一个容器。 -
结构剖析
(1). StringBuffer 的直接父类是AbstractStringBuilder
(2). StringBuffer 实现了Serializable ,即StringBuffer的对象可以序列化(串行化)、比如保存文件、或网络传输。
(3). 在父类中 AbstractStringBuilder 有属性 byte[ ] value,不是final,该value数组存放的是字符串内容,因此存放在堆中,而不是常量池中。
(4). StringBuffer是一个fianl类,不能被继承
(5). 因为StringBuffer 字符内容是在 byte[ ] value,所以在变化(增加/删除)不用每次都更换地址(即不是每次都创建对象),所以效率高于String。 -
String VS StringBuffer
String保存的是字符串常量,里面的值不能更改,每次String类的更新实际上就是更改地址,效率较低 //private final char value[ ];
StringBuffer保存的是字符串变量,里面的值可以更改,每次StringBuffer的更新实际上可以更新内容,不用每次更新地址(除了空间不够),效率较高 // char[ ] value //放在堆中
11.3.2 StringBuffer转换
- StringBuffer的构造器
构造方法 | 描述 |
---|---|
StringBuffer() | 构造一个其中不带字符的字符串缓冲区,其初始容量为16个字符。 |
StringBuffer(CharSequence seq) | 构造一个字符串缓冲区,它包含与指定的CharSequence相同的字符 |
StringBuffer(int capacity) | 构造一个不带字符,但具有指定初始容量的字符串缓冲区。即对byte[ ]大小进行指定 |
StringBuffer(String str) | 构造一个字符串缓冲区,并将其内容初始化为指定的字符串内容。 |
package chapter11.stringbuffer_;
/**
* @aim java基础学习
* @note java笔记
*/
public class StringBuffer01 {
public static void main(String[] args) {
//1.构造一个其中不带字符的字符串缓冲区,其初始容量为16个字符。
StringBuffer stringBuffer = new StringBuffer();//16
System.out.println(stringBuffer.capacity());
//2.构造一个不带字符,但具有指定初始容量的字符串缓冲区。即对byte[ ]大小进行指定
StringBuffer stringBuffer1 = new StringBuffer(4);//4
System.out.println(stringBuffer1.capacity());
//3.构造一个字符串缓冲区,并将其内容初始化为指定的字符串内容。char[ ]大小 str.length()+16
StringBuffer hello = new StringBuffer("hello");//21
System.out.println(hello.capacity());
}
}
- String和StringBuffer相互转换
在开发中,经常需要将String和StringBuffer进行转换,看看如何实现。
package chapter11.stringbuffer_;
/**
* @aim java基础学习
* @note java笔记
*/
public class StringBuffer02 {
public static void main(String[] args) {
//String-->StringBuffer
String s = "hello";
//方式一 使用构造器,对s本身没有任何影响
StringBuffer b1=new StringBuffer(s);
//方式二 使用append()方法
StringBuffer b2=new StringBuffer();
b2.append(s);
//StringBuffer-->String
//方式一 使用StringBuffer提供的toString()方法
String s2=b1.toString();//b1 [StringBuffer]
//方式二 使用构造器
String s3=new String(b2);
}
}
11.3.3 StringBuffer方法
- StringBuffer类常用方法
StringBufferMethod.java
(1). 增 append()
(2). 删 delete(start,end)
(3). 改replace(start,end,string) //将start—end间的内容替换掉,不含end
(4). 查 indexOf() //查找子串在字符串第一次出现的索引,如果找不到返回-1
(5). 插 insert()
(6). 获取长度 length()
package chapter11.stringbuffer_;
/**
* @aim java基础学习
* @note java笔记
*/
public class StringBufferMethod {
public static void main(String[] args) {
StringBuffer strbu=new StringBuffer("hello");
//1. 增
strbu.append(',');
strbu.append("李四");
strbu.append("王五").append(100).append(true).append(19.19);
System.out.println(strbu);//hello,李四王五100true19.19
//2.删 (start,end)左闭右开
strbu.delete(6,10);
System.out.println(strbu);//hello,100true19.19
//3.改(start,end,"")左闭右开
strbu.replace(9,13,"false");
System.out.println(strbu);//hello,100false19.19
//4.查
int ans =strbu.indexOf("1");
System.out.println(ans);//6
//5.插
strbu.insert(6,"小青");//索引6插入,原来索引为6后移
System.out.println(strbu);//hello,小青100false19.19
//6.获取长度
int len=strbu.length();
System.out.println(len);//21
}
}
11.3.4 StringBuffer练习
- 看看下面代码输出什么?为什么?(不要猜,要看看源码)
package chapter11.stringbuffer_;
/**
* @aim java基础学习
* @note java笔记
*/
public class StringBufferExercise01 {
public static void main(String[] args) {
String str =null;
StringBuffer sb=new StringBuffer();
sb.append(str);//查看源码知:如果str=null,就生成一个null的字符串
System.out.println(sb.length());//4
System.out.println(sb);//null
// null.lenth()存在异常:NullPointerException
StringBuffer sb1=new StringBuffer(str);//查看源码知:super(str.length() + 16);
System.out.println(sb1);//
}
}
- 输入商品名称和商品价格,要求打印效果示例,使用StringBuffer的insert的方法来实现:
StringBufferExercise02.java
商品名 商品价格
手机 123,456.48
要求:使用千位分隔符(不考虑进行四舍五入)。
package chapter11.stringbuffer_;
import java.util.Scanner;
/**
* @aim java基础学习
* @note java笔记
*/
public class StringBufferExercise02 {
public static void main(String[] args) {
Scanner scanner=new Scanner(System.in);
System.out.print("请输入商品:");
StringBuffer goods=new StringBuffer(scanner.next());
System.out.print("请输入价格:");
StringBuffer price=new StringBuffer(scanner.next());
int i=price.indexOf(".");
int len=price.length();
if(i==-1){
i=len;
}
while(i>3){
i-=3;
price.insert(i,",");
}
System.out.println(goods);
System.out.println(price);
}
}
/*
请输入商品:123
请输入价格:123456.34
123
123,456.34
*/
11.4 StringBuilder
11.4.1 StringBuilder结构剖析
-
StringBuilder基本介绍
(1). 一个可变的字符序列。此类提供一个与StringBuffer兼容的API,但不保证同步。该类被设计用作StringBuffer的一个简易替换,用在字符串缓冲区被单个线程使用的时候。如果可能,建议优先采用该类,因为在大多数实现中,它比线程使用的时候。如果可能,建议优先采用该类,因为在大多数实现中,它比StringBuffer要快。
(2). 在StringBuilder上的主要操作是append和insert方法,可重载这些方法,以接收任意类型的数据。 -
StringBuilder常用方法
StringBuilder和StringBuffer均代表可变的字符序列,方法是一样的,所以使用和StringBuffer一样。 -
StringBuilder结构剖析
(1). StringBuilder 继承 AbstractStringBuilder类
(2). 实现了Serializable,说明StringBuilder对象是可以串行化(网络传输、保存到文件)
(3). StringBuilder 是final类,不能被继承
(4). StringBuilder 对象字符序列仍然是存放在其父类AbstractStringBuilder 的byte[] value;因此,字符序列是在堆中的。
(5). StringBuilder的方法,没有做互斥的处理,即没有synchronized关键字,因此在单线程的情况下优先使用StringBuilder。
11.4.2 StringBuilder应用
- String、StringBuffer和StringBuilder的比较(面试)
(1). StringBuilder和StringBuffer非常类似,均代表可变的字符序列,而且方法也一样。
(2). String:不可变字符序列,效率低,但是复用率高(即可以被多个变量指向)
(3). StringBuffer:可变字符序列、效率较高(增删)、线程安全
(4). StringBuilder:可变字符序列、效率最高、线程不安全
(5). String使用注意事项:
String s="a";
s+="b";//实际上原来的"a"字符串对象因为没有对象引用指向,所以就丢弃了(被JVM销毁了),现在又生成了一个字符串s+="b"(也就是"ab")。
//如果多次执行这些改变串内容的操作,会导致大量副本字符串对象留在内存中,降低效率。如果这样的操作放到循环中,
// 会极大影响程序的性能==>结论:如果我们对String做大量修改,不要使用String
- 测试String、StringBuffer和StringBuilder执行效率
package chapter11.StringBulider_;
/**
* @aim java基础学习
* @note java笔记
*/
public class StringBuilder01 {
public static void main(String[] args) {
final int ITERATIONS = 1000000;
// 测试 String
long startTime = System.currentTimeMillis();
String str = "";
for (int i = 0; i < ITERATIONS; i++) {
str += "a";
}
long endTime = System.currentTimeMillis();
System.out.println("String 执行时间: " + (endTime - startTime) + " ms");
// 测试 StringBuffer
startTime = System.currentTimeMillis();
StringBuffer stringBuffer = new StringBuffer();
for (int i = 0; i < ITERATIONS; i++) {
stringBuffer.append("a");
}
endTime = System.currentTimeMillis();
System.out.println("StringBuffer 执行时间: " + (endTime - startTime) + " ms");
// 测试 StringBuilder
startTime = System.currentTimeMillis();
StringBuilder stringBuilder = new StringBuilder();
for (int i = 0; i < ITERATIONS; i++) {
stringBuilder.append("a");
}
endTime = System.currentTimeMillis();
System.out.println("StringBuilder 执行时间: " + (endTime - startTime) + " ms");
}
}
/*
String 执行时间: 72706 ms
StringBuffer 执行时间: 12 ms
StringBuilder 执行时间: 9 ms
*/
- String、StringBuffer和StringBuilder的选择(使用的原则)
(1). 如果字符串存在大量的修改操作,一般使用StringBuffer或StringBuilder
(2). 如果字符串存在大量的修改操作,存在单线程的情况,使用StringBuilder
(3). 如果字符串存在大量的修改操作,存在多线程的情况,一般使用StringBuffer
(4). 如果字符串很少修改,被多个对象引用,使用String,比如配置信息等
11.5 Math
- 基本介绍
Math类包含用于执行基本数学运算的方法,如初等指数、对数、平方根和三角函数。 - 方法一览(均为静态方法)只例举了部分(具体查看API)
4. Math类常见方法应用案例MathMethod.java
(1). abs绝对值
(2). pow 求幂
(3). ceil 向上取整
(4). floor 向下取整
(5). round 四舍五入
(6). sqrt 求开方
(7). random 求随机函数
(8). max 求两个数的最大值
(9). min 求两个数的最小值
package chapter11.math_;
/**
* @aim java基础学习
* @note java笔记
*/
public class MathMethod {
public static void main(String[] args) {
//(1). abs绝对值
System.out.println(Math.abs(-99));//99
//(2). pow 求幂,返回double
System.out.println(Math.pow(2,3));//8.0,2的3次方
//(3). ceil 向上取整,返回double
System.out.println(Math.ceil(-2.000001));//-2.0
//(4). floor 向下取整,返回double
System.out.println(Math.floor(-1.0000001));//-2.0
//(5). round 四舍五入,返回long
System.out.println(Math.round(4.56768));//5
//(6). sqrt 求开方,返回double
System.out.println(Math.sqrt(4));//2.0
//(7). random 求随机函数,一个伪随机 double大于或等于 0.0并小于 1.0,返回double
System.out.println(Math.random());
//(8). max 求两个数的最大值
System.out.println(Math.max(10,9));//10
//(9). min 求两个数的最小值
System.out.println(Math.min(10,9));//9
}
}
- 练习
(1). 请使用Math.random获取a-b之间的一个随机整数,a和b均为整数,比如:a=2,b=7
package chapter11.math_;
/**
* @aim java基础学习
* @note java笔记
*/
public class MathExercise {
public static void main(String[] args) {
int a=2;
int b=7;
for (int i = 0; i < 15; i++) {
int ans=(int) (a+Math.random()*(b-a+1));
System.out.println(ans);
}
}
}
//输出随机的2至7
11.6 Date、Calendar、LocalDate…
日期类分为了三代。【知道怎么查,怎么用即可,不用每个方法都背】
11.6.1 第一代日期类
- 日期和时间模式
- Date:精确到毫秒,代表特定的时间
- SimpleDateFormat:格式和解析日期的具体类。它允许进行格式化(日期->文本)、解析(文本->日期)和规范化
package chapter11.date_;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
/**
* @aim java基础学习
* @note java笔记
*/
public class Date01 {
public static void main(String[] args) {
// 1.获取当前系统时间
// 2.这里的Date类是在java.util中的,而不是在java.sql中
// 3.默认输出的日期格式是外国的方式,通常需要进行格式化处理
Date d1 = new Date();
System.out.println(d1);//Sun Aug 11 23:21:36 CST 2024
//获取某个时间对应的毫秒数
System.out.println(d1.getTime());//1723389696776
//通过指定毫秒数得到时间
Date d2 = new Date(9234567);
System.out.println(d2);//Thu Jan 01 10:33:54 CST 1970
//这里的字母是规定好的,不可以乱写
SimpleDateFormat sdf=new SimpleDateFormat("yyyy年MM月dd日 hh:mm:ss E");
//将日期转换成指定格式的字符串
String format =sdf.format(d1);
System.out.println(format);//2024年08月11日 11:32:16 周日
//1.将文本转换成日期格式
//2.把Date输出时,仍然还是外国的方式,如需指定格式还是要转换
//3.在把String-->Date , 使用的sdf格式需要和String的格式一样,否则就会抛出ParseException异常
String s="1996年02月23日 10:20:30 星期一";
try {
Date parse=sdf.parse(s);
System.out.println(parse);//Fri Feb 23 10:20:30 CST 1996
} catch (ParseException e) {
System.out.println("日期格式不对");
}
}
}
11.6.2 第二代日期类
- 第二代日期类,主要就是Calendar类(日历)
public abstract class Calendar implements Serializable, Cloneable, Comparable<Calendar>
- Calendar类是一个抽象类,它为特定瞬间与一组诸如YEAR、MONTH、DAY_OF_MONTH、HUOR等日历字段之间的转换提供了一些方法,并为操作日历字段(例如获得下星期的日期)提供了一些方法
package chapter11.date_;
import java.util.Calendar;
/**
* @aim java基础学习
* @note java笔记
*/
public class Calendar01 {
public static void main(String[] args) {
//1.Calendar是一个抽象类,并且构造器是protected
//2.可以通过getInstance() 来获取实例
//3.提供大量的方法和字段提供给程序员
//4.Calendar没有专门的格式化方法,所以需要程序员自己来组合显示
//5.如果需要按照 24小时进制来获取时间,Calendar.HOUR 改为 Calendar.HOUR_OF_DAY
Calendar c = Calendar.getInstance();//创建日历类对象
//获取日历对象的某个日历字段
System.out.println("年:" + c.get(Calendar.YEAR));
//这里为什么要+1,因为Calendar返回月的时候,是按照0开始编号的
System.out.println("月:" + (c.get(Calendar.MONTH) + 1));
System.out.println("日:" + c.get(Calendar.DAY_OF_MONTH));
System.out.println("小时:" + c.get(Calendar.HOUR));
System.out.println("小时:" + c.get(Calendar.HOUR_OF_DAY));
System.out.println("分钟:" + c.get(Calendar.MINUTE));
System.out.println("秒:" + c.get(Calendar.SECOND));
//Calendar没有专门的格式化方法,所以需要程序员自己来组合显示
System.out.println(c.get(Calendar.YEAR) + "年" + (c.get(Calendar.MONTH) + 1) + "月"
+ c.get(Calendar.DAY_OF_MONTH) + "日");
}
}
/*
年:2024
月:8
日:12
小时:3
小时:15
分钟:48
秒:5
2024年8月12日
*/
11.6.3 第三代日期类
-
前面两代日期类的不足分析(具体使用请查看API文档)
(1). JDK1.0中包含了一个java.util.Date类,但是它的大多数方法已经在JDK1.1引入了Calendar类之后被弃用了。
(2). 而Calendar也存在问题是:
① 可变性:像日期和时间这样的类应该是不可变的。
② 偏移性:Date中的年份是从1900开始的,而月份都从0开始
③ 格式化:格式化只对Date有用,Calendar则不行
④ 此外,它们也不是线程安全的;不能处理闰秒等(每隔两天,多出1s) -
第三代日期类常见方法JDK8加入
LocalDate(日期/年月日)、LocalTime(时间/时分秒)、LocalDateTime(日期时间/年月日时分秒)
(1). LocalDate只包含日期,可以获取日期字段
(2). LocalTime只包含时间,可以获取时间字段
(3). LocalDateTime包含日期+时间,可以获取日期和时间字段
package chapter11.date_;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
/**
* @aim java基础学习
* @note java笔记
*/
public class LocalDate_ {
public static void main(String[] args) {
//第三代日期
LocalDateTime ldt =LocalDateTime.now();//返回当前日期时间(年月日时分秒)的对象
System.out.println(ldt);//2024-08-12T16:09:01.867845500
System.out.println(ldt.getYear());//2024
System.out.println(ldt.getMonth());//AUGUST
System.out.println(ldt.getMonthValue());//8
System.out.println(ldt.getDayOfMonth());//12
System.out.println(ldt.getHour());//16
System.out.println(ldt.getMinute());//9
System.out.println(ldt.getSecond());//1
LocalDate.now();//返回当前年月日
LocalTime.now();//返回当前时分秒
}
}
(4). DateTimeFormatter格式日期类。类似于:SimpleDateFormat
DateTimeFormat dtf=DatetimeFormatter.ofPattern(格式);
String str=dtf.format(日期格式);
package chapter11.date_;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
/**
* @aim java基础学习
* @note java笔记
*/
public class LocalDateFormat_ {
public static void main(String[] args) {
//创建当前日期时间(年月日时分秒)的对象
LocalDateTime ldt = LocalDateTime.now();
//创建DateTimeFormatter对象
DateTimeFormatter dtf = DateTimeFormatter.ofPattern("yyyy年mm月dd日 HH时mm分ss秒");
String format = dtf.format(ldt);
System.out.println(format);//2024年10月12日 19时10分53秒
}
}
(5). Instant时间戳
类似于Date
提供了一系列和Date类转换的方式如下代码:
package chapter11.date_;
import java.time.Instant;
import java.util.Date;
/**
* @aim java基础学习
* @note java笔记
*/
public class Instant_ {
public static void main(String[] args) {
//1.通过 静态方法 now() 获取表示当前时间戳的对象
Instant now=Instant.now();
System.out.println(now);//2024-08-12T11:16:18.989720Z
//2.将Instant----> Date:通过from
Date date=Date.from(now);
System.out.println(date);//Mon Aug 12 19:16:36 CST 2024
//将Date---->Instant:通过Date的toInstant()
Instant instant=date.toInstant();
System.out.println(instant);//2024-08-12T11:16:52.273Z
}
}
(6). 第三代日期类更多方法
- LocalDateTime类
- MonthDay类:检查重复事件
- 是否是闰年
- 增加日期的某个部分
- 使用plus方法测试增加时间的某个部分
- 使用minus方法测试查看一年前和一年后的日期
package chapter11.date_;
import java.time.LocalDateTime;
import java.time.MonthDay;
import java.time.Year;
import java.time.temporal.ChronoUnit;
/**
* @aim java基础学习
* @note java笔记
*/
public class DateTimeMethod_ {
public static void main(String[] args) {
// 当前日期和时间
LocalDateTime now = LocalDateTime.now();
System.out.println("当前日期和时间: " + now);
// MonthDay类检查重复事件
MonthDay event = MonthDay.now();
System.out.println("今天的日期(月-日格式): " + event);
// 是否是闰年
int currentYear = now.getYear();
boolean isLeapYear = Year.isLeap(currentYear);
System.out.println(currentYear + " 是闰年吗? " + isLeapYear);
// 增加日期的某个部分
LocalDateTime futureDate = now.plusDays(10).plusMonths(1);
System.out.println("增加10天和1个月后的日期: " + futureDate);
// 使用plus方法测试增加时间的某个部分
LocalDateTime dateInTwoWeeks = now.plusWeeks(2);
System.out.println("从现在起2周后的日期: " + dateInTwoWeeks);
// 使用minus方法测试查看一年前和一年后的日期
LocalDateTime dateOneYearAgo = now.minusYears(1);
LocalDateTime dateOneYearLater = now.plusYears(1);
System.out.println("一年前的日期: " + dateOneYearAgo);
System.out.println("一年后的日期: " + dateOneYearLater);
// 使用ChronoUnit测试时间差
long daysBetween = ChronoUnit.DAYS.between(now, dateOneYearLater);
System.out.println("从现在到一年后共有 " + daysBetween + " 天");
}
}
/*
当前日期和时间: 2024-08-12T19:32:29.285117800
今天的日期(月-日格式): --08-12
2024 是闰年吗? true
增加10天和1个月后的日期: 2024-09-22T19:32:29.285117800
从现在起2周后的日期: 2024-08-26T19:32:29.285117800
一年前的日期: 2023-08-12T19:32:29.285117800
一年后的日期: 2025-08-12T19:32:29.285117800
从现在到一年后共有 365 天
*/
11.7 System
11.7.1 System类常用的方法和案例
- exit退出当前程序
- arraycopy:复制数组元素,比较适合底层调用,一般使用Arrays.copyOf完成复制数组
- currentTimeMillens:返回当前时间距离1970-1-1的毫秒数
- gc:运行垃圾回收机制System.gc();
package chapter11.system_;
import java.util.Arrays;
/**
* @aim java基础学习
* @note java笔记
*/
public class System01 {
public static void main(String[] args) {
//1. exit退出当前程序
System.out.println("hello");
// System.exit(0);//0表示一个状态,正常的状态。
System.out.println("hello");
//2. arraycopy:复制数组元素,比较适合底层调用,一般使用Arrays.copyOf完成复制数组
/*
形参分析:
src - 源数组。
srcPos - 源数组中的起始位置。
dest - 目标数组。
destPos - 目标数据的起始位置。
length - 要复制的数组元素个数。
*/
int[] src={1,2,3};
int[] dest= new int[3];//当前数组dest={0,0,0}
System.arraycopy(src,1,dest,1,2);
System.out.println(Arrays.toString(dest));//[0, 2, 3]
//3. currentTimeMillens:返回当前时间距离1970-1-1的毫秒数
long start=System.currentTimeMillis();
System.out.println(start);//1723378894796
//4. gc:运行垃圾回收机制System.gc();
System.gc();
}
}
11.8 Arrays
11.8.1 Arrays类常见方法应用案例
- Arrays里面包含了一系列静态方法,用于管理或操作数据(比如排序和搜索)
(1). toString返回数组的字符串形式
(2). sort排序(自然排序和定制排序)。
(3). binarySearch 通过二分查找法进行查找,要求必须排好序。若无则return -(low + 1).
(4). copyOf数组元素的复制
(5). fill 数组元素的填充
(6). equals比较两个数组元素内容是否完全一致。
(7). asList 将一组值,转换成List集合
package chapter11.arrays_;
import java.util.Arrays;
import java.util.Comparator;
import java.util.List;
/**
* @aim java基础学习
* @note java笔记
*/
public class ArraysMethod {
public static void main(String[] args) {
//1.toString返回数组的字符串形式
Integer arr1[] = {1, 2, 3, 4, 5, 6};
System.out.println(Arrays.toString(arr1));//[1, 2, 3, 4, 5, 6]
//2.sort排序(自然排序和定制排序)。
Integer arr2[] = {1, -1, 7, 0, 89};
//(1).默认排序,从小到大
Arrays.sort(arr2);
System.out.println(Arrays.toString(arr2));//[-1, 0, 1, 7, 89]
//(2).定制排序,从大到小,传入两个参数,第一个是arr数组,第二个是实现了Comparator的匿名内部类,实现了compare方法。
/*
①.体现的是接口编程的方式,源码分析:
②.Arrays.sort(arr3, new Comparator(),先进入Arrays的sort中
最终到TimSort类的private static <T> void binarySort(T[] a, int lo, int hi, int start,
Comparator<? super T> c)
③.执行到binarySort方法的代码,会根据动态绑定机制c.compare()执行传入的匿名内部类的方法compare()
while (left < right) {
int mid = (left + right) >>> 1;
if (c.compare(pivot, a[mid]) < 0)
right = mid;
else
left = mid + 1;
}
④.public int compare(Object o1, Object o2) 返回的是>0,还是<0;会影响整个排序结果
这就充分体现了 接口编程+动态绑定+匿名内部类的综合使用;将来的底层框架和源码使用方式,会非常常见。
*/
Integer arr3[] = {1, -1, 7, 0, 89};
Arrays.sort(arr3, new Comparator() {
@Override
public int compare(Object o1, Object o2) {
Integer i1=(Integer) o1;
Integer i2=(Integer) o2;
return i2-i1;
}
});
System.out.println(Arrays.toString(arr3));//[89, 7, 1, 0, -1]
//(3). binarySearch 通过二分查找法进行查找,要求必须排好序。
Integer[] arr4={1,4,5,9,12,34,45};
int index=Arrays.binarySearch(arr4,5);
System.out.println(index);//2
int notindex=Arrays.binarySearch(arr4,35); // return -(low + 1); // key not found.
System.out.println(notindex);//-7,按道理35应该在34后面,即35的索引应该是6,即low=6
//(4). copyOf数组元素的复制
//拷贝的长度要>0,否则就会抛出异常NegativeArraySizeException,
// 若大于拷贝数组arr的长度,就在新数组后面添加 null,若长度在0<=arr<arr.length(),则复制部分元素
//该方法的底层使用的是 System.arraycopy()
Integer[] arr5={1,2,3,4};
Integer[] newArr = Arrays.copyOf(arr5,arr5.length+2);
System.out.println(Arrays.toString(newArr));//[1, 2, 3, 4, null, null]
//(5). fill 数组元素的填充
Integer[] num = new Integer[]{9, 4, 3};
Arrays.fill(num, 99);
System.out.println(Arrays.toString(num));//[99, 99, 99]
//(6). equals比较两个数组元素内容是否完全一致。
Integer[] a1={1,2,3,4};
Integer[] a2={1,2,3,4};
boolean equals =Arrays.equals(a1,a2);
System.out.println(equals);//true
//(7). asList 将一组值,转换成list集合
// 编译类型是List(接口)
// 运行类型是java.util.Arrays$ArrayList,ArrayList是内部类
// 静态内部类 private static class ArrayList<E> extends AbstractList<E>
// implements RandomAccess, java.io.Serializable
List asList = Arrays.asList(1, 2, 3, 4, 5, 6);
System.out.println("asList=" + asList);//asList=[1, 2, 3, 4, 5, 6]
System.out.println(asList.getClass());//class java.util.Arrays$ArrayList
}
}
11.8.2 Arrays类练习
- 实现冒泡排序
(1). 编写一个方法 Bubble 对整数数组进行冒泡排序,默认从小到大排序。
(2). 编写一个重载的方法 Bubble,接受一个 Comparator 对象,按照自定义的排序规则对整数数组进行冒泡排序。
要求:
(1). Bubble(Integer[] arr): 对给定的整数数组进行排序,按照从小到大的顺序。
(2). Bubble(Integer[] arr, Comparator c): 对给定的整数数组进行排序,按照 Comparator 提供的排序规则(可以是从大到小或其他自定义顺序)。
package chapter11.arrays_;
import java.util.Arrays;
import java.util.Comparator;
/**
* @aim java基础学习
* @note java笔记
*/
public class ArraysBubble {
public static void main(String[] args) {
Integer arr[] = {3, -2, 12, 0, 4, 90};
// 使用默认的冒泡排序(从小到大)
Bubble(arr);
System.out.println(Arrays.toString(arr)); // 输出: [-2, 0, 3, 4, 12, 90]
Integer arr1[] = {3, -2, 12, 0, 4, 90};
// 使用带有Comparator的冒泡排序(从大到小)
Bubble(arr1, new Comparator<Integer>() {
@Override
public int compare(Integer i1, Integer i2) {
// 比较两个整数,返回负数表示 i1 应该排在 i2 前面
return i2 - i1;
}
});
System.out.println(Arrays.toString(arr1)); // 输出: [90, 12, 4, 3, 0, -2]
}
/**
* 冒泡排序算法,默认从小到大排序
* @param arr 需要排序的整数数组
*/
public static void Bubble(Integer[] arr) {
for (int i = 0; i < arr.length - 1; i++) {
for (int j = 0; j < arr.length - i - 1; j++) {
// 如果当前元素大于下一个元素,则交换它们
if (arr[j] > arr[j + 1]) {
// 交换 arr[j] 和 arr[j + 1]
int temp = arr[j];
arr[j] = arr[j + 1];
arr[j + 1] = temp;
}
}
}
}
/**
* 带 Comparator 的冒泡排序算法,可以实现自定义排序规则
* @param arr 需要排序的整数数组
* @param c 自定义的 Comparator,用于决定排序规则
*/
public static void Bubble(Integer[] arr, Comparator<Integer> c) {
for (int i = 0; i < arr.length - 1; i++) {
for (int j = 0; j < arr.length - i - 1; j++) {
// 使用 Comparator 比较当前元素和下一个元素
if (c.compare(arr[j], arr[j + 1]) > 0) {
// 交换 arr[j] 和 arr[j + 1]
int temp = arr[j];
arr[j] = arr[j + 1];
arr[j + 1] = temp;
}
}
}
}
}
- 案例:自定义Book类,里面包含name和price。有一个Book[] books= 5本书对象。使用Arrays.sort()方法 实现Comparator接口匿名内部类,也称为定制排序()。要求使用可以按照name长度排序、按照price排序(均可从大到小或从小到大)。
package chapter11.arrays_;
import java.util.Arrays;
import java.util.Comparator;
/**
* @aim java基础学习
* @note java笔记
*/
public class Book {
private String name;
private double price;
public Book(String name, double price) {
this.name = name;
this.price = price;
}
public double getPrice() {
return price;
}
public String getName() {
return name;
}
@Override
public String toString() {
return "name='" + name + '\t' + ", price=" + price;
}
}
class Test{
public static void main(String[] args) {
Book[] books=new Book[4];
books[0]=new Book("西游记",200);
books[1]=new Book("红楼梦",400);
books[2]=new Book("水浒传",150);
books[3]=new Book("三国演义",300);
//这里没学过泛型就把<Book>去了。
Arrays.sort(books, new Comparator() {
@Override
public int compare(Object o1, Object o2) {
Book book1=(Book) o1;
Book book2=(Book) o2;
double price=book1.getPrice()-book2.getPrice();
if(price>0){
return -1;
}else if(price<0){
return 1;
}else {
return 0;
}
}
});
for(Book book:books){
System.out.println(book.toString());
}
//其他方式同理,这里就不写了,提示如果是书名,就length即可
}
}
/*
name='红楼梦 , price=400.0
name='三国演义 , price=300.0
name='西游记 , price=200.0
name='水浒传 , price=150.0
*/
11.9 BigInteger、BigDecimal
11.9.1 BigInteger和BigDecimal介绍
-
应用场景:
(1). BigInteger适合保存比较大的整型
(2). BigDecimal适合保存精度更高的浮点型(小数) -
BigInteger和BigDecimal常见的方法
(1). add 加
(2). subtract
(3). multiple
(4). divide
package chapter11.biginteger_;
import java.math.BigInteger;
/**
* @aim java基础学习
* @note java笔记
*/
public class BigInteger_ {
public static void main(String[] args) {
BigInteger b1=new BigInteger("91234560000");
BigInteger b2=new BigInteger("20000");
// System.out.println(b1+b2);//错误,不允许使用+
System.out.println(b1.add(b2));
System.out.println(b1.subtract(b2));
System.out.println(b1.multiply(b2));
System.out.println(b1.divide(b2));
}
}
/*
91234580000
91234540000
1824691200000000
4561728
*/
package chapter11.bigdecimal;
import java.math.BigDecimal;
/**
* @aim java基础学习
* @note java笔记
*/
public class BigDecimal_ {
public static void main(String[] args) {
BigDecimal b1=new BigDecimal("1234567890.123");
BigDecimal b2=new BigDecimal("10.123");
// System.out.println(b1+b2);错误,不允许使用+
System.out.println(b1.add(b2));
System.out.println(b1.subtract(b2));
System.out.println(b1.multiply(b2));
// System.out.println(b1.divide(b2));//存在异常ArithmeticException,原因:就是除不进,无限小数。
// 解决方法如下:保存的是分子的精度
System.out.println(b1.divide(b2,BigDecimal.ROUND_CEILING));
}
}
/*
1234567900.246
1234567880.000
12497530751.715129
121956721.340
*/
11.10 本章作业
- 编程题 Task01.java
(1). 将字符串中指定部分进行反转。比如将 “abcedf” “aedcbf”
(2). 编写方法public static String reverse(String str,int start,int end) 搞定
package chapter11.task;
/**
* @aim java基础学习
* @note java笔记
*/
public class Task01 {
public static void main(String[] args) {
String str = "abcdef";
String reverse_str = null;
try {
reverse_str = reverse(str, 1, 4);
} catch (Exception e) {
System.out.println(e.getMessage());
}
System.out.println(reverse_str);//aedcbf
}
public static String reverse(String str, int start, int end) {
//对传入的参数做一个验证,一般:写出正确的情况,然后取反即可
if (str == null || start < 0 || end >= str.length() || start > end) {
throw new IllegalArgumentException("传入参数不正确");
}
char[] chars=str.toCharArray();
for (int i=start,j=end; i < j; i++,j--) {
char temp=chars[i];
chars[i]=chars[j];
chars[j]=temp;
}
return new String(chars);
}
}
- 编程题 Task02.java
输入用户名、密码、邮箱,如果信息录入正确,则提示注册成功,否则生成异常对象,要求:
(1). 用户名长度为2-4
(2). 密码的长度为6,要求全是数字 isDigital
(3). 邮箱中包含@和.并且@在.的前面
package chapter11.task;
import java.util.Scanner;
/**
* @aim java基础学习
* @note java笔记
*/
public class Task02 {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
System.out.print("请输入用户名(2-4个字符):");
String username = scanner.next();
System.out.print("请输入密码(6位数字):");
String password = scanner.next();
System.out.print("请输入邮箱:");
String mailbox = scanner.next();
try {
// 调用userRegister方法进行用户注册验证
userRegister(username, password, mailbox);
System.out.println("恭喜你注册成功~");
} catch (Exception e) {
// 捕获并打印注册失败的异常信息
System.out.println("注册失败:" + e.getMessage());
} finally {
// 关闭Scanner对象以释放资源
scanner.close();
}
}
/**
* 验证用户输入的用户名、密码和邮箱是否符合要求
*
* @param username 用户名
* @param password 密码
* @param mailbox 邮箱
* @throws IllegalArgumentException 如果输入的参数不合法,则抛出该异常
*/
public static void userRegister(String username, String password, String mailbox) {
// 检查输入参数是否为null
if (username == null || password == null || mailbox == null) {
throw new IllegalArgumentException("输入的参数不能为空");
}
// 验证用户名长度是否在2到4个字符之间
int userLength = username.length();
if (!(userLength >= 2 && userLength <= 4)) {
throw new RuntimeException("用户名长度为2-4");
}
// 验证密码长度是否为6且全为数字
if (!(password.length() == 6 && isDigital(password))) {
throw new RuntimeException("密码长度为6,且全是数字");
}
// 验证邮箱中@和.的位置关系
int front = mailbox.indexOf("@");
int rear = mailbox.indexOf(".");
if (!(front > 0 && rear > front)) {
throw new RuntimeException("邮箱中包含@和.并且@在.的前面");
}
}
/**
* 判断密码是否全由数字组成
*
* @param password 密码
* @return 如果密码全是数字,则返回true;否则返回false
*/
public static boolean isDigital(String password) {
char[] chars = password.toCharArray();
for (int i = 0; i < chars.length; i++) {
// 检查每个字符是否在'0'到'9'范围内
if (chars[i] < '0' || chars[i] > '9') {
return false;
}
}
return true;
}
}
- 编程题
(1). 编写java程序,输入形式为:Han Shun Ping的人名,以Ping,Han .S的形式打印出来。其中.S是中间单词的首字母。
(2). 例如输入:Willian Jefferson Clinton,输出形式为:Clinton,Willian .J
package chapter11.task;
import java.net.SocketTimeoutException;
import java.util.Scanner;
/**
* @aim java基础学习
* @note java笔记
*/
public class Task03 {
public static void main(String[] args) {
String n1 = "Han Shun Ping";
String n2 = "Willian Jefferson Clinton";
printName(n1);// Han,Ping .S
}
public static void printName(String str) {
if (str == null) {
System.out.println("不能为空");
return;
}
String[] strings = str.split(" ");
if (strings.length != 3) {
System.out.println("字符格式不对");
return;
}
String name = "%s,%s .%c";
String info = String.format(name, strings[0], strings[2], strings[1].toUpperCase().charAt(0));
System.out.println(info);
}
}
- 编程题
输入字符串,判断里面有多少个大写字母,多少个小写字母,多少个数字
package chapter11.task;
import java.util.Scanner;
/**
* @aim java基础学习
* @note java笔记
*/
public class Task04 {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
String str = scanner.next();
count(str);
}
public static void count(String str) {
if (str == null) {
System.out.println("字符串不能为空");
return;
}
int upperCount = 0;
int lowerCount = 0;
int numberCount = 0;
int otherCount = 0;
for (int i = 0; i < str.length(); i++) {
if (str.charAt(i) >= 'A' && str.charAt(i) <= 'Z') {
upperCount++;
} else if (str.charAt(i) >= 'a' && str.charAt(i) <= 'z') {
lowerCount++;
} else if (str.charAt(i) >= '0' && str.charAt(i) <= '9') {
numberCount++;
} else {
otherCount++;
}
}
System.out.println("大写字母=" + upperCount + "小写字母=" + lowerCount + "数字=" + numberCount + "其他=" + otherCount);
}
}
/*
输入:123你好helloHI
大写字母=2小写字母=5数字=3其他=2
*/
- 试写出以下代码的运行结果
已知Animal类有属性name,可以通过有参构造为属性赋值。
package chapter11.task;
/**
* @aim java基础学习
* @note java笔记
*/
public class Task05 {
public static void main(String[] args) {
String s1 = "hello";
Animal a = new Animal(s1);
Animal b = new Animal(s1);
System.out.println(a == b);//false,对比的是不是同一对象
System.out.println(a.equals(b));//false,对比的是不是同一对象
System.out.println(a.name == b.name);//true,对比的是地址
String s2 = new String("hello");
String s3 = "hello";
System.out.println(s1 == s2);//false
System.out.println(s2 == s3);//false
String t1 = "hello" + s1;//实际是一个String对象在堆中
String t2 = "hellohello";
System.out.println(t1.intern() == t2);//true
}
}
class Animal {
String name;
public Animal(String name) {
this.name = name;
}
}