Java核心类库知识目录
一、常用类的概述和使用
1、常用的包(熟悉)
1.1 java.lang-核心包
该包是Java语言的核心包,并且该包中的所有内容由Java虚拟机自动导入。
如:System类、String类
1.2 java.util-工具包
该包中里面提供了大量的工具类以及集合类。
如:Scanner类、Random类、List集合
1.3 java.io-输入输出包
该包中里面提供了大量的读写相关的类。
如:FileInputStream类、FileOutputStream类
1.4 java.net-网络包
该包中提供大量网络编程相关的类
如:ServerSocket类、Socket类
1.5 java.sql-数据包
该包中提供了大量操作数据库的类和接口
如:DriverManager类、Connection接口
2、Object类
2.1 概念
Object类是Java语言类层级的根类,即任何一个类都是该类的直接或间接子类;
如果定一个类时未使用extends关键字声明其父类,则其父类是java.lang.Object类;
Object类定义了“对象”的基本行为,被子类默认继承。
2.2 equals()(重点)
public boolean equals(Object obj)
用于判断调用对象是否与参数对象相等。
该方法默认比较俩个对象的地址是否相等,与==运算符结果一致。
若希望比较对象的内容,则需要重写该方法.
该方法被重写后,则也应该重写hasCode方法保证结果的一致性
2.3 hashCode()(重点)
public int hashCode()
用于获取调用对象的哈希码值(内存地址的编号)
若俩个对象调用equals()方法相等,则各自调用hashCode()方法的结果必须相同
若俩个对象调用equals()方法不相等,则各自调用hashCode()方法的结果应该不相同
为了使得hashCode()方法与equals()方法保持一致,equals()方法重写时,hashCode()方法也必须重写
//重写示例
//重写equals方法
@Override
public boolean equals(Object obj) {
//如果调用对象与参数对象指向同一个对象时,内容一定相同
if(this == obj) return true;
//当调用对象不为空,参数对象为空时,内容一定不相同
if(obj == null)return false;
//调用对象不为空,参数对象不为空,调用对象与参数对象不是指向一个地址时,此时判断姓名和学号属性是否都一致
if(obj instanceof Student){
Student s = (Student) obj;
return this.getId() == s.getId() && this.getName().equals(s.getName());
}
return false;
}
//重写hashCode方法,保证与equals结果一致
@Override
public int hashCode(){
final int type = 12;
return type * 31 + getId() + getName().hashCode();
}
2.4 toString()(重点)
public String toString()
用于获取调用对象的字符串形式;
该方法默认返回的字符串为:包名.类名@哈希码值的十六进制;
为了返回更有意义的数据,需要重写该方法;
使用print/println打印引用/使用字符串拼接引用都会自动调用该方法.
3、包装类(熟悉)
3.1 概念
通常情况下,基本数据类型的变量不是对象,为了满足万物皆对象的理念,需要对基本数据类型的变量进行打包封装处理变成对象,而负责将这些变量声明为成员变量进行对象化处理的相关类,叫包装类
3.2 包装类的分类
包装类 | 对应的基本类型 |
---|---|
java.lang.Byte | byte |
java.lang.Short | short |
java.lang.Integer | int |
java.lang.Long | long |
java.lang.Float | float |
java.lang.Double | double |
java.lang.Boolean | boolean |
java.lang.Character | char |
3.3 Integer类
- 基本概念
java.lang.Integer类内部包装了一个int类型的变量作为成员变量,主要用于实现对int类型的包装,并提供int类型到String类型之间的转换等方法 - 常用的常量
常量类型和名称 | 功能介绍 |
---|---|
public static final int MIN_VALUE | 表示int类型可以描述的最小值,-2^31 |
public static final int MAX_VALUE | 表示int类型可以描述的最大值,2^31-1 |
public static final int SIZE | 表示int类型采用二进制补码形式的位数 |
public static final int BYTES | 表示int类型所占的字节个数 |
public static final Class TYPE | 表示int类型的Class实例(反射用到) |
- 常用的方法
方法声明 | 功能介绍 |
---|---|
@Deprecated(since=“9”) public Integer(int value) | 根据参数指定的整数来构造对象(已过时) |
@Deprecated(since=“9”) public Integer(String s) throws NumberFormatException | 根据参数指定的字符串构造对象(已过时) |
int intValue() | 获取调用对象的整数值并返回(拆箱) |
static Integer valueOf(int i) | 根据参数指定整数值得到Integer对象(装箱) |
boolean equals(Object obj) | 比较调用对象与参数指定的对象是否相等 |
String toString() | 返回调用对象数值的字符串形式 |
static int parseInt(String s) throws NumberFormatException | 字符串转换为int类型并返回。 传入的字符串不是整数时,运行时会报java.lang.NumberFormatException |
static String toString(int i) | 返回参数指定整数的十进制字符串形式 |
static String toBinaryString(int i) | 返回参数指定整数的二进制字符串形式 |
static String toHexString(int i) | 返回参数指定整数的十六进制字符串形式 |
static String toOctalString(int i) | 返回参数指定整数的八进制字符串形式 |
-
装箱和拆箱概念
Java5发布之前,用包装类对象进行运算时,需要“装箱”和“拆箱”操作:运算前先将包装类拆分为基本数据类型,运算后再将结果封装成包装类对象。从Java5开始增加了自动装箱和拆箱的功能。
-
自动装箱池
在Integer内部提供了自动装箱池技术,将-128到127之间的整数已经装箱完毕,当程序中使用该范围之间的整数时,无需装箱直接取用自动装箱池中的对象即可,从而提高效率。
public class IntegerTest2 {
public static void main(String[] args) {
//装箱拆箱笔试考点(自动装箱池)
Integer a = 128;
Integer b = 128;
Integer c = new Integer(128);
Integer d = new Integer(128);
System.out.println("a == b " + (a == b));
System.out.println("a.equals(b) " + a.equals(b));
System.out.println("c == d " + (c == d));
System.out.println("c.equals(d)" + c.equals(d));
System.out.println("-----------------------------");
Integer a2 = 127;
Integer b2 = 127;
Integer c2 = new Integer(127);
Integer d2 = new Integer(127);
//-128-127的int整数,不会再新建Integer对象,而是直接去自动装箱池中获取即可,所以此时a2与b2获取的是同一个对象,内存地址是一样的
System.out.println("a2 == b2 " + (a2 == b2));
System.out.println("a2.equals(b2) " + a2.equals(b2));
System.out.println("c2 == d2 " + (c2 == d2));
System.out.println("c2.equals(d2)" + c2.equals(d2));
}
}
运行结果:
3.4 Double类
- 基本概念
java.lang.Double类内部包装了一个double类型的变量作为成员变量,主要用于实现对double类型的包装,并提供double类型到String类型之间的转换等方法 - 常用的常量
常量类型和名称 | 功能介绍 |
---|---|
public static final int BYTES | 表示double类型的字节个数 |
public static final int SIZE | 表示double类型的二进制位数 |
public static final Class TYPE | 表示double类型的Class实例(反射用到) |
- 常用的方法
方法声明 | 功能介绍 |
---|---|
Double(double value) | 根据参数指定的浮点数来构造对象(已过时) |
Double(String s) | 根据参数指定的字符串构造对象(已过时) |
double doubleValue() | 获取调用对象的浮点数据并返回(拆箱) |
static Double valueOf(double d) | 将浮点数据转换为Double对象(装箱) |
boolean equals(Object obj) | 比较调用对象与参数对象是否相等 |
String toString() | 返回调用对象的字符串形式 |
static double parseDouble(String s) | 将字符串转换为double类型并返回 |
boolean isNaN() | 判断调用对象的数值是否为非数字 |
- 扩展
java.lang.Number是个抽象类,是Byte、Short、Integer、Long、Float、Double等类型的父类,描述所有类共有的成员
3.5 Boolean类
- 基本概念
java.lang.Boolean类内部包装了一个boolean类型的变量作为成员变量,主要用于实现对boolean类型的包装,并提供boolean类型到String类型之间的转换等方法 - 常用的常量
常量类型和名称 | 功能介绍 |
---|---|
static Boolean FALSE | 对应基值为false的对象 |
static Boolean TRUE | 对应基值为true的对象 |
static Class TYPE | 表示boolean类型的Class实例 |
- 常用方法
方法声明 | 功能介绍 |
---|---|
Boolean(boolean value) | 根据参数指定的boolean类型构造对象(已过时) |
Boolean(String s) | 根据参数指定的字符串构造对象(已过时) |
boolean booleanValue() | 获取调用对象的boolean值并返回(拆箱) |
valueOf(boolean b) | 将boolean类型转换为Boolean类型对象(装箱) |
boolean equals(Object obj) | 比较调用对象与参数对象是否相等 |
String toString() | 返回调用对象的字符串形式 |
static boolean parseBoolean(String s) | 将字符串转换为boolean类型并返回 |
3.6 Character类
- 基本概念
java.lang.Character类内部包装了一个char类型的变量作为成员变量,主要用于实现对char类型的包装,并提供char类型到String类型之间的转换等方法 - 常用的常量
常量类型和名称 | 功能介绍 |
---|---|
static int BYTES | 表示char类型的字节数 |
static int SIZE | 表示char类型的二进制位数 |
static Class TYPE | 表示char类型的Class实例 |
- 常用方法
方法声明 | 功能介绍 |
---|---|
Character(char value) | 根据参数指定的字符串构造对象(已过时) |
char charValue() | 获取调用对象的字符数据并返回(拆箱) |
static Character valueOf(char c) | 将char类型转换为Character类型(拆箱) |
boolean equals(Object obj) | 比较调用对象与参数对象是否相等 |
String toString() | 返回调用对象的字符串形式 |
static boolean isUpperCase(char ch) | 判断是否为大写字符 |
static boolean isLowerCase(char ch) | 判断是否为小写字符 |
static boolean isDigit(char ch) | 判断是否为数字字符 |
static char toUpperCase(char ch) | 将参数字符转换为大写字符 |
static char toLowerCase(char ch) | 将参数字符转换为小写字符 |
3.7 包装类的使用总结
-
基本数据类型转换为包装类的方式
(1) 包装类的构造方法
(2) 包装类的静态的valueOf()方法 -
获取包装类的基本数据类型的方式
(1)包装类对象的xxxValue()方法 -
字符串转换为基本数据类型的方式
(1)包装类的静态parseXxx()方法
4、常用的数学处理类(熟悉)
4.1 Math类
- 基本概念
主要用于提供执行数学运算的方法,如对数,平方根; - 常用方法
方法声明 | 功能介绍 |
---|---|
static int max(int a, int b) | 返回俩个参数中最大值 |
static int min(int a, int b) | 返回俩个参数中最小值 |
static double pow(double a, double b) | 返回第一个参数的幂 |
static int abs(int a) | 返回参数数值的绝对值 |
static long round(double a) | 返回参数四舍五入的结果 |
static double sqrt(double a) | 返回参数的平方根 |
static double random() | 返回0.0 - 1.0 的随机数 |
4.2 BigDecimal类
- 基本概念
由于float和double类型运算是可能会有误差,希望精准运算,则借助java.math.BigDecimal类 - 常用方法
方法声明 | 功能介绍 |
---|---|
BigDecimal(String val) | 根据参数指定字符串构造对象 |
BigDecimal add(BigDecimal augend) | 调用对象数值 + 参数对象数值 |
BigDecimal subtract(BigDecimal subtrahend) | 调用对象数值 - 参数对象数值 |
BigDecimal multiply(BigDecimal multiplicand) | 调用对象数值 * 参数对象数值 |
BigDecimal divide(BigDecimal divisor) | 调用对象数值 / 参数对象数值 结果除不尽时,会报java.lang.ArithmeticException异常,需要传入舍入模式RoundingMode |
4.3 BigInteger类
- 基本概念
如果希望表示比long类型范围还大的整数数据,则需要借助java.math.BigInteger类 - 常用方法
方法声明 | 功能介绍 |
---|---|
BigInteger(String val) | 根据参数指定字符串构造对象 |
BigInteger add(BigInteger val) | 加法 |
BigInteger subtract(BigInteger val) | 减法 |
BigInteger multiply(BigInteger val) | 乘法 |
BigInteger divide(BigInteger val) | 除法(取模) |
BigInteger remainder(BigInteger val) | 取余 |
BigInteger[] divideAndRemainder(BigInteger val) | 取模和余数 |
二、String类的概述和使用
1、概念(重点)
- java.lang.String 用于描述字符串,Java程序中所有的字符串字面值都可以使用该类的对象描述
- 该类由final修饰,不能被继承
- 从jdk1.9开始,该类的底层不再使用char[]存储数据,而是改成byte[] 加上编码标记,从而节约了一些空间。
- 该类描述的字符串内容是个常量,不可更改,因此可被共享使用
String s = "abc"; //"abc"是个字符串常量,不可更改
s = "123"; //重新赋值,只是将"123"字符串常量的地址指向变量s,并没有修改s原指向的对象"abc"的内容
//字符串内容不存在修改一说,因为俩个不相等的字符串是属于俩个字符串对象,表面看似修改了字符串内容,实际是指向了一个新的字符串对象地址
2、常量池(重点)
由于String类型描述的字符串内容是常量不可改变,因此Java虚拟机将首次出现的字符串放入常量池中(方法区),若后续代码中出现了相同的字符串内容,则直接使用池中已有的字符串对象,而无需申请内存及创建对象,从而提高了性能。
3、常用的构造方法(重点)
方法声明 | 功能介绍 |
---|---|
String() | 使用无参方式构造对象得到空字符串序列 |
String(byte[] bytes, int offset, int length) | 使用bytes数组下标从offset位置开始的length个字节来构造对象 |
String(byte[] bytes) | 使用bytes数组的所有内容构造对象 |
String(char[] value, int offset, int count) | 使用value数组下标从offset位置开始的count字符来构造对象 |
String(char[] value) | 使用value数组中的所有内容构造对象 |
String(String original) | 根据参数的字符串创建对象,新创建的对象为参数对象的副本 |
4、常用的成员方法(重点)
方法声明 | 功能介绍 |
---|---|
byte[] getBytes() | 将字符串转换为byte数组并返回 |
char[] toCharArray() | 将字符串转换为char数组并返回 |
char charAt(int index) | 返回字符串指定位置的字符 |
String toString() | 返回字符串本身 |
int length() | 返回字符串的长度 |
boolean isEmpty() | 判断字符串是否为空 |
- 练习案例
判断字符串“上海自来水来自海上”是否为回文并打印,回文是指从左到右和从右到左都是相同的句子
public class StringHuiWenTest {
public static void main(String[] args) {
String s = "上海自来水来自海上";
String s2 = "我爱你也爱我";
if(verifyHuiWen(s2)){
System.out.println(s2 + " 是回文!");
}else{
System.out.println(s2 + " 不是回文!");
}
}
public static boolean verifyHuiWen(String s){
int len = s.length();
for(int i = 0; i < len/2; i++){
//判断字符串中从前到后与从后向前位数相同时对应下标的字符是否相等
if(s.charAt(i) != s.charAt(len - i - 1)){
return false;
}
}
return true;
}
}
方法声明 | 功能介绍 |
---|---|
int compareTo(String anotherString) | 用于比较调用对象和参数对象的大小关系 |
int compareToIgnoreCase(String str) | 不考虑大小写,比较字符串对象的大小 |
- 案例题目
判断字符串之间大小的比较并打印
public class StringCompareTest {
public static void main(String[] args) {
String s = "hello";
System.out.println(s.compareTo("world")); // 'h' - 'w' => 104 - 119 => -15
System.out.println(s.compareTo("haha")); // 'e' - 'a' => 101 - 97 => 4
System.out.println(s.compareTo("hele")); // 'l' - 'e' => 104 - 101 => 7
System.out.println(s.compareTo("heihei")); // 'l' - 'i' => 108 - 105 => 3
System.out.println(s.compareTo("helloworld"));//长度:5 - 10 => -5
System.out.println(s.compareTo("HELLO")); // 'h' - 'H' => 104 - 72 => 32
System.out.println(s.compareToIgnoreCase("HELLO")); //0
}
}
方法声明 | 功能介绍 |
---|---|
String concat(String str) | 字符串的拼接 |
boolean contains(CharSequence s) | 判断当前对象是否包含参数指定内容 |
String toLowerCase() | 返回字符串的小写形式 |
String toUpperCase() | 返回字符串的大写形式 |
String trim() | 返回去掉前导和后继空白的字符串 |
boolean startsWith(String prefix) | 判断当前字符串是否以参数指定字符串开头 |
boolean startsWith(String prefix, int toffset) | 当前字符串从指定位置开始,是否以参数指定字符串开头 |
boolean endsWith(String suffix) | 判断当前字符处是否以指定字符串结尾 |
public class StringManyMethodsTest {
public static void main(String[] args) {
String s = "hello";
String s2 = "world";
String s3 = " hello girl ";
String s4 = "I Love You";
System.out.println(s.concat(s2)); //helloworld
System.out.println(s3.contains(s)); //true
System.out.println(s3.toUpperCase()); // HELLO GIRL
System.out.println(s4.toLowerCase()); //i love you
System.out.println(s3.trim()); //hello girl
System.out.println(s4.startsWith("I")); //true
System.out.println(s4.startsWith("Love",2)); //true
System.out.println(s4.endsWith("u")); //true
}
}
方法声明 | 功能介绍 |
---|---|
boolean equals(Object anObject) | 比较字符串内容是否相等 |
int hashCode() | 获取调用对象的哈希码值 |
boolean equalsIgnoreCase(String anotherString) | 不考虑大小写,比较字符串是否相等 |
- 案例题目
提示用户键盘输入用户名和密码信息,输入”admin“和密码”123456“,则提示”登录成功“,否则提示“用户名或密码输入错误,您还有n次机会”,输入三次后依然错误,则提示”账号已冻结“。
import java.util.Scanner;
public class StringLoginTest {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
for(int i = 1; i <= 3; i++) {
System.out.println("请输入用户名");
String username = sc.next();
System.out.println("请输入密码");
String password = sc.next();
if("admin".equals(username) && "123456".equals(password)){
System.out.println("登录成功!");
break;
}
if(i == 3){
System.out.println("已冻结!");
continue;
}
System.out.println("用户名或密码输入错误,剩余输入次数" + (3 - i) + "次");
}
}
}
方法声明 | 功能介绍 |
---|---|
int indexOf(int ch) | 用于返回当前字符串对象中参数ch指定字符第一次出现的下标 |
int indexOf(int ch, int fromIndex) | 用于从fromIndex开始查找指定字符所在下标 |
int indexOf(String str) | 检索当前字符串对象中,参数字符串第一次出现的下标 |
int indexOf(String str, int fromIndex) | 从fromIndex下标开始,参数字符串第一次出现的下标 |
int lastIndexOf(int ch) | 用于返回参数ch指定字符第一次出现的下标 |
int lastIndexOf(int ch, int fromIndex) | 从fromIndex下标开始,参数指定字符最后一次出现的下标 |
int lastIndexOf(String str) | 参数字符串最后一次出现的下标 |
int lastIndexOf(String str, int fromIndex) | 从fromIndex下标开始,参数指定字符串最后一次出现的下标 |
- 案例题目
编写通用代码可以查询字符串"Good Good Study,Day Day Up!"中所有"Day"出现的位置并打印
public class StringIndexOfTest {
public static void main(String[] args) {
String s = "Day Good Good Study,Day Day Up! Day";
show(s);
System.out.println("---------");
show2(s);
}
//优化前方法
public static void show(String str){
int index = 0;
while (index >= 0){
index = str.indexOf("Day",index);
if(index >= 0){
System.out.println("下标 = " + index);
index++;
}
}
}
//优化后方法
public static void show2(String str){
int fromIndex = 0;
while((fromIndex = str.indexOf("Day", fromIndex)) != -1){
System.out.println("下标 = " + fromIndex);
fromIndex += "Day".length();
}
}
}
//下标 = 0
//下标 = 20
//下标 = 24
//下标 = 32
//---------
//下标 = 0
//下标 = 20
//下标 = 24
//下标 = 32
方法声明 | 功能介绍 |
---|---|
String substring(int beginIndex) | 返回字符串中从下标beginIndex下标开始(包含开始)到字符串结尾的字符串 |
String substring(int beginIndex, int endIndex) | 返回字符串中从下标beginIndex开始(包含开始),到下标endIndex(不包含)结束的子字符串 |
- 案例题目
提示用户从键盘输入一个字符串和一个字符,输出该字符(不包含)后面的所有的子字符串
import java.util.Scanner;
public class StirngSubStringTest {
public static void main(String[] args) {
show();
}
public static void show(){
Scanner sc = new Scanner(System.in);
System.out.println("请输入一个字符串:");
String str = sc.next();
System.out.println("请输入一个字符:");
String c = sc.next();
System.out.println(str.substring(str.indexOf(c) + 1));
}
}
5、正则表达式的概念和使用
5.1 正则表达式的概念(了解)
- 正则表达式本质就是一个规则"字符串",可以用于对字符串数据的格式进行验证,以及匹配,替换, 查找等操作。
- 该字符串通常使用^运算符作为开头,$运算符作为结尾,当然也可以省略
5.2 正则表达式常用规则(了解)
正则表达式 | 说明 |
---|---|
[abc] | 可以出现a、b、c中任意一个字符 |
[^abc] | 可以出现除a、b、c以外的任意字符 |
[a-z] | 可以出现a-z中的任意字符 |
[a-zA-Z0-9] | 可以出现a-z、A-Z、0-9中任意一个字符 |
正则表达式 | 说明 |
---|---|
. | 任意一个字符(通常不包含换行符) |
\d | 任意一个数字字符,相当于[0-9] |
\D | 任意一个非数字字符 |
\s | 空白字符,相当于[\t\n\x0B\f\r] 对应:制表符、换行符、垂直制表符、换页符、回车不换行符 |
\S | 非空白字符 |
\w | 任意一个单词字符,相当于[a-zA-Z_0-9] |
\W | 任意一个非单词字符 |
正则表达式 | 说明 |
---|---|
注意 | X表示上方的任意一个规则 |
X? | 表示X可以出现0-1次 |
X* | 表示X可以出现0-n次 |
X+ | 表示X可以出现1-n次 |
X{n} | 表示X可以出现恰好n次 |
X{n,} | 表示X可以出现至少n次,即 n <= 实际次数 |
X{n,m} | 表示X可以出现至少n次,至多m次,即 n <= 实际次数 <= m |
5.3 正则表达式相关的方法(熟悉)
方法声明 | 功能介绍 |
---|---|
boolean matches(String regex) | 判断当前字符串对象是否满足参数指定的正则表达式规则 |
- 案例题目
1). 使用正则表达式描述银行卡密码的规则:6位数字组成
2). 使用正则表达式描述QQ号码的规则:非0开头的5-15位数字
3). 描述手机号码的规则:1开头,第二位是3、4、5、7、8中一位,总共11位
4). 描述身份证号码规则:总共18位,6位数字代表地区,4位数字代表年,2位数字代表月,2位数字代表日期,3位数字代表个人,最后一位可能是数字也可能是X
import java.util.Scanner;
public class StringRegexTest {
public static void main(String[] args) {
judgePassword();
judgeQQNumber();
judgePhoneNumber();
judgeIDCardNumber();
}
/**
* 描述银行卡密码,6位数字组成
*/
public static void judgePassword(){
String regex = "[0-9]{6}";
//String regex = "\\d{6}"; //等价于[0-9]
Scanner sc = new Scanner(System.in);
while(true) {
System.out.println("请输入6位数字密码");
String password = sc.next();
if (password.matches(regex)) {
System.out.println("银行卡密码格式正确!");
break;
} else {
System.out.println("银行卡密码格式错误");
}
}
}
/**
* 描述QQ号码,非0开头的5-15位数字
*/
public static void judgeQQNumber(){
//String regex = "[^0][0-9]{4,14}";
//String regex = "[^0]\\d{4,14}";
//String regex = "[1-9][0-9]{4,14}";
String regex = "[1-9]\\d{4,14}";
Scanner sc = new Scanner(System.in);
while(true) {
System.out.println("请输入您的QQ号码");
String password = sc.next();
if (password.matches(regex)) {
System.out.println("QQ号码格式正确!");
break;
} else {
System.out.println("QQ号码格式错误");
}
}
}
/**
* 描述手机号,1开头,第二位是3、4、5、7、8中一位,总共11位
*/
public static void judgePhoneNumber(){
String regex = "1[34578]\\d{9}";
Scanner sc = new Scanner(System.in);
while(true) {
System.out.println("请输入11位手机号码");
String password = sc.next();
if (password.matches(regex)) {
System.out.println("手机号码格式正确!");
break;
} else {
System.out.println("手机号码格式错误");
}
}
}
/**
* 描述身份证号码,总共18位,6位数字代表地区,
* 4位数字代表年,2位数字代表月,2位数字代表日期,3位数字代表个人,最后一位可能是数字也可能是X
*/
public static void judgeIDCardNumber(){
String regex = "(\\d{6})(\\d{4})([01]\\d)([0-3]\\d)(\\d{4})[0-9X]";
Scanner sc = new Scanner(System.in);
while(true) {
System.out.println("请输入身份证号码");
String password = sc.next();
if (password.matches(regex)) {
System.out.println("身份证号码格式正确!");
break;
} else {
System.out.println("身份证号码格式错误");
}
}
}
}
方法名称 | 方法说明 |
---|---|
String[] split(String regex) | 以参数指定的正则表达式所表示的字符串作为分隔符,将调用的字符串对象拆分为字符串数组 |
String replace(char oldChar, char newChar) | 使用参数中newChar替换字符串中所有oldChar |
String replaceFirst(String regex, String replacement) | 用replacement替换当前字符串对象中匹配正则表达regex式的第一个子字符串 |
String replaceAll(String regex, String replacement) | 将字符串中所有匹配正则表达式regex的子字符串全部替换为replacement |
public class StringRegMethodTest {
public static void main(String[] args) {
//1、split分割方法
String info = "张飞,132,40";
String[] strArr = info.split(",");
for(int i = 0; i < strArr.length; i++){
System.out.println(strArr[i]);
}
System.out.println("--------------------------");
//2、replace方法
String s = "我喜欢你,你愿意么";
System.out.println(s.replaceAll("你","我"));
System.out.println("--------------------------");
//3、replaceFirst方法
//将出现的第一个数字替换为#
String s2 = "d123hfjhehafj8273";
System.out.println(s2.replaceFirst("\\d","#"));
System.out.println("--------------------------");
//4、将所有数字转换为#
String s3 = "1243hhhfga2342";
System.out.println(s3.replaceAll("\\d", "#"));
//将手机号4-7位隐藏
String s4 = "13456451623";
System.out.println(s4.replaceAll("(\\d{3})(\\d{4})(\\d{4})","$1****$2"));
}
}
6、String类的笔试考点(重点)
public class StringExamTest {
public static void main(String[] args) {
//笔试考点1、下面代码会创建几个对象,分别在什么位置
String s1 = "abc"; //创建1个对象,存放在常量池中
String s2 = new String("hello"); //创建2个对象,1个存放在常量池,一个存放在堆区
//笔试考点2、常量池和堆区对象的比较
String s3 = "world";
String s4 = "world";
String s5 = new String("world");
String s6 = new String("world");
System.out.println(s3 == s4); //比较地址 true
System.out.println(s3.equals(s4)); //比较内容 true
System.out.println(s5 == s6); //比较地址 false
System.out.println(s5.equals(s6)); //比较内容 true
System.out.println("-------------------------");
//笔试考点3、常量有优化机制
String str1 = "helloworld";
String str2 = "hello" + "world"; //常量优化机制 : "helloworld"
System.out.println(str1 == str2); //比较地址 true
String str3 = "hello";
String str4 = str3 + "world";
System.out.println(str1 == str4); //比较地址 false
final String str5 = "hello";
String str6 = str5 + "world"; //str5此时属于常量,编译时有常量优化
System.out.println(str1 == str6); //比较地址 true
}
}
public class StringCharTest {
public static void main(String[] args) {
String s = "hello";
//判断字符串是否为空
System.out.println(0 == s.length() ? "字符串为空" : "字符串不为空");
System.out.println(s.isEmpty());
System.out.println("---------------------------------");
//笔试考点1:使用2种方式实现:字符串"12345"转换为整数12345
String s5 = "13575";
//方式一:使用Integer类的parseInt方法
int is = Integer.parseInt(s5);
System.out.println(is);
//方式二:使用ASCII码转换
int is2 = 0;
for(int i = 0; i < s5.length(); i++){
is2 = is2 * 10 + (s5.charAt(i) - '0');
System.out.println(is2);
}
//笔试考点2:实现整数转换为字符串
int ia = 12345;
//方式一:String类的valueOf方法
String s2 = String.valueOf(ia);
System.out.println(s2);
//方式二:直接拼接(推荐)
String s3 = "" + ia;
System.out.println(s3);
}
}
public class StringExamTest2 {
public static void main(String[] args) {
String s = "hello";
String s2 = new String("hello");
s2.intern();//该方法会返回字符串在常量池中的地址
System.out.println(s == s2);
}
}
//false
三、可变字符串类和日期相关类(熟悉)
1、可变字符串类(重点)
1.1 基本概念
- 由于String类描述的字符串内容是个常量,不可变,当需要在Java中需要描述大量类似的字符串时,只能单独申请和存储,此时会造成内存空间的浪费。
- 为解决上述问题,可使用java.lang.StringBuilder类和java.lang.StringBuffer类来描述字符串序列可以改变的字符串
- StringBuffer从jdk1.0开始存在,属于线程安全的类,因此效率较低
- StringBuilder从jdk1.5开始存在,属于非线程安全的类,效率较高
1.2 StringBuilder类常用构造方法
方法声明 | 功能介绍 |
---|---|
StringBuilder() | 使用无参方式构造对象,,容量为16 |
StringBuilder(int capacity) | 根据参数指定容量构造对象 |
StringBuilder(String str) | 根据参数指定字符串构造对象,容量为16+字符串长度 |
public class StringBuilderTest {
public static void main(String[] args) {
//1、使用无参方式构造对象
StringBuilder stringBuilder = new StringBuilder();
System.out.println("字符串内容 = " + stringBuilder.toString());
System.out.println("字符串容量 = " + stringBuilder.capacity());
System.out.println("字符串长度 = " + stringBuilder.length());
System.out.println("----------------------------------");
//2、根据参数指定容量构造对象
StringBuilder stringBuilder1 = new StringBuilder(20);
System.out.println("字符串内容 = " + stringBuilder1.toString());
System.out.println("字符串容量 = " + stringBuilder1.capacity());
System.out.println("字符串长度 = " + stringBuilder1.length());
System.out.println("----------------------------------");
//2、根据参数指定字符串构造对象
StringBuilder stringBuilder2 = new StringBuilder("test");
System.out.println("字符串内容 = " + stringBuilder2.toString());
System.out.println("字符串容量 = " + stringBuilder2.capacity());
System.out.println("字符串长度 = " + stringBuilder2.length());
System.out.println("----------------------------------");
}
}
/*
字符串内容 =
字符串容量 = 16
字符串长度 = 0
----------------------------------
字符串内容 =
字符串容量 = 20
字符串长度 = 0
----------------------------------
字符串内容 = test
字符串容量 = 20
字符串长度 = 4
----------------------------------
*/
如果StringBuilder对象内容超出容量,会自动扩容,扩容规则:原容量*2 +2
1.3 StringBuilder类常用的成员方法
方法声明 | 功能介绍 |
---|---|
int capacity() | 返回调用对象的容量 |
int length() | 返回字符串的长度,即字符的个数 |
StringBuilder insert(int offset, String str) | 插入字符串并返回调用对象本身 |
StringBuilder append(String str) | 追加字符串 |
StringBuilder deleteCharAt(int index) | 将调用对象中下标index位置的字符删除 |
StringBuilder delete(int start, int end) | 删除字符串 |
StringBuilder replace(int start, int end, String str) | 替换字符串 |
StringBuilder reverse() | 字符串反转 |
1.4 笔试考点
public class StringBuilderExamTest {
public static void main(String[] args) {
//笔试考点1: 既然StringBuilder本身可以修改,为何成员方法还有返回值呢?
//目的:为了连续调用
StringBuilder sb = new StringBuilder("bcahhsfsd");
sb.append("tt").insert(5,"yy").deleteCharAt(5).reverse();
//笔试考点2:如何实现StringBuilder类和String类之间的转换
sb.toString(); //StringBuilder => String
StringBuilder sb2 = new StringBuilder(sb); // String => StringBuilder
//笔试考点3:String、StringBuffer、StringBuilder三者效率比较
//String < StringBuffer < StringBuilder
//笔试考点4:String、StringBuilder、StringBuffer三者区别
/*
1)String的内容是不可变的,StringBuffer和StringBuilder内容是可变的
2)StringBuffer从jdk1.0开始存在,线程安全的,效率较低
3)StringBuilder从jdk1.5开始存在,是线程不安全的,效率较高
*/
}
}
2、Java8之前的日期相关类(熟悉)
2.1 System类的概述
- 基本概念
java.lang.System类中提供了一些有用的类字段和方法 - 常用方法
方法声明 | 功能介绍 |
---|---|
static long currentTimeMillis() | 返回当前时间与1970年1月1日0时0分0秒的时间差(毫秒) 应用场景1:通常用于测试某一段代码的执行效率 应用场景2:当作订单号的一部分 |
2.2 Date类概述
- 基本概念
java.util.Date类主要用于描述特定的瞬间,即年月日时分秒,可以精确到毫秒 - 常用方法
方法声明 | 功能介绍 |
---|---|
Date() | 使用无参方式构造对象,即系统当前时间 |
Date(long date) | 根据参数指定毫秒数构造对象,参数为距离1970年1月1日0时0分0秒的毫秒数 |
long getTime() | 获取调用对象距离1970年1月1日0时0分0秒的毫秒数 |
void setTime(long time) | 设置时间为距离1970年1月1日0时0分0秒相差time毫秒的时间点 |
2.3 SimpleFormatDate类概述
- 基本概念
java.text.SimpleDateFormat类主要用于实现日期和文本之间的转换 - 常用方法
方法声明 | 功能介绍 |
---|---|
SimpleDateFormat() | 使用无参方式构造对象 |
SimpleDateFormat(String pattern) | 根据参数指定的格式构造对象,格式主要有:y-年 M-月 d-日 H-时 m-分 s-秒 |
final String format(Date date) | 将日期类型转换为文本型 |
Date parse(String source) | 将文本类型转换为日期 型 |
2.4 Calendar类的概述
- 基本概念
- java.util.Calentar 类主要用于描述特定的瞬间,取代Date类中的过时方法实现全球化
- 该类是个抽象类,因此不能实例化对象,其具体子类针对不同国家的日历系统,其中应用最广泛是GregorianCalendar(格里高利历),对应世界上绝大多数国家/地区使用的标准日历系统
- 常用方法
方法声明 | 功能介绍 |
---|---|
static Calendar getInstance() | 用于获取Calendar类型的引用 |
void set(int year, int month, int date, int hourOfDay, int minute, int second) | 用于设置年月日,时分秒信息 |
Date getTime() | 将Calendar类型转换为Date类 |
void set(int field, int value) | 设置指定字段的数值 |
abstract void add(int field, int amount) | 向指定字段增加数值 |
- 多态的使用场合
//一、通过方法参数传递形成多态
public static void draw(Shape s){
s.show();
}
draw(new Circle(2,3,4));
//二、在方法中直接使用多态的语法格式
Account account = new FixedAccount();
//三、通过方法的返回值类型形成多态
Calendar getInstance(){
return new GregorianCalendar(zone, aLocale)
}
3、Java8增加的日期相关类(熟悉)
3.1 Java8日期类的由来
jdk1.0中包含了java.util.Date类,虽然jdk1.1引入Calendar类解决了Date类存在的一些问题,但是Calendar类本身仍然存在一些问题:
- Date类中年份都是从1900开始,月份对于Date和Calendar都是从0开始
- 格式化只对Date有用,对Calendar类不能使用
- 非线程安全等
3.2 Java8日期类的概述
- Java8通过发布新的Date-Time API进一步加强对日期和时间的处理
- java.time包:为日期/时间的基础包
- java.time.chrono包:提供对不同日历系统的访问
- java.time.format包:格式化和解析日期时间对象
- java.time.temporal包:包含底层框架和扩展特性
- java.time.zone包:支持不同时区及相关规则的类
3.3 LocalDate类的概述
- 基本概念
java.time.LocalDate类,主要用于描述年-月-日格式的时间信息,该类不表示时间和时区信息 - 常用方法
方法声明 | 功能介绍 |
---|---|
static LocalDate now() | 在默认时区中,从系统时区获得当前日期 |
3.4 LocalTime类的概述
- 基本概念
java.time.LocalTime类,描述时间信息,可以描述时分秒以及纳秒 - 常用方法
方法声明 | 功能介绍 |
---|---|
static LocalDate now() | 默认时区中获取当前时间 |
static LocalTime now(ZoneId zone) | 获取指定时区的当前时间 |
3.5 LocalDateTime类的概述
- 基本概念
java.time.LocalDateTime类主要用于描述ISO-8601日历系统中没有时区的日期时间,如:2007-12-03T10:15:30 - 常用方法
方法声明 | 功能介绍 |
---|---|
static LocalDateTime now() | 默认时区中获取当前日期时间 |
static LocalDateTime of(int year, int month, int dayOfMonth, int hour, int minute, int second) | 根据参数指定年月日时分秒设置日期时间 |
int getYear() | 获取年份值 |
int getMonthValue() | 获取月份值,1-12之间 |
int getDayOfMonth() | 获取日期值 |
int getHour() | 获取小时数 |
int getMinute() | 获取分钟数 |
int getSecond() | 获取秒数 |
LocalDateTime withYear(int year) | 设置为参数指定的年 |
LocalDateTime withMonth(int month) | 设置为参数指定的月 |
LocalDateTime withDayOfMonth(int dayOfMonth) | 设置为参数指定的日期 |
LocalDateTime withHour(int hour) | 设置为参数指定的小时 |
LocalDateTime withMinute(int minute) | 设置为参数指定的分钟 |
LocalDateTime withSecond(int second) | 设置为参数指定的秒数 |
LocalDateTime plusYears(long years) | 加上参数指定的年 |
LocalDateTime plusMonths(long months) | 加上参数指定的月 |
LocalDateTime plusDays(long days) | 加上参数指定的日 |
LocalDateTime plusHours(long hours) | 加上参数指定的时 |
LocalDateTime plusMinutes(long minutes) | 加上参数指定的分 |
LocalDateTime plusSeconds(long seconds) | 加上参数指定的秒 |
LocalDateTime minusYears(long years) | 减去参数指定的年 |
LocalDateTime minusMonths(long months) | 减去参数指定的月 |
LocalDateTime minusDays(long days) | 减去参数指定的日 |
LocalDateTime minusHours(long hours) | 减去参数指定的时 |
LocalDateTime minusMinutes(long minutes) | 减去参数指定的分 |
LocalDateTime minusSeconds(long seconds) | 减去参数指定的秒 |
3.6 Instant类的概述
- 基本概念
java.time.Instant类主要用于描述瞬间的时间点信息 - 常用方法
方法声明 | 功能介绍 |
---|---|
static Instant now() | 从系统时钟获取当前时间 |
OffsetDateTime atOffset(ZoneOffset offset) | 将此瞬间与偏移量组合,创建偏移日期时间 |
static Instant ofEpochMilli(long epochMilli) | 根据参数指定的毫秒数构造对象,参数为距离1970年1月1日0时0分0秒的毫秒数 |
long toEpochMilli() | 获取距离1970年1月1日0时0分0秒的毫秒数 |
3.7 DateTimeFormatter
- 基本概念
java.time.format.DateTimeFormatter类主要用于格式化和解析日期 - 常用方法
方法声明 | 功能介绍 |
---|---|
static DateTimeFormatter ofPattern(String pattern) | 根据参数指定的模式获取对象 |
String format(TemporalAccessor temporal) | 将参数指定的日期时间转换为字符串 |
TemporalAccessor parse(CharSequence text) | 将参数指定的字符串转换为日期时间 |
- 笔试考题
public class StringBuilderTest2 {
public static void main(String[] args) {
StringBuilder sb1 = new StringBuilder("1");
StringBuilder sb2 = new StringBuilder("2");
show(sb1,sb2);
System.out.println("sb1 = " + sb1);
System.out.println("sb2 = " + sb2);
}
public static void show(StringBuilder x, StringBuilder y){
x.append(y);
y = x;
}
}
//打印输出结果
//12
//2
四、集合类库(上)
1、集合的概述(重点)
1.1 集合的由来
- 当需要在Java程序中记录单个数据内容时,声明一个变量
- 当需要在Java程序中记录多个类型相同的数据内容时,声明一个一维数组
- 当需要在Java程序中记录多个类型不同的数据内容时,创建一个对象
- 当需要在Java程序中记录多个类型相同的对象数据时,创建一个对象数组
- 当需要在Java程序中记录多个类型不同的对象数据时,则准备一个集合
1.2 集合的框架结构
- Java集合框架顶层框架是:java.util.Collection集合和java.util.Map集合
- Collection集合中存取元素的基本单位:单个元素
- Map集合存取元素的基本单位:单对元素
2、Collection集合(重点)
2.1 基本概念
java.util.Collection接口是List接口,Queue接口,以及Set接口的父接口,因此该接口中定义的方法,可以操作List集合、Queue集合、Set集合
2.2 常用方法(练熟)
方法声明 | 功能介绍 |
---|---|
boolean add(E e) | 向集合中添加对象 |
boolean addAll(Collection<? extends E> c) | 参数指定集合元素添加到该集合中 |
boolean contains(Object o) | 判断是否包含指定对象 |
boolean containsAll(Collection<?> c) | 判断是否包含参数指定的所有对象 |
boolean retainAll(Collection<?> c) | 保留当前集合中存在且参数集合中存在的所有对象 |
boolean remove(Object o) | 从集合中删除对象 |
boolean removeAll(Collection<?> c) | 从集合中删除参数指定的所有对象 |
void clear() | 清空集合 |
int size() | 返回该集合的元素个数 |
boolean isEmpty() | 判断集合是否为空 |
boolean equals(Object o) | 判断是否相等 |
int hashCode()获取集合的哈希码值 | |
Object[] toArray() | 将集合转换为数组 |
Iterator iterator() | 获该集合的迭代器 |
2.3 笔试考题
public class CollectionExamTest {
public static void main(String[] args) {
//笔试考点:contains与containsAll的区别
Collection c = new ArrayList();
c.add(5);
c.add("abc");
Collection c2 = new ArrayList();
c2.add(5);
c2.add("abc");
System.out.println(c.containsAll(c2)); //判断集合c中是否包含集合c2的全部元素
System.out.println(c.contains(c2)); //判断集合c中是否包含集合c2这个整体为单位的元素
}
}
//true
//false
public class CollectionTest2 {
public static void main(String[] args) {
//集合与数组的转换 通常认为,集合是取代数组的结构
Collection c4 = new ArrayList();
c4.add(5);
c4.add(10);
//集合转换为数组
Object[] objects = c4.toArray();
System.out.println(Arrays.toString(objects));
//数组转换为集合
List<Object> list = Arrays.asList(objects);
System.out.println(list);
}
}
考点:
containsAll 和 removeAll是分别判断参数集合中的每一个元素,是否满足元素类型的equals方法;
contains 和 remove方法是将参数集合作为一个整体,判断参数集合是否在调用的集合中。
3、Iterator接口(重点)
3.1 基本概念
- java.util.Iterator接口主要用于描述迭代器对象,可以遍历集合中的所有元素
- java.util.Collection接口继承Iterator接口,因此所有实现了Collection接口的实现类都可以使用该迭代器对象
3.2 常用方法
方法声明 | 功能介绍 |
---|---|
boolean hasNext() | 判断集合中是否有可以迭代的元素 |
E next() | 用于取出一个元素并指向下一个元素 |
default void remove() | 用于删除迭代器访问到的元素 |
- 案例题目
使用迭代器实现toString方法的打印效果
public class CollectionTest3 {
public static void main(String[] args) {
Collection c4 = new ArrayList();
c4.add(5);
c4.add(10);
c4.add(99);
//使用迭代器打印与集合的toString一样的效果
iterator = c4.iterator();
StringBuilder sb = new StringBuilder();
sb.append("[");
while(iterator.hasNext()){
Object obj = iterator.next();
//如果最后没有元素,则拼接"]"
if(!iterator.hasNext()){
sb.append(obj).append("]");
}else {
sb.append(obj).append(", ");
}
}
System.out.println("sb = " + sb);
}
}
4、for each循环(重点)
4.1 基本概念
- Java5推出了增强for循环语句,可以应用与集合和数组的遍历
- 是经典迭代的"简化版"
4.2 语法格式
for(元素类型 变量名:数组/集合名称){
循环体;
}
4.3 执行流程
- 不断的从数组/集合中取出一个元素赋值给变量名,并执行循环体,直到取完所有元素为止
5、List集合(重点)
5.1 基本概念
- java.util.List集合是Collection集合的子集合,该集合中允许有重复的元素,并且有先后放入次序
- 该集合的主要实现类有:ArrayList类、LinkedList类、Stack类、Vector类
- ArrayList底层采用动态数组进行数据管理,支持下标访问,增删元素不方便
- LinkedList底层采用双向链表进行数据管理,访问不方便,增删元素方便
- 可以认为ArrayList和LinkedList的方法在逻辑上完全一样,只是在性能上有一定差异。
ArrayList更适用于访问,而LinkedList更适用于插入和删除;
在性能要求不是特别严苛的情况下可以忽略这个差别 - Stack底层采用动态数组进行数据管理,该类主要用于描述一种具有后进先出特征的数据结构,叫做栈(last in first out LIFO)
- Vector底层采用动态数组进行数据管理,该类与ArrayList相比属于线程安全的类,效率较低,以后开发中基本不用
5.2 常用方法
方法声明 | 功能介绍 |
---|---|
void add(int index, E element) | 向List中指定位置添加元素 |
boolean addAll(int index, Collection<? extends E> c) | 向调用的List的指定位置添加参数集合的所有元素 |
E get(int index) | 获取指定位置元素 |
int indexOf(Object o) | 返回指定元素在此列表中首次出现的索引;如果此列表不包含该元素,则返回-1 |
int lastIndexOf(Object o) | 返回指定元素在此列表中最后一次出现的索引;如果此列表不包含该元素,则返回-1 |
E set(int index, E element) | 用指定的元素替换此列表中指定位置的元素 |
E remove(int index) | 删除此列表中指定位置的元素 |
List subList(int fromIndex, int toIndex) | 返回此列表在指定的fromIndex(包括)和toIndex(不包括)之间的子List 子列表与该列表共用同一块内存,list与子列表的变化可能会互相影响 |
- 案例题目
准备一个Stack集合,将数据11、22、33、44、55依次入栈并打印,然后查看栈顶元素并打印,然后将栈中的数据依次取出并打印。
再准备一个Stack对象,将数据从第一个栈中取出,放入第二个栈中,然后再从第二个栈取出并打印。
public class StackTest {
public static void main(String[] args) {
//1、准备Stack类型对象并打印
Stack sk = new Stack();
Stack sk2 = new Stack();
System.out.println("sk = " + sk);
//2、将数据11、22、33、44、55依次入栈并打印
sk.push(11);
sk.push(22);
sk.push(33);
sk.push(44);
sk.push(55);
System.out.println("sk = " + sk);
//3、查看栈顶元素值并打印
System.out.println("栈顶元素 = " + sk.peek());
//4、对栈中所有元素依次出站,并放入第二个栈中,打印
// int size = sk.size();
// for (int i = 0; i < size; i++) {
// System.out.println(sk.pop());
// }
for (int i = sk.size()-1; i >= 0 ; i--) {
Object obj = sk.pop();
sk2.push(obj);
System.out.println("sk取出的元素 = " + obj);
}
//5、打印栈中所有元素
System.out.println("取走所有元素后sk = " + sk);
System.out.println("放入所有元素后sk2 = " + sk2);
//6、将sk2元素依次取出
int size2 = sk2.size();
for (int i = 0; i < size2; i++) {
System.out.println("sk2取出的元素 = " + sk2.pop());
}
}
}
/*
sk = []
sk = [11, 22, 33, 44, 55]
栈顶元素 = 55
sk取出的元素 = 55
sk取出的元素 = 44
sk取出的元素 = 33
sk取出的元素 = 22
sk取出的元素 = 11
取走所有元素后sk = []
放入所有元素后sk2 = [55, 44, 33, 22, 11]
sk2取出的元素 = 11
sk2取出的元素 = 22
sk2取出的元素 = 33
sk2取出的元素 = 44
sk2取出的元素 = 55
*/
5.3 ArrayList动态扩容原理解析
- 访问方便,增删不方便
public class ArrayListTest {
public static void main(String[] args) {
//由源码可知,new对象时,并未申请底层数组的内存空间
List list = new ArrayList();
//添加第一个元素时,自动扩容,声明了一个容量为10的数组,并将元素添加到该数组中
list.add(1);
list.add(2);
list.add(3);
list.add(4);
list.add(5);
list.add(6);
list.add(7);
list.add(8);
list.add(9);
list.add(10);
//添加第11个元素时,ArrayList底层的数组自动扩容为原来的1.5倍,也就是数组长度length从10 变为15
list.add("11");
list.add("12");
list.add("13");
list.add("14");
list.add("15");
//添加第16个元素时,底层数组自动扩容为15的1.5倍,计算公式为:15 + 15 >> 1 => 15 + 15/2 => 22
list.add("16");
System.out.println("此时集合的元素个数 = " + list.size());//16
}
}
5.4 LinkedList源码解析
- 访问不方便,增删方便
public class LinkedListTest {
public static void main(String[] args) {
Collection c = new LinkedList();
//新增第一个元素时,链表的first节点和last节点都指向该元素
c.add(1);
//新增第二个元素时:
// 1、链表的last节点指向新元素,
// 2、last节点的prev属性指向新增之前的last节点地址
// 3、同时,新增之前的last节点(新增元素的上一个元素)的next属性指向新增元素的地址,完成链表的双向绑定
c.add(2);
System.out.println("集合c的元素 = " + c);
}
}
5.5 笔试考点
ArrayList和Vector的区别
- ArrayList是线程不安全的,效率高,Vector所有方法都是同步的,是线程安全的,效率低;
- ArrayList与Vector底层均是由动态数组进行数据管管理,ArrayList自动扩容是扩容为1.5倍,Vector是扩容为2倍;
- Vector是Java1.0以后出现,ArrayList是Java1.2以后出现;
- ArrayList出现是因为Vector所有方法都是同步的,多线程访问时虽然安全,但是单线程访问时会因为同步导致效率很低,所以出现了ArrayList
(类似于StringBuffer与StringBuilder的关系。StringBuffer在JDK1.0出现,是线程安全的,但是效率低,JDK1.5出现了StringBuilder,线程不安全但是效率高)。
List集合遍历的方式有哪些?
- toString()
- Iterator迭代器
- for循环
- for each循环
6、Queue集合(重点)
6.1 基本概念
- java.util.Queue集合是Collection集合的子集合,与List集合属于平级关系
- 该集合主要描述具有先进先出特征的数据结构,叫做队列(first in first out FIFO)
- 该集合主要的实现类时LinkedList类,因为该类在增删方面比较有优势
6.2 常用方法
方法声明 | 功能介绍 |
---|---|
boolean offer(E e) | 将一个对象添加至队尾 |
E poll() | 从队首删除并返回一个元素 |
E peek() | 返回队首的元素,但不删除 |
- 案例题目
准备一个Queue集合,将数据11、22、33、44、55依次插入队列并打印,然后查看队首元素并打印,然后将队列中所有元素依次出队并打印
public class QueueTest {
public static void main(String[] args) {
//1、准备队列集合并打印
Queue q = new LinkedList();
System.out.println("创建完队列后队列为" + q);
//2、将数据依次入队并打印
for (int i = 1; i <= 5; i++) {
q.offer(i * 11);
System.out.println("队列q中元素为" + q);
}
//3、打印队首元素
System.out.println("打印队首元素为 " + q.peek());
//4、依次取出队列并打印
int size = q.size();
for (int i = 0; i < size; i++) {
System.out.println("取出的元素为" + q.poll());
}
//5、查看队列最终元素
System.out.println("取出所有元素后队列q = " + q);
}
}
五、集合类库下
1、泛型机制(熟悉)
1.1 基本概念
- 通常情况下,集合中可以存放不同类型的对象,是因为将所有对象都当作Object类型放入的,因此从集合中取出对象的时候也是Object类型,为了表达该元素真实的数据类型,则需要强制类型转换,但是强制类型转换可能会引发类型转换异常。
- 为了避免上述错误的发生,从Java5增加泛型机制,也就是在集合名称的右侧,使用<数据类型>的方式来明确要求该集合中可存放的元素的数据类型,若放入其他数据类型的元素则编译报错。
- 泛型只在编译时期有效,在运行时期不区分是什么类型
public class ListGenericTest {
public static void main(String[] args) {
//1、准备一个支持泛型机制的List集合,明确要求结合中元素类型为String
List<String> list = new ArrayList<String>();
//2、向集合中添加元素并打印
list.add("aa");
System.out.println("list集合元素为" + list);
//3、获取集合中的元素并打印
String s = list.get(0);
System.out.println("获取到的元素为" + s);
//Java7开始新特性:菱形特性:后面<>中的数据类型改可以省略
List<Double> lt3 = new LinkedList<>();
//笔试考点
//集合中的数据类型不同时,不支持赋值,虽然JVM运行时期不区分集合中存放的类型,但是在编译阶段泛型机制会禁止该情况发生
//lt3 = list; //编译报错
}
}
1.2 底层原理
- 泛型的本质就是参数化类型,也就是让数据类型作为参数传递,其中E相当于形式参数负责占位,而使用集合时<>中的数据类型相当于实际参数,用于给形式参数E进行初始化,从而使得集合中所有的E被实际参数替换,由于实际参数可以传递各种各样广泛的数据类型,因此得名为泛型。
1.3 自定义泛型接口
- 泛型接口和普通接口的区别就是后面添加了类型参数列表,可以有多个类型参数,如<E,T,…>等。
1.4 自定义泛型类
- 泛型类和普通类的区别就是类名后面添加了类型参数列表,可以有多个类型参数,如<E,T,…>等
- 实例化泛型类型时,应该指定具体的数据类型,并且是引用数据类型不是基本数据类型。
- 父类有泛型,子类可以选择保留泛型,也可以选择指定泛型类型
- 子类除了可以指定和保留泛型外,还可以还可以增加自己的泛型
1.5 自定义泛型方法
- 泛型方法就是输入参数的时候,输入的是一个泛型参数,而不是具体的参数。调用泛型方法的时候需要对这个参数进行实例化
- 泛型方法的格式:
[访问权限] <泛型标识> 返回值类型 方法名(泛型标识 参数名称){ 方法体 ; } - 静态方法中使用泛型参数时,需要把静态方法定义为泛型方法
参考代码
package com.lagou.test.generictest;
/**
* @program: proj_homework_1_3
* @description: 自定义泛型类Person,其中T相当于形式参数负责占位,具体数值由实参决定
* @Param<T>: 看做是一种名字为T的数据类型即可
* @author: WangJie
* @create: 2020-11-04 21:25
**/
public class Person<T> {
private String name;
private int age;
private T gender;
public Person() {
}
public Person(String name, int age, T gender) {
this.name = name;
this.age = age;
this.gender = gender;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
//不是泛型方法,该方法中不能用static修饰,因为该方法中的T需要new对象时才能确定,而使用static后意味不用new对象也可以访问,前后矛盾,
// 所以静态方法中使用泛型参数时,需要把静态方法定义为泛型方法
public /*static*/ T getGender() {
return gender;
}
public void setGender(T gender) {
this.gender = gender;
}
//自定义泛型方法,将参数指定数组的所有元素打印
public static <T1> void printArray(T1[] arr){
for (T1 tt:arr
) {
System.out.println("tt = " + tt);
}
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", age=" + age +
", gender=" + gender +
'}';
}
}
1.6 泛型在继承上的体现
- 如果B是A的一个子类或子接口,而G是具有泛型声明的类或接口,则G<B>并不是G<A>的子类型!
比如:String是Object的子类,但是List<String>并不是List<Object>的子接口
1.7 通配符的使用
- 有时候希望传入的类型在一个指定的范围内,此时可以使用泛型通配符
- 如:之前传入的类型为Integer类型,但是后来业务需要Integer的父类Number类也可以传入。
- 泛型有三种通配符形式:
通配符形式 | 含义 | 注意事项 |
---|---|---|
<?> | 无限制通配符:表示可以传入任意类型的参数 | 支持获取,但不支持添加元素 |
<? extends E> | 表示类型的上界是E,只能是E或者是E的子类 | 支持获取,但不支持添加元素,上界通配符主要用于读数据 |
<? Super E> | 表示类型的下届是E,只能是E或者是E的父类 | 支持添加元素,读取元素,下界通配符主要用于写数据。 |
2、Set集合(熟悉)
2.1 基本概念
- java.util.Set集合是Collection的子集合,与List集合平级
- 该集合的元素没有先后放入次序,且不允许重复
- 该集合的主要实现类:HashSet、TreeSet、LinkedHashSet类
- HashSet底层采用哈希表进行数据管理
- TreeSet底层采用红黑树进行数据管理
- LinkedHashSet与HashSet不同在于前者内部维护了一个双向链表,链表中记录了元素的迭代顺序,也就是元素插入集合的先后顺序,因此便于迭代
2.2 常用方法
- 参考Collection集合的方法
2.3 元素放入HashSet集合的原理
- 使用元素调用hashcode方法获取对应的哈希码值,再由某种哈希算法计算出该元素在数组中索引位置
- 若该位置没有元素,则直接放入即可
- 若该位置有元素,则使用新元素与已有元素依次比较哈希值,若哈希值都不相同,则将该元素直接放入已有元素后面
- 若新元素与已有元素哈希值相同,则使用新元素调用equals方法依次与已有元素比较。
- 若相等则添加失败,若都不相等将元素直接放入已有元素后面???是否需要都不相等才会插入
- 思考:为什么重写equals方法后要重写hashcode方法
解析:当俩个元素调用equals方法相等时说明这俩个元素相同,重写hashcode方法后保证这俩个元素得到的哈希码值相同,由同一个哈希算法计算到的索引位置相同,此时只需要与该索引位置已有元素比较,从而提高效率并避免重复元素的出现
3、Map集合(重点)
3.1 基本概念
- java.util.Map<K,V> 中存取元素的基本单位是:单对元素。参数如下:
K:键 key
V:值value - 该集合中key不允许重复,一个key只能对应一个value
- 该集合主要实现类有:HashMap类、TreeMap类、LinkedHashMap类、Hashtable类、Properties类
- HashMap底层采用哈希表进行数据管理
- TreeMap底层采用红黑树进行数据管理
- LinkedHashMap与HashMap区别在于内部维护了一个双向链表,链表中记录了元素的迭代顺序,也就是元素插入集合的先后顺序,便于迭代
- Hashtable是古老的Map实现类,与HashMap相比属于线程安全的类且key与value均不允许为null
- Properties类是Hashtable的子类,该对象用于处理属性文件,key 和 value都是String类型的。
- Map集合是面向查询优化的数据结构,大数据量情况下有优秀的查询性能
- 经常用于根据key检索value业务场景
3.2 常用方法
方法声明 | 功能介绍 |
---|---|
V put(K key, V value) | 将key-value存入map,若集合中已经存在key,则替换该key对应的value; 返回值为key原来对应的value |
V get(Object key) | 返回key对应的value对象,不存在则返回null |
boolean containsKey(Object key) | 判断集合中是否包含指定的key |
boolean containsValue(Object value) | 判断集合中是否包含指定的value |
V remove(Object key) | 根据参数指定key删除元素 |
Set<K> keySet() | 返回集合中包含键的set视图 |
Collection values() | 返回集合中包含的值的set视图 |
Set<Map.Entry<K,V>> entrySet() | 返回集合中映射的set集合 |
3.3 元素放入HashMap集合的原理
- 使用元素的key调用hashCode方法获取对应的哈希码值,再由某种哈希算法计算在数组中的索引位置
- 若该位置没有元素,则将该键值对直接放入即可
- 若该位置有元素,则使用key与已有元素依次比较哈希值,若哈希值不相同,则将该元素直接放入
- 若key与已有键的哈希值相同,则使用key调用equals方法与已有元素依次比较
- 若相等则将对应的value修改,否则直接将键值对放入即可
3.4 相关的常量
- DEFAULT_INITIAL_CAPACITY:HashMap的默认容量为16
- DEFAULT_LOAD_FACTOR:HashMap的默认加载因子为0.75
- threshold:扩容的临界值,该数值为:容量填充因子,也就是160.75=12
- TREEIFY_THRESHOLD:默认为8,若Bucket中链表长度大于该默认值则转换为红黑树存储
- MIN_TREEIFY_CAPACITY:桶中的Node被树化时最小的hash表容量,为64
4、Collections类
4.1 基本概念
- java.util.Collections类主要提供了对集合操作或者返回集合的静态方法
4.2 常用方法
方法声明 | 功能介绍 |
---|---|
static <T extends Object & Comparable<? super T>>T max(Collection<? extends T> coll) | 根据元素的自然顺序返回给定集合的最大元素 |
static <T> T max(Collection<? extends T> coll, Comparator<? super T> comp) | 根据指定比较器引发的顺序返回给定集合的最大元素 |
static <T extends Object & Comparable<? super T>>T min(Collection<? extends T> coll) | 根据元素的自然顺序返回给定集合的最小元素 |
static <T> T min(Collection<? extends T> coll, Comparator<? super T> comp) | 根据指定比较器引发的顺序返回给定集合的最小元素 |
static <T> void copy(List<? super T> dest, List<? extends T> src) | 将一个列表中所有元素复制到另一个列表中 |
方法声明 | 功能介绍 |
---|---|
static void reverse(List<?> list) | 反转指定列表中元素的顺序 |
static void shuffle(List<?> list) | 使用默认的随机源随机置换指定的列表元素 |
static <T extends Comparable<? super T>>void sort(List<T> list) | 根据元素的自然顺序将指定列表按升序排列 |
static void sort(List list, Comparator<? super T> c) | 根据指定比较器指定的顺序进行列表排序 |
static void swap(List<?> list, int i, int j) | 交换指定列表中指定位置元素 |
文章内容输出来源:拉勾教育_大数据开发高新训练营第3期