JAVA学习第一阶段模块三

模块三 Java常用类库(上)

常用类

  • java.lang包,java虚拟机自动导入的

    如System类、String类等

  • java.util包,java语言工具包

    如Scanner类、Random类、List集合等

  • java.io包,java语言输入输出包,对文件操作相关的类

    如FileInputStream类、FileOutputStream类等

  • java.net包,java语言中的网络包,提供了大量网络编程相关的类

    如ServerSocker类、Socker类等

  • java.sql包,java语言中的数据包,提供了大量操作数据库的类和接口等

    如DriverManager类、Connection接口等

  • ……

Object类

  • 每个类都由Object类作为超类,任何一个类都是该类的子类或间接子类
方法声明 功能介绍
Object() 使用无参方式构造对象
boolean equals(Object obj) 判断调用对象和传入对象是否相等,比较的是内存地址与==代表含义相同
int hashCode() 返回调用对象的哈希码值(内存地址的编号 十六进制
如果两个对象equals方法返回true,则hashCode值相同
如果两个对象equals方法返回false,则hashCode值不同
为了使得hashCode的结果与equals方法返回的结果保持一致,因此需要重写hashCode方法
String toString() 获取对象的字符串形式
打印引用变量时会自动调用toString()方法
Class getClass()

包装类

  • 通常情况下,基本数据类型的变量不是对象,对了满足万物皆对象的理念,需要对基本数据类型的变量进行打包封装处理变成对象,而负责将这些变量声明为成员变量进行对象化处理的相关类,叫做包装类
包装类 基本类型
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

Integer

常量 功能介绍
public static final int MAX_VALUE 表示int类型可以描述的最大值,即2^31-1
public static final int MIN_VALUE 表示int类型可以描述的最小值,即-2^31
public static final int SIZE 表示int类型采用二进制补码形式的位数
public static final int BYTES 表示int类型所占的字节个数
public static final Class TYPE 表示int类型的Class实例
public class IntegerTest {

    public static void main(String[] args) {
        System.out.println(Integer.MAX_VALUE); //最大值:输出2147483647
        System.out.println(Integer.MIN_VALUE); //最小值:输出-2147483648
        System.out.println(Integer.SIZE); //所表示的二进制位数:输出32
        System.out.println(Integer.BYTES); //所占字节个数:输出4
        System.out.println(Integer.TYPE); //输出int
    }
}
  • static Integer valueOf(int i)返回Integer对象
Integer int1 = Integer.valueOf(123); //从int类型转换为Integer类型(装箱)
int ia = int1.intValue(); //从Integer类型转换为int类型(拆箱)
Integer value = Integer.valueOf("123"); //从String类型转换为Integer类型
  • java5之后通过赋值运算符实现自动装箱拆箱
Integer int1 = 100; //自动装箱
int int2 = int1; //自动拆箱
笔试题
Integer it1 = 128;
Integer it2 = 128;
Integer it3 = new Integer(128);
Integer it4 = new Integer(128);

System.out.println(it1 == it2);      // 比较地址 false
System.out.println(it1.equals(it2)); // 比较内容 true
System.out.println(it3 == it4);      // 比较地址 false
System.out.println(it3.equals(it4)); // 比较内容 true
Integer it1 = 127;
Integer it2 = 127;
Integer it3 = new Integer(127);
Integer it4 = new Integer(127);

System.out.println(it1 == it2);      // 比较地址 true 地址一样
System.out.println(it1.equals(it2)); // 比较内容 true
System.out.println(it3 == it4);      // 比较地址 false
System.out.println(it3.equals(it4)); // 比较内容 true
  • 自动装箱池

    将-128~127范围内的整数装箱完毕,当程序中使用该范围之间的整数时,无需装箱直接取用自动装箱池中的对象即可,从而提高效率。

  • static Integer parseInt(String s)将字符串转换为int类型

int ic = Integer.parseInt("200");
System.out.println(ic);

int id = Integer.parseInt("abc"); //java.lang.NumberFormatException 数字格式异常
System.out.println(id);
  • static String toString(int i) 将整数转换为字符串类型
System.out.println(Integer.toString(200));       //获取整数的十进制字符串 200
System.out.println(Integer.toBinaryString(200)); //获取整数的二进制字符串 11001000
System.out.println(Integer.toHexString(200)); //获取整数的十六进制字符串 c8
System.out.println(Integer.toOctalString(200)); //获取整数的八进制字符串 310

Double

  • isNaN() 判断是否为非数字
double db1 = 3.14;
Double db2 = db1;
System.out.println(db2.isNaN()); //是数字打印false 
Double db3 = Double.valueOf(0 / 0.0);
System.out.println(db3.isNaN()); //非数字打印true

Boolean

  • static Boolean parseBoolean(String s) 字符串类型转换为boolean类型
//"true".equalsIgnoreCase(String s) 不是true的字符串全部转换为false
Boolean b1 = Boolean.parseBoolean("true");
System.out.println(b1); //输出true
Boolean b2 = Boolean.parseBoolean("true1");
System.out.println(b2); //输出false

Character

  • boolean isUpperCase() 判断是否为大写字母
  • boolean isLowerCase() 判断是否为小写字母
  • boolean isDigit() 判断是否为数字字符
  • toUpperCase() 转换为大写字符
  • toLowerCase() 转换为小写字符
char a1 = 'a';
Character ca1 = a1;

System.out.println(Character.isUpperCase(ca1)); //返回false
System.out.println(Character.isLowerCase(ca1)); //返回true
System.out.println(Character.isDigit(ca1)); //返回false
System.out.println(Character.toUpperCase(ca1)); //打印A
System.out.println(Character.toLowerCase(ca1)); //打印a

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的随机数
public static void main(String[] args) {
    //获取两个整数中最大值的结果是:101
    System.out.println("获取两个整数中最大值的结果是:" + Math.max(100, 101));
    //获取两个整数中最小值的结果是:100
    System.out.println("获取两个整数中最小值的结果是:" + Math.min(100, 101));
    //获取次方的结果是:8.0
    System.out.println("获取次方的结果是:" + Math.pow(2, 3));
    //获取绝对值的结果是:2
    System.out.println("获取绝对值的结果是:" + Math.abs(-2));
    //获取四舍五入的结果是:3
    System.out.println("获取四舍五入的结果是:" + Math.round(3.14));
    //获取平方根的结果是:4.0
    System.out.println("获取平方根的结果是:" + Math.sqrt(16));
    //生成的随机数是:0.9524640840846081
    System.out.println("生成的随机数是:" + Math.random());
}

BigDecimal

  • 由于float类型和double类型在运算时可能会有误差,若希望实现精确运算则借助java.math.Bigcimal类加以描述
方法名 功能介绍
BigDecimal(String val) 根据参数指定的字符串来构造对象
BigDecimal add(BigDecimal augend) 用于实现加法运算
BigDecimal subtract(BigDecimal subtrahend) 用于实现减法运算
BigDecimal multiply(BigDecimal multiplicand) 用于实现乘法运算
BigDecimal divide(BigDecimal divisor) 用于实现除法运算
  • divide方法重载方法,四舍五入
public static void main(String[] args) {
    BigDecimal b1 = new BigDecimal("3.14");
    BigDecimal b2 = new BigDecimal("4.11");

    System.out.println(b1.add(b2));      //加法运算 7.25
    System.out.println(b1.subtract(b2)); //减法运算 -0.97
    System.out.println(b1.multiply(b2)); //乘法运算 12.9054
    //无限循环小数除法  BigDecimal必须要精确运算
    System.out.println(b1.divide(b2));   //除法运算 算数异常java.lang.ArithmeticException
    //使用重载方法
    System.out.println(b1.divide(b2, RoundingMode.HALF_UP)); //四舍五入 0.76
}

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) 用于实现取商和余数的运算
public static void main(String[] args) {
    BigInteger b1 = new BigInteger("200");
    BigInteger b2 = new BigInteger("201");

    System.out.println(b1.add(b2));      // 加法运算 401
    System.out.println(b1.subtract(b2)); // 减法运算 -1
    System.out.println(b1.multiply(b2)); // 乘法原酸 40200
    System.out.println(b1.divide(b2));   // 除法运算 0
    System.out.println(b1.remainder(b2));// 取余运算 200
    BigInteger[] integers = b1.divideAndRemainder(b2); //一次性获得商和余数 [0,200]
    for (int i = 0; i < integers.length; i++) {
        System.out.println(integers[i]);
    }
}

