一、包装类
1.1 包装类的分类
基本数据类型 | 包装类 |
---|---|
boolean | Boolean |
char | Character |
byte | Byte |
short | Short |
long | Long |
int | Integer |
float | Float |
double | Double |
- 针对八种基本定义相应的引用类型——包装类
- 有了类的特点,就可以调用类中的方法
>> 继承体系图:
1.2 包装类和基本数据的转换
jdk5 前的手动装箱和拆箱方式,装箱:基本类型 -> 包装类型 ,反之,拆箱
//jdk5 之前:手动装箱和拆箱
//手动装箱 int -> Integer
int n1 = 100;
Integer integer = new Integer(n1);
Integer integer1 = Integer.valueOf(n1);
//手动拆箱 Integer -> int
int i = integer.intValue();
jdk 以后(含 jdk5)的自动装箱和拆箱方式
//jdk5 之后:自动装箱和拆箱
//自动装箱 int -> Integer
int n2 = 200;
Integer integer2 = n2; //底层使用的仍然是 Integer.valueOf()
//自动拆箱 Integer -> int
int n3 = integer2;
自动装箱底层调用的是 valueOf 方法,比如:Integer.valueOf()
- 其他包装类的用法类似
⏱ 小练习
下面代码是否正确?
Double d = 100d; //ok.自动装箱 Double.valueOf(100d);
Float f = 1.5f; //ok.自动装箱 Float.valueOf(1.5f);下面两段代码输出结果相同吗?各自输出什么?
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 分别运算
1.3 包装类型 和 String类型 的相互转换
public class WrapperVsString {
public static void main(String[] args) {
//包装类(Integer) -> String
Integer i1 =100; //自动装箱
String str1 = i1 + ""; //方式1
String str2 = i1.toString(); //方式2
String str3 = String.valueOf(i1); //方式3
//String -> 包装类(Integer)
Integer i2 = Integer.parseInt(str1); //返回的是int类型,自动装箱到Integer
Integer i3 = new Integer(str1); //方式2
}
}
1.4 Integer类 和 Character类 的常用方法
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')); //转成小写
Integer类面试题1
看看下面代码,输出结果是什么?并分析原因
public void method() {
Integer i = new Integer(1);
Integer j = new Integer(1);
System.out.println(i == j); //False
Integer m = 1; //底层 Integer.valueOf(1) -> 阅读源码
Integer n = 1;
System.out.println(m == n); //True 分析底层源码
Integer x = 128;
Integer y = 128;
System.out.println(x == y); //False
}
Integer类面试题2
看看下面代码输出什么?
public static void main(String[] args) {
//示例一
Integer i1 = new Integer(127);
Integer i2 = new Integer(127);
System.out.println(i1 == i2);
//示例二
Integer i3 = new Integer(128);
Integer i4 = new Integer(128);
System.out.println(i3 == i4);
//示例三
Integer i5 = 127;
Integer i6 = 127;
System.out.println(i5 == i6);
//示例四
Integer i7 = 128;
Integer i8 = 128;
System.out.println(i7 == i8);
//示例五
Integer i9 = 127;
Integer i10 = new Integer(127);
System.out.println(i9 == i10);
//示例六
Integer i11 = 127;
int i12 = 127;
System.out.println(i11 == i12);
//示例七
Integer i13 = 128;
Integer i14 = 128;
System.out.println(i13 == i14);
}
小结:
- 形如:Integer m = 1; 虽然会自动装箱,底层还是调用了 valueOf()方法,但是根据装入的值不不同,如果装入的值在 -128 ~ 127 范围内,则不会创建对象,直接返回数值,否则创建一个新的对象返回。
- ==比较运算时,只要有一方为 int 类型,则比较的是数值是否相等,而不是地址是否相同
二、String 类
2.1 String类的理解和创建对象
- String 对象用于保存字符串,也就是一组字符序列
- 字符串常量对象是用双引号括起来的字符序列。例如:”你好”、”12.98”、”boy”等
- 字符串的字符使用Unicode字符编码,一个字符(不区分字母还是汉字)占两个字节
- String类较常用构造器(其他看手册):
- String s1 = new String();
- String s2 = new String(String original);
- String s3 = new String(char[] a);
- String s4 = new String(char[] a,int startIndex,int count);
- String s5 = new String(byte[] b);
- String类 实现了接口 Serializable【String可以串行化:可以在网络传输】
- String类 实现了接口 Comparable【String对象可以互相比较】
- String 是 final 类,不能被其他类继承
- String 有属性 private final char value[]; 用于存放字符串内容
- 一定要注意:value 是一个 final类型,不可以修改【指向的地址】
final char[] value = {'a','b','c'};
value[1] = 'D'; //可以改变数组内的值
char[] v2 = {'t','o','m'};
value = v2; //错误,final类型不能改变地址指向
2.2 创建 String对象的两种方式
- 方式一:直接赋值 String s = “java”;
- 方式二:调用构造器 String s = new String(“java”);
区别:
- 方式一:先从常量池查看是否有”java”数据空间,如果有,直接访问;如果没有则创建,然后指向。s 最后指向的是常量池的空间地址。
- 方式二:先在堆中创建空间,里面维护了 value 属性,指向常量池的 “java” 空间。如果常量池没有 “java”,重新创建,如果有,直接通过 value 指向。最终指向的是堆中的空间地址。
- 两种方式的内存分布图
小练习
- 判断下面代码输出结果:
String a = “abc”;
String b = “abc”;
System.out.println(a.equals(b));
System.out.println(a == b);
String c= new String(“abc”);
String d = new String(“abc”);
System.out.println(c.equals(d));
System.out.println(c == b);
- 判断下面代码的输出结果:
String a = “java”;
String b = new String(“java”);
System.out.println(a.equals(b));
System.out.println(a == b);
System.out.println(a == b.intern());
System.out.println(b == b.intern());
知识点:intern() 方法的作用是返回String对象所指向常量池空间元素的地址
- 测试题
String s1 = “hspedu”;
String s2 = “java”;
String s3 = “java”;
String s4 = new String(“java”);
System.out.println(s2 == s3);
System.out.println(s2 == s4);
System.out.println(s2.equals(s4));
System.out.println(s1 == s2);
- 测试题
Person p1 = new Person();
p1.name = “hspedu”;
Person p2 = new Person();
p2.name = “hspedu”;
System.out.println(p1.name.equals(p2.name)); //t
System.out.println(p1.name == p2.name); //t
System.out.println(p1.name == “hspedu”); //True “hspedu”在参与==运算时返回的就是在常量池中的地址
String s1 = new String(“bcde”);
String s2 = new String(“bcde”);
System.out.println(s1 == s2); //f
// 验证"java"在参与 ==运算 时返回的就是在常量池中的地址
String a = "java";
System.out.println(a.hashCode());
System.out.println("java".hashCode());
2.3 字符串的特性
- String 是一个 final类,代表不可变的字符序列
- 字符串是不可变的。一个字符串对象一旦被分配,其内容是不可变的。
例题:以下语句创建了几个对象?(2个)
String s1 = “hello”;
s1 = “haha”;
面试题1
String a = “hello” + “abc”;
创建了几个对象?(1个)
解析:编译器在底层会自动将+号两边的字符串拼接成一个字符串的优化,会判断创建的常量池对象,是否有引用指向。
面试题2
String a = “hello”;
String b = “abc”;
String c = a + b;
创建了几个对象?(3个)
解读:底层实现过程
- 先创建一个 StringBuilder sb = StringBuilder()
- 执行 sb.append(“hello”)
- 执行 sb.append(“abc”)
- 执行 String c = sb.toString()
- 最后 c 指向的是堆中的对象 (String) value[] —再指向—> 池中的 “helloabc”
重要规则:常量相加,看的是池;变量相加,看的是堆
测试题3
下面代码输出什么?并说出原因
String s1 = “hspedu”;
String s2 = “java”;
String s5 = “hspedujava”;
String s6 = (s1 + s2).intern();
System.out.println(s5 == s6); //T
System.out.println(s5.equals(s6)); //T
测试题4
下面程序运行的结果是什么?可以在纸上画出内存布局图加以分析。
public class StringExercise04 {
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);
}
}
class Test1 {
String str = new String(“hsp”);
final char[] ch = {‘j’,’a’,’v’,’a’};
public void change(String str, char ch[]) {
str = “java”;
ch[0] = ‘h’;
}
}
2.4 String类的常见方法
String类是保存字符串常量的。每次更新都需要重新开辟空间,效率较低,因此Java设计者还提供了StringBuilder 和 StringBuffer 来增强 String 的功能,并提高效率。
看如下代码,分析执行过程
String s = new String(“”);
for(int i = 0; i < 80000; i++) {
s += “hello”;
}
常用方法一览:
method | 作用 |
---|---|
equals | 区分大小写,判断内容是否相等 |
equalsIgnoreCase | 忽略大小写,判断内容是否相等 |
length | 获取字符个数,字符串的长度 |
indexOf | 获取字符在字符串中第1次出现的索引,索引从0开始,如果找不到,返回-1 |
lastIndexOf | 获取字符在字符串中最后1次出现的索引,索引从0开始,如果找不到,返回-1 |
substring | 截取指定范围的子串 |
trim | 去前后空格 |
charAt | 获取某索引处的字符,注意不能使用 Str[index]这种方式 |
toUpperCase | 将字符串转成大写 |
toLowerCase | 将字符串转成小写 |
concat | 连接两个字符串 |
compareTo | 比较两个字符串 |
toCharArray | 转换成字符数组 |
format | 格式化字符串 %s 字符串 %c 字符 %d 整型 %.2f 浮点型 |
replace | 替换字符串中的字符 |
split | 分割字符串,对于某些分割字符,我们需要转义字符 \ |
public class StringMethod {
public static void main(String[] args) {
String a = "java";
String b = "JAVA";
System.out.println(a.equals(b));
System.out.println(a.equalsIgnoreCase(b));
System.out.println(a.length());
System.out.println(a.charAt(2));
System.out.println(a.indexOf('a'));
System.out.println(a.lastIndexOf('a'));
String c = "i am learning java!";
String d = c.substring(2); //一个参数:从索引为2开始,截取到字符串尾
System.out.println(d);
String e = c.substring(2,6); //两个参数:从索引2开始,截取至索引为(6-1)
//辅助记忆: 左闭右开 [2,6)
System.out.println(e);
System.out.println(" j a v a ");
System.out.println(" j a v a ".trim()); //去首尾空格,不去中间空格
System.out.println(a.toUpperCase()); //全部转为大写
System.out.println(b.toLowerCase()); //全部转为小写
System.out.println(a.concat(b)); //拼接两字符串
String g = "贾宝玉 and 林黛玉 林黛玉 林黛玉";
System.out.println(g.replace("林黛玉","薛宝钗")); //替代字符串内容
String poem = "锄禾日当午,汗滴禾下土,谁知盘中餐,粒粒皆辛苦";
String[] split = poem.split(","); //以,为标准,对字符串进行分割,返回的是字符串数组
String fileA = "E:\\aaa\\bbb";
String[] split2 = fileA.split("\\|");
String[] split3 = fileA.split("\\\\");
for (int i = 0; i < split.length; i++) {
System.out.println(split[i]);
}
for (int i = 0; i < split2.length; i++) {
System.out.println(split2[i]);
}
for (int i = 0; i < split3.length; i++) {
System.out.println(split3[i]);
}
String bj = "jchk";
//比较过程:
// (1) 先获取两字符串长度,取最小值min
// (2) 从索引为0开始依次比较两字符串,若出现不同值则返回(前一个字符对应编码值 - 后一个字符对应编码值)的结果
// (3) 若在比较到(min-1)索引都相同,则返回(前一个字符串长度 - 后一个字符串长度)的结果
// (4) 两字符串相等 返回0
System.out.println(a.compareTo(bj));
char[] chars = c.toCharArray(); //将字符串转换成字符数组
for (int i = 0; i < chars.length; i++) {
System.out.println(chars[i]);
}
// format 格式化字符串
/* 占位符有
* %s 字符串 %c 字符 %d 整型 %.2f 浮点型
*
*/
String name = "john";
int age = 10;
double score = 98.3 / 3;
char gender = '男';
String info = "我的名字是" + name + " 年龄是" + age + ",成绩是" + score + " 性别是" + gender + "。希望大家喜欢我!";
System.out.println(info);
String information = "我的名字是%s 年龄是%d,成绩是%.2f 性别是%c。希望大家喜欢我!";
String info2 = String.format(information,name,age,score,gender);
System.out.println(info2);
}
}
三、StringBuffer 类
3.1 基本介绍
java.lang.StringBuffer 代表可变的字符序列,可以对字符串内容进行增删
很多方法与 String 相同,但 StringBuffer 是可变长度的
StringBuffer 是一个容器
3.2 StringBuffer 特点
- StringBuffer 是 final 类,不能被其他类继承
- 实现了接口 Serializable【可以保存到文件,或网络传输】
- 继承了抽象类 AbstractStringBuilder
- AbstractStringBuilder 有属性 char[] value 不是 final 类型,用于存放字符串内容,存放在堆中
- 因为StringBuffer 字符内容是存在 char[] value,所以发生变化(增加/删除)不用每次都更换地址(即不是每次都创建新对象),所以效率高于String
3.3 String VS StringBuffer
- String 保存的是字符串常量,里面的值不能更改,每次String类的更新实际上就是更改地址,效率较低
- StringBuffer 保存的是字符串变量,里面的值可以更改,每次StringBuffer的更新实际上可以更新内容,不用更新地址,效率较高,值保存在堆中
3.4 StringBuffer 构造器
StringBuffer( ) | 构造一个其中不带字符的字符串缓冲区,其初始容量为16个字符 |
---|---|
StringBuffer(CharSequence seq) | 构造一个字符串缓冲区,它包含与指定的CharSequence相同的字符 |
StringBuffer(int capacity) | 构造一个不带字符,但具有指定初始容量的字符串缓冲区。即对char[]大小进行指定 |
StringBuffer(String str) | 构造一个字符串缓冲区,并将其内容初始化为指定的字符串内容,容量为指定字符串长度+16 |
3.5 String 和 StringBuffer 相互转换
String -> StringBuffer
String s = “hello”;
方式一:StringBuffer b1 = new StringBuffer(s);
方式二:StringBuffer b2 = new StringBuffer();
b2.append(s);
StringBuffer -> String
方式一:String s2 = b1.toString();
方式二:String s3 = new String(b1);
3.6 StringBuffer类 常见方法
method | 作用 |
---|---|
append | 在字符串末尾增加内容 |
delete(start,end) | 删除字符串内容 |
replace(start,end,String) | 更改字符串内容 |
indexOf | 获取字符在字符串中第1次出现的索引,索引从0开始,如果找不到,返回-1 |
lastIndexOf | 获取字符在字符串中最后1次出现的索引,索引从0开始,如果找不到,返回-1 |
insert | 在字符串中插入内容 |
length | 获取字符串长度 |
public class StringBufferMethod {
public static void main(String[] args) {
StringBuffer sbr = new StringBuffer("hello");
sbr.append(','); //增加
sbr.append("张三丰").append(100).append(true).append(10.5);
System.out.println(sbr);
sbr.delete(5,9); //删除 [5,9) 左闭右开 删除索引5-8的字符
System.out.println(sbr);
sbr.replace(0,5,"java"); //替换索引0-4的字符
System.out.println(sbr);
System.out.println(sbr.indexOf("10"));
sbr.insert(4,"hello"); //在索引3和4之间插入字符内容
System.out.println(sbr);
System.out.println(sbr.length());
}
}
练习题1
看下面代码输出什么?为什么?
public class StringBufferExercise01 {
public static void main(String[] args) {
String str = null;
StringBuffer sb = new StringBuffer();
sb.append(str);
System.out.println(sb.length());
System.out.println(sb);
StringBuffer sb1 = new StringBuffer(str);
System.out.println(sb1);
}
}
知识点:StringBuffer使用 append() 方法时,如果传入的是 null,就会将null 转换成 “null”字符串传入,
但是构造器中传入 null 的 String对象,就会抛出空指针异常,原因是底层代码中的 super(str.length() + 16)。
练习题2
输入商品名称和商品价格,要求打印效果示例,使用前面学习的方法完成:
商品名 商品价格
手机 123,456.59
要求:价格的小数点前面每三位用逗号隔开
public class StringBufferExercise02 {
public static void main(String[] args) {
StringBuffer name = new StringBuffer("手机");
StringBuffer price = new StringBuffer("1123564.59");
int point = price.lastIndexOf(".");
for (int i = point - 3; i > 0 ; i -= 3) {
price.insert(i,",");
}
System.out.println("商品名\t商品价格\n" + name + "\t" + price);
}
}
四、StringBuilder 类
4.1 基本介绍
一个可变的字符序列。此类提供一个与 StringBuffer 兼容的API,但不保证同步(StringBuilder 不是线程安全)。该类被设计用作 StringBuffer 的一个简易替换,用在字符串缓冲区被单个线程使用的时候。如果可能,建议优先采用该类,因为在大多数实现中,它比StringBuffer 要快。
在 StringBuilder 上的主要操作是 append 和 insert 方法,可重载这些方法,以接受任意类型的数据。
4.2 StringBuilder 特点
- StringBuilder 是final 类,不能被其他类继承
- 继承了 AbstractStringBuilder,属性 char[] value,内容存到 value
- 实现了接口 Serializable【可以保存到文件,或网络传输】,序列化【可以保存类型和数据本身】
- StringBuilder 的方法,没有做互斥的处理,即没有 synchronized 关键字的处理,因此在单线程的情况下使用
4.2 StringBuilder 常见方法
StringBuilder 和 StringBuffer 均代表可变的字符序列,方法是一样的,所以使用和 StringBuffer一样。
4.3 String、StringBuilder、StringBuffer 的比较
- StringBuilder 和 StringBuffer 非常类似,均代表可变的字符序列,而且方法也一样。
- String:不可变字符序列,效率低,但是复用性高。
- StringBuffer:可变字符序列,效率较高(增删)、线程安全。
- StringBuilder:可变字符序列,效率最高,线程不安全。
- String 使用注意:
- String s = “a”; //创建了一个字符串
- s += “b”; //实际上原来的 “a”字符串对象已经丢弃了,现在又产生一个字符串s + “b”(也就是”ab”)。如果多次执行这些改变字符串的内容的操作,会导致大量副本字符串对象存留在内存中,降低效率。如果这样的操作放到循环中,会极大影响程序的性能
- 结论:如果我们对String 做大量修改,不要使用String
String、StringBuilder、StringBuffer 的效率测试
public class StringBuilder01 {
public static void main(String[] args) {
long startTime = 0L;
long endTime = 0L;
startTime = System.currentTimeMillis();
StringBuffer buffer = new StringBuffer("");
for (int i = 0; i < 80000; i++) {
buffer.append(String.valueOf(i));
}
endTime = System.currentTimeMillis();
System.out.println("StringBuffer的执行时间:" + (endTime - startTime));
startTime = System.currentTimeMillis();
StringBuilder builder = new StringBuilder("");
for (int i = 0; i < 80000; i++) {
builder.append(String.valueOf(i));
}
endTime = System.currentTimeMillis();
System.out.println("StringBuilder的执行时间:" + (endTime - startTime));
startTime = System.currentTimeMillis();
String text = "";
for (int i = 0; i < 80000; i++) {
text = text + i;
}
endTime = System.currentTimeMillis();
System.out.println("StringBuffer的执行时间:" + (endTime - startTime));
}
}
String、StringBuilder、StringBuffer 的选择
使用原则,结论:
- 如果字符串存在大量的修改操作,一般使用 StringBuffer 或者 StringBuilder
- 如果字符串存在大量的修改操作,并且在单线程的情况,使用 StringBuilder
- 如果字符串存在大量的修改操作,并且在多线程的情况,使用 StringBuffer
- 如果字符串很少修改,被多个对象引用,使用String,比如配置信息等
五、Math 类
5.1 基本介绍
Math 类包含用于执行基本数学运算的方法,如初等指数、对数、平方根和三角函数。
5.2 Math类常见方法(静态方法)
method | 作用 |
---|---|
abs | 取绝对值 |
pow | 求幂 |
ceil | 向上取整 |
floor | 向下取整 |
round | 四舍五入 |
sqrt | 求开方 |
random | 获取随机数 |
max | 取最大值 |
min | 取最小值 |
public class MathMethod {
public static void main(String[] args) {
//看看Math常用的方法(静态方法)
//1.abs 绝对值
int abs = Math.abs(-9);
System.out.println(abs);
//2.pow 求幂
double pow = Math.pow(2,4);
System.out.println(pow);
//3.ceil 向上取整 返回大于等于该参数的最小整数
double ceil = Math.ceil(-3.0001);
System.out.println(ceil);
//4.floor 向下取整 返回小于等于该参数的最大整数
double floor = Math.floor(-4.999);
System.out.println(floor);
//5.round 四舍五入 Math.floor(该参数+0.5)
double round = Math.round(-5.501);
System.out.println(round);
//6.sqrt 开平方
double sqrt = Math.sqrt(9.0);
System.out.println(sqrt);
//7.0 random 求随机数
// 获取 a - b 之间的一个随机整数,a,b均为整数
int a = 2;
int b = 7;
double x = 0;
for (int i = 0; i < 50; i++) {
x = (int)(Math.random() * (b+1-a) + a);
System.out.println(x);
}
}
}
六、Arrays类
6.1 基本介绍
Arrays 里面包含了一系列静态方法,用于管理或操作数组(比如排序和搜索)。
6.2 Arrays 常见方法
method | 作用 |
---|---|
sort | 自然排序,从小到大 |
toString | 转成字符串 |
binarySearch | 二分查找 |
copyOf | 数组拷贝 |
fill | 数组填充 |
equals | 数组比较 |
asList | 将一组值,转换成list |
package com.hspedu.arrays_;
import java.util.Arrays;
import java.util.Comparator;
import java.util.List;
/**
* @author HarborGao
* @version 1.0
*/
public class Arrays01 {
public static void main(String[] args) {
Integer arr[] = {1, 5, 10, 8, 6, 22};
System.out.println(Arrays.toString(arr));
Arrays.sort(arr, 0, 4); //指定索引范围内自然排序
System.out.println(Arrays.toString(arr));
Arrays.sort(arr); //自然排序 从小到大
System.out.println(Arrays.toString(arr));
int find = Arrays.binarySearch(arr,11);
System.out.println(find);
// 排序
//1. 可以直接使用冒泡排序,也可以直接使用Arrays提供的sort方法排序
//2. 因为数组是引用类型,索引进行sort排序后,会直接影响到实参 arr
//3. sort 重载的,也可以通过传入一个接口 Comparator 实现定制排序
//4. 调用定制排序时,传入两个参数 (1) 排序数组 arr
// (2) 实现了Comparator接口的匿名内部类,要求实现 compare 方法
//5. 这里体现了接口编程的一种方式
Arrays.sort(arr, 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(arr));
System.out.println("==自定义排序==");
int[] arr2 = {1, -1, 5, 3, 8, 10};
// bubble01(arr2);
bubble02(arr2, new Comparator() {
@Override
public int compare(Object o1, Object o2) {
int i1 = (Integer) o1;
int i2 = (Integer) o2;
return i2 - i1;
}
});
System.out.println(Arrays.toString(arr2));
Integer arr3[] = {10, 5, 2, 1};
int index = Arrays.binarySearch(arr3,1, new Comparator(){
@Override
public int compare(Object o1, Object o2) {
Integer n1 = (Integer) o1;
Integer n2 = (Integer) o2;
return n2 - n1;
}
});
System.out.println(index);
//copyOf 数组拷贝
Integer[] newArr = Arrays.copyOf(arr,arr.length - 1 );
System.out.println(Arrays.toString(newArr));
//fill 数组填充
Integer[] num = {1,9,3};
Arrays.fill(num,99); //用99替换数组所有值
System.out.println(Arrays.toString(num));
//equals 数组比较
Integer[] num2 = {99,99,99};
System.out.println(Arrays.equals(num,num2));
//asList 将一组值,转换成list
//解读:
//1. asList方法,会将(2,3,5,7,9)数据转成一个List集合
//2. 返回的 asList 编译类型 List(接口)
//3. asList 运行类型 java.util.Arrays#ArraysList,是Arrays类的静态内部类
List asList = Arrays.asList(2,3,5,7,9);
System.out.println("asList = " + asList);
}
//冒泡排序
public static void bubble01(int[] arr) {
int temp = 0;
for (int i = 0; i < arr.length; i++) {
for (int j = 0; j < arr.length - 1 - i; j++) {
if (arr[j] > arr[j + 1]) {
temp = arr[j];
arr[j] = arr[j + 1];
arr[j + 1] = temp;
}
}
}
}
//冒泡排序 + 定制
public static void bubble02(int[] arr, Comparator c) {
int temp = 0;
for (int i = 0; i < arr.length; i++) {
for (int j = 0; j < arr.length - 1 - i; j++) {
if (c.compare(arr[j], arr[j + 1]) > 0) {
temp = arr[j];
arr[j] = arr[j + 1];
arr[j + 1] = temp;
}
}
}
}
}
/*
使用binarySearch时
1. 如果传入两个参数,第一个参数是数组,第二个参数是要查找的值,数组必须是有序递增的
2. 如果传入三个参数,第一个参数是数组,第二个参数是要查找的值,第三个参数是匿名内部类Comparator
数组必须是有序(递增或递减)的,匿名内部类重写compare方法用于定制查询
3. 如果传入四个参数,第一个参数是数组,第二个参数是起始索引,第三个是结束索引,第四个是要查找的值
用于在指定索引范围内查找,要求数组必须是有序递增的
3. 查找策略依据以下底层源码,如果找不到,返回负数,代表的是该值应该在的位置
public static int binarySearch(int[] a, int key) {
return binarySearch0(a, 0, a.length, key);
}
private static int binarySearch0(int[] a, int fromIndex, int toIndex,
int key) {
int low = fromIndex; // 0
int high = toIndex - 1; // a.length - 1
while (low <= high) {
int mid = (low + high) >>> 1;
int midVal = a[mid];
if (midVal < key)
low = mid + 1;
else if (midVal > key)
high = mid - 1;
else
return mid; // key found
}
return -(low + 1); // key not found.
}
*/
6.3 小练习
案例:自定义Book类,里面包含 name 和 price,。要求使用两种方式排序,分别按price 排序(从大到小)和按书名排序(从长到短)。 Book[] books = 4本书对象。
其中一种使用前面学习过的传递,实现Comparator接口匿名内部类,也称为定制排序。
package com.hspedu.arrays_;
import java.util.Arrays;
import java.util.Comparator;
/**
* @author HarborGao
* @version 1.0
*/
public class ArraysExercise01 {
public static void main(String[] args) {
Book[] books = new Book[4];
books[0] = new Book("红楼梦~~~~", 100);
books[1] = new Book("金瓶梅~", 90);
books[2] = new Book("青年文摘~", 5);
books[3] = new Book("java从入门到放弃", 300);
//方法一 sort方法
// Arrays.sort(books, new Comparator() {
// @Override
// public int compare(Object o1, Object o2) {
// Book book1 = (Book) o1;
// Book book2 = (Book) o2;
// double res = book2.getPrice() - book1.getPrice();
// if (res > 0) {
// return 1;
// } else if (res < 0) {
// return -1;
// } else {
// return 0;
// }
// }
// });
// System.out.println(Arrays.toString(books));
//方法二 冒泡排序
for (int i = 0; i < books.length; i++) {
for (int j = 0; j < books.length - i - 1; j++) {
if (books[j].getName().length() - books[j + 1].getName().length() < 0) {
Book temp = books[j];
books[j] = books[j + 1];
books[j + 1] = temp;
}
}
}
System.out.println(Arrays.toString(books));
}
}
class Book {
private String name;
private double price;
public Book(String name, double price) {
this.name = name;
this.price = price;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public double getPrice() {
return price;
}
public void setPrice(double price) {
this.price = price;
}
@Override
public String toString() {
return "Book{" +
"name='" + name + '\'' +
", price=" + price +
'}';
}
}
七、System 类
7.1 System类常见方法
method | 作用 |
---|---|
exit | 退出 |
arraycopy | 复制数组元素,比较适合底层调用,一般使用Arrays.copyOf |
currentTimeMillis | 返回当前时间距离1970-1-1的毫秒数 |
gc | 运行垃圾回收机制 |
八、BigInteger 和 BigDecimal 类
8.1 应用场景
- BigInteger 适合保存比较大的整型
- BigDecimal 适合保存精度更高的浮点型
8.2 BigInteger 和 BigDecimal 类常见方法
method | 作用 |
---|---|
add | 加 |
subtract | 减 |
multiply | 乘 |
divide | 除 |
public static void main(String[] args) {
//当编程中需要使用很大的整数,long不够用
//可以使用 BigInteger类
// long l = 16546546464646464159999l;
BigInteger bigInteger = new BigInteger("16546546464646464159999");
BigInteger bigInteger1 = new BigInteger("1111");
System.out.println(bigInteger);
//解读:
//1. 在对BigInteger 进行加减乘除的时候,需要使用对应的方法,不能直接使用+-*/运算符
//2. 可以创建一个 要操作的 BigInteger 然后进行相应操作
System.out.println(bigInteger.add(bigInteger1));
System.out.println(bigInteger.subtract(bigInteger1));
System.out.println(bigInteger.multiply(bigInteger1));
System.out.println(bigInteger.divide(bigInteger1));
//当编程中需要使用精度很高的小数,double不够用
//可以使用 BigC类
double d = 3.14159267777888899999999999;
System.out.println(d); //只输出 3.141592677778889
BigDecimal bigDecimal = new BigDecimal("3.14159267777888899999999999");
BigDecimal bigDecimal1 = new BigDecimal("3.1");
System.out.println(bigDecimal);
//解读:
//1. 在对BigDecimal 进行加减乘除的时候,需要使用对应的方法,不能直接使用+-*/运算符
//2. 可以创建一个 要操作的 BigDecimal 然后调用相应方法进行操作
System.out.println(bigDecimal.add(bigDecimal1));
System.out.println(bigDecimal.subtract(bigDecimal1));
System.out.println(bigDecimal.multiply(bigDecimal1));
// System.out.println(bigDecimal.divide(bigDecimal1)); //可能抛出ArithmeticException异常
//解决方法 调用divide方法时指定精度 BigDecimal.ROUND_CEILING
//如果有无限循环小数,就会保留被除数精度
System.out.println(bigDecimal.divide(bigDecimal1, BigDecimal.ROUND_CEILING));
}
九、日期类
9.1 第一代日期
- Date:精确到毫秒,代表特定的瞬间。
- SimpleDateFormat:格式化和解析日期的具体类。它允许进行格式化(日期->文本)、解析(文本->日期)和规范化。 ```java package com.hspedu.date_;
import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.Date;
/**
- @author HarborGao
@version 1.0 */ public class Date01 { public static void main(String[] args) throws ParseException {
//解读:
//1. 获取当前系统时间
//2. 这里的Date类 引用的是 java.util包
//3. 默认输出的日期格式是国外的方式,因此通常需要对格式进行转换
Date d1 = new Date(); //获取当前系统时间
System.out.println("当前日期 " + d1);
Date d2 = new Date(1632219604198l); //通过指定毫秒数得到时间
System.out.println("当前日期 " + d2);
System.out.println(d1.getTime()); //获取某个时间对应的毫秒数
//解读
//1. 创建 SimpleDateFormat 对象,可以指定相应格式
//2. 这里的格式使用的字母是规定好的,参考模式字母表
SimpleDateFormat sdf = new SimpleDateFormat("yyyy年MM月dd日 hh:mm:ss E");
String format = sdf.format(d1); //将日期转换成指定格式的字符串
System.out.println(format);
//解读:
//1. 可以把一个格式化的String 转成对应的 Date
//2. 得到的Date 在输出时默认还是国外的格式,可以通过SimpleDateFormat转换
//3. 在把String 转成 Date 时,字符串的格式需要和创建的SimpleDateFormat对象的格式一致,否则无法完成转换
String s = "1996年01月01日 10:20:30 星期一";
Date parse = sdf.parse(s);
System.out.println("parse = " + sdf.format(parse));
} } ```
9.2 SimpleDateFormat 中的模式字母
字母 | 日期或时间元素 | 表示 | 示例 |
---|---|---|---|
G | Era 标志符 | Text | AD |
y | 年 | Year | 1996; 96 |
M | 年中的月份 | Month | July; Jul; 07 |
w | 年中的周数 | Number | 27 |
W | 月份中的周数 | Number | 2 |
D | 年中的天数 | Number | 189 |
d | 月份中的天数 | Number | 10 |
F | 月份中的星期 | Number | 2 |
E | 星期中的天数 | Text | Tuesday; Tue |
a | Am/pm 标记 | Text | PM |
H | 一天中的小时数(0-23) | Number | 0 |
k | 一天中的小时数(1-24) | Number | 24 |
K | am/pm 中的小时数(0-11) | Number | 0 |
h | am/pm 中的小时数(1-12) | Number | 12 |
m | 小时中的分钟数 | Number | 30 |
s | 分钟中的秒数 | Number | 55 |
S | 毫秒数 | Number | 978 |
z | 时区 | General time zone | Pacific Standard Time; PST; GMT-08:00 |
Z | 时区 | RFC 822 time zone | -0800 |
9.3 第二代日期类
- 第二代日期类,主要就是 Calender类(日历)。
- Calendar 类是一个抽象类,它为特定瞬间与一组诸如 YEAR、MONTH、DAYOF_MONTH、HOUR 等日历字段之间的转换提供了一些方法,并未操作日历字段(例如获得下星期的日期)提供了一些方法。 ```java package com.hspedu.date;
import java.util.Calendar;
/**
- @author HarborGao
@version 1.0 */ public class Calendar01 { public static void main(String[] args) {
//解读
//1. Calendar 是一个抽象类,并且构造器是protected
//2. 可以通过 getInstance() 来获取实例
//3. 提供大量的方和字段给程序员
Calendar c = Calendar.getInstance(); //创建日历类对象//比较简单,自由
System.out.println(c);
//获取日历对象的某个字段
System.out.println("年:" + c.get(Calendar.YEAR));
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.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))
+ "日" + (c.get(Calendar.HOUR)) + "时" + (c.get(Calendar.MINUTE)) + "分" + (c.get(Calendar.SECOND)) + "秒");
} } ```
9.4 第三代日期类
前面两代日期类的不足分析
jdk 1.0 中包含了一个java.util.Date类,但是它的大多数方法已经在 jdk 1.1 引入Calendar类之后被弃用了。
而Calendar 也存在问题是:
- 可变性:像日期和时间这样的类应该是不可变的
- 偏移性:Date 中的年份是从1900开始的,而月份都是从0开始
- 格式化:格式化只对 Date有用,Calendar则不行
- 此外,它们也不是线程安全的,不能处理闰秒等(每隔两天,多出1s)
9.5 第三代日期类常见方法(jdk8 加入)
- LocalDate(日期):只包含日期,可以获取日期字段
- LocaTime(时间):只包含时间,可以获取时间字段
- LocalDateTime(日期时间):包含日期+时间,可以获取日期和时间字段 ```java package com.hspedu.date_;
import java.time.LocalDateTime; import java.time.Year;
/**
- @author HarborGao
- @version 1.0
*/
public class Date03 {
public static void main(String[] args) {
} } ```//第三代日期
//解读:
//1. 使用 now() 返回表示当前日期时间的对象
LocalDateTime ldt = LocalDateTime.now(); //LocalDate.now(); //LocalTime.now();
System.out.println(ldt);
String time = ldt.getYear() + "年" + ldt.getMonthValue() + "月" + ldt.getDayOfMonth() + "日 " + ldt.getHour() + ":" + ldt.getMinute() + ":" + ldt.getSecond();
System.out.println(time);
System.out.println(ldt.getMonth());
9.6 DateTimeFormatter 格式日期类
类似于SimpleDateFormat
DateTimeFormatter dtf = DateTimeFormatter.ofPattern(格式);
String str = dtf.format(日期对象);
//2. 使用DateTimeFormatter
DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy年MM月dd日 HH:mm:ss");
String format = dateTimeFormatter.format(ldt);
System.out.println("格式化的日期:" + format);
9.7 第三代日期 - 时间戳 Instant
类似于 Date
提供了一系列和 Date 类转换的方式:
Instant -> Date:
Date date = Date.from(instant);
Date -> Instant:
Instant instant = date.toInstant();
9.8 第三代日期类更多方法
LocalDateTime 类
MonthDay 类:检查重复事件
是否是闰年
增加日期的某个部分
使用 plus 或者 minus 相关方法跳转日期
其他的方法参考API文档
十、章节练习
- 编程题
- 将字符串中指定的部分进行反转。比如”abcdef”反转为”aedcbf”
- 编写方法 public static String reverse(String str, int start, int end) 来搞定 ```java package com.hspedu.homework_.homework01;
/**
- @author HarborGao
@version 1.0 */ public class Homework01 { public static void main(String[] args) {
String src = "abcdef";
// String reverse = reverse(src, 0, 3); // System.out.println(reverse);
try {
src = change(src,8,4);
} catch (Exception e) {
System.out.println(e.getMessage());
return;
}
System.out.println(src);
} //方案一 public static String reverse(String str, int start, int end) {
char[] chars = str.toCharArray();
char[] newChar = new char[chars.length];
for (int i = 0,j = 0; i < chars.length; i++) {
if (i < start || i > end) {
newChar[i] = chars[i];
} else {
newChar[end - j] = chars[i];
j++;
}
}
return new String(newChar);
} //方案二 public static String change(String str, int start, int end) {
//对输入的参数校验
//重要的编程技巧!!!
//(1) 写出正确的情况
//(2) 然后取反即可
if (!(str != null && start >=0 && end > start && end < str.length())) {
throw new RuntimeException("参数有误");
}
char[] chars = str.toCharArray();
char temp = ' ';//交换辅助变量
for (int i = start,j = end; i < j ; i++,j--) {
temp = chars[i];
chars[i] = chars[j];
chars[j] = temp;
}
//使用chars 重新构建一个String 返回即可
return new String(chars);
} } ```
- 编程题
输入用户名、密码、邮箱,如果信息录入正确,则提示注册成功,否则生成异常对象
要求:
- 用户名长度为2或3或4
- 密码的长度为6,要求全是数字 isDigital
- 邮箱中包含 @ 和 . 并且 @ 在 . 的前面 ```java package com.hspedu.homework_.homework02;
public class Register { public static void main(String[] args) { String name = “jas”; String password = “126456”; String email = “abc@163.com”; try { userRegister(name, password, email); System.out.println(“注册成功!”); } catch (Exception e) { System.out.println(e.getMessage()); } } /**
* 输入用户名、密码、邮箱,如果信息录入正确,则提示注册成功,否则生成异常对象
* 要求:
* (1) 用户名长度为2或3或4
* (2) 密码的长度为6,要求全是数字 isDigital
* (3) 邮箱中包含 @ 和 . 并且 @ 在 . 的前面
*
* 思路分析:
* (1) 先编写方法 userRegister(String name, String pwd, String email) {}
* (2) 针对 输入的内容进行校验,如果发现有问题,就抛出异常,给出提示
* (3) 单独的写一个方法,判断 密码是否全部都是数字字符 boolean
*/
public static void userRegister(String name, String pwd, String email) {
//补充校验
if (name == null || pwd == null || email == null) {
throw new RuntimeException("参数不能为空");
}
//第一关
int userLength = name.length();
if(!(userLength >= 2 && userLength <= 4)) {
throw new RuntimeException("用户名长度为2或3或4");
}
//第二关
if (!(pwd.length() == 6 && isDigital(pwd))) {
throw new RuntimeException("密码的长度为6,要求全是数字");
}
//第三关
int i = email.indexOf('@');
int j = email.indexOf('.');
if (!(i > 0 && i < j)) {
throw new RuntimeException("邮箱中包含 @ 和 . 并且 @ 在 . 的前面");
}
}
public static boolean isDigital(String pwd) {
char[] chars = pwd.toCharArray();
for (int i = 0; i < chars.length; i++) {
if (chars[i] < '0' || chars[i] > '9') {
return false;
}
}
return true;
}
}
3. 编程题
1. 编写Java程序,输入形式为:Han Shun Ping 的人名,以 Ping,Han.S 的形式打印出来。其中,.S 是中间单词的首字母。
1. 例如输入 "Willian Jefferson Clinton",输出形式为:Clinton,Willian.J
```java
package com.hspedu.homework_.homework03;
public class Homework03 {
public static void main(String[] args) {
String name = "Han Shun Ping";
String name2 = "Willian Jefferson Clinton";
try {
reName(name);
} catch (Exception e) {
System.out.println(e.getMessage());
}
}
public static void reName(String name) {
if (name == null) {
throw new RuntimeException("参数不能为空!");
}
String[] names = name.split(" ");
if (names.length != 3) {
throw new RuntimeException("传入的格式有误!");
}
String format = String.format("%s,%s.%c",names[2],names[0],names[1].toUpperCase().charAt(0));
System.out.println(format);
}
}
- 编程题
输入字符串,判断里面有多少个大写字母,多少个小写字母,多少个数字
package com.hspedu.homework_.homework04;
public class Homework04 {
public static void main(String[] args) {
String n = "asf1654asfAFAF";
countStr(n);
}
public static void countStr(String str) {
if (str == null) {
System.out.println("字符串不能为 null");
return;
}
int countUpper = 0;
int countLower = 0;
int countNum = 0;
for (int i = 0; i < str.length(); i++) {
if (str.charAt(i) >= 'A' && str.charAt(i) <= 'Z') {
countUpper++;
} else if (str.charAt(i) >= 'a' && str.charAt(i) <= 'z') {
countLower++;
} else if (str.charAt(i) >= '0' && str.charAt(i) <= '9') {
countNum++;
}
}
String format = String.format("该字符串含有大写字母%d个,小写字母%d个,数字%d个",countUpper,countLower,countNum);
System.out.println(format);
}
}
- 试写出下面程序的运行结果
已知Animal类有属性name, 可以通过有参构造为属性赋值
class Animal {
String name;
public Animal(String name) {
this.name = name;
}
}
//main方法
String s1 = "hspedu";
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 s4 = new String("hspedu");
String s5 = "hspedu";
System.out.println(s1 == s4); //false
System.out.println(s4 == s5); //false
String t1 = "hello" +s1;
String t2 = "hellohspedu";
System.out.println(t1.intern() == t2); //true
学习参考(致谢):
- B站 @程序员鱼皮 Java学习一条龙
- B站 @韩顺平 零基础30天学会Java