• JAVA基础


    Java

    cmd命令

    盘的名称+冒号:进入该盘

    dir:显示该路径下所有文件

    cd+路径:进入某一目录

    cd…:退到上一级

    打开程序:进入exe文件的目录,直接输入exe可以启动

    用cmd编译并运行Java

    C:\Users\张瑞枝>D:
    //进入盘
    D:\>cd eclipse-workspace\Homework\src
    //进入Java文件所在目录
    D:\eclipse-workspace\Homework\src>javac Helloworld.java
    //用Javac编译Java文件
    D:\eclipse-workspace\Homework\src>java Helloworld
    Helloworld!
    //用Java运行文件
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    ‘\t’ 制表符 将前面字符串的长度变成8或者8的倍数,便于对齐

    标识符:起名字,可由数字、字母、下划线(_)和美元符($)组成

    Java结构:project - module - package - class

    二进制:0b开头

    十进制:不加开头

    八进制:0开头

    十六进制:0x开头

    byte:1个字节

    short:2个字节

    int:4个字节

    long:8个字节

    long n = 9999999999L;
    float f = 10.1F;
    //上面两个赋值时需要在后面加相应字母,最好大写
    boolean b = true;
    //Java中布尔类型只有false和true,没有0和1
    
    • 1
    • 2
    • 3
    • 4
    • 5
    //键盘录入
    //快速生成第三行:psvm
    //快速生成打印:sout
    import java.util.Scanner;//导包
    public class ScannerDemo {
    	public static void main(String[] args) {
    		Scanner sc=new Scanner(System.in);//创建对象
    		int i=sc.nextInt();//接收数据
    		int k=sc.nextInt();
    		System.out.println(i);
    		System.out.println(k);
    	}
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    数据类型

    基本数据类型:整数类型、浮点数类型、布尔类型、字符类型

    直接存储数据,存在栈内存中

    赋值给其他变量,也是赋的真实的值

    引用数据类型:除了左边的其他所有类型

    存储的是数据在其他空间的地址值

    赋值给其他变量,赋的是地址值

    在这里插入图片描述

    参数传递

    如果直接传基本数据类型,则两个方法之间不会相互影响

    在这里插入图片描述

    如果传的是引用数据类型,传递的是地址,则会改变地址所在处的值

    在这里插入图片描述

    运算符

    运算符的类型转换

    隐式转换

    取值范围小的数值 --> 取值范围大的数值

    byte --> short --> int --> long --> float --> double

    byte、short、char三种类型的数据在运算的时候,都会直接先提升为int,然后再进行运算

    强制转换
    public class Main {
        public static void main(String[] args) {
            int i = 8;
            double k =(double)(i * i);
            System.out.println(k);
        }
    }
    
    64.0
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    运算符

    ++和–在同一行时放在前面和后面都一样

    否则b=a++是先赋值后自增,b=++a是先自增后赋值

    += 、-= 、*= 、/= 、%=都隐藏着强制类型转换

    且:& 两边都要判断

    或:|

    左移:<< 向左移动,低位补0

    右移:>> 向右移动,高位补0或1(正数补0,负数补1)

    无符号右移:>>>(向右移动,高位补0)

    异或:^ 相同为false,不同为true

    上面是对二进制补码进行操作

    非:!

    短路逻辑运算符

    而且:&& 前面的判断为假就不判断下一个

    或:|| 前面的判断为假就不判断下一个

    打印

    //把ln删掉时没有换行
    public class practice1 {
        public static void main(String[] args) {
            int[] a = {1,2,3,4,5};
            int b = a[0];
            a[0] = a[4];
            a[4] = b;
            for (int i = 0; i < a.length; i++) {
                System.out.print(a[i] + ",");
            }
            //下面这个用法和c++的printf相似
            System.out.printf("你好%d",5);
        }
    }
    5,2,3,4,1,你好5
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    判断与循环及键盘录入

    //“:”可以换成“->”,不过要版本高,就可以省略break
    public class Main {
        public static void main(String[] args) {
           int number = 1;
           switch(number){
               case 1 :{
                   System.out.println("one");
                   break;
               }
               case 2 :{
                   System.out.println("two");
                   break;
               }
               case 3 :{
                   System.out.println("three");
                   break;
               }
               default :{
                   System.out.println("none");
                   break;
               }
           }
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    import java.util.Scanner;
    
    public class Main {
        public static void main(String[] args) {
            Scanner sc = new Scanner(System.in);
            //录入整数
            //录入字符串为next()或nextLine()
            int day = sc.nextInt();
            switch(day){
                case 1: case 2: case 3: case 4:case 5:
                   System.out.println("工作日");
                   break;
                case 6:case 7:
                    System.out.println("休息日");
                    break;
               default :{
                   System.out.println("none");
               }
            }
        }
    }
    //键盘录入
    //第一套体系:nextInt(),nextDouble(),next()(接受字符串,遇到空格、制表符、回车就不接收了)
    //第二套体系:nextLine(),接受字符串,遇到空格和制表符仍然可以接受,遇到回车不接收
    //如果用了体系一的再用体系二,可能会导致nextLine()接收不到
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25

    数组

    每个方法依次放入栈内存中,main方法放在最下面

    每new一个就在堆里开辟一个空间,存储数组中的数据,故数组本身是地址值

    //静态数组初始化 
    //两种写法
    public class array {
        public static void main(String[] args) {
            int[] array1 = new int[]{1,2,3};
            int[] array2 = {1,2,3};
            String[] array3 = new String[]{"aa","bb","cc"};
            String[] array4 = {"aa","bb","cc"};
            double[] array5 = new double[]{1.1,2.2,3.3};
            double[] array6 = {1.1,2.2,3.3};
            System.out.println(array1);
            System.out.println(array5);
        }
    }
    [I@4554617c
    [D@1540e19d
    //[:表示当前是一个数组
    //D:表示当前数组的元素都是double类型的
    //I:表示当前数组的元素都是int类型的
    //@:表示一个间隔符号(固定格式)
    //4554617c和1540e19d才是真正的地址值(十六进制)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    //数组遍历
    //快速生成for那一行:arr.fori
    public class array {
        public static void main(String[] args) {
            int[] arr = {1,2,3,4,5};
            for (int i = 0; i < arr.length; i++) {
                System.out.println(arr[i]);
            }
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    //动态初始化数组
    public class array {
        public static void main(String[] args) {
            String[] s = new String[50];
            s[0] = "haha";
            s[1] = "yes";
            System.out.println(s[0]);
            System.out.println(s[1]);
            System.out.println(s[2]);
    
            int[] a = new int[5];
            System.out.println(a[0]);
            System.out.println(a[1]);
        }
    }
    haha
    yes
    null
    0
    0
    //数组默认初始化规律
    //整数类型:0
    //小数类型:0.0
    //字符类型:空格字符
    //布尔类型:false
    //引用数据类型:null
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    //二维数组的初始化
    public class DoubleArray {
        public static void main(String[] args) {
            int[][] arr1 = new int[][]{{1,2},{3,4}};
            int[][] arr2 = {
                    {1,2},
                    {3,4}
            };
            int[][] arr3 = new int[3][4];
            System.out.println(arr1[0]);
            System.out.println(arr1[0][0]);
        }
    }
    [I@4554617c
    1
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    //二维数组中每一项是一维数组
    public class DoubleArray {
        public static void main(String[] args) {
            int[][] arr3 = new int[2][];
            int[] arr1 = {1,2,3,4,5};
            int[] arr2 = {6,7,8};
            //赋值的改变是直接改变地址
            arr3[0] = arr1;
            arr3[1] = arr2;
            for (int i = 0; i < arr3.length; i++) {
                for (int j = 0; j < arr3[i].length; j++) {
                    System.out.print(arr3[i][j]);
                }
            }
        }
    }
    12345678
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    随机数

    public class array {
        public static void main(String[] args) {
            int[] a = new int[10];
            Random r = new Random();
            for (int i = 0; i < a.length; i++) {
                //r.nextInt(100)生成0到99的随机数,加一则得到1到100随机数
                int num = r.nextInt(100) + 1;
                a[i] = num;
            }
            for (int i = 0; i < a.length; i++) {
                System.out.println(a[i]);
            }
    
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    方法的重载

    • 在同一个类中,定义了多个同名的方法,这些同名的方法具有同种的功能

    • 每个方法具有不同的参数类型或参数个数,这些同名的方法,就构成了重载关系

    • 简单记:同一个类中,方法名相同,参数不同的方法,与返回值无关。

      参数不同:个数不同、类型不同、顺序不同

    面向对象

    一些规范:类名首字母大写每个单词第一个字母大写,方法名及其他名首字母小写,第二个单词开始每个单词第一个字母大写。

    • 用来描述一类事物的类,叫做Javabean类

      在Javabean类中,是不写main方法的

    • 编写main方法的类,叫做测试类

      我们可以在测试类中创建Javabean类的对象并进行赋值调用

    //创建类
    public class Phone {
        //成员变量
        String brand;
        double price;
    
        //成员方法
        public void call(){
            System.out.println("手机在打电话");
        }
        public void playGame(){
            System.out.println("手机在玩游戏");
        }
    }
    
    //创建对象并赋值调用
    public class PhoneTest {
        public static void main(String[] args) {
            Phone p = new Phone();
            p.brand = "华为";
            p.price = 3999.9;
            System.out.println(p.brand);
            System.out.println(p.price);
            p.call();
            p.playGame();
        }
    }
    华为
    3999.9
    手机在打电话
    手机在玩游戏
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31

    封装

    对象有什么属性,就封装其属性对应的行为。

    private

    • 是一个权限修饰符
    • 可以修饰成员(成员变量和成员方法)
    • 被private修饰的成员只能在本类中才能访问
    • 目的是防止值被随意错误更改
    //创建类
    //提供setXxx方法,用于给成员变量赋值,方法用public修饰
    //提供getXxx方法,用于获取成员变量的值,方法用public修饰
    public class BoyFriend {
        private String name;
        private int age;
    
        public void setName(String n){
            name = n;
        }
        public String getName(){
            return name;
        }
    
        public void setAge(int a){
            if(a>=18 && a<=30) age = a;
            else System.out.println("非法参数");
        }
        public int getAge(){
            return age;
        }
    
        public void sing(){
            System.out.println("男朋友在唱歌");
        }
        public void dance(){
            System.out.println("男朋友在跳舞");
        }
    }
    
    //创建对象并赋值调用
    //这里打bf.name或bf.age会出错
    public class BoyFriendTest {
        public static void main(String[] args) {
            BoyFriend bf = new BoyFriend();
            bf.setAge(40);
            bf.setName("薛之谦");
            System.out.println(bf.getName());
            System.out.println(bf.getAge());
            bf.sing();
            bf.dance();
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43

    this

    //创建类
    public class Phone {
        private String brand;
        private double price;
    
        public void method(){
            double price = 10.0;
            //就近原则,所以下面的price是局部变量的price
            System.out.println(price);
            //this则表示成员位置的值
            System.out.println(this.price);
        }
    }
    
    //创建对象,赋值并调用方法
    public class PhoneTest {
        public static void main(String[] args) {
            Phone p = new Phone();
            p.method();
        }
    }
    10.0
    0.0
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    //创建类,使用this
    public class BoyFriend {
        private String name;
        private int age;
    
        public void setName(String name){
            this.name = name;
        }
        public String getName(){
            return name;
        }
    
        public void setAge(int age){
            if(age>=18 && age<=30) this.age = age;
            else System.out.println("非法参数");
        }
        public int getAge(){
            return age;
        }
    
        public void sing(){
            System.out.println("男朋友在唱歌");
        }
        public void dance(){
            System.out.println("男朋友在跳舞");
        }
    }
    
    //创建对象,赋值并调用方法
    public class BoyFriendTest {
        public static void main(String[] args) {
            BoyFriend bf = new BoyFriend();
            bf.setAge(40);
            bf.setName("薛之谦");
            System.out.println(bf.getName());
            System.out.println(bf.getAge());
            bf.sing();
            bf.dance();
        }
    }
    非法参数
    薛之谦
    0
    男朋友在唱歌
    男朋友在跳舞
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45

    构造方法

    1. 方法名与类名相同,大小写也相同
    2. 没有返回值类型,void也没有
    3. 没有具体的返回值,不能用return返回结果数据
    4. 每创建一次对象,虚拟机就会调用一次构造方法,不能手动调用构造方法

    如果定义了构造方法,则系统不再提供默认构造方法。

    无论是否使用,都手动书写无参数构造方法,和带全部参数的构造方法。

    //创建类
    public class Student {
        private String name;
        private int age;
    
        //默认的构造方法
        //这里也体现了构造方法的重载
        //快捷键:alt+insert,选择Constructor
        //另外可以用插件,右键选择Ptg To JavaBean快速构造JavaBean
        public Student(){
        }
        
        //自己定义的构造方法,最好两种构造方法都要写
        public Student(String name,int age){
            this.name = name;
            this.age = age;
        }
    
        //快捷键:alt+insert,选择Getter and Setter
        public void setName(String name){
            this.name = name;
        }
        public String getName(){
            return name;
        }
        public void setAge(int age){
            this.age = age;
        }
        public int getAge(){
            return age;
        }
    }
    
    //创建对象,赋值并调用方法
    public class StudentTest {
        public static void main(String[] args) {
            Student s = new Student();
            //可以在创建对象时直接赋值
            Student e = new Student("薛之谦",40);
            System.out.println(s.getName());
            System.out.println(s.getAge());
            System.out.println(e.getName());
            System.out.println(e.getAge());
        }
    }
    null
    0
    薛之谦
    40
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49

    JavaBean

    标准的JavaBean类

    1. 类名见名知意
    2. 所有成员变量使用private修饰
    3. 提供至少两个构造方法:无参构造方法和带全部参数的构造方法
    4. 提供每个成员变量的setXxx和getXxx

    内存

    栈内存:存储方法,先进后出

    堆内存:存储new的对象

    方法区:存储类

    对象存储的是在堆内存的地址,成员方法存储的是在方法区的地址

    在这里插入图片描述

    下面这个新建两个对象时,class文件不需要再次加载在方法区了,可直接使用

    在这里插入图片描述

    下面是两个引用指向同一个对象,则是地址值的赋值

    在这里插入图片描述

    this的内存原理

    this的本质:代表方法调用者的地址

    s存储的是在堆内存中的地址,调用method方法后,this表示的就是s存储的地址

    在这里插入图片描述

    setName中this的原理也是如此

    在这里插入图片描述

    字符串

    构造方法

    字符串是java定义好的一个类,有一些构造方法

    public class s1 {
        public static void main(String[] args) {
            String s1 = "abc";
            System.out.println(s1);
    
            //空参构造
            String s2 = new String();
            System.out.println(s2);
    
            //传递字符串构造
            String s3 = new String("abc");
            System.out.println(s3);
    
            //传递字符数组构造
            char[] c = {'a','b','c','d'};
            String s4 = new String(c);
            System.out.println(s4);
    
            //传递字节数组,根据字节数组对应在ASCII表中字符创建一个字符串
            byte[] b ={97,98,99,100};
            String s5 = new String(b);
            System.out.println(s5);
        }
    }
    
    abc
    
    abc
    abcd
    abcd
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30

    字符串的比较

    //基本数据类型比较的是数据值,引用数据类型比较的是地址值
    public class s1 {
        public static void main(String[] args) {
            //两个字符串都是存储在串池中,结果为相等
            String s1 = "abc";
            String s2 = "abc";
            System.out.println(s1 == s2);
    
            //每new一次会在堆中开辟一个新的地址,故两个的地址不同,结果为不相等
            String s3 = new String("abc");
            String s4 = new String("abc");
            System.out.println(s1 == s3);
    
            System.out.println(s1 == s3);
            //键盘录入的也会new一个String,故地址不同
            Scanner sc = new Scanner(System.in);
            String s5 = sc.next();
            System.out.println(s1 == s5);
        }
    }
    true
    false
    false
    abc
    false
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    public class s1 {
        public static void main(String[] args) {
            String s1 = "abc";
            String s2 = "abc";
            String s3 = "ABc";
            //equals()和equalsIgnoreCase()可以用来比较字符串的内容,返回的是布尔类型
            //equals()方法完全相同才是true
            //erualsIgnoreCase()方法不比较大小写
            boolean result1 = s1.equals(s2);
            boolean result2 = s1.equals(s3);
            boolean result3 = s1.equalsIgnoreCase(s3);
            System.out.println(result1);
            System.out.println(result2);
            System.out.println(result3);
        }
    }
    true
    false
    true
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    字符串索引

    public class ForString {
        public static void main(String[] args) {
            Scanner sc = new Scanner(System.in);
            String s = sc.next();
            //快捷键:s.length().fori
            //s.length().forr倒着遍历
            for(int i = 0;i< s.length();i++){
                //charAt()方法,用来索引
                System.out.print(s.charAt(i));
            }
        }
    }
    hahaxzqloveyou
    hahaxzqloveyou
        
    public class ForString {
        public static void main(String[] args) {
            Scanner sc = new Scanner(System.in);
            String s = sc.next();
            int upper = 0, lower = 0, number = 0;
            for (int i = 0; i < s.length(); i++) {
                if(s.charAt(i) >= 'a' && s.charAt(i) <= 'z') lower ++;
                else if(s.charAt(i) >= 'A' && s.charAt(i) <= 'Z') upper ++;
                else if(s.charAt(i) >= '0' && s.charAt(i) <= '9') number ++;
            }
            System.out.println(upper + ", " + lower + ", " + number);
        }
    }
    loveXZQ1314
    3, 4, 4
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30

    substring

    public class Substring {
        public static void main(String[] args) {
            String s1 = "anbcgak";
            //包前不包后,都是索引
            String s2 = s1.substring(2,5);
            //下面这个表示索引3一直截取到字符串最后
            String s3 = s1.substring(3);
            System.out.println(s1);
            System.out.println(s2);
            System.out.println(s3);
        }
    }
    anbcgak
    bcg
    cgak
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    replace

    public class StringDemo1 {
        public static void main(String[] args) {
            String num = "lovexzqmd";
            String s = new String();
            //参数:被替代的字符串,替代的字符串
            s = num.replace("md","1314");
            System.out.println(s);
        }
    }
    lovexzq1314
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    StringBuilder

    一个类,StringBuilder可以看成是一个容器,创建之后里面的内容是可变的。

    作用是提高字符串的操作效率。

    //两个构造方法
    //空参构造
    public StringBuilder()
    //根据字符串的内容,创建可变字符的对象
    public StringBuilder(String s)
    
    • 1
    • 2
    • 3
    • 4
    • 5

    常用方法

    public class StringDemo2 {
        public static void main(String[] args) {
            StringBuilder sb = new StringBuilder();
            //打印出来的不是地址值而是属性值
            //因为这是Java已经写好的类,Java在底层对它做了特殊处理
            System.out.println(sb);
    
            //可以直接对类中对象修改
            //append()向字符串添加内容
            sb.append(1);
            sb.append(2.3);
            sb.append(true);
            System.out.println(sb);
            //可以使用链式编程,如下
            //sb.append(1).append(2.3).append(true)
    
            //reverse反转字符串
            sb.reverse();
            System.out.println(sb);
            
            //toString方法把它变成字符串类型
            String s = sb.toString();
            System.out.println(s);
        }
    }
    
    
    12.3true
    eurt3.21
    eurt3.21  
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30

    StringJoiner

    和StringBuilder一样,可以看成是一个容器,创建后里面的内容是可变的。

    作用是提高字符串的操作效率。

    //构造方法 没有空参构造
    public StringJoiner(间隔符号)
    public StringJoiner(间隔符号,开始符号,结束符号)
    
    • 1
    • 2
    • 3
    public class StringDemo5 {
        public static void main(String[] args) {
            StringJoiner sj = new StringJoiner("---");
            //add方法
            sj.add("aaa").add("bbb").add("ccc");
            System.out.println(sj.toString());
    
            StringJoiner s = new StringJoiner(",","[","]");
            s.add("aaa").add("bbb").add("ccc");
            System.out.println(s);
            System.out.println(s.length());
        }
    }
    aaa---bbb---ccc
    [aaa,bbb,ccc]
    13
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    字符串拼接的底层原理

    情况一:拼接的时候没有变量参与

    会复用串池中的字符串,直接赋值也会复用串池中的字符串

    在这里插入图片描述

    情况二:拼接的时候有变量参与

    会创建StringBuilder对象

    JDK7及以前的创建方法

    在这里插入图片描述

    在这里插入图片描述

    JDK8的创建方法

    先预估字符串长度,然后创建数组,将对象放进去,再转化为字符串
    在这里插入图片描述

    字符串拼接时最好用StringBuilder或者StringJoiner

    StringBuilder源码分析

    • 默认创建一个容量为16的的字节数组
    • 添加的内容长度小于等于16,直接存
    • 添加的内容长度大于16会扩容(原来的容量*2+2)
    • 如果添加的内容长度大于扩容之后的长度,则直接创建添加的内容长度的数组
    //注意这里是初始添加的情况
    public class StringDemo6 {
        public static void main(String[] args) {
            StringBuilder sb = new StringBuilder();
            //capacity()返回容量
            System.out.println(sb.capacity());
            System.out.println(sb.length());
    
            sb.append("qwertyuiopasdfghjklzxcvbnm");
            System.out.println(sb.capacity());
            System.out.println(sb.length());
            
            StringBuilder sb2 = new StringBuilder();
            sb2.append("qwertyuiopasdfghjklzxcvbnm1234567890");
            System.out.println(sb2.capacity());
            System.out.println(sb2.length());
        }
    }
    16
    0
    34
    26
    36
    26
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24

    toCharArray

    public class StringDemo7 {
        public static void main(String[] args) {
            String s = "abcde";
            char[] c = s.toCharArray();
            //得到的数组是['a','b','c','d','e']
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    包装类

    基本数据类型包装类
    byteByte
    shortShort
    charCharacter
    intInteger
    longLong
    floatFloat
    doubleDouble
    booleanBoolean

    static

    静态方法中没有this关键字

    静态方法中,只能调用静态

    非静态方法可以访问所有

    被static修饰的成员变量,叫做静态变量。

    • 被该类所有对象共享
    • 不属于对象,属于类
    • 随着类的加载而加载,优先于对象存在

    被static修饰的成员变量,叫做静态方法。

    • 多用在测试类和工具类中
    • Javabean类中很少会用
    //创建类
    public class Student {
        private String name;
        private int age;
        private String gender;
        //创建一个static的属性,则该类共享这一属性的值
        public static String teacher;
    
        public Student() {
        }
    
        public Student(String name, int age, String 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;
        }
    
        public String getGender() {
            return gender;
        }
    
        public void setGender(String gender) {
            this.gender = gender;
        }
    }
    
    public class StudentTest {
        public static void main(String[] args) {
            Student s1 = new Student("xzq",40,"男");
            Student s2 = new Student("zrz",19,"女");
            //直接对类进行赋值
            Student.teacher = "阿玮老师";
            System.out.println(s1.getName() + ", " + s1.getGender() + ", " + s1.getAge() + ", " + s1.teacher);//xzq, 男, 40, 阿玮老师
            System.out.println(s2.getName() + ", " + s2.getGender() + ", " + s2.getAge() + ", " + s2.teacher);//zrz, 女, 19, 阿玮老师
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52

    static内存图

    静态区在堆内存中

    在这里插入图片描述

    在这里插入图片描述

    工具类

    帮我们做一些事情,不描述任何事物的类。

    //类名见名知意
    public class ArrUtil {
        //私有化构造方法
        private ArrUtil(){}
    
        //方法定义为静态
        public static int getMax(){}
        public static int getMin(){}
        public static int getSum(){}
        public static int getAvg(){}
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    继承

    当类与类之间,存在共性的内容,并满足子类是父类中的一种,就可以考虑使用继承来优化代码。

    继承可以把多个子类中重复的代码抽取到父类中,子类可以直接使用,减少代码冗余,提高代码的复用性。

    //继承格式
    //子类可以使用父类的属性和行为
    //子类可以在父类的基础上新增其他功能,子类更强大
    public class 子类 extends 父类 {}
    
    • 1
    • 2
    • 3
    • 4

    Java支持单继承,不支持多继承,支持多层继承。

    单继承:一个子类只能继承一个父类

    多继承:一个子类可以继承多个父类

    多层继承:子类A继承父类B,父类B继承父类C

    每个类都直接或间接继承于Object类

    画图法:从子类到父类画,抽取共性

    写代码:从父类到子类

    子类只能访问父类中非私有的成员。

    //构造方法私有还是非私有都不能被继承
    //成员变量私有还是非私有都可以被继承,私有的可以被继承,不能直接使用
    //成员方法可以被添加到虚方法表的可以被继承,否则不可以被继承
    
    • 1
    • 2
    • 3

    继承的内存图如下

    在这里插入图片描述

    A继承C时不是一层一层往上找的

    只有父类中的虚方法才能被子类继承

    虚方法如下图

    在这里插入图片描述

    //成员变量的访问:就近原则
    //先在本类找,找不到再去父类找
    public class Fuzi {
        public static void main(String[] args) {
            Zi z = new Zi();
            z.show();
        }
    }
    
    class Fu{
        String name = "Fu";
    }
    
    class Zi extends Fu{
        String name = "Zi";
        public void show(){
            String name = "ziShow";
            //就近原则
            System.out.println(name);//ziShow
            //调用本类的
            System.out.println(this.name);//Zi
            //调用父类的
            //最多只能调用一个直接父类的
            System.out.println(super.name);//Fu
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    //继承中方法的调用:就近原则
    public class Test {
        public static void main(String[] args) {
            OverseasStudent os = new OverseasStudent();
            os.lunch();
        }
    }
    
    class Person{
        public void eat(){
            System.out.println("eating");
        }
    
        public void drink(){
            System.out.println("drinking");
        }
    }
    
    class OverseasStudent extends Person{
    
        public void lunch(){
            //先在本类找,没有再去父类找
            this.eat();
            this.drink();
    
            //直接去父类找
            super.eat();
            super.drink();
        }
    
        public void eat(){
            System.out.println("eating other");
        }
    
        public void drink(){
            System.out.println("drinking other");
        }
    }
    
    class Students extends Person{
        public void lunch(){
            //先在本类找,再去父类找
            eat();
            drink();
        }
    }
    
    
    eating
    drinking
    eating other
    drinking other
    eating
    drinking
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54

    方法的重写

    • 当父类的方法不能满足子类的需求时,需要进行方法重写
    • @Override是放在重写后的方法上,校验子类重写时语法是否正确。
    class Person{
        public void eat(){
            System.out.println("eating");
        }
    
        public void drink(){
            System.out.println("drinking");
        }
    }
    
    class OverseasStudent extends Person{
    
        public void lunch(){
            this.eat();
            this.drink();
    
            super.eat();
            super.drink();
        }
    
        @Override
        public void eat(){
            System.out.println("eating other");
        }
    
        @Override
        public void drink(){
            System.out.println("drinking other");
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30

    方法重写的本质:覆盖父类给的虚方法表

    在这里插入图片描述

    在这里插入图片描述

    public class DogTest {
        public static void main(String[] args) {
            Husky h = new Husky();
            h.eat();
            h.drink();
            h.lookHome();
            h.destory();
    
            ChineseDog cd = new ChineseDog();
            cd.eat();
            cd.drink();
            cd.lookHome();
        }
    }
    
    public class Dog {
    
        public void eat(){
            System.out.println("吃狗粮");
        }
        public void drink(){
            System.out.println("喝水");
        }
    
        public void lookHome(){
            System.out.println("看家");
        }
    
    }
    
    public class Husky extends Dog{
        public void destory(){
            System.out.println("拆家");
        }
    }
    
    public class ShapiDog extends Dog{
        //这里可以直接快捷写eat()
        @Override
        public void eat() {
            //先调用父类的,再进行补充
            super.eat();
            System.out.println("吃骨头");
        }
    }
    
    public class ChineseDog extends Dog{
    
        //同样可以快捷键eat()
        @Override
        public void eat(){
            System.out.println("吃剩饭");
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55

    继承中构造方法的访问

    //子类中所有构造方法默认先访问父类中的无参构造,再执行自己
    //因为子类初始化前,一定要调用父类构造方法完成父类数据空间的初始化
    //子类构造方法第一句默认是super(),不写也存在,必须写在第一句
    //如果要调用父类有参构造,必须手动写super进行调用
    public class Person {
        String name;
        int age;
    
        public Person() {
            System.out.println("这里是父类");
        }
    
        public Person(String name, int age) {
            this.name = name;
            this.age = age;
        }
    }
    
    public class Student extends Person{
        public Student(){
            //先调用父类的无参构造,再调用子类的
            super();
            System.out.println("这里是子类");
        }
    
        //直接传递参数,传到super里,就会去父类找到对应的有参构造
        public Student(String name,int age){
            super(name,age);
        }
    }
    
    public class PersonTest {
        public static void main(String[] args) {
            Student s1 = new Student();
            /*这里是父类
              这里是子类*/
            Student s2 = new Student("xzq",40);
            System.out.println(s2.name + ", " + s2.age);//xzq, 40
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    public class Person {
        String name;
        int age;
    
        public Person() {
            System.out.println("这里是父类");
        }
    
        public Person(String name, int age) {
            this.name = name;
            this.age = age;
        }
    }
    
    public class Student extends Person{
        public Student(){
            //表示调用本类其他构造方法,即下面的构造方法
            //没传参时默认传的是调用者的this
            this(null,18);
        }
    
        public Student(String name,int age){
            super(name,age);
        }
    }
    
    public class PersonTest {
        public static void main(String[] args) {
            Student s1 = new Student();
            System.out.println(s1.name + ", " + s1.age);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32

    多态

    多态即同类型的对象,表现出的不同形态。

    //多态优势:方法中,使用父类型作为参数,可以接收所有子类对象
    //多态弊端:不能使用子类特有的功能
    //强制类型转换可以转换成真正的子类类型,从而调用子类独有功能
    
    • 1
    • 2
    • 3

    表现形式:父类类型 对象名称 = 子类对象;

    多态的前提

    • 有继承关系
    • 有父类引用指向子类对象
    • 有方法重写
    public class Person {
        private String name;
        private int age;
    
        public Person() {
        }
    
        public Person(String name, int age) {
            this.name = name;
            this.age = age;
        }
    
        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 void show(){
            System.out.println(name + ", " + age);
        }
    }
    
    public class Student extends Person{
        @Override
        public void show() {
            System.out.println(this.getName() + ", " + this.getAge());
        }
    }
    
    public class Teacher extends Person{
        @Override
        public void show() {
            System.out.println(this.getName() + ", " + this.getAge());
        }
    }
    
    public class Test {
    
        public static void main(String[] args) {
    
            Student s = new Student();
            s.setName("xzq");
            s.setAge(40);
    
            Teacher t = new Teacher();
            t.setName("zrz");
            t.setAge(19);
    
            show(s);
            show(t);
        }
    
        //使用父类型作为参数,可以接收所有子类对象
        //不过必须要有方法的重写
        public static void show(Person p){
            p.show();
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    public class AnimalTest {
        public static void main(String[] args) {
            Animal a = new Dog();
            //访问成员属性时:编译看左边,运行看左边
            //javac编译时,会看父类中有没有这个成员变量,有则编译成功,没有则编译失败
            //java运行时,实际获取的是左边父类中成员变量的值
            System.out.println(a.name);//动物
            
            //访问成员方法时:编译看左边,运行看右边
            //javac编译时,会看父类中有没有这个成员方法,有则编译成功,没有则编译失败
            //java运行时,实际获取的是右边子类中的成员方法
            a.show();//dog show
        }
    }
    
    class Animal{
        String name = "动物";
    
        public void show(){
            System.out.println("animal show");
        }
    }
    
    class Dog extends Animal{
        String name = "狗";
    
        @Override
        public void show() {
            System.out.println("dog show");
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31

    在这里插入图片描述

    public class AnimalTest {
        public static void main(String[] args) {
            Animal a = new Dog();
           
            //instanceof用于判断前面那个对象是不是属于后面那个类
            if(a instanceof Dog){
                //若不强转,则用a无法调用子类方法中的eat()
                Dog d = (Dog) a;
                d.eat();//dog is eating
            }else if(a instanceof Cat){
                Cat c = (Cat) a;
                c.eat();
            }
            
            //另一个简单写法,要新版本可用
            //如果a是Dog类则强转且转后命名为d
            if(a instanceof Dog d){
                d.eat();
            }else if(a instanceof Cat c){
                c.eat();
            }
        }
    }
    
    class Animal{
        String name = "动物";
    
        public void show(){
            System.out.println("animal show");
        }
    }
    
    class Dog extends Animal{
        String name = "狗";
    
        @Override
        public void show() {
            System.out.println("dog show");
        }
    
        public void eat(){
            System.out.println("dog is eating");
        }
    }
    
    class Cat extends Animal{
        @Override
        public void show() {
            System.out.println("cat show");
        }
    
        public void eat(){
            System.out.println("cat is eating");
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55

    包就是文件夹,用来管理各种不同功能的Java类。

    **包名的规则:公司域名反写 + 包的作用,需要全部英文小写,见名知意。**例:com.itheima.domain

    一个类的全类名应为 包名.类名 例:com.itheima.domain.Student

    • 使用同一个包中的类时,不需要导包
    • 使用java.lang包中的类时,不需要导包
    • 其他情况都要导包,例import com.itheima.domain.Student则默认用到的Student类都是导包中的这个类
    • 如果同时使用两个包中的同名类,需要用全类名

    final

    • final修饰方法,表示该方法是最终方法,不能被子类重写
    • final修饰类,表示该类是最终类,不能被继承
    • final修饰变量,叫做常量,只能被赋值一次

    常量命名规范

    • 单个单词:全部大写
    • 多个单词:全都大写,单词之间用下划线隔开
    //final修改基本数据类型,记录的值不能发生改变
    //final修饰引用数据类型,记录的地址值不能发生改变,内部的属性值还是可以改变
    public class Test {
    
        public static void main(String[] args) {
    
            final Student S = new Student("xzq",40);
            S.setName("zrz");
            S.setAge(19);
            System.out.println(S.getName() + ", " + S.getAge());//zrz, 19
            
            final int[] ARR = {1,2,3,4,5};
            ARR[0] = 10;
            ARR[1] = 20;
            for (int i = 0; i < ARR.length; i++) {
                System.out.println(ARR[i]);
            }/*10
               20
               3
               4
               5*/
        }
    }
    
    class Student{
        private String name;
        private int age;
    
        public Student() {
        }
    
        public Student(String name, int age) {
            this.name = name;
            this.age = age;
        }
    
        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;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52

    权限修饰符

    用来控制一个成员能被访问的范围的。可以修饰成员变量、方法、构造方法、内部类。

    在这里插入图片描述

    代码块

    构造代码块

    public class Test {
    
        public static void main(String[] args) {
    
            Student s1 = new Student();
            Student s2 = new Student("xzq",40);
        }
    }
    
    /*我要开始构造了
      有参构造
      我要开始构造了
      无参构造*/
    
    class Student{
        private String name;
        private int age;
       
        //构造代码块
        //写在成员位置的代码块
        //可以把多个构造方法中重复的代码抽取出来
        //每新建一个对象就会执行一次
        //先执行构造代码块,再执行构造方法
        {
            System.out.println("我要开始构造了");
        }
    
        public Student() {
            System.out.println("有参构造");
        }
    
        public Student(String name, int age) {
            System.out.println("无参构造");
            this.name = name;
            this.age = age;
        }
    
        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;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    public class Test {
    
        public static void main(String[] args) {
    
            Student s1 = new Student();
            Student s2 = new Student("xzq",40);
        }
    }
    
    /*
    我要开始构造了
    有参构造
    无参构造
    */
    
    class Student{
        private String name;
        private int age;
    
        //静态代码块
        //随着类的加载而加载,只会被执行一次
        //可以用来进行数据初始化
        static {
            System.out.println("我要开始构造了");
        }
    
        public Student() {
            System.out.println("有参构造");
        }
    
        public Student(String name, int age) {
            System.out.println("无参构造");
            this.name = name;
            this.age = age;
        }
    
        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;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52

    抽象类和抽象方法

    //抽象类不能实例化,不能创建对象
    //抽象类中不一定有抽象方法,有抽象方法的类一定是抽象类
    //可以有构造方法
    //抽象类的子类 要么重写抽象类中的所有抽象方法 要么是抽象类
    public class Test {
    
        public static void main(String[] args) {
    
            Student s = new Student("xzq",40);
            System.out.println(s.getName() + ", " + s.getAge());//xzq, 40
        }
    }
    
    abstract class Person{
        private String name;
        private int age;
    
        //抽象类可以有构造方法
        //可以在子类创建对象时,给属性进行赋值
        public Person() {
        }
    
        public Person(String name, int age) {
            this.name = name;
            this.age = age;
        }
    
        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;
        }
        
        //抽象类的格式,没有大括号
        abstract void work();
    }
    
    class Student extends Person{
    
        public Student() {}
    
        public Student(String name, int age) {
            super(name,age);
        }
        
        //抽象类的子类一定要重写抽象方法
        @Override
        public void work(){
            System.out.println("working");
        }
    }
    
    //抽象类的子类也可以是抽象类,但这样就也不能创建对象,只能再来一个子类创建对象
    abstract class student2 extends Person{
        
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66

    接口

    接口是一种规则,是对行为的抽象。

    • 接口用关键字interface来定义:public interface 接口名 {}
    • 接口不能实例化
    • 接口和类之间是实现关系,通过implements关键字表示:public class 类名 implements 接口名 {}
    • 接口的子类(实现类)要么重写接口中的所有抽象方法,要么是抽象类
    • 接口和类的实现关系,可以单实现,也可以多实现:public class 类名 implements 接口名1 接口名2 {}
    • 实现类还可以在继承一个类的同时实现多个接口。public class 类名 extends 父类 implements 接口名1 接口名2 {}
    //接口中
    //成员变量:只能是常量,默认修饰符:public static final
    //没有构造方法
    //成员方法:只能是抽象方法,默认修饰符:public abstract
    public class Test {
        public static void main(String[] args) {
    
            //可以直接调用,说明了默认static
            System.out.println(Inter.a);//10
        }
    }
    
    public interface Inter {
    
        //默认是public static final int a = 10
        int a = 10;
        //默认是public abstract void method()
        void method();
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    public interface Inter1 {
        public abstract void method1();
        public abstract void method2();
    }
    
    public interface Inter2 {
        public abstract void method1();
        public abstract void method2();
    }
    
    //可以同时继承多个接口
    //当接口中的方法重名时,重写一次即可
    public class Inter implements Inter1,Inter2{
        @Override
        public void method1() {
    
        }
    
        @Override
        public void method2() {
    
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    public interface Inter1 {
        public abstract void method1();
    }
    
    public interface Inter2 {
        public abstract void method2();
    }
    
    //接口之间可以继承,且可以单继承和多继承
    public interface Inter3 extends Inter1,Inter2{
        public abstract void method3();
    }
    
    //实现了子接口,则要重写子接口和所有父接口的抽象方法,如果父接口有父接口,则也要重写抽象方法
    public class Inter implements Inter3{
        @Override
        public void method1() {
    
        }
    
        @Override
        public void method2() {
    
        }
    
        @Override
        public void method3() {
    
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    public interface Inter1 {
        public abstract void method1();
        
        //接口中可以有默认方法,default不能省略
        //默认方法可以不被重写,如果被重写要去掉default关键字
        //如果实现了多个接口,都有同名的默认方法,则子类必须要重写
        public default void method2(){
            System.out.println("default method");
        }
    }
    
    public class Inter implements Inter1{
        @Override
        public void method1() {
            System.out.println("method1");
        }
        
        //如果要重写是这样的
        @Override
        public void method2() {
            Inter1.super.method2();
        }
    }
    
    public class Test {
        public static void main(String[] args) {
            Inter i = new Inter();
            i.method1();//method1
            i.method2();//default method
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    public interface Inter1 {
        
        //接口中静态方法,static关键字不能省略
        public static void show(){
            System.out.println("Inter1 show");
        }
    }
    
    public class Inter implements Inter1{
        
        //静态方法不能被重写,因为静态方法无法进入虚方法表
        //下面这个不是重写,只是又写了个一样名字的方法
        public static void show(){
            System.out.println("Inter show");
        }
    }
    
    public class Test {
        public static void main(String[] args) {
            
            //静态方法可以直接被类名调用
            Inter1.show();
            Inter.show();
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    //私有方法,只能在本类中被调用
    public interface Inter1 {
        public default void show1(){
            System.out.println("Inter1 show1");
            show3();
        }
    
        public default void show2(){
            System.out.println("Inter1 show2");
            show3();
        }
        
        //普通的私有方法,不用写default,但是是给默认方法服务的
        private void show3(){
            System.out.println("Inter show3");
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    public interface Inter1 {
        public static void show1(){
            System.out.println("Inter1 show1");
            show3();
        }
    
        public static void show2(){
            System.out.println("Inter1 show2");
            show3();
        }
    
        //静态的私有方法,一定要写static,给静态方法服务
        private static void show3(){
            System.out.println("Inter show3");
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    接口的应用

    //接口类型 j = new 实现类对象();
    //当一个方法的参数是接口时,可以传递该接口所以实现类对象,这叫做接口多态。
    
    • 1
    • 2
    //适配器设计模式
    //如下如果一个接口有五个方法,但是我们只想使用方法3
    public interface Inter1 {
        public abstract void method1();
        public abstract void method2();
        public abstract void method3();
        public abstract void method4();
        public abstract void method5();
    }
    
    //可以用一个适配器来实现接口,重写全部接口方法并且全部是空实现
    //为防止适配器被创建对象,设为abstract
    public abstract class Inter1Adapter implements Inter1{
    
        @Override
        public void method1() {
    
        }
    
        @Override
        public void method2() {
    
        }
    
        @Override
        public void method3() {
    
        }
    
        @Override
        public void method4() {
    
        }
    
        @Override
        public void method5() {
    
        }
    }
    
    //再用我们想要的类去继承适配器,重写想要的方法即可
    public class Inter extends Inter1Adapter{
        @Override
        public void method3() {
            System.out.println("new method3");
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47

    内部类

    即在一个类的里面,再定义一个类

    类的五个成员:属性、方法、构造方法、代码块、内部类

    • 内部类表示的事物是外部类的一部分
    • 内部类单独出现没有任何意义
    //内部类可以直接访问外部类的成员,包括私有
    //外部类要访问内部类的成员,必须创建对象
    public class Car {
        String carName;
        int carAge;
        String carColor;
    
        public void show(){
            System.out.println(carName);
            //外部类访问内部类成员要先创建对象
            Engine e = new Engine();
            System.out.println(e.engineName);
        }
    
        class Engine{
            String engineName;
            int engineAge;
            public void show(){
                //内部类可以直接访问外部类成员,因为默认传this
                System.out.println(engineName);
                System.out.println(carName);
            }
        }
    }
    
    public class CarTest {
        public static void main(String[] args) {
            Car c = new Car();
            c.carName = "宾利";
            c.carAge = 3;
            c.carColor = "粉色";
            c.show();
        }
    }
    宾利
    null
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36

    成员内部类

    • 写在成员位置的,属于外部类的成员。
    • 成员内部类可以被一些修饰符所修饰,比如:private、默认、protected、public、static等
    //构建内部类对象的方法
    public class Outer {
        String name;
        
        class Inner{
            
        }
        
        //可以在外部类中写一个方法返回内部类
        public Inner getInstance(){
            return new Inner();
        }
    }
    
    public class OuterTest {
        public static void main(String[] args) {
            //方法一:按以下格式新建对象
            //要内部类不是私有的情况下才行
            Outer.Inner oi = new Outer().new Inner();
    
            //方法二:创建外部类对象,再调用方法创建内部类对象
            //通常内部类是私有时使用该方法,可以用Object接收
            Outer ou = new Outer();
            Object o = ou.getInstance();
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    public class Outer {
        private int a = 10;
    
        class Inner{
            private int a = 20;
            public void show(){
                int a = 30;
                System.out.println(a);//30
                System.out.println(this.a);//20
                //Outer.this 获取了外部类对象的地址值
                System.out.println(Outer.this.a);//10
            }
        }
    
        public Inner getInstance(){
            return new Inner();
        }
    }
    
    public class OuterTest {
        public static void main(String[] args) {
            Outer.Inner oi = new Outer().new Inner();
            oi.show();
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25

    在这里插入图片描述

    内部类的堆内存中有外部类的this,故可以用Outer.this访问外部类的成员变量

    静态内部类

    • 静态内部类是成员内部类的一种,即有static修饰时
    • 静态内部类只能访问外部类中的静态变量和静态方法,如果想要访问非静态的需要创建外部类对象
    public class Outer {
        int a = 10;
        static int b = 20;
    
        static class Inner{
            public void show1(){
                //静态内部类可以直接访问静态外部类的成员变量
                System.out.println(b);
                
                //如果要访问外部类的非静态成员变量,需要创建外部类的对象再访问
                Outer o = new Outer();
                System.out.println(o.a);
            }
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    public class Outer {
        static class Inner{
            public void show1(){
                System.out.println("no static");
            }
    
            public static void show2(){
                System.out.println("static");
            }
        }
    }
    
    public class OuterTest {
        public static void main(String[] args) {
            //创建静态内部类,直接外部类点就行
            //只要是静态的东西,都可以用类名直接获取
            Outer.Inner oi = new Outer.Inner();
            
            oi.show1();//no static
            //调用静态内部类中的静态方法
            Outer.Inner.show2();//static
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23

    局部内部类

    将内部类定义在方法里面就叫做局部内部类,类似于方法里面的局部变量。

    public class Outer {
        int b = 20;
    
        public void show(){
            int a = 10;
    
            class Inner{
                
                String name;
                int age;
    
                public void method1(){
                    
                    //该类可以直接访问外部类的成员,也可以访问方法内的局部变量
                    System.out.println(a);
                    System.out.println(b);
                    System.out.println("method1");
                }
    
                public static void method2(){
                    System.out.println("static method2");
                }
            }
    
            //外界无法直接使用局部内部类
            //需要在方法内部创建对象并使用
            Inner i = new Inner();
            System.out.println(i.name);
            System.out.println(i.age);
            i.method1();
            Inner.method2();
        }
    
    }
    
    public class OuterTest {
        public static void main(String[] args) {
            Outer o = new Outer();
            o.show();
        }
    }
    
    null
    0
    10
    20
    method1
    static method2
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48

    匿名内部类

    本质是隐藏了名字的内部类

    public interface Swim {
        public void swim();
    }
    
    public abstract class Animal {
        public abstract void eat();
    }
    
    public class SwimTest {
        public static void main(String[] args) {
            
            //实质上大括号及里面的内容才是匿名的内部类
            //new Swim()则是创建了一个对象
            //这个匿名内部类实现Swim接口,所以要重写swim方法
            //所以这个实质上是匿名内部类的对象
            new Swim(){
                @Override
                public void swim() {
                    System.out.println("override swim");
                }
            };//后面有个分号
            
            //这个匿名内部类是重写了Animal的抽象方法
            //所以这个是继承关系,匿名的内部类继承了Animal类
            new Animal(){
                @Override
                public void eat() {
                    System.out.println("override eat");
                }
            };
            
            //当要调用一个方法,但是创建对象只是被传参无意义
            //可以用匿名内部类传参
            //匿名内部类的使用场景
            show(
                    new Animal() {
                        @Override
                        public void eat() {
                            System.out.println("eating");
                        }
                    }
            );
            
            //创建一个接口的实现类对象
            //接口多态
            Swim s = new Swim() {
                @Override
                public void swim() {
                    System.out.println("swimming");
                }
            };
            
            new Swim(){
                @Override
                public void swim() {
                    System.out.println("swimming");//swimming
                }
            }.swim();//用接口的实现类对象调用自己重写的方法
        }
        
        public static void show(Animal a){
            
            //编译看左边,运行看右边
            a.eat();
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66

    集合

    • 集合分为单列集合和双列集合
    • 单列集合即一个一个数据添加元素
    • 双列集合是一对一对数据添加元素

    Collection

    • Collection即单列集合,包含List和Set两个
    • List序列集合:添加的元素是有序、可重复、有索引
    • Set系列集合:添加的元素是无序、不重复、无索引

    Collection是单列集合的祖宗接口,它的功能是全部单列集合都可以继承使用的。

    import java.util.ArrayList;
    import java.util.Collection;
    
    public class Test {
        public static void main(String[] args) {
            Collection<String> coll = new ArrayList<>();
    
            //add()方法
            coll.add("aaa");
            coll.add("bbb");
            //返回布尔值
            //如果是往List系列集合添加元素,永远返回true
            //如果是往Set系列集合添加元素,集合中元素不存在返回true,集合中元素存在返回false
            //因为Set系列集合不允许重复
            System.out.println(coll.add("ccc"));//true
            System.out.println(coll);//[aaa, bbb, ccc]
    
            //clear()方法
            coll.clear();
            System.out.println(coll);//[]
    
            coll.add("aaa");
            coll.add("bbb");
            //集合元素存在返回true,不存在则返回false
            System.out.println(coll.remove("aaa"));//true
            System.out.println(coll);//[bbb]
    
            //集合中有这个元素则为true,否则为false
            //contains()方法底层用equals()方法判断,故若集合中存储的是自定义对象,需要重写equals()方法
            System.out.println(coll.contains("bbb"));//true
            
            System.out.println(coll.isEmpty());//false
    
            System.out.println(coll.size());//1
        }
    }
    
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    //Collection的contains()方法底层用equals()方法判断,故若集合中存储的是自定义对象,需要重写equals()方法
    public class Student {
        private String name;
        private int age;
    
        public Student() {
        }
    
        public Student(String name, int age) {
            this.name = name;
            this.age = age;
        }
    
        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;
        }
    
        //可以用alt加insert插入重写的equals()方法
        @Override
        public boolean equals(Object o) {
            if (this == o) return true;
            if (o == null || getClass() != o.getClass()) return false;
            Student student = (Student) o;
            return age == student.age && Objects.equals(name, student.name);
        }
    }
    
    public class StudentTest {
        public static void main(String[] args) {
            Student s1 = new Student("xzq",40);
            Collection<Student> coll = new ArrayList<>();
            coll.add(s1);
            Student s2 = new Student("xzq",40);
            //如果没有重写equals()方法则为false,因为Object类中的equals方法判断的是地址值
            System.out.println(coll.contains(s2));//true
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49

    迭代器遍历

    迭代器在Java中的类是Iterator,迭代器是集合专用的遍历方式。

    迭代器在遍历集合的时候是不依赖索引的,是用指针。

    //通常需要删除元素时才使用迭代器遍历
    import java.util.ArrayList;
    import java.util.Collection;
    import java.util.Iterator;
    
    public class Test {
        public static void main(String[] args) {
            Collection<String> coll = new ArrayList<>();
    
            coll.add("aaa");
            coll.add("bbb");
    
            //创建迭代器对象,默认指向0索引处
            Iterator<String> it = coll.iterator();
            
            //hasNext()方法判断当前位置是否有元素
            while(it.hasNext()){
                //next()方法有两个作用:获取当前位置的元素,指针移到下一个位置
                String str = it.next();
                
                //这个if语句会报错
                //迭代器遍历的时候,不能用集合的方法进行增加或者删除
                if("bbb".equals(str)){
                    coll.remove("bbb");
                }
                
                //可以用迭代器带的remove方法
                if("bbb".equals(str)){
                    it.remove();
                }
                System.out.println(str);//aaa
            }
            //注意点:迭代器遍历完毕,指针不会复位
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35

    增强for遍历

    • 增强for遍历的底层就是迭代器,为了简化迭代器的代码书写的
    • 所有单列集合和数组才能用增强for进行遍历
    • 在用增强for遍历时,也不能用集合的方法进行添加和删除
    public class ForTest {
        public static void main(String[] args) {
            Collection<String> coll = new ArrayList<>();
            coll.add("xzq");
            coll.add("love");
            
            //快捷键:coll.for
            //s只是一个第三方变量,改变其值不会改变集合中原本的数据
            for(String s : coll){
                System.out.println(s);
            }
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    Lambda表达式遍历

    public class ForTest {
        public static void main(String[] args) {
            Collection<String> coll = new ArrayList<>();
            coll.add("xzq");
            coll.add("love");
            
            //利用匿名内部类
            //底层也是遍历集合,依次得到每一个元素
            //把得到的每一个元素传递给下面的accept方法
            //s表示集合中的每一个数据
            coll.forEach(new Consumer<String>() {
                @Override
                public void accept(String s) {
                    System.out.println(s);
                }
                //xzq
                //love
            });
            
            //Lambda表达式
            coll.forEach((String s) -> {
                System.out.println(s);
            });
    
            //简化写法,可以不写数据类型,且方法体只有一行
            coll.forEach(s -> System.out.println(s));
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28

    List集合

    • 有序、有索引、可重复
    • Collection的方法List都继承了
    • List集合因为有索引,所以多了很多索引操作的方法
    public class ListTest {
        public static void main(String[] args) {
            List<String> list = new ArrayList<>();
            list.add("xzq");
            list.add("love");
            list.add("you");
            System.out.println(list);//[xzq, love, you]
    
            //List集合有的在指定索引处添加元素
            list.add(1,"i");
            System.out.println(list);//[xzq, i, love, you]
    
            //返回被删除的元素
            System.out.println(list.remove(3));//you
            list.remove("xzq");
            System.out.println(list);//[i, love]
    
            //返回被替代的元素
            System.out.println(list.set(0,"qqq"));//i
            System.out.println(list);//[qqq, love]
            
            //获得指定索引处的元素
            System.out.println(list.get(1));//love
    
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26

    在这里插入图片描述

    public class IntRemoveTest {
        public static void main(String[] args) {
            List<Integer> list = new ArrayList<>();
            list.add(1);
            list.add(2);
            list.add(3);
            
            //remove方法有两种参数传递类型,见上面的图
            //默认是删除1索引的
            //本质:在调用方法的时候,如果方法出现了重载,会优先调用实参和形参一致的方法
            list.remove(1);
    
            //如果要删除Object的,需要先封装再传递
            //即可以删除值1
            Integer i = Integer.valueOf(1);
            list.remove(i);
    
            System.out.println(list);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    List系列集合的五种遍历方式:

    1. 迭代器(在遍历过程中需要删除元素)
    2. 列表迭代器(在遍历过程中需要添加元素)
    3. 增强for循环(只是想遍历)
    4. Lambda表达式遍历(只是想遍历)
    5. 普通for循环(遍历的时候想操作索引)
    //列表迭代器
    public class ListTest {
        public static void main(String[] args) {
            List<String> list = new ArrayList<>();
            list.add("xzq");
            list.add("love");
            list.add("you");
    
            //创建列表迭代器对象
            ListIterator<String> it = list.listIterator();
            
            //和Collection不同的是多了个add()方法
            while(it.hasNext()){
                String str = it.next();
                
                //remove()方法直接删去str元素
                if("love".equals(str)) {
                    it.remove();
                }
                
                //add()方法在str元素后面一个位置加上新元素
                if("you".equals(str)){
                    it.add("tt");
                }
            }
            System.out.println(list);//[xzq, you, tt]
    
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29

    ArrayList集合

    集合和数组对比:

    • 数组长度固定,集合长度可变
    • 数组可以存基本数据类型和引用数据类型,集合可以存引用数据类型,如果要存基本数据类型,要变成包装类后才可以存
    public class Demo1 {
        public static void main(String[] args) {
            //集合是Java已经写好的一个类,底层做了处理,打印出来是里面的数据值,且会有[]将数据值包裹起来
            ArrayList<String> list = new ArrayList<>();
            System.out.println(list);
        }
    }
    []
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    基本方法

    public class Demo1 {
        public static void main(String[] args) {
            ArrayList<String> list = new ArrayList<>();
            //增加操作
            //返回值是boolean,永远是true
            list.add("aaa");
            list.add("bbb");
            list.add("ccc");
            list.add("ddd");
            System.out.println(list);//[aaa, bbb, ccc, ddd]
    
            //删除操作
            //下面这个返回被删除的数据
            String s1 = list.remove(0);
            //下面这个若数据存在返回true,否则返回false
            boolean b1 = list.remove("ccc");
            System.out.println(s1);//aaa
            System.out.println(list);//[bbb, ddd]
    
            //修改操作,将对应索引的值更改
            //返回被修改的数据
            String s2 = list.set(0,"eee");
            System.out.println(s2);//bbb
            System.out.println(list);//[eee, ddd]
    
            //查询操作
            //返回被查询的数据
            String s3 = list.get(0);
            System.out.println(s3);//eee
    
            for (int i = 0; i < list.size(); i++) {
                System.out.println(list.get(i));
            }
            //eee
            //ddd
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    public class Demo3 {
        public static void main(String[] args) {
            //使用包装类
            ArrayList<Integer> list = new ArrayList<>();
            
            //int和Integer类型可以相互转化
            list.add(1);
            list.add(7);
            list.add(1);
            list.add(7);
            for (int i = 0; i < list.size(); i++) {
                System.out.println(list.get(i));
            }
        }
    }
    1
    7
    1
    7
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    //调用Student类创建集合
    public class StudentTest {
        public static void main(String[] args) {
            ArrayList<Student> list = new ArrayList<>();
            Scanner sc = new Scanner(System.in);
            for(int i = 0;i<3 ;i++){
                String name = sc.next();
                int age = sc.nextInt();
                Student s = new Student(name,age);
                list.add(s);
            }
            for (int i = 0; i < list.size(); i++) {
                System.out.print(list.get(i).getName() + ", " + list.get(i).getAge());
                System.out.println();
            }
        }
    }
    xzq 40
    zrz 19
    xxg 5
    xzq, 40
    zrz, 19
    xxg, 5
     
    //创建Student类
    public class Student {
        private String name;
        private int age;
    
        public Student(){}
        public Student(String name,int age){
            this.name = name;
            this.age = age;
        }
    
        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;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    public class AddAllTest {
        public static void main(String[] args) {
            ArrayList<String> list1 = new ArrayList<>();
            list1.add("xzq");
            list1.add("love");
    
            ArrayList<String> list2 = new ArrayList<>();
            list2.add("i");
            
            //addAll()方法,将一个集合中全部元素加入另一个集合
            list2.addAll(list1);
            System.out.println(list2);
    
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    ArrayList集合底层原理

    1. 利用空参创建的集合,在底层创建一个默认长度为0的数组
    2. 添加第一个元素时,底层会创建一个新的长度为10的数组
    3. 存满时,会扩容1.5倍
    4. 如果一次性添加多个元素,1.5倍还放不下,则新创建数组的长度以实际为准

    泛型

    • 格式:<数据类型>
    • 泛型只能支持引用数据类型,如果要加int要写Integer
    • 泛型在编译时可以指定数据类型,但是在字节码文件中仍然是Object类型
    //没泛型时,可以往集合加任何数据
    public class ArrayListTest {
        public static void main(String[] args) {
            ArrayList list = new ArrayList();
            list.add(123);
            list.add("aaa");
            list.add(new Student("xzq",40));
    
            Iterator it = list.iterator();
            while(it.hasNext()){
                
                //多态的弊端是不能访问子类的特有功能
                //所以我们无法调用特有行为,强转也又得无法转
                //所以泛型很重要
                Object o = it.next();
                System.out.println(o);
            }
        }
    }
    123
    aaa
    collection.Student@4554617c
    
    public class Student {
        private String name;
        private int age;
    
        public Student() {
        }
    
        public Student(String name, int age) {
            this.name = name;
            this.age = age;
        }
    
        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;
        }
    
        @Override
        public boolean equals(Object o) {
            if (this == o) return true;
            if (o == null || getClass() != o.getClass()) return false;
            Student student = (Student) o;
            return age == student.age && Objects.equals(name, student.name);
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60

    泛型类

    当一个类中,某个变量的数据类型不确定时,就可以定义带有泛型的类。

    //自己写一个泛型类,不确定数据类型,可以用任意大写字母表示,通常为E
    public class MyArrayList<E> {
        Object[] obj = new Object[10];
        int size;
    
        public boolean add(E e){
            obj[size] = e;
            size++;
            return true;
        }
    
        public E get(int index){
            //要将Object类型强转为E类型
            return (E)obj[index];
        }
    
        @Override
        public String toString() {
            return Arrays.toString(obj);
        }
    }
    
    public class MyArrayListTest {
        public static void main(String[] args) {
            //此时E为String
            MyArrayList<String> list1 = new MyArrayList<>();
            list1.add("xzq");
            list1.add("love");
            System.out.println(list1);//[xzq, love, null, null, null, null, null, null, null, null]
    
            //此时E为Integer
            MyArrayList<Integer> list2 = new MyArrayList<>();
            list2.add(717);
            list2.add(1717);
            System.out.println(list2.get(1));//1717
            System.out.println(list2);//[717, 1717, null, null, null, null, null, null, null, null]
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39

    泛型方法

    方法中形参类型不确定时,可以使用类名后面定义的泛型(所有方法都能用),或者在方法上申明定义自己的泛型(只有本方法能用)。

    //定义一个工具类
    public class ListUtil {
        private ListUtil(){}
    
        //泛型方法
        //泛型放在修饰符后面
        //因为无法确定集合泛型故也要在方法前加泛型才能传入参数
        //E...e其实是传入一个数组,可以是任意长度
        public static<E> void addAll(ArrayList<E> list,E...e){
            for (int i = 0; i < e.length; i++) {
                list.add(e[i]);
            }
        }
    }
    
    public class ListUtilTest {
        public static void main(String[] args) {
            ArrayList<String> list1 = new ArrayList<>();
            ListUtil.addAll(list1,"xzq","i","love");
            System.out.println(list1);//[xzq, i, love]
    
            ArrayList<Integer> list2 = new ArrayList<>();
            ListUtil.addAll(list2,1017,1317,1717,17171);
            System.out.println(list2);//[1017, 1317, 1717, 171717]
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26

    泛型接口

    当一个接口中,某个变量的数据类型不确定时,就可以定义带有泛型的接口。

    如何使用一个带泛型的接口:

    • 方法一:实现类给出具体类型
    • 方法二:实现类延续泛型,创建对象时再确定类型
    //方法一:实现类给出具体类型
    public class MyArrayList implements List<String> {
        //重写方法
    }
    
    public class MyArrayListTest {
        public static void main(String[] args) {
            //此时创建对象不用写泛型,因为已经确定了
            MyArrayList list = new MyArrayList();
        }
    }
    
    //方法二:实现类延续泛型,创建对象时再确定类型
    public class MyArrayList<E> implements List<E> {
        //重写方法
    }
    
    public class MyArrayListTest {
        public static void main(String[] args) {
            //此时创建对象时需要确定类型
            MyArrayList<String> list = new MyArrayList();
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    //泛型不具备继承性,但是数据具备继承性
    public class Generics {
        public static void main(String[] args) {
            ArrayList<Ye> list1 = new ArrayList<>();
            ArrayList<Fu> list2 = new ArrayList<>();
            ArrayList<Zi> list3 = new ArrayList<>();
            
            //只能传list1,传list2和list3会报错
            method(list1);
    
            //数据有继承性,多态
            list1.add(new Ye());
            list1.add(new Fu());
            list1.add(new Zi());
        }
    
        public static void method(ArrayList<Ye> list){
    
        }
    }
    
    class Ye{}
    class Fu extends Ye{}
    class Zi extends Fu{}
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    //如果我们想传集合且集合里面是Ye或者Fu或者Zi
    //可以使用泛型的通配符
    //    ?也表示不确定的类型
    //    他可以进行类型额限定
    //    ? extends E:表示可以传递E或者E所有的子类类型
    //    ? super E:表示可以传递E或者E所有的父类类型
    public class Generics {
        public static void main(String[] args) {
            ArrayList<Ye> list1 = new ArrayList<>();
            ArrayList<Fu> list2 = new ArrayList<>();
            ArrayList<Zi> list3 = new ArrayList<>();
            method(list1);
            method(list2);
            method(list3);
        }
    
        //利用泛型的通配符
        public static void method(ArrayList<? extends Ye> list){
    
        }
    }
    
    class Ye{}
    class Fu extends Ye{}
    class Zi extends Fu{}
    
    //应用场景
    //1.如果我们在定义类、方法、接口的时候,如果类型不确定,就可以定义泛型、泛型方法、泛型接口。
    //2.如果类型不确定,但是能知道以后只能传递某个继承体系中的,就可以使用泛型的通配符
    //泛型的通配符关键点:可以限定泛型的范围
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30

    Set

    Set接口中的方法基本上与Collection的API一致

    • HashSet:无序、不重复、无索引
    • LinkedHashSet:有序、不重复、无索引
    • TreeSet:可排序、不重复、无索引
    public class SetTest {
        public static void main(String[] args) {
            Set<String> s = new HashSet<>();
    
            //Set系列集合不重复,若集合中元素不存在为true,反之为false
            s.add("张三");
            System.out.println(s.add("张三"));//false
            s.add("李四");
            s.add("王五");
    
            //Set系列集合是无序的
            System.out.println(s);//[李四, 张三, 王五]
    
            //迭代器遍历
            Iterator<String> it = s.iterator();
            while(it.hasNext()){
                String str = it.next();
                System.out.println(str);
            }
    
            //增强for遍历
            for (String str : s) {
                System.out.println(str);
            }
    
            //Lambda表达式遍历,匿名内部类
            s.forEach(new Consumer<String>() {
                @Override
                public void accept(String str) {
                    System.out.println(str);
                }
            });
    
            //Lambda表达式遍历
            s.forEach(str -> System.out.println(str));
        }
    }
    李四
    张三
    王五
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40

    哈希值

    • 根据hashCode方法算出来的int类型的整数
    • 该方法定义在Object类中,所有对象都可以调用,默认使用地址值进行计算
    • 一般情况下,会重写hashCode方法,利用对象内部的属性值计算哈希值

    对象的哈希值特点

    • 如果没有重写hashCode方法,不同对象计算出的哈希值是不同的
    • 如果已经重写HashCode方法,不同的对象只要属性值相同,计算出的哈希值就是一样的
    • 在小部分情况下,不同的属性值或者不同的地址值计算出来的哈希值也有可能一样(哈希碰撞)
    public class HashTest {
        public static void main(String[] args) {
            Student s1 = new Student("xzq",40);
            Student s2 = new Student("xzq",40);
    	
            //如果没有重写hashCode方法,不同对象计算出的哈希值是不同的
            //是根据地址值计算的
            System.out.println(s1.hashCode());//1163157884
            System.out.println(s2.hashCode());//1956725890
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    public class Student {
        private String name;
        private int age;
    
    
        public Student() {
        }
    
        public Student(String name, int age) {
            this.name = name;
            this.age = age;
        }
    
        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 String toString() {
            return "Student{name = " + name + ", age = " + age + "}";
        }
    
        @Override
        public boolean equals(Object o) {
            if (this == o) return true;
            if (o == null || getClass() != o.getClass()) return false;
            Student student = (Student) o;
            return age == student.age && Objects.equals(name, student.name);
        }
    
        //重写hashCode方法
        @Override
        public int hashCode() {
            return Objects.hash(name, age);
        }
    }
    
    public class HashTest {
        public static void main(String[] args) {
            Student s1 = new Student("xzq",40);
            Student s2 = new Student("xzq",40);
    
            //如果已经重写HashCode方法,不同的对象只要属性值相同,计算出的哈希值就是一样的
            System.out.println(s1.hashCode());//3696666
            System.out.println(s2.hashCode());//3696666
            
            //哈希碰撞
            System.out.println("abc".hashCode());//96354
            System.out.println("acD".hashCode());//96354
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63

    HashSet底层原理

    • HashSet是集合底层采取哈希表存储数据
    • 哈希表是一种对于增删改查数据性能都较好的结构

    哈希表组成

    • JDK8之前:数组+链表
    • JDK8开始:数组+链表+红黑树
    1. 创建一个默认长度16,默认加载因子为0.75(用于扩容)的数组,数组名为table

    2. 根据元素的哈希值跟数组的长度计算出应存入的位置

      int index = (数组长度 - 1) & 哈希值;

    3. 判断当前位置是否为null,如果是null直接存入

    4. 如果位置不为null,表示有元素,则调用equals方法比较属性值

    5. 一样:不存 不一样:存入数组,形成链表

      JDK8以前:新元素存入数组,老元素挂在新元素下面

      JDK8以后:新元素直接挂在老元素下面

    • JDK8以后,当链表长度超过8,而且数组长度大于等于64时,自动转换为红黑树
    • 如果集合中存储的是自定义对象,必须要重写hashCode和equals方法
  • 相关阅读:
    [C++][算法基础]求组合数(II)
    如何在Linux上安装Tomcat
    Registry Keys for Windows 10 Application Privacy Settings
    Qt4升级到Qt5中文乱码问题的解决
    07-prometheus的自定义监控-pushgateway工具组件
    检验科LIS系统,即实验室信息管理系统
    2022下半年软件评测师真题评析
    Android组件通信——ActivityGroup(二十五)
    模型又nan了(原因:数据有全零段)
    基于electron+vue+element构建项目模板之【自定义标题栏&右键菜单项篇】
  • 原文地址:https://blog.csdn.net/m0_74053777/article/details/133971140