String类

  • 由final修饰,不可被继承

  • 从jdk1.9开始该类的底层不使用char[]来存储数据,而是改成 byte[]加上编码标记,从而节约了一些空间。

  • 该类描述的字符串内容是个常量不可更改,因此可以被共享使用。

    如:String str1 = “abc”; - 其中"abc"这个字符串是个常量不可改变。

    ​ str1 = “123”; - 将“123”字符串的地址赋值给变量str1。

    ​ - 改变str1的指向并没有改变指向的内容

常量池

  • 由于String类型描述的字符串内容是常量不可改变,因此Java虚拟机将首次出现的字符串放入常量池中,若后续代码中出现了相同字符串内容,则直接使用池中已有的字符串对象而无需申请内容及创建对象,从而提高了性能
public static void main(String[] args) {
    String str1 = "abc";
    String str2 = "abc";
    System.out.println(str1 == str2); //由于常量池 所以返回的是true
}

常用构造方法

方法名 功能介绍
String() 使用无参方式构造对象得到空字符序列
String(byte[] bytes, int offffset, int length) 使用bytes数组中下标从offffset位置开始的length个字节来构造对象
String(byte[] bytes) 使用bytes数组中的所有内容构造对象
String(char[] value, int offffset, intcount) 使用value数组中下标从offffset位置开始的count个字符来构造对象
String(char[] value) 使用value数组中的所有内容构造对象
String(String original) 根据参数指定的字符串内容来构造对象,新创建对象为参
public static void main(String[] args) {
    String str1 = new String();//this.value = "".value;
    System.out.println(str1);  //打印 ""
    System.out.println("---------------------");
    byte[] bArr = {97, 98, 99, 100, 101};
    // 98 -> b 99 -> c 100 -> d
    String str2 = new String(bArr, 1, 3); //使用byte数组中某几个元素构造对象
    System.out.println(str2); //打印 bcd
    System.out.println("---------------------");
    String str3 = new String(bArr); //使用byte中全部元素构造对象
    System.out.println(str3); //打印abcde
    System.out.println("---------------------");
    char[] cArr = {'a', 'b', 'c', 'd'};
    String str4 = new String(cArr, 1, 3); //使用char数组中某几个元素构造对象
    System.out.println(str4); //打印bcd
    String str5 = new String(cArr); //使用char数组中全部元素构造对象
    System.out.println(str5); //打印abcd
    System.out.println("---------------------");
    String str6 = new String("orrr"); //使用字符串构造对象
    System.out.println(str6); //打印orrr
}

笔试题

public static void main(String[] args) {
    // 1.请问以下代码会创建几个对象?分别存放在什么地方?
    //1个对象,存放在常量池中
    String str1 = "hello";
    String str2 = "hello";
    //2个对象 "hello"参数对象在常量池中,新创建的str2在内存堆区
    String str3 = new String("hello");
    String str4 = new String("hello");

    String str5 = "abcd";
    String str6 = "ab" + "cd"; //常量优化机制

    String str7 = "ab";
    String str8 = str7 + "cd";  //str7非常量
    System.out.println(str1 == str2);      //打印true 常量池中比较
    System.out.println(str1.equals(str2)); //打印true 比较字符串的值
    System.out.println(str3 == str4);      //打印false 内存堆区空间不同
    System.out.println(str3.equals(str4)); //打印true 比较字符串的值相同
    System.out.println(str2 == str4);      //打印false 常量池和内存堆区空间比较
    System.out.println(str2.equals(str4)); //打印true 比较字符串的值相同
    System.out.println(str5 == str6);      //打印true 常量池中比较
    System.out.println(str5 == str8);      //打印false 使用+连接 新的对象产生
}

常用的成员方法

