常用类
包装类(Wrapper)
为什么要有包装类
java在面向对象的路上越走越远 连基本数据类型都不放过 为他们都添加了包装类 在使用时不用担心有自动的装箱拆箱使用包装类的目的是让基本数据类型也享有Object的方法 当用到包装类的时候就知道问什么基本数据类型会用到object的方法了 因为java就是按照万物皆object的想法构思的 基本数据类型如果没有包装类的话就会在java里格格不入 迟早陷入尴尬的局面
自动拆装箱如何使用 这没啥好讲的 无非就是编译过程中去除了相关的检查 在编译时自动将对应的两个类型转换一下罢了 没啥好讲的
数包装类型都继承自number类 number作为一个抽象类存在的目的就是为了被继承作为一个父类
统领所有的包装数类给他们添加了转换为基本数据类型的方法 但其实质也就是强制转换罢了 难道强制转换还不配你去学习吗
自动拆装箱不仅擦除了编译时异常 在两者出现的任何时间任何地点都做了智能处理 如时智能处理并不会拘泥于引用类型与基本数据类型为false的情况 就如string重写equals方法一样智能 自动拆装箱的存在你可以完全将integer看做int而不用担心任何事情 甚至Integer a=1;a==1时为true;看到有多智能了没
包装类的分类
- 针对八种基本数据类型相应的引用类型 - 包装类
- 有了类的特点,就可以调用类中的方法
基本数据类型 | 包装类 |
---|---|
boolean | Boolean |
char | Character |
byte | Byte |
short | Short |
int | Integer |
long | Long |
float | Float |
double | Double |
表格中后面 6 中类型都继承了 Number 类,如下图所示
包装类和基本数据的转换
装箱:基本类型 -> 包装类型,反之,拆箱
-
在 jdk5 前的手动装箱和拆箱方式
以 int 和 Integer 为例
//手动装箱 int->Integer int n1 = 100; Integer integer = new Integer(n1); // 方式一 Integer integer1 = Integer.valueOf(n1);// 方式二 //手动拆箱 //Integer -> int int i = integer.intValue()
-
jdk5(含)以后是自动装箱和拆箱
int n2 = 200;
//自动装箱 int->Integer
Integer integer2 = n2; //底层使用的是 Integer.valueOf(n2)
//自动拆箱 Integer->int
int n3 = integer2; //底层仍然使用的是 intValue()方法
包装类型和 String 类型的相互转换
以 Integer 和 String 转换为例
//包装类(Integer)->String
Integer i = 100;//自动装箱
//方式 1
String str1 = i + "";
//方式 2
String str2 = i.toString();
//方式 3
String str3 = String.valueOf(i);
//String -> 包装类(Integer)
String str4 = "12345";
Integer i2 = Integer.parseInt(str4);//使用到自动装箱
Integer i3 = new Integer(str4);//构造器
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'));//转成小写
输出结果:
-2147483648
2147483647
false
true
false
true
false
A
a
Integer 类面试题
Integer i = new Integer(1);
Integer j = new Integer(1);
System.out.println(i == j); //False
因为是 new 出来的,==
比较的是两个是否为同一个对象,故此题为错
Integer m = 1; //底层 Integer.valueOf(1); -> 阅读源码
Integer n = 1;//底层 Integer.valueOf(1);
System.out.println(m == n); // True
Integer x = 128;//底层 Integer.valueOf(1);
Integer y = 128;//底层 Integer.valueOf(1);
System.out.println(x == y);// False
关于上面两个结果,必须要阅读源码
public static Integer valueOf(int i) {
if (i >= IntegerCache.low && i <= IntegerCache.high)
return IntegerCache.cache[i + (-IntegerCache.low)];
return new Integer(i);
}
如果 i 在 IntegerCache.low(-128) ~ IntegerCache.high(127),就直接从数组返回
注意:IntegerCache.cache[]里存的值为 -128 ~ 127
如果不在 -128~127,就直接 new Integer()
//示例一
Integer i1 = new Integer(127);
Integer i2 = new Integer(127);
System.out.println(i1 == i2);//F
//示例二
Integer i3 = new Integer(128);
Integer i4 = new Integer(128);
System.out.println(i3 == i4);//F
//示例三
Integer i5 = 127;//底层 Integer.valueOf(127)
Integer i6 = 127;//-128~127
System.out.println(i5 == i6); //T
//示例四
Integer i7 = 128;
Integer i8 = 128;
System.out.println(i7 == i8);//F
//示例五
Integer i9 = 127; //Integer.valueOf(127)
Integer i10 = new Integer(127);
System.out.println(i9 == i10);//F,第 18 行是 cache 数组里的,19 行是 new 的,肯定不是同一个对象
//示例六
Integer i11=127;
int i12=127;
//只有有基本数据类型,判断的是值是否相同
System.out.println(i11==i12); //T
//示例七
Integer i13=128;
int i14=128;
System.out.println(i13==i14);//T
String🚩
String 类的介绍
-
String 对象用于保存字符串,也就是一组字符序列
-
字符串常量对象是用双引号括起的字符序列
-
字符串的字符使用 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 可以串行化:可以在网络传输】,接口 Comparable【String 对象可以比较大小】
-
String 是 final 类,不能被其它类继承
-
String 有属性 private final char value[];用于存放字符串内容(String 底层是用 char 数组实现的)
千万注意:value 是一个 final 类型,不可以修改:即 value 不能指向新的地址,但是单个字符内容是可以变化的
final char[] value = {'a','b','c'}; char[] v2 = {'t','o','m'}; value[0] = 'H'; //value = v2; 不可以修改 value 地址
-
创建 String 对象的两种方式
- 直接赋值:String s = “bestpig”
- 调用构造器 String s2 = new String(“bestpig”)
以上两种方式的区别:第一种是先从常量池中查看是否有 “bestpig” 数据空间,如果有,直接指向;如果没有,则重新创建,然后再指向。s 最终指向的是常量池的空间地址。第二种是先在堆中创建空间,里面维护了 value 属性,value 再指向常量池的 “bestpig” 空间。如果常量池中没有 “bestpig”,重新创建;如果有,直接通过 value 指向。
内存分布图:
判断下面代码的对错
String a = "abc";
String b = "abc";
System.out.println(a.equals(b)); //T
System.out.println(a == b; //T
String a = new String("abc");
String b = new String("abc");
System.out.println(a.equals(b)); //T
System.out.println(a == b); //F
System.out.println(a == b.intern()); //T
System.out.println(b == b.intern()); //F
知识点:当调用 intern 方法时,如果池已经包含一个等于此 String 对象的字符串(用 equals(Object) 方法确定),则返回池中的字符串。否则,将此 String 对象添加到池中,并返回此 String 对象的引用。即 b.intern() 方法最终返回的是常量池的地址(对象)。
String s1 = "bsetpig"; // 指向常量池 “bestpig”
String s2 = "java"; // 指向常量池 “java”
String s4 = "java"; // 指向常量池 "java"
String s3 = new String("java"); // 指向堆中对象
System.out.println(s2 == s3); //F
System.out.println(s2 == s4); //T
System.out.println(s2,equals(s3)); //T
System.out.println(s2 == s2);// F
Person p1 = new Person();
p1.name = "bestpig";
Person p2 = new Person();
p2.name = "bestpig";
System.out.println(p1.name.equals(p2.name)); // T
System.out.println(p1.name == p2.name);// T,二者都指向 "bestpig"
System.out.println(p1.name == "bestpig");// T
字符串的特性
- String 是一个 final 类,代表不可变的字符序列
- 字符串是不可变的。一个字符串对象一旦被分配,其内容是不可变的。(就是说在常量池中创建了字符串 “bestpig”,创建了之后就不可以更改了)
问:以下语句创建了几个对象?画出内存布局图
String s1 = "bestpig";
s1 = "pig1";
创建了两个对象
String a = "best" + "pig";
创建了几个对象?
千万注意:不要认为创建了 “best” 、“pig”、“bestpig” 三个对象
创建了一个对象,编译器不是傻子,会做一个优化,判断创建的常量池对象,是否有引用指向,上式中的 “best” 和 “pig” 都没有被引用。故上式等价于‘
String a = "bestpig";
String a = "best";
String b = "pig";
String c = a + b;
创建了几个对象?画出内存图。关键就是要分析 String c = a + b;
是如何执行的
答:一共有 3 个对象
debug可知 String c = a + b;
的执行过程是
// 1.
StringBuilder sb = new StringBuilder();
// 2.
sb.append("best");
// 3.
sb.append("pig");
// 4.
sb.toString()
千万注意:第 4 步的 toString() 方法就是在堆中 new 了一个对象,所以内存图如下
强烈建议:
String s = "best" + "pig";
常量相加,看的是池
String s = a + b;
变量相加,是在堆中
下列程序运行额结果是什么,尝试画出内存布局图
public class Test{
String str = new String("pig");
final char[] ch = {'j', 'a', 'v', 'a'};
public void change(String str, char ch[]){
str = "java";
ch[0] = 'h';
}
public static void main(String[] args){
Test ex = new Test();
ex.change(ex.str, ex.ch);
System.out.print(ex.str + "and");
System.out.print(ex.ch);
}
}
执行一个方法会创建一个栈,执行完之后会销毁
数组是放在堆里的
ex.str 是指向 value 的,所以 change 方法里的 str 也是指向 value
执行结果:
pig and hava
String 常用方法
方法 | 说明 |
---|---|
equals | 区分大小写,判断内容是否相等 |
equalslgnoreCase | 忽略大小写的判断内容是否相等 |
length | 获取字符的个数,字符串长度 |
indexOf | 获取字符在字符串中第1次出现的索引,找不到返回 -1 |
lastInedxOf | 获取字符在字符串中最后1次出现的索引, |
substring | 截取指定范围的字串 |
trim | 去前后空格 |
charAt | 获取某索引处的字符 |
toUpperCase | |
toLowerCase | |
concat | |
replace | 替换字符串中的字符 |
split | 分割字符串,对于某些分割字符,需要转义 |
compareTo | |
toCharArray | 转换成字符数组 |
format | 格式字符串,%s字符串、%c字符、%d整型 |
StringBuffer🚩
StringBuffer介绍
-
StringBuffer 代表可变的字符序列,可以对字符串内容进行增删
-
很多方法与 String 相同,但 StringBuffer 是可变长度的
-
StringBuffer 是一个容器
-
StringBuffer 实现了 Serializable,即 StringBuffer 的对象可以串行化
-
StringBuffer 是一个 final 类,不能被继承
-
StringBuffer 的直接父类是 AbstractStringBuffer,在父类中 AbstractStringBuffer 有属性 char[] value,不是 final,该 value 数组存放字符串内容,是存放在堆中的
-
String 保存的是字符串常量,里面的值不能更改,每次 String 类的更新实际上就是更改地址,效率低。StringBuffer 保存的是字符串变量,里面的值可以更改(因为 char[] value 是放在堆中的)。
String 和 StringBuffer 相互转换
String 👉 StringBuffer
String str = "bestpig";
- 使用构造器
StringBuffer stringBuffer = new StringBuffer();
- 使用的是 append 方法
StringBuffer stringBuffer1 = new StringBuffer();
stringBuffer1 = stringBuffer1.append(str)
StringBuffer → String
StringBuffer stringBuffer3 = new StringBuffer("bestpig")
- 使用 StringBuffer 提供的 toString() 方法
String s = stringBuffer3.toString
- 使用构造器
String s1 = new String(stringBuffer3)
StringBuffer 常用方法
- 增 append
- 删 delete(start,end)
- 改 replace(start,end,string)
- 查 indexOf
- 插 insert
- 获取长度 length
StringBuilder🚩
基本介绍:
- StringBuilder 继承 AbstractStringBuilder 类
- 实现了 Serializable,说明 StringBuilder 对象是可以串行化(对象可以网络传输。可以保存到文件)
- StringBuilder 是 final 类,不能被继承
- StringBuilder 对象字符序列仍然是存放在其父类StringBuilder 的 char[] vlaue,因此字符序列是在堆中
- StringBuilder 方法没有做互斥的处理,即没有 synchronized 关键字,因此在单线程的情况下使用 StringBuilder
String、StringBuffer、StringBuilder 比较
-
StringBuilder 和 StringBuffer 非常类似,均代表可变的字符序列,而且方法也一样
-
String:不可变字符序列,效率低,但是复用率高
-
StringBuffer:可变字符序列,效率较高(增删),线程安全
-
StringBuilder:可变字符序列,效率最高,线程不安全
-
String 使用说明:
String s = "a"; s += "b";
执行
s += "b";
时,实际上原来的 “a” 字符串对象已经丢弃了,现在又产生了一个字符串 s + “b”(也就是 “ab”)。如果多次执行这些改变串内容的操作,会导致大量副本字符串对象存留在内存中,降低效率。如果这样的操作放到循环中,会极大影响程序的性能。故如果我们对 String 做大量修改,不要使用 String
三者的选择:
- 如果字符串存在大量的修改操作,一般使用 StringBuffer 或 StringBuilder
- 如果字符串存在大量的修改操作,并在单线程的情况,使用 StringBuilder
- 如果字符串存在大量的修改操作,并在多线程的情况,使用 StringBuffer
- 如果字符串很少修改,被多个对象引用,使用 String,比如配置信息等
Math类
Math 类包含用于执行基本数学运算的方法,如初等指数、对数、平方根和三角函数
abs | 绝对值 |
pow | 求幂 |
ceil | 向上取整 |
floor | 向下取整 |
sqrt | 求开方 |
random | 求随机数 |
max | 求两个数的最大值 |
min | 求两个数的最小值 |
Arrays类
Arrays 里包含了一系列静态方法,用于管理或操作数组(比如排序和搜索)
-
toString 返回数组的字符串形式
Arrays.toString()
-
sort 排序
-
binarySearch 通过二分搜索法进行查找,要求必须排好序
int index = Arrays.binarySearch(arr, 3);
-
copyOf 数组元素的复制
Integer[] newArr = Arrays.copyOf(arr, arr.length)
-
fill 数组元素的填充
Integer[] num = new Integer[]{9,3,2}
Arrays.fill(num,99)
-
equals 比较两个数组元素内容是否完全一致
boolean equals = Arrays.equals(arr, arr2)
-
asList 将一组值转换成 list
List<Integer> asList = Arrays.asList(2,3,4,5,6)
System类
system 类常见方法
- exit 退出当前程序
- arraycopy:复制数组元素,比较适合底层调用,一般使用 Arrays.copyOf 完成数组赋值
- currentTimeMillens:返回当前时间距离1970-1-1的毫秒数
- gc:运行垃圾回收机制
BigInteger 和 BigDecimal类
应用场景:
- BigInteger 适合保存比较大的整型
- BigDecimal 适合保存精度更高的浮点型(小数)
BigInteger 和 BigDecimal 常用方法
- add 加
- subtract 减
- multiply 乘
- divide 除
日期类
第一代日期类
-
Date:精确到毫秒,代表特定的时间
Date d1 = new Date(); System.out.println(d1);
输出的格式为
Thu Dec 08 18:40:15 CST 2022
-
SimpleDateFormat :格式和解析日期的类,SimpleDateFormat 格式化和解析日期的具体类。它允许进行格式化(日期 -> 文本)、解析(文本 -> 日期)和规范化
SimpleDateFormat sdf = new SimpleDateFormat("yyyy 年 MM 月 dd 日 hh:mm:ss E"); String format = sdf.format(d1); // format:将日期转换成指定格式的字符串 System.out.println("当前日期=" + format);
当前日期=2022 年 12 月 08 日 06:42:56 周四
把一个格式化的 String 转成对应的 Date
String s = "1996 年 01 月 01 日 10:20:30 星期一"; Date parse = sdf.parse(s); System.out.println("parse=" + sdf.format(parse));
parse=1996 年 01 月 01 日 10:20:30 周一
第二代日期类
第二代日期类主要就是 Calendar
Calendar 是一个抽象类,并且构造器是 private,可以通过 getInstance()类获取
Calendar c = Calendar.getInstance(); //创建日历类对象//比较简单,自由
System.out.println("c=" + c);
//2.获取日历对象的某个日历字段
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.MINUTE));
System.out.println("秒:" + c.get(Calendar.SECOND));
//Calender 没有专门的格式化方法,所以需要程序员自己来组合显示
System.out.println(c.get(Calendar.YEAR) + "-" + (c.get(Calendar.MONTH) + 1) + "-" +
c.get(Calendar.DAY_OF_MONTH) +
" " + c.get(Calendar.HOUR_OF_DAY) + ":" + c.get(Calendar.MINUTE) + ":" + c.get(Calendar.SECOND) );
如果我们需要按照 24 小时进制来获取时间, Calendar.HOUR ==改成=> Calendar.HOUR_OF_DAY
第三代日期类🚩
LocalDate(日期/年月日)
LocalTime(时间/时分秒)
LocalDateTime(日期时间/年月日时分秒)
DateTimeFormatter 格式日期类
//1. 使用 now() 返回表示当前日期时间的 对象
LocalDateTime ldt = LocalDateTime.now(); //LocalDate.now();//LocalTime.now()
System.out.println(ldt);
//2. 使用 DateTimeFormatter 对象来进行格式化
// 创建 DateTimeFormatter 对象
DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
String format = dateTimeFormatter.format(ldt);
System.out.println("格式化的日期=" + format);
System.out.println("年=" + ldt.getYear());
System.out.println("月=" + ldt.getMonth());
System.out.println("月=" + ldt.getMonthValue());
System.out.println("日=" + ldt.getDayOfMonth());
System.out.println("时=" + ldt.getHour());
System.out.println("分=" + ldt.getMinute());
System.out.println("秒=" + ldt.getSecond());
时间戳
类似于 Date
//1.通过 静态方法 now() 获取表示当前时间戳的对象
Instant now = Instant.now();
System.out.println(now);
//2. 通过 from 可以把 Instant 转成 Date
Date date = Date.from(now);
//3. 通过 date 的 toInstant() 可以把 date 转成 Instant 对象
Instant instant = date.toInstant()
第三代日期类更多方法
- 是否为闰年
- 增加日期的某个部分
- 使用 plus 方法测试增加时间的某个部分
- 使用 minus 方法测试查看一年前和一年后的日期