第13章:常用类
总体内容
八大包装类(Wrapper)
介绍
- 分类
- 继承关系
装箱和拆箱
装箱:基本数据类型–>包装类,反之拆箱
- 手动装箱:
int n = 10;
Integer i1 = new Integer(n);
Integer i2 = Integer.valueOf(n);
手动拆箱:
int i3 = i1.intValue();
- 自动装箱
int n = 10;
Integer i1 = n;
//底层用的还是Integer.valueOf(n)
自动拆箱
Integer i2 = new Integer(99);
int i3 = i2;
包装类小练习
注意这里的精度问题!
包装类型和String类型相互转换
- 包装类–>String
- String --> 包装类
包装类的常用方法
Integer类面试题
- 自动装箱时,底层用的是Integer.valueOf(),注意该方法会根据参数范围,返回不同内容
Integer源码
- IntegerCache.low = -128
- IntegerCache.high = 127
- 如果-128<= i <= 127,则直接从cache数组返回数值
否则返回new Integer对象
public static Integer valueOf(int i) {
if (i >= IntegerCache.low && i <= IntegerCache.high)
return IntegerCache.cache[i + (-IntegerCache.low)];
return new Integer(i);
}
2. 组合考察
String类
String类结构剖析(基础)
串行化:该类可以在网络上传输
String创建剖析(2种方式)
内存布局:
Sting基础测试题
1、练习1
注意:
- 都是用第一种创建方式,从常量池中找有没有"abc",如果有,则指向该地址,若没有,则在常量池中创建"abc"
- 所以变量a和b指向的是常量池中的同一个地址
2. 练习2
3. 练习3(对象中的String属性)
String对象特性测试题(重点练习5的讲解)
1、练习1
- 在常量池中,创建了hello对象(字符串对象),s1指向该对象
- 在常量池中找haha对象,未找到,在常量池中创建haha对象,s1指向haha对象
- 当执行s1=“haha”,不会把hello删掉然后在该位置创建haha,而是在另一个地方创建haha,因为字符串对象一旦被分配,其内容不可变
2、 练习2(面试题)
3、练习3
解读:
sb.toString()方法内部是:
return new String(value,0,count);
所以c是指向的是堆中的对象
4、练习4
5、综合练习(好好看这个)
注意:
① String中的value[]是final类型,不能指向新地址,但是单个字符的内容可以变化
② 字符串对象一旦被分配,其内容是不可变的
③ value指向的地址不能改变,可以改变对象引用指向的地址
//value指向的地址不能改变,但可以改变对象引用指向的地址
//下面这段代码是ok的,这两个name的hashCode是不同的
//第一句 在堆中开辟地址,value指向常量池中的wpz
//第三句 在堆中开辟地址,value指向常量池中的yyy
//各自的value指向都没有变,变的是name的指向
String name = new String("wpz");
System.out.println(name.hashCode());
name = new String("yyy");
System.out.println(name.hashCode());
分析步骤:
① 在堆中创建ex对象
,该对象中有两个属性(str和ch),
str是String类型的对象,所以在堆中开辟空间,其中value属性指向常量池中的"hsp"
ch是char类型的数组,也是引用数据类型,所以在堆中开辟空间,写入java
到此ex对象创建完毕
②ex.change(………)
,执行方法时会在栈中开辟一个新栈,将ex.str和ex.ch都传入方法栈中,由于它们都是引用数据类型,所以开始时:栈中的str指向堆中的str对象,ch也指向堆中的ch对象
str = "java"
,因为String对象中的value是final类型的,它指向的地址不能变,所以不会修改value指向的空间,转而修改str指向的空间,常量池中创建java对象,str指向该对象
ch[0] = "h"
final不能修改指向的地址,但单个字符的内容可以改变,所以在堆中ch的地址中修改第一个字符为 h
③ 方法执行完毕后,方法栈销毁,ex.str会找到堆中String对象,访问到value指向的hsp(方法栈中的str指向常量池中的java已经被销毁了,所以只能找到原先的位置)
ex.ch找到原来的位置,输出hava(修改了一个字符)
内存布局:
String常用方法
说明
常用方法一览
(学会怎么用就好)
部分一
讲解:
- subString()
第一个参数:第一个想要的
第二个参数:第一个不想要的
- indexOf()和lastIndexOf
参数可以是"t" 也可以是"ter"
部分二
讲解:
- replace(… , …)
1.1 第一个参数:原来的字符串
1.2 第二个参数:替换后的字符串
1.3 注意:单独执行s.replace(…)不会改变s本身,这个方法返回的结果才是替换过的,这里是用s本身接收了一下,s才变的
s = "王胖子 高瘦子 小艺艺 王胖子";
s = s.replace("王胖子","小福子");
就是把 王胖子 替换成 小福子,返回的结果是:小福子 高瘦子 小艺艺 小福子- split()
2.1 参数是:以什么标准(分割符)分割字符串
2.2 返回的结果是:数组
2.3 分割符如果是特殊符号,需要加转义符,比如’ / ’
- conpareTo()
String a = "jac";
String b = "jack"
这两个前面部分是相同的,满足第三点,所以
int i= a.compareTo(b);
i值为 3 - 4 = -1- format(……)
4.1 %s(字符串),%d(整数),%f(浮点数,保留到小数点后两位),%c(字符)都是占位符
4.2 这些占位符由后面变量来替换(占位符:先占着这些位置,让后面的变量替换)
用String.format(……)方法来格式化输出人的信息
String name = "王胖子";
int age = 20;
double score = 98.4;
char gender = '女';
String formatStr = "我的名字是%s,年龄是%d,成绩是%.2f,性别是%c,希望大家喜欢我";
String info = String.format(formatStr,name,age,score,gender);
System.out.println(info);
StringBuffer类(字符串缓存区)
StringBuffer结构剖析
介绍
String和StringBuffer的区别
StringBuffer转换
构造器
常用的就是第1,3,4
无参构造器:char[ ]大小为 16
参数为String(str):char[ ]大小为str.length()+16
String和StringBuffer相互转换
String --> StringBuffer
StringBuffer --> String
StringBuffer常用方法
简单演示使用方法:
//append(……)
//append方法组后返回的还是StringBuffer
StringBuffer s = new StringBuffer("王胖");
s.append("子");//王胖子
//delete(…,…)
//删除索引为>=start && <end处的字符
s.delete(0,2);
//replace(……,……,……)
//用 小明 替换 索引为[9,11)的字符串
s.replace(9,11,"小明");
//indexOf(……)查找
//查找指定字符串第一次出现的索引,没有则返回-1
int index = s.indexOf("王胖子");
//insert(…,…)
//在索引为9的位置插入"小猫咪",原来索引为9的内容自动后移
//这个方法会改变s本身
s.insert(9,"小猫咪");
StringBuffer练习
练习1
练习2
/**
* @author 王胖子
* @version 1.0
*/
public class Excise {
public static void main(String[] args) {
String price = "129876345.69";
StringBuffer sb = new StringBuffer(price);
//①找到小数点的索引,②然后在该位置的前三位插入,即可
//③依次往前推三位,然后插入-->使用循环
for (int i = price.lastIndexOf('.')-3;i >0;i-=3){
sb.insert(i,',');
}
System.out.println(sb);
}
}
StringBuilder类
StringBuilder结构剖析
StringBuilder是StringBuffer的简易替换
String vs StringBuilder vs StringBuffer
区分:
效率:String < StringBuffer < StringBuilder
使用原则:
Math类的常用方法
基本介绍
方法一览
方法使用
若开方的数为负数,则输出NAN(not a number)
编程:
- 思考:返回一个数x,2 <= x <= 7
- 公式就是:(int)(a + Math.random() * (b-a +1))
public class Excise {
public static void main(String[] args) {
/*
random返回的是 0 <= x < 1 之间的一个随机小数
- 思考:返回一个数x,2 <= x <= 7
- 公式就是:(int)(a + Math.random() * (b-a +1))
解读:
1. Math.random()*(7-2 +1)-->Math.random()*6
返回的就是0 <= x < 6 的小数
2. a+Math.random()*6 返回的是 2 <= x < 8的小数
3. (int)(a+Math.random()*6) 返回的是 2 <= x <= 7的整数
*/
for (int i = 0; i < 10; i++) {
System.out.println((int) (2 + Math.random() * (7 - 2 + 1)));
}
}
}
Arrays类的常用方法
binarySearch 二分查找
- 数组必须有序
- 第一个参数为 数组,第二个参数为要查找的值
- 返回该值在数组的下标,若没有找到,返回
-(low+1)
low+1也就是应该在的下标+1
copyOf
- 从arr数组中,拷贝arr.length个元素到newArr数组中
- 如果拷贝的长度>arr.length,则在新数组后面增加null,如果长度<0,则抛出异常NegativeArraySizeException
int[] newArr = Arrays.copyOf(arr,arr.length);
定制排序——从大到小
import java.util.Arrays;
import java.util.Comparator;
public class Excise {
public static void main(String[] args) {
Integer[] integers = {1,90,-1,6};
System.out.println(Arrays.toString(integers));;//数组字符串形式[1,90,-1,6]
// Arrays.sort(integers);//默认排序(从小到大)
Arrays.sort(integers, 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(integers));
}
}
冒泡+定制来模拟Arrays的排序(使用Comparator接口)
import java.util.Arrays;
import java.util.Comparator;
public class Excise {
public static void main(String[] args) {
int[] arr = {1, 49, 23, -1, 78, 3};
// bubble01(arr);
bubble02(arr, new Comparator() {
@Override
public int compare(Object o1, Object o2) {
int i1 = (Integer) o1;
int i2 = (Integer) o2;
//此处为从大到小
return i2 - i1;//或为 i1 - i2
}
});
System.out.println(Arrays.toString(arr));
}
//普通冒泡
//因为数组是引用数据类型,所以不用返回接收了
public static void bubble01(int[] arr) {
int temp = 0;
for (int i = 0; i < arr.length - 1; 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;
}
}
}
}
//冒泡+定制来模拟Arrays的排序思想
//使用Comparator接口
public static void bubble02(int[] arr, Comparator c) {
int temp = 0;
for (int i = 0; i < arr.length - 1; i++) {
for (int j = 0; j < arr.length - 1 - i; j++) {
//数组的排序由c.compare(arr[j],arr[j+1])返回的值决定
//若成立则交换,否则不交换
if (c.compare(arr[j], arr[j + 1]) > 0) {
temp = arr[j];
arr[j] = arr[j + 1];
arr[j + 1] = temp;
}
}
}
}
}
Arrays小练习
import java.util.Arrays;
import java.util.Comparator;
public class Excise {
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);
//(1)价格从小到大(2)价格从大到小
Arrays.sort(books, new Comparator<Book>() {
@Override
public int compare(Book o1, Book o2) {
//注意这里的返回类型是整数,但是价格相减是double,所以要转换一下
// double priceVal = o1.getPrice() - o2.getPrice();//价格从小到大
double priceVal = o2.getPrice() -o1.getPrice();//价格从大到小
if (priceVal > 0) {
return 1;
} else if (priceVal < 0) {
return -1;
} else {
return 0;
}
}
});
//名字从长到短
Arrays.sort(books, new Comparator<Book>() {
@Override
public int compare(Book o1, Book o2) {
//书名长度相减为整数,直接return就行
return o2.getName().length()-o1.getName().length();
}
});
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 double getPrice() {
return price;
}
@Override
public String toString() {
return "Book{" +
"name='" + name + '\'' +
", price=" + price +
'}'+"\n";
}
}
System类的常用方法
System.arraycopy(…, …, …, …, …)
BigInteger类和BigDecimal类
大数处理方案:
加减乘除需要使用对应的方法
Date、Calendar、LocalDate类
Date类
Date的两种构造器
日期的格式转换
SimpleDateFormat格式中规定的字母
String ——> Date
Calendar类
如果我们需要按照24小时禁止来获取时间,Calendar.HOUR
改成Calendar.HOUR_OF_DAY
第三代日期类
不足
第三代日期类
使用方法:
格式化:
//获取当前日期时间对象
LocalDateTime now = LocalDateTime.now();
//创建格式化对象
DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy年MM月dd日 HH时mm分ss秒");
//使用格式化对象 将当前日期时间对象格式化
String format = dateTimeFormatter.format(now);
System.out.println(format);
instant时间戳
类似Date,提供了一系列和Date类转换的方法
引申:类图中图标含义
本章作业
1. Sting翻转
思路分析图
记住的点:
- String–> char数组
char[] chars = str.toCharArray();
- char数组–>String
new String(chars)
- 校验时的技巧
(1) 如果正确的情况较容易实现,则写出正确的情况
(2) 然后给正确的情况取反
if (!(str != null && start >= 0 && end > start && end < str.length()))
public class Excise {
public static void main(String[] args) {
String str = "我想告诉你:你是年少的欢喜";
System.out.println("转换前~~~~~~~~~");
System.out.println(str);
try {
str = reverse(str, 6, str.length() - 1);
System.out.println("转换后~~~~~~~~~");
System.out.println(str);
} catch (Exception e) {
System.out.println(e.getMessage());
}
}
public static String reverse(String str, int start, int end) {
/*
对输入的参数做一个校验
重要的编程技巧:
(1) 如果正确的情况较容易实现,则写出正确的情况
(2) 然后给正确的情况取反
*/
if (!(str != null && start >= 0 && end > start && end < str.length())) {
throw new RuntimeException("输入的参数异常,转换失败!");
}
//将String转换成char[],因为char数组中元素可以相互交换
char[] chars = str.toCharArray();//String --> char数组
char temp = ' ';
//交换:只要end > start就可以交换
for (int i = start, j = end; i < j; i++, j--) {
temp = chars[i];
chars[i] = chars[j];
chars[j] = temp;
}
//返回类型要求是String,所以把char数组转换成String
return new String(chars);
}
}
输出结果:
2. 注册处理题
巧妙地利用了过关斩将的思想
- 对每一关判断是否出错,若出错则抛出错误或输出提示信息
- 判断是否出错:正确条件取反就是出错的条件了
if (!(name != null && pwd != null && email != null))//三个信息不为空是正确的,取反就是错误的了
- 异常处理机制的使用 可以使出错时不执行输出语句,当没错时才会输出
try { userRegister(name, pwd, email); System.out.println("注册成功!");}
import java.util.Scanner;
public class Excise {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
System.out.printf("姓名:");
String name = scanner.next();
System.out.printf("密码:");
String pwd = scanner.next();
System.out.printf("邮箱:");
String email = scanner.next();
try {
//如果有错就会抛出错误,输出语句不执行,若没错,才输出注册成功
userRegister(name, pwd, email);
System.out.println("注册成功!");
} catch (Exception e) {
System.out.println(e.getMessage());
}
}
public static void userRegister(String name, String pwd, String email) {
/*
1. 采用过关斩将的思想
2. 找出正确的条件,然后取反得到不符合的条件-->抛出异常
3. 某一关失败则抛出异常
*/
//第0关:输入信息不能为空
if (!(name != null && pwd != null && email != null)) {
throw new RuntimeException("输出信息不能为空");
}
//第一关:用户名长度为2或3或4
if (!(name.length() >= 2 && name.length() <= 4)) {
throw new RuntimeException("用户名长度要求为2或3或4");
}
//第二关:密码长度为6,且要求全是数字
//- 另外写一个方法 来判断是否是数字
if (!(pwd.length() == 6 && isDigital(pwd))) {
throw new RuntimeException("要求密码长度为6,且全是数字");
}
//第三关:密码中包含@和. 且@在.的前面
int i1 = email.indexOf('@');
int i2 = email.indexOf('.');
//若没找到则,indexOf返回-1,i1和i2都要>0,但是写了i2>i1所以省略了i2>0
if (!(i1 > 0 && i2 > i1)) {
throw new RuntimeException("要求密码中包含@和. 且@在.的前面");
}
}
//
public static boolean isDigital(String pwd) {
char[] chars = pwd.toCharArray();
for (char c : chars) {
//字符'0' - '9'表示数字,注意不要写成数字0和9
if (!(c >= '0' && c <= '9')) {
return false;
}
}
return true;
}
}
输出结果 - 成功
失败
3. 字符串分割+格式化
本题用到
- split() 分割 - 返回字符串数组
- format() 格式化 - 返回格式化后的字符串(对于固定格式的语句,要想到String的format方法)
- toUpperCase() 字符串整体转换为大写字母
- charAt() 取出字符串的第i个字符
public class Excise {
public static void main(String[] args) {
String str = "Wang pang Zi";
printName(str);
}
public static void printName(String str){
//- 判断name是否为空
if (str ==null){
System.out.println("字符串为null");
return;
}
//1. 将字符串分隔
String[] name = str.split(" ");
//- 判断是否是三部分组成
if (name.length!=3){
System.out.println("字符串格式错误,要求为XXX XXX XXX");
return;
}
//2. 格式化 name[1].toUpperCase().charAt(0),先整体大写,然后取第一个字符
String format = String.format("%s,%s .%c", name[2], name[0], name[1].toUpperCase().charAt(0));
System.out.println(format);
}
}
4. 字符统计
读取字符串中的字符 的方法
- String转换成char数组,然后
char[ i ]
- 使用字符串的charAt(),
str.charAt(i)
public class Excise {
public static void main(String[] args) {
String str = "1w2SsY34我";
T(str);
}
public static void T(String str) {
if (str == null) {
System.out.println("字符串为空");
return;
}
int upperCount = 0;//大写字母
int lowCount = 0;//小写字母
int numCount = 0;//数字
int otherCount = 0;//其它
//方法一:String转成char数组
// char[] chars = str.toCharArray();
// for (int i = 0; i < chars.length; i++) {
// if (chars[i]>='A'&&chars[i]<='Z'){
// upperCount++;
// }else if (chars[i]>='a'&&chars[i]<='z'){
// lowCount++;
// }else if (chars[i]>='1'&&chars[i]<='9'){
// numCount++;
// }else {
// otherCount++;
// }
// }
//方法二:直接用charAt取字符(只能读取,不能修改)
int length = str.length();
for (int i = 0; i < length; i++) {
if (str.charAt(i) >= 'A' && str.charAt(i) <= 'Z') {
upperCount++;
} else if (str.charAt(i) >= 'a' && str.charAt(i) <= 'z') {
lowCount++;
} else if (str.charAt(i) >= '1' && str.charAt(i) <= '9') {
numCount++;
} else {
otherCount++;
}
}
String format = String.format("大写字母:%d个,小写字母:%d个,数字:%d个,其它字符:%d个",
upperCount, lowCount, numCount, otherCount);
System.out.println(format);
}
}