方法名 功能介绍
String toString() 返回字符串本身
byte[] getBytes() 将当前字符串内容转换为byte数组并返回
char[] toCharArray() 用于将当前字符串内容转换为char数组并返回
public static void main(String[] args) {
    String str1 = new String("hello");
    byte[] bytes = str1.getBytes(); //先将字符串转换为单个字符
    for (int i = 0; i < bytes.length; i++) {
        //104
        //101
        //108
        //108
        //111
        System.out.println(bytes[i]); //循环打印每个字符的ASCII码
    }
    //将byte数组转换为String类型
    String str2 = new String(bytes);
    System.out.println(str2); //打印hello
    //将String转换为char数组类型
    char[] chars = str1.toCharArray();
    for (int i = 0; i < chars.length; i++) {
        //h
        //e
        //l
        //l
        //o
        System.out.println(chars[i]);
    }
    //将char数组转换为String
    String str3 = new String(chars);
    System.out.println(str3); //打印hello
}

方法名 功能介绍
char charAt(int index) 方法charAt用于返回字符串指定位置的字符。
int length() 返回字符串字符序列的长度
boolean isEmpty() 判断字符串是否为空
public static void main(String[] args) {
    String str1 = new String("hello");

    System.out.println(str1.charAt(0)); //打印h
    System.out.println(str1.charAt(3)); //打印l
    System.out.println(str1.charAt(4)); //打印o
    System.out.println(str1.charAt(5)); //StringIndexOutOfBoundsException

    System.out.println(str1.length()); //打印5

    System.out.println(str1.isEmpty()); //打印false
}

笔试考点

//请使用两种方式将"12345"转换为整数型12345
//方式1:
String str2 = new String("12345");
int ia = Integer.parseInt(str2);
System.out.println(ia);
//方式2: 利用ASCII码值实现类型转换并打印
//'1' - 48 -> 1
//'1' - '0' -> 1
int ib = 0;
for (int i = 0; i < str2.length(); i++) {
    ib = ib * 10 + (str2.charAt(i) - '0'); //ib * 10提升身位
}
System.out.println(ib);

案例题目1

  • 判断字符串"上海自来水来自海上"是否为回文
String str = "上海自来水来自海上";
for (int i = 0; i < str.length(); i++) {
    if (str.charAt(i) != str.charAt(str.length() - i - 1)) {
        System.out.println("不是回文");
        return;
    }
}
System.out.println("是回文");

方法名 功能介绍
int compareTo(String anotherString) 用于比较调用对象和参数对象的大小关系
int compareToIgnoreCase(String str) 不考虑大小写,也就是’a’和’A’是相等的关系
public static void main(String[] args) {
    String str1 = new String("hello");
    String str2 = new String("world");
    //按字符串索引从第一个开始逐一对比,第一个相同和第二个比
    //h和w的ASCII码比 'h'-'w' -> 104-119 = -15
    System.out.println(str1.compareTo(str2));    
    //第一个相同,比较第二个 'e'-'h' -> 101-104 = -3
    System.out.println(str1.compareTo("hhhhhhhh")); 
    System.out.println(str1.compareTo("hello")); //打印0
    System.out.println(str1.compareToIgnoreCase("HELLO")); //打印0
}

方法名 功能介绍
String concat(String str) 用于实现字符串的拼接
boolean contains(CharSequence s) 用于判断当前字符串是否包含参数指定的内容
String toLowerCase() 返回字符串的小写形式
String toUpperCase() 返回字符串的大写形式
String trim() 返回去掉前导和后继空白的字符串
boolean startsWith(String prefifix) 判断字符串是否以参数字符串开头
boolean startsWith(String prefifix, int toffffset) 从指定位置开始是否以参数字符串开头
boolean endsWith(String suffiffiffix) 判断字符串是否以参数字符串结尾
public static void main(String[] args) {
    String str1 = new String("  Hello World  ");
    System.out.println(str1.contains("hello")); //区分大小写,返回false
    System.out.println(str1.contains("Hello")); //返回true
    System.out.println(str1.toUpperCase()); //转换为大写   HELLO WORLD
    System.out.println(str1); //打印  Hello World  常量 不会因为方法的调用而改变
    System.out.println(str1.toLowerCase());  //转换为小写   hello world
    System.out.println(str1.trim()); //去除空格首尾两边Hello World
    System.out.println(str1.startsWith("H")); //返回false 是以空格开头因此是false
    String str2 = str1.trim();
    System.out.println(str2.startsWith("H")); //返回true
    System.out.println(str2.startsWith("e", 1)); //返回true
    System.out.println(str2.endsWith("d")); //返回true
}

案例题目2

  • 提示用户从键盘输入用户名和密码信息,若输入”admin”和”123456”则提示“登录成功,欢迎使用”,否则提示“用户名或密码错误,您还有n次机会”,若用户输入三次后依然错误则提示“账户已冻结,请联系客服人员!”
public static void main(String[] args) {
    Scanner sc = new Scanner(System.in);
    for (int i = 3; i > 0; 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 (1 == i) {
            System.out.println("账户已冻结,请联系管理员!");
            break;
        }
        System.out.println("用户名或密码输入错误,您还有" + (i - 1) + "次机会");
    }
    sc.close();
}

方法名 功能介绍
int indexOf(int ch) 用于返回当前字符串中参数ch指定的字符第一次出现的下标
int indexOf(int ch, int fromIndex) 用于从fromIndex位置开始查找ch指定的字符
int indexOf(String str) 在字符串中检索str返回其第一次出现的位置,若找不到返回-1
int indexOf(String str, int fromIndex) 表示从字符串的fromIndex位置开始检索str第一次出现的位置
int lastIndexOf(int ch) 用于返回参数ch指定的字符最后一次出现的下标
int lastIndexOf(int ch, int fromIndex) 用于从fromIndex位置开始查找ch指定字符出现的下标
int lastIndexOf(String str) 返回str指定字符串最后一次出现的下标
int lastIndexOf(String str, int fromIndex) 用于从fromIndex位置开始反向搜索的第一次出现的下标
public static void main(String[] args) {
    String str = new String("Hello World");

    System.out.println(str.indexOf('e')); //有该字符返回索引位置1
    System.out.println(str.indexOf('0')); //无该字符返回-1
    System.out.println(str.indexOf('o')); //返回第一次出现的位置4
    System.out.println(str.indexOf('o',7)); //返回从下标为7的元素之后的元素位置 7
    System.out.println(str.indexOf("Wor")); //返回字符串中第一个字符的下标位置6
}

案例题目3

  • 编写通用的代码可以查询字符串"Good Good Study, Day Day Up!"中所有"Day"出现的索引位置并打印出来。
public static void FindDay(String str) {
    int indexOf = str.indexOf("Day");
    while (indexOf != -1) {
        System.out.println(indexOf);
        indexOf += "Day".length();
        indexOf = str.indexOf("Day", indexOf);
    }
}

方法名 功能介绍
String substring(int beginIndex, int endIndex) 返回字符串中从下标beginIndex(包括)开始到endIndex(不包括)结束的子字符串
String substring(int beginIndex) 返回字符串中从下标beginIndex(包括)开始到字符串结尾的子字符串

案例题目4

  • 提示用户从键盘输入一个字符串和一个字符,输出该字符(不含)后面的所有子字符串。
public static void test() {
    Scanner sc = new Scanner(System.in);
    System.out.println("请输入一个字符串");
    String str = sc.next();
    System.out.println("请输入一个字符");
    String next = sc.next();

    int indexOf = str.indexOf(next);
    String substring = str.substring(indexOf + 1);
    System.out.println(substring);
}

正则表达式

  • 通常以^开头,以$结尾,可以省略
正则表达式 说明
[abc] 只可以出现abc中的任意一个字符
[^abc] 除了abc之外的任意字符
[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可以出现一次或一次都没有,也就是0-1次
X* 表示X可以出现0次或多次,也就是0-n次
X+ 表示X可以出现1次或多次,也就是1-n次
X{n} 表示X可以出现n次,也就是=n
X{n, } 表示X可以出现至少n次,也就是>=n次
X{n,m} 表示X可以出现n-m次,>=n && <=m次

相关方法1

方法名 功能介绍
boolean mathches(String regex) 判断当前正在调用方法的对象是否满足参数的正则表达式规则
regex -->规则

案例题目1

  • 使用正则表达式描述一下银行卡密码的规则:要求是由6位数字组成
public static void test1() {
    String regex = "^\\d{6}$";
    System.out.println("请输入银行卡密码");
    Scanner scanner = new Scanner(System.in);
    while (true) {
        String str = scanner.next();
        if (str.matches(regex)) {
            System.out.println("输入正确!");
            break;
        } else {
            System.out.println("输入错误,请重新输入!");
        }
    }
}

案例题目2

  • 使用正则表达式描述一下QQ号码的规则:要求是由非0开头的5~15位数组成
public static void test2() {
    String regex = "[1-9]\\d{4,14}";
    System.out.println("请输入QQ账号");
    Scanner scanner = new Scanner(System.in);
    while (true) {
        String str = scanner.next();
        if (str.matches(regex)) {
            System.out.println("输入正确!");
            break;
        } else {
            System.out.println("输入错误,请重新输入!");
        }
    }
}

案例题目3

  • 使用正则表达式描述一下手机号码的规则:要求是由1开头,第二位数是3、4、5、7、8中的一位,总共11位
public static void test3(){
    String regex = "1[34578]\\d{9}";
    System.out.println("请输入手机号");
    Scanner scanner = new Scanner(System.in);
    while (true) {
        String str = scanner.next();
        if (str.matches(regex)) {
            System.out.println("输入正确!");
            break;
        } else {
            System.out.println("输入错误,请重新输入!");
        }
    }
}

案例题目4

  • 描述身份证号码的规则:总共18位,6位数字代表地区,4位数字代表年,2位数字代表月,2位数字代表日期, 3位数字代表个人,最后一位可能数字也可能是X。
public static void test4(){
    String regex = "(\\d{6})(\\d{4})(\\d{2})(\\d{2})(\\d{3})([0-9|X])";
    System.out.println("请输入身份证号");
    Scanner scanner = new Scanner(System.in);
    while (true) {
        String str = scanner.next();
        if (str.matches(regex)) {
            System.out.println("输入正确!");
            break;
        } else {
            System.out.println("输入错误,请重新输入!");
        }
    }
}

相关方法2

方法名 功能介绍
String[] split(String regex) 参数regex为正则表达式,以regex所表示的字符串为分隔符,将字符串拆分成字符串数组
String replace(char oldChar, char newChar) 使用参数newChar替换此字符串中出现的所有参数oldChar
String replaceFirst(String regex, String replacement) 替换此字符串匹配给定的正则表达式的第一个子字符串
String replaceAll(String regex, String replacement) 将字符串中匹配正则表达式regex的字符串替换成replacement
String str1 = "1001,zhangfei,30";
String[] split = str1.split(",");
for (int i = 0; i < split.length; i++) {
    //1001
    //zhangfei
    //30
    System.out.println(split[i]);
}

String str2 = "Day Day Up!";
String replace = str2.replace("Day", "PP");
System.out.println(replace); //打印PP PP Up!

String replaceFirst = str2.replaceFirst("Day", "PP");
System.out.println(replaceFirst); //打印PP Day Up!

String str3 = "12321asdsa32123sdkasda";
//将前面数字替换为"#"
String replaceFirst1 = str3.replaceFirst("\\d+", "#");
System.out.println(replaceFirst1); //打印#asdsa32123sdkasda
String replaceFirst1 = str3.replaceFirst("\\d", "#");
System.out.println(replaceFirst1); //打印#2321asdsa32123sdkasda
//将所有字母替换为"A"
String replaceAll = str3.replaceAll("[a-z]+", "A");
System.out.println(replaceAll); //打印12321A32123A
String replaceAll = str3.replaceAll("[a-z]", "A");
System.out.println(replaceAll); //打印12321AAAAA32123AAAAAAA

可变字符串类和时间类

  • 由于String类描述的字符串内容是个常量,不可改变,当需要在java代码中描述大量类似的字符串时,只能单独申请和存储,此时会造成内存空间的浪费
  • 为了解决上述问题,可以使用java.lang.StringBuilder类和java.lang.StringBuffer类来描述字符序列可以改变的字符串
  • StringBuffer类从jdk1.0开始存在,属于线程安全的类,因此效率比较低
  • StringBuilder类从jdk1.5开始存在,属于非线程安全的类,因此效率比较高

StringBuilder

常用的构造方法

方法声明 功能介绍
StringBuilder() 使用无参方式构造对象,容量为16
StringBuilder(int capacity) 使用指定容量的参数来构造对象,容量为参数指定的大小
StringBuilder(String str) 使用指定字符串构造对象,容量为16+传入字符串长度
public static void main(String[] args) {
    StringBuilder str = new StringBuilder();
    System.out.println(str.capacity()); //打印16
    System.out.println(str); //打印空字符串

    StringBuilder str1 = new StringBuilder(22);
    System.out.println(str1.capacity()); //打印22
    System.out.println(str1);//打印空字符串

    StringBuilder str2 = new StringBuilder("hello world");
    System.out.println(str2.capacity()); //打印27
    System.out.println(str2);//打印hello world
}

常用的成员方法

方法声明 功能介绍
StringBuilder insert(int offset, String str) 插入字符串并返回调用对象的引用,就是自己
StringBuilder append(String str) 在末尾位置追加字符串
StringBuilder deleteCharAt(int index) 将当前字符串中下标为index位置的单个字符删除
StringBuilder delete(int start,int end) 删除字符串(不包括end位置的字符)
StringBuilder replace(int start,int end,String str) 替换字符串
StringBuilder reverse() 字符串反转
public static void main(String[] args) {
    StringBuilder str1 = new StringBuilder("hello");
    StringBuilder str2 = str1.insert(0, "abcd");
    System.out.println(str1); //打印abcdhello
    System.out.println(str2); //打印abcdhello
    str2.append("ABCD");
    System.out.println(str2); //打印abcdhelloABCD
}

  • 当字符串长度超过字符串初始容量时,该字符串容量会自动扩容
  • 默认扩容算法是原始容量*2+2
int newCapacity = (oldCapacity << 1) + 2; //向左移位运算

public static void main(String[] args) {
    StringBuilder str2 = new StringBuilder("abcdhelloABCD");
    str2.deleteCharAt(1); 	  //删除后字符串下标会前移
    System.out.println(str2); //打印acdhelloABCD
    str2.delete(0,3);
    System.out.println(str2); //打印helloABCD
}

public static void main(String[] args) {
    StringBuilder str1 = new StringBuilder("hello");
    str1.replace(1,4,"ooo");
    System.out.println(str1); //打印hoooo
    str1.setCharAt(3,'p');
    System.out.println(str1); //打印hoopo
    str1.reverse();
    System.out.println(str1); //打印opooh
}

笔试考点

  • 既然StringBuilder类的对象本身可以修改,那么为什么成员方法还有返回值呢?
  • 答:为了连续调用
str1.replace(1,4,"000").delete(0,3).insert(3,"aaaa");

  • 如何实现StringBuilder和String之间的类型转换?
StringBuilder str1 = new StringBuilder("hello");
String string = str1.toString();
StringBuilder builder = new StringBuilder(string);

  • String、StringBuilder、StringBuffer谁的效率高?
  • 答:String < StringBuffer < StringBuilder

时间相关类

System类

  • java.lang.System类中提供了一些有用的类字段和方法
常用方法
方法名 功能介绍
static long currentTimeMillis() 返回当前系统时间距离1970年1月1日0时0分0秒的毫秒数
public static void main(String[] args) {
    long startTime = System.currentTimeMillis();
    for (int i = 0; i < 10000; i++) {
        System.out.println(" ");
    }
    System.out.println(System.currentTimeMillis() - startTime);
}

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) 设置调用对象为距离基准时间time毫秒的时间点
public static void main(String[] args) {
    Date date = new Date();
    System.out.println(date); //打印Wed Oct 07 10:09:20 CST 2020
    Date date1 = new Date(1000);
    System.out.println(date1); //打印Thu Jan 01 08:00:01 CST 1970
    long time = date.getTime();
    System.out.println(time); //等同于System.currentTimeMills()
    date.setTime(1000);       //等同于Date(long date)
    System.out.println(date); //打印Thu Jan 01 08:00:01 CST 1970 
}

SimpleDateFormat类

  • java.text.SimpleDateFormat类主要用于实现日期和文本之间的转换
常用方法
方法名 功能介绍
SimpleDateFormat() 使用无参方式构造对象
SimpleDateFormat(String pattern) 根据参数指定的模式来构造对象,模式主要有: y-年 M-月 d-日 H-时 m-分 s-秒
final String format(Date date) 用于将日期类型转换为文本类型
Date parse(String source) 用于将文本类型转换为日期类型
public static void main(String[] args) throws ParseException {
    Date date = new Date();
    System.out.println(date);   //Wed Oct 07 10:20:16 CST 2020
    SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
    String format = simpleDateFormat.format(date);
    System.out.println(format); //2020-10-07 10:20:16
    Date parse = simpleDateFormat.parse(format);
    System.out.println(parse);  //Wed Oct 07 10:20:16 CST 2020
}

Calendar类

  • java.util.Calender类主要用于描述特定的瞬间,取代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 fifield, int value) 设置指定字段的数值
void add(int fifield, int amount) 向指定字段增加数值
public static void main(String[] args) {
    Calendar calendar = Calendar.getInstance();
    calendar.set(2008, 8 - 1, 8, 20, 8, 8);
    SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
    String format = simpleDateFormat.format(calendar.getTime());
    System.out.println(format); //打印2008-08-08 20:08:08
    calendar.set(Calendar.YEAR, 2018);
    calendar.add(Calendar.MONTH,2);
    SimpleDateFormat simpleDateFormat1 = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
    String format1 = simpleDateFormat.format(calendar.getTime());
    System.out.println(format1); //打印2018-10-08 20:08:08
}

笔试考点
  • 既然Calendar是个抽象类不能创建对象,那么为什么下面的方法可以获取Calendar类型的引用呢?

  • Calendar.getInstance()

  • 答:由源码可知,返回的并不是Calendar类型的对象,而是Calendar的子类BuddhistCalendar、JapaneseImperialCalendar、GregorianCalendar等类型的对象形成多态

Calendar cal = null;

if (aLocale.hasExtensions()) {
    String caltype = aLocale.getUnicodeLocaleType("ca");
    if (caltype != null) {
        switch (caltype) {
            case "buddhist":
                cal = new BuddhistCalendar(zone, aLocale);
                break;
            case "japanese":
                cal = new JapaneseImperialCalendar(zone, aLocale);
                break;
            case "gregory":
                cal = new GregorianCalendar(zone, aLocale);
                break;
        }
    }
}
if (cal == null) {
    // If no known calendar type is explicitly specified,
    // perform the traditional way to create a Calendar:
    // create a BuddhistCalendar for th_TH locale,
    // a JapaneseImperialCalendar for ja_JP_JP locale, or
    // a GregorianCalendar for any other locales.
    // NOTE: The language, country and variant strings are interned.
    if (aLocale.getLanguage() == "th" && aLocale.getCountry() == "TH") {
        cal = new BuddhistCalendar(zone, aLocale);
    } else if (aLocale.getVariant() == "JP" && aLocale.getLanguage() == "ja"
               && aLocale.getCountry() == "JP") {
        cal = new JapaneseImperialCalendar(zone, aLocale);
    } else {
        cal = new GregorianCalendar(zone, aLocale);
    }
}
return cal;

java8中日期相关类

  • JDK 1.0中包含了一个java.util.Date类,但是它的大多数方法已经在JDK 1.1引入Calendar类之后被弃用了。而Calendar并不比Date好多少。它们面临的问题是:

  • Date类中的年份是从1900开始的,而月份都从0开始。

  • 格式化只对Date类有用,对Calendar类则不能使用。

  • 非线程安全等。

  • Java 8通过发布新的Date-Time API来进一步加强对 日期与时间的处理。

  • java.time包:该包日期/时间API的基础包。

  • java.time.chrono包:该包提供对不同日历系统的访问。

  • java.time.format包:该包能够格式化和解析日期时间对象。

  • java.time.temporal包:该包包含底层框架和扩展特性。

  • java.time.zone包:该包支持不同时区以及相关规则的类。

LocalDate类

  • java.time.LocalDate类主要用于描述年-月-日格式的日期信息,该类不表示时间和时区信息。
常用方法
方法名 功能介绍
static LocalDate now() 在默认时区中从系统时钟获取当前日期
public static void main(String[] args) {
    LocalDate date = LocalDate.now();
    System.out.println(date); //打印2020-10-07
}

LocalTime类

  • java.time.LocalTime 类主要用于描述时间信息,可以描述时分秒以及纳秒
常用方法
方法名 功能介绍
static LocalTime now() 从默认时区的系统时间中获取当前时间
static LocalTime now(ZoneId zone) 获取指定时区的当前时间

LocalDateTime类

常用方法
方法名 功能介绍
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() 获取秒数
public static void main(String[] args) {
    LocalDate date = LocalDate.now();
    System.out.println(date); //打印2020-10-07
    LocalTime localTime = LocalTime.now();
    System.out.println(localTime); //打印10:59:55.236568700
    LocalDateTime localDateTime = LocalDateTime.now();
    System.out.println(localDateTime); //打印2020-10-07T10:59:55.237566
    LocalDateTime of = LocalDateTime.of(2008, 8, 8, 20, 8, 8);
    System.out.println(of); //打印2008-08-08T20:08:08
}

Instant类

  • java.time.Instant类主要用于描述瞬间的时间点信息
常用方法
方法名 功能介绍
static Instant now() 从系统时钟上获取当前时间
OffffsetDateTime atOffffset(ZoneOffffset offffset) 将此瞬间与偏移量组合以创建偏移日期时间
static Instant ofEpochMilli(long epochMilli) 根据参数指定的毫秒数来构造对象,参数为距离1970年1月1 日0时0分0秒的毫秒数
long toEpochMilli() 获取距离1970年1月1日0时0分0秒的毫秒数
public static void main(String[] args) {
    Instant instant = Instant.now();
    //并不是系统的默认时区  本初子午线 -8小时
    System.out.println(instant); //打印2020-10-07T03:14:06.060947100Z
    //加上8小时 偏移日期时间
    OffsetDateTime time = instant.atOffset(ZoneOffset.ofHours(8));
    System.out.println(time);    //打印2020-10-07T11:17:10.435331100+08:00
    long milli = instant.toEpochMilli();
    System.out.println(milli);   //打印1602040719046
    Instant instant1 = Instant.ofEpochMilli(1000);
    System.out.println(instant1); //打印1970-01-01T00:00:01Z
}

DateTimeFormatter类

  • java.time.format.DateTimeFormatter类主要用于格式化和解析日期
常用方法
方法名 功能介绍
static DateTimeFormatter ofPattern(String pattern) 根据参数指定的模式来获取对象
String format(TemporalAccessor temporal) 将参数指定日期时间转换为字符串
TemporalAccessor parse(CharSequence text) 将参数指定字符串转换为日期时间
public static void main(String[] args) {
    DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
    String format = dateTimeFormatter.format(LocalDateTime.now());
    System.out.println(format);  //打印2020-10-07 11:23:23

    TemporalAccessor parse = dateTimeFormatter.parse(format);
    System.out.println(parse);  //打印{},ISO resolved to 2020-10-07T11:24:01
}

集合类库

概述

  • 当需要描述一个类型的单个数据时,使用变量记录
  • 当需要描述一个类型的多个数据时,使用数组记录
  • 当需要描述多个类型不同的多个数据时,使用对象记录
  • 当需要描述多个类型相同的对象数据时,使用对象数组记录
  • 当需要描述多个类型不同的对象数据时,使用集合记录

框架结构

  • Java中集合框架顶层框架是:java.util.Collection集合和java.util.Map集合
  • 其中Collection集合中存取元素的基本单位是:单个元素
  • Mao集合中存取元素的基本单位是:单对元素
Collection接口
List接口
Queue接口
Set接口
ArrayList类
LinkedList类
Stack类
Vector类
HashSet类
TreeSet类
LinkedHashSet类
Map接口
HashMap类
TreeMap类
HashTable类
LinkedHashMap类
Properties

Collection接口

  • java.util.Collection接口是List接口、Queue 接口以及Set接口的父接口,因此该接口里定义的方法既可用于操作List集合,也可用于操作Queue集合和Set集合。

常用方法

方法名 功能介绍
boolean add(E e); 向集合中添加对象
boolean addAll(Collection c) 用于将参数指定集合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() 获取当前集合的迭代器
public static void main(String[] args) {
    //接口类型的引用指向实现类的对象,形成多态
    Collection c1 = new ArrayList();
    System.out.println(c1); //集合中无内容,打印[]
    boolean b1 = c1.add("111");
    System.out.println(b1); //添加成功 打印true
    b1 = c1.add(123);
    System.out.println(b1); //添加成功 打印true
    c1.add(new Date());
    System.out.println(c1); //打印[111, 123, Wed Oct 07 12:21:47 CST 2020]
}

public static void main(String[] args) {
    //接口类型的引用指向实现类的对象,形成多态
    Collection c1 = new ArrayList();
    c1.add("111");
    c1.add(new Person(1, "zhangfei"));
    System.out.println(c1);
    //使用参数对象与集合中已有元素依次进行比较,比较方式调用Object中的equals方法
    //当Person类中没有重写equals方法时,则调用Object中的equals方法
    boolean b1 = c1.contains("111");
    System.out.println(b1); //集合中包含111,打印true
    b1 = c1.contains(new Person(1, "zhangfei"));
    System.out.println(b1); //两个Person对象内存地址不同,打印false
}

public static void main(String[] args) {
    //接口类型的引用指向实现类的对象,形成多态
    Collection c1 = new ArrayList();
    c1.add("111");
    c1.add(new Person(1, "zhangfei"));
    Collection c2 = new ArrayList();
    c2.add(new Person(1, "zhangfei"));
    c2.add(5);
    //removeAll实际上就是一个一个元素删除
    boolean b1 = c1.removeAll(c2);
    System.out.println(c1); //打印[111]
    System.out.println(b1);
}

  • 集合通常情况下认为是数组的替代
public static void main(String[] args) {
    //接口类型的引用指向实现类的对象,形成多态
    Collection c1 = new ArrayList();
    c1.add("111");
    c1.add(new Person(1, "zhangfei"));
    Object[] objects = c1.toArray();
    //集合转换为数组类型
    System.out.println(Arrays.toString(objects));
    //数组转换为集合类型
    Collection list = Arrays.asList(objects);
    System.out.println(list);
}

Iterator接口

  • java.util.Iterator接口主要用于描述迭代器对象,可以遍历Collection集合中的所有元素。
  • java.util.Collection接口继承Iterator接口,因此所有实现Collection接口的实现类都可以使用该迭代器对象。
  • Collection接口继承于Iterator接口

常用方法

方法名 功能介绍
boolean hasNext() 判断集合中是否有可以迭代/访问的元素
E next() 用于取出一个元素并指向下一个元素
void remove() 用于删除访问到的最后一个元素
public static void main(String[] args) {
    Collection c1 = new ArrayList();
    c1.add("123");
    c1.add(new Person(1,"zhangfei"));
    c1.add(100);
    Iterator iterator = c1.iterator();
    while (iterator.hasNext()){
        //123
        //Person{id=1, name='zhangfei'}
        //100
        System.out.println(iterator.next());
    }
}

案例题目

  • 使用迭代器模拟toString()方法实现效果
  • AbstractCollection中toString()方法也是使用迭代器实现
public static void main(String[] args) {
    Collection c1 = new ArrayList();
    c1.add("123");
    c1.add(new Person(1, "zhangfei"));
    c1.add(100);
    Iterator iterator = c1.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);
}

  • 删除迭代器内元素使用Iterator中的remove方法
  • 不能使用集合的remove方法,会出现ConcurrentModificationException,属于另外一个线程操作
public static void main(String[] args) {
    Collection c1 = new ArrayList();
    c1.add("123");
    c1.add(new Person(1, "zhangfei"));
    c1.add(100);
    Iterator iterator = c1.iterator();
    while (iterator.hasNext()) {
        Object obj = iterator.next();
        if("123".equals(obj)){
            c1.remove(obj); //java.util.ConcurrentModificationException
        }
    }
    System.out.println(c1);
}

for-each循环

public static void main(String[] args) {
    Collection c1 = new ArrayList();
    c1.add("123");
    c1.add(new Person(1, "zhangfei"));
    c1.add(100);
    for (Object obj : c1) {
        System.out.println(obj);
    }
}

List集合

  • java.util.List集合是Collection集合的子类,该集合中允许有重复的元素,并且有先后放入的顺序

  • List集合的主要实现类:ArrayList类、LinkedList类、Stack类、Vector类

ArrayList

  • 其中ArrayList类的底层是采用动态数组进行数据管理的,支持下标访问,增删元素不方便
public static void main(String[] args) {
    //由源码可知,当new对象时并没有申请数组的内存空间
    List list = new ArrayList();
    //当添加调用add方法时,会给数组申请长度为10的一维数组,扩容原理是原长度的1.5倍
    list.add("one");
    System.out.println(list);
}

LinkedList

  • 其中LinkedList类的底层是采用双向链表进行数据管理的,访问方便,增删元素方便
/**
 * Links e as last element.
 */
void linkLast(E e) {
    final Node<E> l = last;
    final Node<E> newNode = new Node<>(l, e, null);
    last = newNode;
    if (l == null)
        first = newNode;
    else
        l.next = newNode;
    size++;
    modCount++;
}

常用的方法

方法名 功能介绍
void add(int index, E element) 向集合中指定位置添加元素
boolean addAll(int index, Collection c) 向集合中添加所有元素
E get(int index) 从集合中获取指定位置元素
int indexOf(Object o) 查找参数指定的对象
int lastIndexOf(Object o) 反向查找参数指定的对象
E set(int index, E element) 修改指定位置的元素
E remove(int index) 删除指定位置的元素
List subList(int fromIndex, int toIndex) 用于获取子List
public static void main(String[] args) {
    List list = new ArrayList();
    list.add("one");
    list.add("two");
    list.add("three");
    list.add("four");
    System.out.println(list);           //[one, two, three, four]
    //子集合和当前集合共用一块内存空间
    List subList = list.subList(1, 3);  //[two, three]
    System.out.println(subList);
    list.remove(1);
    System.out.println(list);           //[one, three, four]
    subList = list.subList(1, 3);
    System.out.println(subList);        //[three, four]

}

Stack(栈)

  • 其中Stack类的底层是采用动态数组进行数据管理的,该类主要用于描述一种具有后进先出特征的数据结构,叫做栈(last in first out LIFO)

案例题目

  • 准备一个Stack集合,将数据11、22、33、44、55依次入栈并打印,然后查看栈顶元素并打印,然后将栈中所有数据依次出栈并打印。
public static void main(String[] args) {
    Stack stack = new Stack();
    for (int i = 1; i < 6; i++) {
        stack.push(i * 11);
    }
    System.out.println(stack);
    System.out.println(stack.peek());
    int len = stack.size();
    for (int i = 0; i < len ; i++) {
        Object pop = stack.pop();
        System.out.println(pop);
    }
}

  • 其中Vector类的底层是采用动态数组进行数据管理的,该类与ArrayList类相比属于线程安全的类,效率比较低,以后开发中基本不用。

Queue集合(队列)

  • java.util.Queue集合是Collection集合的子集合,与List集合属于平级关系
  • 该集合的主要用于描述具有先进先出特征的数据结构,叫做队列(fifirst in fifirst out FIFO)
  • 该集合的主要实现类是LinkedList类,因为该类在增删方面比较有优势。

常用的方法

方法名 功能介绍
boolean offffer(E e) 将一个对象添加至队尾,若添加成功则返回true
E poll() 从队首删除并返回一个元素
E peek() 返回队首的元素(但并不删除)
public static void main(String[] args) {
    Queue queue = new LinkedList();
    for (int i = 1; i <= 5; i++) {
        boolean offer = queue.offer(i * 11);
        System.out.println(queue);
    }
    //查看队首元素
    System.out.println(queue.peek());
    int len = queue.size();
    //循环打印队列内元素
    for (int i = 0; i < len; i++) {
        System.out.println(queue.poll());
    }
}

泛型机制

  • 通常情况下集合中可以存放不同类型的对象,是因为将所有对象都看做Object类型放入的,因此从集合中取出元素时也是Object类型,为了表达该元素真实的数据类型,则需要强制类型转换,而强制类型转换可能会引发类型转换异常
  • 为了避免上述错误的发生,从Java5开始增加泛型机制,也就是在**集合名称的右侧使用<数据类型>**的方式来明确要求该集合中可以存放的元素类型,若放入其它类型的元素则编译报错。
  • 泛型只在编译时期有效,在运行时期不区分是什么类型。
public static void main(String[] args) {
    //菱形特性,后面<>里面的内容可以省略
    List<Integer> list = new ArrayList<>();
    list.add(1);
    list.add("one"); //编译报错
    list.add(new Person(1, "zhangfei")); //编译报错
}

笔试考点

  • 支持的泛型类型不同,不可以互相赋值
public static void main(String[] args) {
    List<Integer> list = new ArrayList<>();
    List<Double> list1 = new ArrayList<>();
    list1 = list; //Error
}

#### 底层原理

  • 泛型的本质就是参数化类型,也就是让数据类型作为参数传递,其中E相当于形式参数负责占位,而使用集合时<>中的数据类型相当于实际参数,用于给形式参数E进行初始化,从而使得集合中所有的E被实际参数替换,由于实际参数可以传递各种各样广泛的数据类型,因此得名为泛型。

  • 如:

    //其中i叫做形式参数,负责占位 其中E叫做形式参数,负责占位

    //int i = 10; E = String;

    //int i = 20; E = Integer;

    public static void show(int i) { public interface List {

    … …

    } }

    //其中10叫做实际参数,负责给形式参数初始化 //其中String叫做实际参数

    show(10); List lt1 = …;

    show(20); List lt2 = …;

自定义泛型接口

  • 泛型接口和普通接口的区别就是后面添加了类型参数列表,可以有多个类型参数,如:等。
package com.lagou.generic;

/**
 * 自定义泛型类Person,其中T相当于形式参数负责占位,具体数值由实参决定
 * @param  看作是一种名字为T的数据类型
 */
public class Person<T> {

    private String name;
    private int age;
    private T 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;
    }

    public T getGender() {
        return gender;
    }

    public void setGender(T gender) {
        this.gender = gender;
    }

    @Override
    public String toString() {
        return "Person{" +
                "name='" + name + '\'' +
                ", age=" + age +
                ", gender=" + gender +
                '}';
    }
}

public class PersonTest {
    
    public static void main(String[] args) {
        Person person = new Person();
        person.setGender("男");
        Person<Integer> person1 = new Person<>();
        person1.setGender(1);
        person1.setGender("男"); //Error
    }
}

自定义泛型类

  • 子类继承可指定泛型也可以不指定泛型
  • 实例化泛型类时应该指定具体的数据类型,并且是引用数据类型而不是基本数据类型。
  • 父类有泛型,子类可以选择保留泛型也可以选择指定泛型类型。
  • 子类必须是“富二代”,子类除了指定或保留父类的泛型,还可以增加自己的泛型。
//不保留泛型,且没有指定类型,此时Person类中的T默认为Object类型
//public class SubPerson extends Person { 
//保留泛型且指定类型,此时Person类中的T是String类型
//public class SubPerson extends Person {  
//保留父类的泛型,可以在构造对象时来指定T的类型
//public class SubPerson extends Person {  
//保留父类泛型,且还可以自定义自己的泛型
public class SubPerson<T, T1> extends Person<T> { 
}

自定义泛型方法

  • 泛型方法就是我们输入参数的时候,输入的是泛型参数,而不是具体的参数。我们在调用这个泛型方法的时需要对泛型参数进行实例化。
  • 泛型方法的格式:[访问权限] <泛型> 返回值类型 方法名([泛型标识 参数名称]) { 方法体; }
  • 在静态方法中使用泛型参数的时候,需要我们把静态方法定义为泛型方法。
public class SubPerson<T> extends Person<T> { 

    public static <T1> void printArray(T1[] arr) {
        for (T1 t1 : arr) {
            System.out.println(t1);
        }
    }

    public static void main(String[] args) {
        Integer[] arr = {11, 22, 33, 44, 55};
        SubPerson.printArray(arr);
    }
}

泛型在继承上的体现