【学习笔记】Java基础——进阶(继承、修饰符、多态、抽象类、接口,内部类,参数传递,常用API,异常,Collection集合,List集合,基础数据结构,Set集合,泛型,可变参数,Map集合)

目录

1. 继承

1.1 继承的实现

1.2 继承的好处和弊端

2. 继承中的成员访问特点

2.1 继承中变量的访问特点

2.2 super

2.3 继承中构造方法的访问特点

2.4 继承中成员方法的访问特点

2.5 super内存图

2.6 方法重写

2.7 方法重写的注意事项

2.8 Java中继承的注意事项

3. 继承练习

3.1 老师和学生

3.2 猫和狗

4. 修饰符

4.1 package

4.2 import

4.3 权限修饰符

4.4 final

4.5 final修饰局部变量

4.6 static

4.7 static访问特点

5. 多态

5.1 多态的概述

5.2 多态中的成员访问特点

5.3 多态的好处和弊端

5.4 多态中的转型

5.5 多态的案例

6. 抽象类

6.1 抽象类的概述

6.2 抽象类的特点

6.3 抽象类的成员特点

6.4 抽象类的案例

7. 接口

7.1 接口的概述

7.2 接口的特点

7.3 接口的成员特点

7.4 接口的案例

7.5 类和接口的关系

7.6 抽象类和接口的区别

8. 综合案例

8.1 案例需求

8.2 代码实现

9. 参数传递

9.1 类名作为形参和返回

9.2 抽象类作为形参和返回值

9.3 接口名作为形参和返回值

10. 内部类

10.1 内部类的基本使用

10.2 成员内部类

10.3 局部内部类

10.4 匿名内部类

10.4 匿名内部类在开发中的使用

11. 常用API

11.1 Math

11.2 System

11.3 Object类的toString方法

11.4 Object类的equals方法

11.5 冒泡排序原理

11.6 冒泡排序代码实现(理解)

11.7 Arrays

12. 包装类

12.1 基本类型包装类

12.2 Integer类

12.3 int和String类型的相互转换

12.4 字符串数据排序案例

12.5 自动拆箱和自动装箱

13. 时间日期类

13.1 Date类

13.2 Date类常用方法

13.3 SimpleDateFormat类

13.4 日期工具类案例

13.5 Calendar类

13.6 二月天案例

14. 异常

14.1 异常

14.2 JVM默认处理异常的方式

14.3 try-catch方式处理异常

14.4 Throwable成员方法

14.5 编译时异常和运行时异常的区别

14.6 throws方式处理异常

14.7 throws和throw的区别

14.8自定义异常

15. Collection集合

15.1 集合体系结构

15.2 Collection集合概述和基本使用

15.3 Collection集合的常用方法

15.4 Collection集合的遍历

15.5 集合使用步骤图解

15.6 集合的案例-Collection集合存储学生对象并遍历

16. List集合

16.1 List集合概述和特点

16.2 List集合的特有方法

16.3 集合的案例-List集合存储学生对象并遍历

16.4 并发修改异常

16.5 列表迭代器

16.6 增强for循环

16.7 集合的案例-List集合存储学生对象三种方式遍历

17. 数据结构

17.1 数据结构之栈和队列

17.2 数据结构之数组和链表

18. List集合的实现类

18.1 List集合子类的特点

18.2 集合的案例-ArrayList集合存储学生对象三种方式遍历

18.3 LinkedList集合的特有功能

19. Set集合

19.1 Set集合概述和特点

19.2 哈希值

19.3 HashSet集合概述和特点

19.4 HashSet集合保证元素唯一性源码分析

19.5 常见数据结构之哈希表

19.6 HashSet集合存储学生对象并遍历

19.7 LinkedHashSet集合概述和特点

20. Set集合排序

20.1 TreeSet集合概述和特点

20.2 自然排序Comparable的使用

20.3 比较器排序Comparator的使用

20.4成绩排序案例

20.5不重复的随机数案例

21. 泛型

21.1 泛型概述和好处

21.2 泛型类

21.3 泛型方法

21.4 泛型接口

21.5 类型通配符

22. 可变参数

22.1 可变参数

22.2 可变参数的使用

23.2 Map集合的基本功能

23.3 Map集合的获取功能

23.4 Map集合的遍历(方式1)

23.5 Map集合的遍历(方式2)

23.6 Map集合的案例

23.6.1 HashMap集合练习之键是String值是Student

23.6.2 HashMap集合练习之键是Student值是String

23.6.3 集合嵌套之ArrayList嵌套HashMap

23.6.4 集合嵌套之HashMap嵌套ArrayList

23.6.5 统计字符串中每个字符出现的次数

27. Collections集合工具类

27.1 Collections概述和使用

27.2 ArrayList集合存储学生并排序

28. 斗地主案例

28.1 模拟斗地主案例-普通版本

28.2 模拟斗地主案例-升级版本

23. Map集合

23.1 Map集合概述和特点


1. 继承

1.1 继承的实现

  • 继承的概念

    • 继承是面向对象三大特征之一,可以使得子类具有父类的属性和方法,还可以在子类中重新定义,以及追加属性和方法

  • 实现继承的格式

    • 继承通过extends实现

    • 格式:class 子类 extends 父类 { }

      • 举例:class Dog extends Animal { }

  • 继承带来的好处

    • 继承可以让类与类之间产生关系,子父类关系,产生子父类后,子类则可以使用父类中非私有的成员。

  • 示例代码

    public class Fu {
        public void show() {
            System.out.println("show方法被调用");
        }
    }
    public class Zi extends Fu {
        public void method() {
            System.out.println("method方法被调用");
        }
    }
    public class Demo {
        public static void main(String[] args) {
            //创建对象,调用方法
            Fu f = new Fu();
            f.show();
    ​
            Zi z = new Zi();
            z.method();
            z.show();
        }
    }

1.2 继承的好处和弊端

  • 继承好处

    • 提高了代码的复用性(多个类相同的成员可以放到同一个类中)

    • 提高了代码的维护性(如果方法的代码需要修改,修改一处即可)

  • 继承弊端

    • 继承让类与类之间产生了关系,类的耦合性增强了,当父类发生变化时子类实现也不得不跟着变化,削弱了子类的独立性

  • 继承的应用场景:

    • 使用继承,需要考虑类与类之间是否存在is..a的关系,不能盲目使用继承

      • is..a的关系:谁是谁的一种,例如:老师和学生是人的一种,那人就是父类,学生和老师就是子类

2. 继承中的成员访问特点

2.1 继承中变量的访问特点

在子类方法中访问一个变量,采用的是就近原则。

  1. 子类局部范围找

  2. 子类成员范围找

  3. 父类成员范围找

  4. 如果都没有就报错(不考虑父亲的父亲…)

  • 示例代码

    class Fu {
        int num = 10;
    }
    class Zi {
        int num = 20;
        public void show(){
            int num = 30;
            System.out.println(num);
        }
    }
    public class Demo1 {
        public static void main(String[] args) {
            Zi z = new Zi();
            z.show();   // 输出show方法中的局部变量30
        }
    }

2.2 super

  • this&super关键字:

    • this:代表本类对象的引用

    • super:代表父类存储空间的标识(可以理解为父类对象引用)

  • this和super的使用分别

    • 成员变量:

      • this.成员变量 - 访问本类成员变量

      • super.成员变量 - 访问父类成员变量

    • 成员方法:

      • this.成员方法 - 访问本类成员方法

      • super.成员方法 - 访问父类成员方法

  • 构造方法:

    • this(…) - 访问本类构造方法

    • super(…) - 访问父类构造方法

2.3 继承中构造方法的访问特点

注意:子类中所有的构造方法默认都会访问父类中无参的构造方法

子类会继承父类中的数据,可能还会使用父类的数据。所以,子类初始化之前,一定要先完成父类数据的初始化,原因在于,每一个子类构造方法的第一条语句默认都是:super()

问题:如果父类中没有无参构造方法,只有带参构造方法,该怎么办呢?

1. 通过使用super关键字去显示的调用父类的带参构造方法
2. 在父类中自己提供一个无参构造方法

推荐方案:

自己给出无参构造方法

2.4 继承中成员方法的访问特点

通过子类对象访问一个方法

  1. 子类成员范围找

  2. 父类成员范围找

  3. 如果都没有就报错(不考虑父亲的父亲…)

2.5 super内存图

  • 对象在堆内存中,会单独存在一块super区域,用来存放父类的数据

2.6 方法重写

  • 1、方法重写概念

    • 子类出现了和父类中一模一样的方法声明(方法名一样,参数列表也必须一样)

  • 2、方法重写的应用场景

    • 当子类需要父类的功能,而功能主体子类有自己特有内容时,可以重写父类中的方法,这样,即沿袭了父类的功能,又定义了子类特有的内容

  • 3、Override注解

    • 用来检测当前的方法,是否是重写的方法,起到【校验】的作用

2.7 方法重写的注意事项

  • 方法重写的注意事项

  1. 私有方法不能被重写(父类私有成员子类是不能继承的)

  2. 子类方法访问权限不能更低(public > 默认 > 私有)

  • 示例代码

public class Fu {
    private void show() {
        System.out.println("Fu中show()方法被调用");
    }
​
    void method() {
        System.out.println("Fu中method()方法被调用");
    }
}
​
public class Zi extends Fu {
​
    /* 编译【出错】,子类不能重写父类私有的方法*/
    @Override
    private void show() {
        System.out.println("Zi中show()方法被调用");
    }
   
    /* 编译【出错】,子类重写父类方法的时候,访问权限需要大于等于父类 */
    @Override
    private void method() {
        System.out.println("Zi中method()方法被调用");
    }
​
    /* 编译【通过】,子类重写父类方法的时候,访问权限需要大于等于父类 */
    @Override
    public void method() {
        System.out.println("Zi中method()方法被调用");
    }
}

2.8 Java中继承的注意事项

  • Java中继承的注意事项

    1. Java中类只支持单继承,不支持多继承

      • 错误范例:class A extends B, C { }

    2. Java中类支持多层继承

  • 多层继承示例代码:

    public class Granddad {
    ​
        public void drink() {
            System.out.println("爷爷爱喝酒");
        }
    ​
    }
    ​
    public class Father extends Granddad {
    ​
        public void smoke() {
            System.out.println("爸爸爱抽烟");
        }
    ​
    }
    ​
    public class Mother {
    ​
        public void dance() {
            System.out.println("妈妈爱跳舞");
        }
    ​
    }
    public class Son extends Father {
        // 此时,Son类中就同时拥有drink方法以及smoke方法
    }

3. 继承练习

3.1 老师和学生

  • 需求:定义老师类和学生类,然后写代码测试;最后找到老师类和学生类当中的共性内容,抽取出一个父类,用继承的方式改写代码,并进行测试

  • 步骤:

    ①定义老师类(姓名,年龄,教书())

    ②定义学生类(姓名,年龄,学习())

    ③定义测试类,写代码测试

    ④共性抽取父类,定义人类(姓名,年龄)

    ⑤定义老师类,继承人类,并给出自己特有方法:教书()

    ⑥定义学生类,继承人类,并给出自己特有方法:学习()

    ⑦定义测试类,写代码测试

  • 示例代码:

    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;
        }
    }
    ​
    class Teacher extends Person {
    ​
        public Teacher() {}
    ​
        public Teacher(String name,int age) {
            super(name,age);
        }
    ​
        public void teach() {
            System.out.println("用爱成就每一位学员");
        }
    ​
    }
    ​
    class Student extends Person{
        public Student() {}
        
        public Student(String name, int age) {
            super(name,age);
        }
        
        public void study(){
            System.out.println("学生学习");
        }
        
    }
    ​
    class PersonDemo {
        public static void main(String[] args){
            //创建老师类对象并进行测试
            Teacher t1 = new Teacher();
            t1.setName("林青霞");
            t1.setAge(30);
            System.out.println(t1.getName() + "," + t1.getAge());
            t1.teach();
    ​
    ​
            Teacher t2 = new Teacher("风清扬", 33);
            System.out.println(t2.getName() + "," + t2.getAge());
            t2.teach();
            
            // 创建学生类对象测试
            Student s = new Student("张三",23);
            System.out.println(s.getName() + "," + s.getAge());
            s.study();
        }
    }

3.2 猫和狗

  • 需求:请采用继承的思想实现猫和狗的案例,并在测试类中进行测试

  • 分析:

    ①猫:

    成员变量:姓名,年龄

    构造方法:无参,带参

    成员方法:get/set方法,抓老鼠()

    ②狗:

    成员变量:姓名,年龄

    构造方法:无参,带参

    成员方法:get/set方法,看门()

    ③共性:

    成员变量:姓名,年龄;构造方法:无参,带参;成员方法:get/set方法

  • 步骤:

    1、定义动物类(Animal)

    【成员变量:姓名,年龄】【 构造方法:无参,带参】【成员方法:get/set方法】

    2、定义猫类(Cat),继承动物类

    【构造方法:无参,带参】【成员方法:抓老鼠() 】

    3、定义狗类(Dog),继承动物类

    【构造方法:无参,带参】【成员方法:看门() 】

    4、定义测试类(AnimalDemo),写代码测试

  • 示例代码:

    class Animal {
        private String name;
        private int age;
    ​
        public Animal() {
        }
    ​
        public Animal(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;
        }
    }
    class Cat extends Animal {
    ​
        public Cat() {
        }
    ​
        public Cat(String name, int age) {
            super(name, age);
        }
    ​
        public void catchMouse() {
            System.out.println("猫抓老鼠");
        }
    }
    class Dog extends Animal {
    ​
        public Dog() {
        }
    ​
        public Dog(String name, int age) {
            super(name, age);
        }
    ​
        public void lookDoor() {
            System.out.println("狗看门");
        }
    }
    /*
        测试类
     */
    public class AnimalDemo {
        public static void main(String[] args) {
            //创建猫类对象并进行测试
            Cat c1 = new Cat();
            c1.setName("加菲猫");
            c1.setAge(5);
            System.out.println(c1.getName() + "," + c1.getAge());
            c1.catchMouse();
    ​
            Cat c2 = new Cat("加菲猫", 5);
            System.out.println(c2.getName() + "," + c2.getAge());
            c2.catchMouse();
        }
    }

4. 修饰符

4.1 package

  • 1、包的概念

    • 包就是文件夹,用来管理类文件的

  • 2、包的定义格式

    • package 包名; (多级包用.分开)

    • 例如:package com.heima.demo;

  • 3、带包编译&带包运行

    • 带包编译:javac –d . 类名.java

      • 例如:javac -d . com.heima.demo.HelloWorld.java

    • 带包运行:java 包名+类名

      • 例如:java com.heima.demo.HelloWorld

4.2 import

  • 导包的意义

    使用不同包下的类时,使用的时候要写类的全路径,写起来太麻烦了

    为了简化带包的操作,Java就提供了导包的功能

  • 导包的格式

    格式:import 包名;

    范例:import java.util.Scanner;

  • 示例代码(没有使用导包,创建的Scanner对象)

package com.heima;
​
public class Demo {
    public static void main(String[] args) {
        // 1. 没有导包,创建Scnaner对象
        java.util.Scanner sc = new java.util.Scanner(System.in);
    }
}
  • 示例代码(使用导包后,创建的Scanner对象)

package com.heima;

import java.util.Scanner;

public class Demo {
    public static void main(String[] args) {
        // 1. 没有导包,创建Scnaner对象
        Scanner sc = new Scanner(System.in);
    }
}

4.3 权限修饰符

4.4 final

  • fianl关键字的作用

    • final代表最终的意思,可以修饰成员方法,成员变量,类

  • final修饰类、方法、变量的效果

    • fianl修饰类:该类不能被继承(不能有子类,但是可以有父类)

    • final修饰方法:该方法不能被重写

    • final修饰变量:表明该变量是一个常量,不能再次赋值

4.5 final修饰局部变量

  • fianl修饰基本数据类型变量

    • final 修饰指的是基本类型的数据值不能发生改变

  • final修饰引用数据类型变量

    • final 修饰指的是引用类型的地址值不能发生改变,但是地址里面的内容是可以发生改变的

    • 举例:

      public static void main(String[] args){
          final Student s = new Student(23);
        	s = new Student(24);  // 错误
       	s.setAge(24);  // 正确
      }

4.6 static

  • static的概念

    • static关键字是静态的意思,可以修饰【成员方法】,【成员变量】

  • static修饰的特点

    1. 被类的所有对象共享,这也是我们判断是否使用静态关键字的条件

    2. 可以通过类名调用当然,也可以通过对象名调用【推荐使用类名调用】

  • 示例代码:

class Student {

    public String name; //姓名
    public int age; //年龄
    public static String university; //学校	共享数据!所以设计为静态!

    public void show() {
        System.out.println(name + "," + age + "," + university);
    }

}

public class StaticDemo {
    public static void main(String[] args) {
	    // 为对象的共享数据赋值
        Student.university = "传智大学";

        Student s1 = new Student();
        s1.name = "林青霞";
        s1.age = 30;
        s1.show();

        Student s2 = new Student();
        s2.name = "风清扬";
        s2.age = 33;
        s2.show();
    }
}

4.7 static访问特点

  • static的访问特点

    • 非静态的成员方法

      • 能访问静态的成员变量

      • 能访问非静态的成员变量

      • 能访问静态的成员方法

      • 能访问非静态的成员方法

    • 静态的成员方法

      • 能访问静态的成员变量

      • 能访问静态的成员方法

    • 总结成一句话就是:

      • 静态成员方法只能访问静态成员

5. 多态

5.1 多态的概述

  • 什么是多态

    同一个对象,在不同时刻表现出来的不同形态

  • 多态的前提

    • 要有继承或实现关系

    • 要有方法的重写

    • 要有父类引用指向子类对象

5.2 多态中的成员访问特点

  • 成员访问特点

    • 成员变量

      编译看父类,运行看父类

    • 成员方法

      编译看父类,运行看子类

  • 代码演示

    • 动物类

      public class Animal {
          public int age = 40;
      ​
          public void eat() {
              System.out.println("动物吃东西");
          }
      }

    • 猫类

      public class Cat extends Animal {
          public int age = 20;
          public int weight = 10;
      ​
          @Override
          public void eat() {
              System.out.println("猫吃鱼");
          }
      ​
          public void playGame() {
              System.out.println("猫捉迷藏");
          }
      }

    • 测试类

      public class AnimalDemo {
          public static void main(String[] args) {
              //有父类引用指向子类对象
              Animal a = new Cat();
      ​
              System.out.println(a.age);
      //        System.out.println(a.weight);
      ​
              a.eat();
      //        a.playGame();
          }
      }

5.3 多态的好处和弊端

  • 好处

    提高程序的扩展性。定义方法时候,使用父类型作为参数,在使用的时候,使用具体的子类型参与操作

  • 弊端

    不能使用子类的特有成员

5.4 多态中的转型

  • 向上转型

    父类引用指向子类对象就是向上转型

  • 向下转型

    格式:子类型 对象名 = (子类型)父类引用;

  • 代码演示

    • 动物类

    public class Animal {
        public void eat() {
            System.out.println("动物吃东西");
        }
    }
    • 猫类

    public class Cat extends Animal {
        @Override
        public void eat() {
            System.out.println("猫吃鱼");
        }
    ​
        public void playGame() {
            System.out.println("猫捉迷藏");
        }
    }
    • 测试类

    public class AnimalDemo {
        public static void main(String[] args) {
            //多态
            //向上转型
            Animal a = new Cat();
            a.eat();
    //      a.playGame();
    ​
    ​
            //向下转型
            Cat c = (Cat)a;
            c.eat();
            c.playGame();
        }
    }

5.5 多态的案例

  • 案例需求

    请采用多态的思想实现猫和狗的案例,并在测试类中进行测试

  • 代码实现

    • 动物类

    public class Animal {
        private String name;
        private int age;
    ​
        public Animal() {
        }
    ​
        public Animal(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 eat() {
            System.out.println("动物吃东西");
        }
    }
    • 猫类

    public class Cat extends Animal {
    ​
        public Cat() {
        }
    ​
        public Cat(String name, int age) {
            super(name, age);
        }
    ​
        @Override
        public void eat() {
            System.out.println("猫吃鱼");
        }
    }
    • 狗类

    public class Dog extends Animal {
    
        public Dog() {
        }
    
        public Dog(String name, int age) {
            super(name, age);
        }
    
        @Override
        public void eat() {
            System.out.println("狗吃骨头");
        }
    }
    • 测试类

    public class AnimalDemo {
        public static void main(String[] args) {
            //创建猫类对象进行测试
            Animal a = new Cat();
            a.setName("加菲");
            a.setAge(5);
            System.out.println(a.getName() + "," + a.getAge());
            a.eat();
    
            a = new Cat("加菲", 5);
            System.out.println(a.getName() + "," + a.getAge());
            a.eat();
        }
    }

6. 抽象类

6.1 抽象类的概述

当我们在做子类共性功能抽取时,有些方法在父类中并没有具体的体现,这个时候就需要抽象类了!

在Java中,一个没有方法体的方法应该定义为抽象方法,而类中如果有抽象方法,该类必须定义为抽象类!

6.2 抽象类的特点

  • 抽象类和抽象方法必须使用 abstract 关键字修饰

    //抽象类的定义
    public abstract class 类名 {}
    
    //抽象方法的定义
    public abstract void eat();

  • 抽象类中不一定有抽象方法,有抽象方法的类一定是抽象类

  • 抽象类不能实例化

    抽象类如何实例化呢?参照多态的方式,通过子类对象实例化,这叫抽象类多态

  • 抽象类的子类

    要么重写抽象类中的所有抽象方法

    要么是抽象类

6.3 抽象类的成员特点

  • 成员的特点

    • 成员变量

      • 既可以是变量

      • 也可以是常量

    • 构造方法

      • 空参构造

      • 有参构造

    • 成员方法

      • 抽象方法

      • 普通方法

  • 代码演示

    • 动物类

    public abstract class Animal {
    
        private int age = 20;
        private final String city = "北京";
    
        public Animal() {}
    
        public Animal(int age) {
            this.age = age;
        }
    
    
        public void show() {
            age = 40;
            System.out.println(age);
    //        city = "上海";
            System.out.println(city);
        }
    
        public abstract void eat();
    
    }
    • 猫类

    public class Cat extends Animal {
        @Override
        public void eat() {
            System.out.println("猫吃鱼");
        }
    }
    • 测试类

    public class AnimalDemo {
        public static void main(String[] args) {
            Animal a = new Cat();
            a.eat();
            a.show();
        }
    }

6.4 抽象类的案例

  • 案例需求

    请采用抽象类的思想实现猫和狗的案例,并在测试类中进行测试

  • 代码实现

    • 动物类

    public abstract class Animal {
        private String name;
        private int age;
    
        public Animal() {
        }
    
        public Animal(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 abstract void eat();
    }
    • 猫类

    public class Cat extends Animal {
    
        public Cat() {
        }
    
        public Cat(String name, int age) {
            super(name, age);
        }
    
        @Override
        public void eat() {
            System.out.println("猫吃鱼");
        }
    }
    • 狗类

    public class Dog extends Animal {
    
        public Dog() {
        }
    
        public Dog(String name, int age) {
            super(name, age);
        }
    
        @Override
        public void eat() {
            System.out.println("狗吃骨头");
        }
    }
    • 测试类

    public class AnimalDemo {
        public static void main(String[] args) {
            //创建对象,按照多态的方式
            Animal a = new Cat();
            a.setName("加菲");
            a.setAge(5);
            System.out.println(a.getName()+","+a.getAge());
            a.eat();
            System.out.println("--------");
    
            a = new Cat("加菲",5);
            System.out.println(a.getName()+","+a.getAge());
            a.eat();
        }
    }

7. 接口

7.1 接口的概述

接口就是一种公共的规范标准,只要符合规范标准,大家都可以通用。

Java中的接口更多的体现在对行为的抽象!

7.2 接口的特点

  • 接口用关键字interface修饰

    public interface 接口名 {} 
  • 类实现接口用implements表示

    public class 类名 implements 接口名 {}
  • 接口不能实例化

    接口如何实例化呢?参照多态的方式,通过实现类对象实例化,这叫接口多态。

    多态的形式:具体类多态,抽象类多态,接口多态。

  • 接口的子类

    要么重写接口中的所有抽象方法

    要么子类也是抽象类

7.3 接口的成员特点

  • 成员特点

    • 成员变量

      只能是常量 ​ 默认修饰符:public static final

    • 构造方法

      没有,因为接口主要是扩展功能的,而没有具体存在

    • 成员方法

      只能是抽象方法

      默认修饰符:public abstract

      关于接口中的方法,JDK8和JDK9中有一些新特性,后面再讲解

  • 代码演示

    • 接口

    public interface Inter {
        public int num = 10;
        public final int num2 = 20;
    //    public static final int num3 = 30;
        int num3 = 30;
    
    //    public Inter() {}
    
    //    public void show() {}
    
        public abstract void method();
        void show();
    }
    • 实现类

    public class InterImpl extends Object implements Inter {
        public InterImpl() {
            super();
        }
    
        @Override
        public void method() {
            System.out.println("method");
        }
    
        @Override
        public void show() {
            System.out.println("show");
        }
    }
    • 测试类

    public class InterfaceDemo {
        public static void main(String[] args) {
            Inter i = new InterImpl();
    //        i.num = 20;
            System.out.println(i.num);
    //        i.num2 = 40;
            System.out.println(i.num2);
            System.out.println(Inter.num);
        }
    }

7.4 接口的案例

  • 案例需求

    对猫和狗进行训练,他们就可以跳高了,这里加入跳高功能。

    请采用抽象类和接口来实现猫狗案例,并在测试类中进行测试。

  • 代码实现

    • 动物类

    public abstract class Animal {
        private String name;
        private int age;
    
        public Animal() {
        }
    
        public Animal(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 abstract void eat();
    }
    • 跳高接口

    public interface Jumpping {
        public abstract void jump();
    }
    • 猫类

    public class Cat extends Animal implements Jumpping {
    
        public Cat() {
        }
    
        public Cat(String name, int age) {
            super(name, age);
        }
    
        @Override
        public void eat() {
            System.out.println("猫吃鱼");
        }
    
        @Override
        public void jump() {
            System.out.println("猫可以跳高了");
        }
    }
    • 测试类

    public class AnimalDemo {
        public static void main(String[] args) {
            //创建对象,调用方法
            Jumpping j = new Cat();
            j.jump();
            System.out.println("--------");
    
            Animal a = new Cat();
            a.setName("加菲");
            a.setAge(5);
            System.out.println(a.getName()+","+a.getAge());
            a.eat();
    //        a.jump();
    
            a = new Cat("加菲",5);
            System.out.println(a.getName()+","+a.getAge());
            a.eat();
            System.out.println("--------");
    
            Cat c = new Cat();
            c.setName("加菲");
            c.setAge(5);
            System.out.println(c.getName()+","+c.getAge());
            c.eat();
            c.jump();
        }
    }

7.5 类和接口的关系

  • 类与类的关系

    继承关系,只能单继承,但是可以多层继承

  • 类与接口的关系

    实现关系,可以单实现,也可以多实现,还可以在继承一个类的同时实现多个接口

  • 接口与接口的关系

    继承关系,可以单继承,也可以多继承

7.6 抽象类和接口的区别

  • 成员区别

    • 抽象类

      变量,常量;有构造方法;有抽象方法,也有非抽象方法

    • 接口

      常量;抽象方法

  • 关系区别

    • 类与类

      继承,单继承

    • 类与接口

      实现,可以单实现,也可以多实现

    • 接口与接口

      继承,单继承,多继承

  • 设计理念区别

    • 抽象类

      对类抽象,包括属性、行为

    • 接口

      对行为抽象,主要是行为

8. 综合案例

8.1 案例需求

我们现在有乒乓球运动员和篮球运动员,乒乓球教练和篮球教练。

为了出国交流,跟乒乓球相关的人员都需要学习英语。

请用所学知识分析,这个案例中有哪些具体类,哪些抽象类,哪些接口,并用代码实现。

8.2 代码实现

  • 抽象人类

public 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;
    }

    public abstract void eat();
}
  • 抽象运动员类

public abstract class Player extends Person {
    public Player() {
    }

    public Player(String name, int age) {
        super(name, age);
    }

    public abstract void study();
}
  • 抽象教练类

public abstract class Coach extends Person {
    public Coach() {
    }

    public Coach(String name, int age) {
        super(name, age);
    }

    public abstract void teach();
}
  • 学英语接口

public interface SpeakEnglish {
    public abstract void speak();
}
  • 蓝球教练

public class BasketballCoach extends Coach {
    public BasketballCoach() {
    }

    public BasketballCoach(String name, int age) {
        super(name, age);
    }

    @Override
    public void teach() {
        System.out.println("篮球教练教如何运球和投篮");
    }

    @Override
    public void eat() {
        System.out.println("篮球教练吃羊肉,喝羊奶");
    }
}
  • 乒乓球教练

public class PingPangCoach extends Coach implements SpeakEnglish {

    public PingPangCoach() {
    }

    public PingPangCoach(String name, int age) {
        super(name, age);
    }

    @Override
    public void teach() {
        System.out.println("乒乓球教练教如何发球和接球");
    }

    @Override
    public void eat() {
        System.out.println("乒乓球教练吃小白菜,喝大米粥");
    }

    @Override
    public void speak() {
        System.out.println("乒乓球教练说英语");
    }
}
  • 乒乓球运动员

public class PingPangPlayer extends Player implements SpeakEnglish {

    public PingPangPlayer() {
    }

    public PingPangPlayer(String name, int age) {
        super(name, age);
    }

    @Override
    public void study() {
        System.out.println("乒乓球运动员学习如何发球和接球");
    }

    @Override
    public void eat() {
        System.out.println("乒乓球运动员吃大白菜,喝小米粥");
    }

    @Override
    public void speak() {
        System.out.println("乒乓球运动员说英语");
    }
}
  • 篮球运动员

public class BasketballPlayer extends Player {

    public BasketballPlayer() {
    }

    public BasketballPlayer(String name, int age) {
        super(name, age);
    }

    @Override
    public void study() {
        System.out.println("篮球运动员学习如何运球和投篮");
    }

    @Override
    public void eat() {
        System.out.println("篮球运动员吃牛肉,喝牛奶");
    }
}

9. 参数传递

9.1 类名作为形参和返回

  • 1、类名作为方法的形参

    方法的形参是类名,其实需要的是该类的对象

    实际传递的是该对象的【地址值】

  • 2、类名作为方法的返回值

    方法的返回值是类名,其实返回的是该类的对象

    实际传递的,也是该对象的【地址值】

  • 示例代码:

    class Cat {
        public void eat() {
            System.out.println("猫吃鱼");
        }
    }
    class CatOperator {
        public void useCat(Cat c) { //Cat c = new Cat();
            c.eat();
        }
        public Cat getCat() {
            Cat c = new Cat();
            return c;
        }
    }
    public class CatDemo {
        public static void main(String[] args) {
            //创建操作类对象,并调用方法
            CatOperator co = new CatOperator();
            Cat c = new Cat();
            co.useCat(c);
    ​
            Cat c2 = co.getCat(); //new Cat()
            c2.eat();
        }
    }

9.2 抽象类作为形参和返回值

  • 抽象类作为形参和返回值

    • 方法的形参是抽象类名,其实需要的是该抽象类的子类对象

    • 方法的返回值是抽象类名,其实返回的是该抽象类的子类对象

  • 示例代码:

    abstract class Animal {
        public abstract void eat();
    }
    class Cat extends Animal {
        @Override
        public void eat() {
            System.out.println("猫吃鱼");
        }
    }
    class AnimalOperator {
        public void useAnimal(Animal a) { //Animal a = new Cat();
            a.eat();
        }
        public Animal getAnimal() {
            Animal a = new Cat();
            return a;
        }
    }
    public class AnimalDemo {
        public static void main(String[] args) {
            //创建操作类对象,并调用方法
            AnimalOperator ao = new AnimalOperator();
            Animal a = new Cat();
            ao.useAnimal(a);
    ​
            Animal a2 = ao.getAnimal(); //new Cat()
            a2.eat();
        }
    }

9.3 接口名作为形参和返回值

  • 接口作为形参和返回值

    • 方法的形参是接口名,其实需要的是该接口的实现类对象

    • 方法的返回值是接口名,其实返回的是该接口的实现类对象

  • 示例代码:

    interface Jumpping {
        void jump();
    }
    class JumppingOperator {
        public void useJumpping(Jumpping j) { //Jumpping j = new Cat();
            j.jump();
        }
        public Jumpping getJumpping() {
            Jumpping j = new Cat();
            return j;
        }
    }
    class Cat implements Jumpping {
        @Override
        public void jump() {
            System.out.println("猫可以跳高了");
        }
    }
    public class JumppingDemo {
        public static void main(String[] args) {
            //创建操作类对象,并调用方法
            JumppingOperator jo = new JumppingOperator();
            Jumpping j = new Cat();
            jo.useJumpping(j);
    ​
            Jumpping j2 = jo.getJumpping(); //new Cat()
            j2.jump();
        }
    }
    ​

10. 内部类

10.1 内部类的基本使用

  • 内部类概念

    • 在一个类中定义一个类。举例:在一个类A的内部定义一个类B,类B就被称为内部类

  • 内部类定义格式

    • 格式&举例:

      /*
          格式:
          class 外部类名{
              修饰符 class 内部类名{
              
              }
          }
      */
      ​
      class Outer {
          public class Inner {
              
          }
      }

  • 内部类的访问特点

    • 内部类可以直接访问外部类的成员,包括私有

    • 外部类要访问内部类的成员,必须创建对象

  • 示例代码:

    /*
        内部类访问特点:
            内部类可以直接访问外部类的成员,包括私有
            外部类要访问内部类的成员,必须创建对象
     */
    public class Outer {
        private int num = 10;
        public class Inner {
            public void show() {
                System.out.println(num);
            }
        }
        public void method() {
            Inner i = new Inner();
            i.show();
        }
    }

10.2 成员内部类

  • 成员内部类的定义位置

    • 在类中方法,跟成员变量是一个位置

  • 外界创建成员内部类格式

    • 格式:外部类名.内部类名 对象名 = 外部类对象.内部类对象;

    • 举例:Outer.Inner oi = new Outer().new Inner();

  • 成员内部类的推荐使用方案

    • 将一个类,设计为内部类的目的,大多数都是不想让外界去访问,所以内部类的定义应该私有化,私有化之后,再提供一个可以让外界调用的方法,方法内部创建内部类对象并调用。

  • 示例代码:

    class Outer {
        private int num = 10;
        private class Inner {
            public void show() {
                System.out.println(num);
            }
        }
        public void method() {
            Inner i = new Inner();
            i.show();
        }
    }
    public class InnerDemo {
        public static void main(String[] args) {
            //Outer.Inner oi = new Outer().new Inner();
            //oi.show();
            Outer o = new Outer();
            o.method();
        }
    }

10.3 局部内部类

  • 局部内部类定义位置

    • 局部内部类是在方法中定义的类

  • 局部内部类方式方式

    • 局部内部类,外界是无法直接使用,需要在方法内部创建对象并使用

    • 该类可以直接访问外部类的成员,也可以访问方法内的局部变量

  • 示例代码

    class Outer {
        private int num = 10;
        public void method() {
            int num2 = 20;
            class Inner {
                public void show() {
                    System.out.println(num);
                    System.out.println(num2);
                }
            }
            Inner i = new Inner();
            i.show();
        }
    }
    public class OuterDemo {
        public static void main(String[] args) {
            Outer o = new Outer();
            o.method();
        }
    }
    ​

10.4 匿名内部类

  • 匿名内部类的前提

    • 存在一个类或者接口,这里的类可以是具体类也可以是抽象类

  • 匿名内部类的格式

    • 格式:new 类名 ( ) { 重写方法 } new 接口名 ( ) { 重写方法 }

    • 举例:

      new Inter(){
          @Override
          public void method(){}
      } 

  • 匿名内部类的本质

    • 本质:是一个继承了该类或者实现了该接口的子类匿名对象

  • 匿名内部类的细节

    • 匿名内部类可以通过多态的形式接受

      Inter i = new Inter(){
        @Override
          public void method(){
              
          }
      }

  • 匿名内部类直接调用方法

    interface Inter{
        void method();
    }
    ​
    class Test{
        public static void main(String[] args){
            new Inter(){
                @Override
                public void method(){
                    System.out.println("我是匿名内部类");
                }
            }.method(); // 直接调用方法
        }
    }

10.4 匿名内部类在开发中的使用

  • 匿名内部类在开发中的使用

    • 当发现某个方法需要,接口或抽象类的子类对象,我们就可以传递一个匿名内部类过去,来简化传统的代码

  • 示例代码:

    interface Jumpping {
        void jump();
    }
    class Cat implements Jumpping {
        @Override
        public void jump() {
            System.out.println("猫可以跳高了");
        }
    }
    class Dog implements Jumpping {
        @Override
        public void jump() {
            System.out.println("狗可以跳高了");
        }
    }
    class JumppingOperator {
        public void method(Jumpping j) { //new Cat();   new Dog();
            j.jump();
        }
    }
    class JumppingDemo {
        public static void main(String[] args) {
            //需求:创建接口操作类的对象,调用method方法
            JumppingOperator jo = new JumppingOperator();
            Jumpping j = new Cat();
            jo.method(j);
    ​
            Jumpping j2 = new Dog();
            jo.method(j2);
            System.out.println("--------");
    ​
            // 匿名内部类的简化
            jo.method(new Jumpping() {
                @Override
                public void jump() {
                    System.out.println("猫可以跳高了");
                }
            });
            // 匿名内部类的简化
            jo.method(new Jumpping() {
                @Override
                public void jump() {
                    System.out.println("狗可以跳高了");
                }
            });
        }
    }

11. 常用API

11.1 Math

  • 1、Math类概述

    • Math 包含执行基本数字运算的方法

  • 2、Math中方法的调用方式

    • Math类中无构造方法,但内部的方法都是静态的,则可以通过 类名.进行调用

  • 3、Math类的常用方法

    方法名 方法名说明
    public static int abs(int a)返回参数的绝对值
    public static double ceil(double a)返回大于或等于参数的最小double值,等于一个整数
    public static double floor(double a)返回小于或等于参数的最大double值,等于一个整数
    public static int round(float a)按照四舍五入返回最接近参数的int
    public static int max(int a,int b)返回两个int值中的较大值
    public static int min(int a,int b)返回两个int值中的较小值
    public static double pow (double a,double b)返回a的b次幂的值
    public static double random()返回值为double的正值,[0.0,1.0)

11.2 System

  • System类的常用方法

方法名说明
public static void exit(int status)终止当前运行的 Java 虚拟机,非零表示异常终止
public static long currentTimeMillis()返回当前时间(以毫秒为单位)
  • 示例代码

    • 需求:在控制台输出1-10000,计算这段代码执行了多少毫秒

    public class SystemDemo {
        public static void main(String[] args) {
            // 获取开始的时间节点
            long start = System.currentTimeMillis();
            for (int i = 1; i <= 10000; i++) {
                System.out.println(i);
            }
            // 获取代码运行结束后的时间节点
            long end = System.currentTimeMillis();
            System.out.println("共耗时:" + (end - start) + "毫秒");
        }
    }

11.3 Object类的toString方法

  • Object类概述

    • Object 是类层次结构的根,每个类都可以将 Object 作为超类。所有类都直接或者间接的继承自该类,换句话说,该类所具备的方法,所有类都会有一份

  • 查看方法源码的方式

    • 选中方法,按下Ctrl + B

  • 重写toString方法的方式

      1. Alt + Insert 选择toString

      1. 在类的空白区域,右键 -> Generate -> 选择toString

  • toString方法的作用:

    • 以良好的格式,更方便的展示对象中的属性值

  • 示例代码:

    class Student extends Object {
        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 String toString() {
            return "Student{" +
                    "name='" + name + '\'' +
                    ", age=" + age +
                    '}';
        }
    }
    public class ObjectDemo {
        public static void main(String[] args) {
            Student s = new Student();
            s.setName("林青霞");
            s.setAge(30);
            System.out.println(s); 
            System.out.println(s.toString()); 
        }
    }

  • 运行结果:

    Student{name='林青霞', age=30}
    Student{name='林青霞', age=30}

11.4 Object类的equals方法

  • equals方法的作用

    • 用于对象之间的比较,返回true和false的结果

    • 举例:s1.equals(s2); s1和s2是两个对象

  • 重写equals方法的场景

    • 不希望比较对象的地址值,想要结合对象属性进行比较的时候。

  • 重写equals方法的方式

      1. alt + insert 选择equals() and hashCode(),IntelliJ Default,一路next,finish即可

      1. 在类的空白区域,右键 -> Generate -> 选择equals() and hashCode(),后面的同上。

  • 示例代码:

    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) {
            //this -- s1
            //o -- s2
            if (this == o) return true;
            if (o == null || getClass() != o.getClass()) return false;
    ​
            Student student = (Student) o; //student -- s2
    ​
            if (age != student.age) return false;
            return name != null ? name.equals(student.name) : student.name == null;
        }
    }
    public class ObjectDemo {
        public static void main(String[] args) {
            Student s1 = new Student();
            s1.setName("林青霞");
            s1.setAge(30);
    ​
            Student s2 = new Student();
            s2.setName("林青霞");
            s2.setAge(30);
    ​
            //需求:比较两个对象的内容是否相同
            System.out.println(s1.equals(s2));
        }
    }
    ​

11.5 冒泡排序原理

  • 冒泡排序概述

    • 一种排序的方式,对要进行排序的数据中相邻的数据进行两两比较,将较大的数据放在后面,依次对所有的数据进行操作,直至所有数据按要求完成排序

  • 如果有n个数据进行排序,总共需要比较n-1次

  • 每一次比较完毕,下一次的比较就会少一个数据参与

11.6 冒泡排序代码实现(理解)

  • 代码实现

/*
    冒泡排序:
        一种排序的方式,对要进行排序的数据中相邻的数据进行两两比较,将较大的数据放在后面,
        依次对所有的数据进行操作,直至所有数据按要求完成排序
 */
public class ArrayDemo {
    public static void main(String[] args) {
        //定义一个数组
        int[] arr = {24, 69, 80, 57, 13};
        System.out.println("排序前:" + arrayToString(arr));
​
        // 这里减1,是控制每轮比较的次数
        for (int x = 0; x < arr.length - 1; x++) {
            // -1是为了避免索引越界,-x是为了调高比较效率
            for (int i = 0; i < arr.length - 1 - x; i++) {
                if (arr[i] > arr[i + 1]) {
                    int temp = arr[i];
                    arr[i] = arr[i + 1];
                    arr[i + 1] = temp;
                }
            }
        }
        System.out.println("排序后:" + arrayToString(arr));
​
    }
​
    //把数组中的元素按照指定的规则组成一个字符串:[元素1, 元素2, ...]
    public static String arrayToString(int[] arr) {
        StringBuilder sb = new StringBuilder();
        sb.append("[");
        for (int i = 0; i < arr.length; i++) {
            if (i == arr.length - 1) {
                sb.append(arr[i]);
            } else {
                sb.append(arr[i]).append(", ");
            }
        }
        sb.append("]");
        String s = sb.toString();
        return s;
    }
}

11.7 Arrays

  • Arrays的常用方法

    方法名说明
    public static String toString(int[] a)返回指定数组的内容的字符串表示形式
    public static void sort(int[] a)按照数字顺序排列指定的数组
  • 工具类设计思想

    1、构造方法用 private 修饰

    2、成员用 public static 修饰

12. 包装类

12.1 基本类型包装类

  • 基本类型包装类的作用

    将基本数据类型封装成对象的好处在于可以在对象中定义更多的功能方法操作该数据

    常用的操作之一:用于基本数据类型与字符串之间的转换

  • 基本类型对应的包装类

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

12.2 Integer类

  • Integer类概述

    包装一个对象中的原始类型 int 的值

  • Integer类构造方法

    方法名说明
    public Integer(int value)根据 int 值创建 Integer 对象(过时)
    public Integer(String s)根据 String 值创建 Integer 对象(过时)
    public static Integer valueOf(int i)返回表示指定的 int 值的 Integer 实例
    public static Integer valueOf(String s)返回一个保存指定值的 Integer 对象 String
  • 示例代码

    public class IntegerDemo {
        public static void main(String[] args) {
            //public Integer(int value):根据 int 值创建 Integer 对象(过时)
            Integer i1 = new Integer(100);
            System.out.println(i1);
    ​
            //public Integer(String s):根据 String 值创建 Integer 对象(过时)
            Integer i2 = new Integer("100");
    //        Integer i2 = new Integer("abc"); //NumberFormatException
            System.out.println(i2);
            System.out.println("--------");
    ​
            //public static Integer valueOf(int i):返回表示指定的 int 值的 Integer 实例
            Integer i3 = Integer.valueOf(100);
            System.out.println(i3);
    ​
            //public static Integer valueOf(String s):返回一个保存指定值的Integer对象 String
            Integer i4 = Integer.valueOf("100");
            System.out.println(i4);
        }
    }

12.3 int和String类型的相互转换

  • int转换为String

    • 转换方式

      • 方式一:直接在数字后加一个空字符串

      • 方式二:通过String类静态方法valueOf()

    • 示例代码

      public class IntegerDemo {
          public static void main(String[] args) {
              //int --- String
              int number = 100;
              //方式1
              String s1 = number + "";
              System.out.println(s1);
              //方式2
              //public static String valueOf(int i)
              String s2 = String.valueOf(number);
              System.out.println(s2);
              System.out.println("--------");
          }
      }

  • String转换为int

    • 转换方式

      • 方式一:先将字符串数字转成Integer,再调用valueOf()方法

      • 方式二:通过Integer静态方法parseInt()进行转换

    • 示例代码

      public class IntegerDemo {
          public static void main(String[] args) {
              //String --- int
              String s = "100";
              //方式1:String --- Integer --- int
              Integer i = Integer.valueOf(s);
              //public int intValue()
              int x = i.intValue();
              System.out.println(x);
              //方式2
              //public static int parseInt(String s)
              int y = Integer.parseInt(s);
              System.out.println(y);
          }
      }

12.4 字符串数据排序案例

  • 案例需求

    有一个字符串:“91 27 46 38 50”,请写程序实现最终输出结果是:“27 38 46 50 91”

  • 代码实现

    public class IntegerTest {
        public static void main(String[] args) {
            //定义一个字符串
            String s = "91 27 46 38 50";
    ​
            //把字符串中的数字数据存储到一个int类型的数组中
            String[] strArray = s.split(" ");
    //        for(int i=0; i<strArray.length; i++) {
    //            System.out.println(strArray[i]);
    //        }
    ​
            //定义一个int数组,把 String[] 数组中的每一个元素存储到 int 数组中
            int[] arr = new int[strArray.length];
            for(int i=0; i<arr.length; i++) {
                arr[i] = Integer.parseInt(strArray[i]);
            }
    ​
            //对 int 数组进行排序
            Arrays.sort(arr);
    ​
            //把排序后的int数组中的元素进行拼接得到一个字符串,这里拼接采用StringBuilder来实现
            StringBuilder sb = new StringBuilder();
            for(int i=0; i<arr.length; i++) {
                if(i == arr.length - 1) {
                    sb.append(arr[i]);
                } else {
                    sb.append(arr[i]).append(" ");
                }
            }
            String result = sb.toString();
    ​
            //输出结果
            System.out.println(result);
        }
    }

12.5 自动拆箱和自动装箱

  • 自动装箱

    把基本数据类型转换为对应的包装类类型

  • 自动拆箱

    把包装类类型转换为对应的基本数据类型

  • 示例代码

    Integer i = 100;  // 自动装箱
    i += 200;         // i = i + 200;  i + 200 自动拆箱;i = i + 200; 是自动装箱

13. 时间日期类

13.1 Date类

  • Date类概述

    Date 代表了一个特定的时间,精确到毫秒

  • Date类构造方法

    方法名说明
    public Date()分配一个 Date对象,并初始化,以便它代表它被分配的时间,精确到毫秒
    public Date(long date)分配一个 Date对象,并将其初始化为表示从标准基准时间起指定的毫秒数
  • 示例代码

    public class DateDemo01 {
        public static void main(String[] args) {
            //public Date():分配一个 Date对象,并初始化,以便它代表它被分配的时间,精确到毫秒
            Date d1 = new Date();
            System.out.println(d1);
    ​
            //public Date(long date):分配一个 Date对象,并将其初始化为表示从标准基准时间起指定的毫秒数
            long date = 1000*60*60;
            Date d2 = new Date(date);
            System.out.println(d2);
        }
    }

13.2 Date类常用方法

  • 常用方法

    方法名说明
    public long getTime()获取的是日期对象从1970年1月1日 00:00:00到现在的毫秒值
    public void setTime(long time)设置时间,给的是毫秒值
  • 示例代码

    public class DateDemo02 {
        public static void main(String[] args) {
            //创建日期对象
            Date d = new Date();
    ​
            //public long getTime():获取的是日期对象从1970年1月1日 00:00:00到现在的毫秒值
    //        System.out.println(d.getTime());
    //        System.out.println(d.getTime() * 1.0 / 1000 / 60 / 60 / 24 / 365 + "年");
    ​
            //public void setTime(long time):设置时间,给的是毫秒值
    //        long time = 1000*60*60;
            long time = System.currentTimeMillis();
            d.setTime(time);
    ​
            System.out.println(d);
        }
    }

13.3 SimpleDateFormat类

  • SimpleDateFormat类概述

    SimpleDateFormat是一个具体的类,用于以区域设置敏感的方式格式化和解析日期。

    我们重点学习日期格式化和解析

  • SimpleDateFormat类构造方法

    方法名说明
    public SimpleDateFormat()构造一个SimpleDateFormat,使用默认模式和日期格式
    public SimpleDateFormat(String pattern)构造一个SimpleDateFormat使用给定的模式和默认的日期格式
  • SimpleDateFormat类的常用方法

    • 格式化(从Date到String)

      • public final String format(Date date):将日期格式化成日期/时间字符串

    • 解析(从String到Date)

      • public Date parse(String source):从给定字符串的开始解析文本以生成日期

  • 示例代码

    public class SimpleDateFormatDemo {
        public static void main(String[] args) throws ParseException {
            //格式化:从 Date 到 String
            Date d = new Date();
    //        SimpleDateFormat sdf = new SimpleDateFormat();
            SimpleDateFormat sdf = new SimpleDateFormat("yyyy年MM月dd日 HH:mm:ss");
            String s = sdf.format(d);
            System.out.println(s);
            System.out.println("--------");
    ​
            //从 String 到 Date
            String ss = "2048-08-09 11:11:11";
            //ParseException
            SimpleDateFormat sdf2 = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
            Date dd = sdf2.parse(ss);
            System.out.println(dd);
        }
    }

13.4 日期工具类案例

  • 案例需求

    定义一个日期工具类(DateUtils),包含两个方法:把日期转换为指定格式的字符串;把字符串解析为指定格式的日期,然后定义一个测试类(DateDemo),测试日期工具类的方法

  • 代码实现

    • 工具类

    public class DateUtils {
        private DateUtils() {}
    
        /*
            把日期转为指定格式的字符串
            返回值类型:String
            参数:Date date, String format
         */
        public static String dateToString(Date date, String format) {
            SimpleDateFormat sdf = new SimpleDateFormat(format);
            String s = sdf.format(date);
            return s;
        }
    
    
        /*
            把字符串解析为指定格式的日期
            返回值类型:Date
            参数:String s, String format
         */
        public static Date stringToDate(String s, String format) throws ParseException {
            SimpleDateFormat sdf = new SimpleDateFormat(format);
            Date d = sdf.parse(s);
            return d;
        }
    
    }
    • 测试类

    public class DateDemo {
        public static void main(String[] args) throws ParseException {
            //创建日期对象
            Date d = new Date();
    
            String s1 = DateUtils.dateToString(d, "yyyy年MM月dd日 HH:mm:ss");
            System.out.println(s1);
    
            String s2 = DateUtils.dateToString(d, "yyyy年MM月dd日");
            System.out.println(s2);
    
            String s3 = DateUtils.dateToString(d, "HH:mm:ss");
            System.out.println(s3);
            System.out.println("--------");
    
            String s = "2048-08-09 12:12:12";
            Date dd = DateUtils.stringToDate(s, "yyyy-MM-dd HH:mm:ss");
            System.out.println(dd);
        }
    }

13.5 Calendar类

  • Calendar类概述

    Calendar 为特定瞬间与一组日历字段之间的转换提供了一些方法,并为操作日历字段提供了一些方法

    Calendar 提供了一个类方法 getInstance 用于获取这种类型的一般有用的对象。

    该方法返回一个Calendar 对象。

    其日历字段已使用当前日期和时间初始化:Calendar rightNow = Calendar.getInstance();

  • Calendar类常用方法

    方法名说明
    public int get(int field)返回给定日历字段的值
    public abstract void add(int field, int amount)根据日历的规则,将指定的时间量添加或减去给定的日历字段
    public final void set(int year,int month,int date)设置当前日历的年月日
  • 示例代码

    public class CalendarDemo {
        public static void main(String[] args) {
            //获取日历类对象
            Calendar c = Calendar.getInstance();
    
            //public int get(int field):返回给定日历字段的值
            int year = c.get(Calendar.YEAR);
            int month = c.get(Calendar.MONTH) + 1;
            int date = c.get(Calendar.DATE);
            System.out.println(year + "年" + month + "月" + date + "日");
    
            //public abstract void add(int field, int amount):根据日历的规则,将指定的时间量添加或减去给定的日历字段
            //需求1:3年前的今天
    //        c.add(Calendar.YEAR,-3);
    //        year = c.get(Calendar.YEAR);
    //        month = c.get(Calendar.MONTH) + 1;
    //        date = c.get(Calendar.DATE);
    //        System.out.println(year + "年" + month + "月" + date + "日");
    
            //需求2:10年后的10天前
    //        c.add(Calendar.YEAR,10);
    //        c.add(Calendar.DATE,-10);
    //        year = c.get(Calendar.YEAR);
    //        month = c.get(Calendar.MONTH) + 1;
    //        date = c.get(Calendar.DATE);
    //        System.out.println(year + "年" + month + "月" + date + "日");
    
            //public final void set(int year,int month,int date):设置当前日历的年月日
            c.set(2050,10,10);
            year = c.get(Calendar.YEAR);
            month = c.get(Calendar.MONTH) + 1;
            date = c.get(Calendar.DATE);
            System.out.println(year + "年" + month + "月" + date + "日");
    
        }
    }

13.6 二月天案例

  • 案例需求

    获取任意一年的二月有多少天

  • 代码实现

    public class CalendarTest {
        public static void main(String[] args) {
            //键盘录入任意的年份
            Scanner sc = new Scanner(System.in);
            System.out.println("请输入年:");
            int year = sc.nextInt();
    
            //设置日历对象的年、月、日
            Calendar c = Calendar.getInstance();
            c.set(year, 2, 1);
    
            //3月1日往前推一天,就是2月的最后一天
            c.add(Calendar.DATE, -1);
    
            //获取这一天输出即可
            int date = c.get(Calendar.DATE);
            System.out.println(year + "年的2月份有" + date + "天");
        }
    }

14. 异常

14.1 异常

  • 异常的概述

    异常就是程序出现了不正常的情况

  • 异常的体系结构

14.2 JVM默认处理异常的方式

  • 如果程序出现了问题,我们没有做任何处理,最终JVM 会做默认的处理,处理方式有如下两个步骤:

  • 把异常的名称,错误原因及异常出现的位置等信息输出在了控制台

  • 程序停止执行

14.3 try-catch方式处理异常

  • 定义格式

    try {
    	可能出现异常的代码;
    } catch(异常类名 变量名) {
    	异常的处理代码;
    }
  • 执行流程

    • 程序从 try 里面的代码开始执行

    • 出现异常,就会跳转到对应的 catch 里面去执行

    • 执行完毕之后,程序还可以继续往下执行

  • 示例代码

    public class ExceptionDemo01 {
        public static void main(String[] args) {
            System.out.println("开始");
            method();
            System.out.println("结束");
        }
    
        public static void method() {
            try {
                int[] arr = {1, 2, 3};
                System.out.println(arr[3]);
                System.out.println("这里能够访问到吗");
            } catch (ArrayIndexOutOfBoundsException e) {
    //            System.out.println("你访问的数组索引不存在,请回去修改为正确的索引");
                e.printStackTrace();
            }
        }
    }

14.4 Throwable成员方法

  • 常用方法

    方法名说明
    public String getMessage()返回此 throwable 的详细消息字符串
    public String toString()返回此可抛出的简短描述
    public void printStackTrace()把异常的错误信息输出在控制台
  • 示例代码

    public class ExceptionDemo02 {
        public static void main(String[] args) {
            System.out.println("开始");
            method();
            System.out.println("结束");
        }
    
        public static void method() {
            try {
                int[] arr = {1, 2, 3};
                System.out.println(arr[3]); //new ArrayIndexOutOfBoundsException();
                System.out.println("这里能够访问到吗");
            } catch (ArrayIndexOutOfBoundsException e) { //new ArrayIndexOutOfBoundsException();
    //            e.printStackTrace();
    
                //public String getMessage():返回此 throwable 的详细消息字符串
    //            System.out.println(e.getMessage());
                //Index 3 out of bounds for length 3
    
                //public String toString():返回此可抛出的简短描述
    //            System.out.println(e.toString());
                //java.lang.ArrayIndexOutOfBoundsException: Index 3 out of bounds for length 3
    
                //public void printStackTrace():把异常的错误信息输出在控制台
                e.printStackTrace();
    //            java.lang.ArrayIndexOutOfBoundsException: Index 3 out of bounds for length 3
    //            at com.itheima_02.ExceptionDemo02.method(ExceptionDemo02.java:18)
    //            at com.itheima_02.ExceptionDemo02.main(ExceptionDemo02.java:11)
    
            }
        }
    }

14.5 编译时异常和运行时异常的区别

  • 编译时异常

    • 都是Exception类及其子类

    • 必须显示处理,否则程序就会发生错误,无法通过编译

  • 运行时异常

    • 都是RuntimeException类及其子类

    • 无需显示处理,也可以和编译时异常一样处理

14.6 throws方式处理异常

  • 定义格式

    public void 方法() throws 异常类名 {
        
    }
  • 示例代码

    public class ExceptionDemo {
        public static void main(String[] args) {
            System.out.println("开始");
    //        method();
            try {
                method2();
            }catch (ParseException e) {
                e.printStackTrace();
            }
            System.out.println("结束");
        }
    
        //编译时异常
        public static void method2() throws ParseException {
            String s = "2048-08-09";
            SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
            Date d = sdf.parse(s);
            System.out.println(d);
        }
    
        //运行时异常
        public static void method() throws ArrayIndexOutOfBoundsException {
            int[] arr = {1, 2, 3};
            System.out.println(arr[3]);
        }
    }

  • 注意事项

    • 这个throws格式是跟在方法的括号后面的

    • 编译时异常必须要进行处理,两种处理方案:try...catch …或者 throws,如果采用 throws 这种方案,将来谁调用谁处理

    • 运行时异常可以不处理,出现问题后,需要我们回来修改代码

14.7 throws和throw的区别

14.8自定义异常

  • 自定义异常类

    public class ScoreException extends Exception {
    
        public ScoreException() {}
    
        public ScoreException(String message) {
            super(message);
        }
    
    }

  • 老师类

    public class Teacher {
        public void checkScore(int score) throws ScoreException {
            if(score<0 || score>100) {
    //            throw new ScoreException();
                throw new ScoreException("你给的分数有误,分数应该在0-100之间");
            } else {
                System.out.println("成绩正常");
            }
        }
    }

  • 测试类

     
public class Demo {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        System.out.println("请输入分数:");
​
        int score = sc.nextInt();
​
        Teacher t = new Teacher();
        try {
            t.checkScore(score);
        } catch (ScoreException e) {
            e.printStackTrace();
        }
    }
}

15. Collection集合

15.1 集合体系结构

  • 集合类的特点

    提供一种存储空间可变的存储模型,存储的数据容量可以随时发生改变

  • 集合类的体系图

15.2 Collection集合概述和基本使用

  • Collection集合概述

    • 是单例集合的顶层接口,它表示一组对象,这些对象也称为Collection的元素

    • JDK 不提供此接口的任何直接实现,它提供更具体的子接口(如Set和List)实现

  • Collection集合基本使用

    public class CollectionDemo01 {
        public static void main(String[] args) {
            //创建Collection集合的对象
            Collection<String> c = new ArrayList<String>();
    ​
            //添加元素:boolean add(E e)
            c.add("hello");
            c.add("world");
            c.add("java");
    ​
            //输出集合对象
            System.out.println(c);
        }
    }

15.3 Collection集合的常用方法

方法名说明
boolean add(E e)添加元素
boolean remove(Object o)从集合中移除指定的元素
void clear()清空集合中的元素
boolean contains(Object o)判断集合中是否存在指定的元素
boolean isEmpty()判断集合是否为空
int size()集合的长度,也就是集合中元素的个数

15.4 Collection集合的遍历

  • 迭代器的介绍

    • 迭代器,集合的专用遍历方式

    • Iterator<E> iterator():返回此集合中元素的迭代器,通过集合的iterator()方法得到

    • 迭代器是通过集合的iterator()方法得到的,所以我们说它是依赖于集合而存在的

  • Collection集合的遍历

public class IteratorDemo {
    public static void main(String[] args) {
        //创建集合对象
        Collection<String> c = new ArrayList<>();
​
        //添加元素
        c.add("hello");
        c.add("world");
        c.add("java");
        c.add("javaee");
​
        //Iterator<E> iterator():返回此集合中元素的迭代器,通过集合的iterator()方法得到
        Iterator<String> it = c.iterator();
​
        //用while循环改进元素的判断和获取
        while (it.hasNext()) {
            String s = it.next();
            System.out.println(s);
        }
    }
}

15.5 集合使用步骤图解

  • 使用步骤

15.6 集合的案例-Collection集合存储学生对象并遍历

  • 案例需求

    创建一个存储学生对象的集合,存储3个学生对象,使用程序实现在控制台遍历该集合

  • 代码实现

    • 学生类

    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 class CollectionDemo {
        public static void main(String[] args) {
            //创建Collection集合对象
            Collection<Student> c = new ArrayList<Student>();
    ​
            //创建学生对象
            Student s1 = new Student("林青霞", 30);
            Student s2 = new Student("张曼玉", 35);
            Student s3 = new Student("王祖贤", 33);
    ​
            //把学生添加到集合
            c.add(s1);
            c.add(s2);
            c.add(s3);
    ​
            //遍历集合(迭代器方式)
            Iterator<Student> it = c.iterator();
            while (it.hasNext()) {
                Student s = it.next();
                System.out.println(s.getName() + "," + s.getAge());
            }
        }
    }

16. List集合

16.1 List集合概述和特点

  • List集合概述

    • 有序集合(也称为序列),用户可以精确控制列表中每个元素的插入位置。用户可以通过整数索引访问元素,并搜索列表中的元素

    • 与Set集合不同,列表通常允许重复的元素

  • List集合特点

    • 有索引

    • 可以存储重复元素

    • 元素存取有序

16.2 List集合的特有方法

方法名描述
void add(int index,E element)在此集合中的指定位置插入指定的元素
E remove(int index)删除指定索引处的元素,返回被删除的元素
E set(int index,E element)修改指定索引处的元素,返回被修改的元素
E get(int index)返回指定索引处的元素

16.3 集合的案例-List集合存储学生对象并遍历

  • 案例需求

    创建一个存储学生对象的集合,存储3个学生对象,使用程序实现在控制台遍历该集合

  • 代码实现

    • 学生类

      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 class ListDemo {
          public static void main(String[] args) {
              //创建List集合对象
              List<Student> list = new ArrayList<Student>();
      ​
              //创建学生对象
              Student s1 = new Student("林青霞", 30);
              Student s2 = new Student("张曼玉", 35);
              Student s3 = new Student("王祖贤", 33);
      ​
              //把学生添加到集合
              list.add(s1);
              list.add(s2);
              list.add(s3);
      ​
              //迭代器方式
              Iterator<Student> it = list.iterator();
              while (it.hasNext()) {
                  Student s = it.next();
                  System.out.println(s.getName() + "," + s.getAge());
              }
              
              System.out.println("--------");
      ​
              //for循环方式
              for(int i=0; i<list.size(); i++) {
                  Student s = list.get(i);
                  System.out.println(s.getName() + "," + s.getAge());
              }
      ​
          }
      }

16.4 并发修改异常

  • 出现的原因

    迭代器遍历的过程中,通过集合对象修改了集合中的元素,造成了迭代器获取元素中判断预期修改值和实际修改值不一致,则会出现:ConcurrentModificationException

  • 解决的方案

    用for循环遍历,然后用集合对象做对应的操作即可

  • 示例代码

    public class ListDemo {
        public static void main(String[] args) {
            //创建集合对象
            List<String> list = new ArrayList<String>();
    ​
            //添加元素
            list.add("hello");
            list.add("world");
            list.add("java");
    ​
            //遍历集合,得到每一个元素,看有没有"world"这个元素,如果有,我就添加一个"javaee"元素,请写代码实现
    //        Iterator<String> it = list.iterator();
    //        while (it.hasNext()) {
    //            String s = it.next();
    //            if(s.equals("world")) {
    //                list.add("javaee");
    //            }
    //        }
    ​
            for(int i=0; i<list.size(); i++) {
                String s = list.get(i);
                if(s.equals("world")) {
                    list.add("javaee");
                }
            }
    ​
            //输出集合对象
            System.out.println(list);
        }
    }

16.5 列表迭代器

  • ListIterator介绍

    • 通过List集合的listIterator()方法得到,所以说它是List集合特有的迭代器

    • 用于允许程序员沿任一方向遍历的列表迭代器,在迭代期间修改列表,并获取列表中迭代器的当前位置

  • 示例代码

    public class ListIteratorDemo {
        public static void main(String[] args) {
            //创建集合对象
            List<String> list = new ArrayList<String>();
    ​
            //添加元素
            list.add("hello");
            list.add("world");
            list.add("java");
    ​
            //获取列表迭代器
            ListIterator<String> lit = list.listIterator();
            while (lit.hasNext()) {
                String s = lit.next();
                if(s.equals("world")) {
                    lit.add("javaee");
                }
            }
    ​
            System.out.println(list);
    ​
        }
    }

16.6 增强for循环

  • 定义格式

    for(元素数据类型 变量名 : 数组/集合对象名) {
        循环体;
    }
  • 示例代码

    public class ForDemo {
        public static void main(String[] args) {
            int[] arr = {1,2,3,4,5};
            for(int i : arr) {
                System.out.println(i);
            }
            
            System.out.println("--------");
    
            String[] strArray = {"hello","world","java"};
            for(String s : strArray) {
                System.out.println(s);
            }
            
            System.out.println("--------");
    
            List<String> list = new ArrayList<String>();
            list.add("hello");
            list.add("world");
            list.add("java");
    
            for(String s : list) {
                System.out.println(s);
            }
            
            System.out.println("--------");
    
            //内部原理是一个Iterator迭代器
            /*
            for(String s : list) {
                if(s.equals("world")) {
                    list.add("javaee"); //ConcurrentModificationException
                }
            }
            */
        }
    }

16.7 集合的案例-List集合存储学生对象三种方式遍历

  • 案例需求

    创建一个存储学生对象的集合,存储3个学生对象,使用程序实现在控制台遍历该集合

  • 代码实现

    • 学生类

      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 class ListDemo {
          public static void main(String[] args) {
              //创建List集合对象
              List<Student> list = new ArrayList<Student>();
      
              //创建学生对象
              Student s1 = new Student("林青霞", 30);
              Student s2 = new Student("张曼玉", 35);
              Student s3 = new Student("王祖贤", 33);
      
              //把学生添加到集合
              list.add(s1);
              list.add(s2);
              list.add(s3);
      
              //迭代器:集合特有的遍历方式
              Iterator<Student> it = list.iterator();
              while (it.hasNext()) {
                  Student s = it.next();
                  System.out.println(s.getName()+","+s.getAge());
              }
              System.out.println("--------");
      
              //普通for:带有索引的遍历方式
              for(int i=0; i<list.size(); i++) {
                  Student s = list.get(i);
                  System.out.println(s.getName()+","+s.getAge());
              }
              System.out.println("--------");
      
              //增强for:最方便的遍历方式
              for(Student s : list) {
                  System.out.println(s.getName()+","+s.getAge());
              }
          }
      }

17. 数据结构

17.1 数据结构之栈和队列

  • 栈结构

    先进后出

  • 队列结构

    先进先出

17.2 数据结构之数组和链表

  • 数组结构

    查询快、增删慢

  • 队列结构

    查询慢、增删快

18. List集合的实现类

18.1 List集合子类的特点

  • ArrayList集合

    底层是数组结构实现,查询快、增删慢

  • LinkedList集合

    底层是链表结构实现,查询慢、增删快

18.2 集合的案例-ArrayList集合存储学生对象三种方式遍历

  • 案例需求

    创建一个存储学生对象的集合,存储3个学生对象,使用程序实现在控制台遍历该集合

  • 代码实现

    • 学生类

      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 class ArrayListDemo {
          public static void main(String[] args) {
              //创建ArrayList集合对象
              ArrayList<Student> array = new ArrayList<Student>();
      
              //创建学生对象
              Student s1 = new Student("林青霞", 30);
              Student s2 = new Student("张曼玉", 35);
              Student s3 = new Student("王祖贤", 33);
      
              //把学生添加到集合
              array.add(s1);
              array.add(s2);
              array.add(s3);
      
              //迭代器:集合特有的遍历方式
              Iterator<Student> it = array.iterator();
              while (it.hasNext()) {
                  Student s = it.next();
                  System.out.println(s.getName() + "," + s.getAge());
              }
              System.out.println("--------");
      
              //普通for:带有索引的遍历方式
              for(int i=0; i<array.size(); i++) {
                  Student s = array.get(i);
                  System.out.println(s.getName() + "," + s.getAge());
              }
              System.out.println("--------");
      
              //增强for:最方便的遍历方式
              for(Student s : array) {
                  System.out.println(s.getName() + "," + s.getAge());
              }
          }
      }

18.3 LinkedList集合的特有功能

  • 特有方法

    方法名说明
    public void addFirst(E e)在该列表开头插入指定的元素
    public void addLast(E e)将指定的元素追加到此列表的末尾
    public E getFirst()返回此列表中的第一个元素
    public E getLast()返回此列表中的最后一个元素
    public E removeFirst()从此列表中删除并返回第一个元素
    public E removeLast()从此列表中删除并返回最后一个元素

19. Set集合

19.1 Set集合概述和特点

  • Set集合的特点

    • 元素存取无序

    • 没有索引、只能通过迭代器或增强for循环遍历

    • 不能存储重复元素

  • Set集合的基本使用

public class SetDemo {
    public static void main(String[] args) {
        //创建集合对象
        Set<String> set = new HashSet<String>();
​
        //添加元素
        set.add("hello");
        set.add("world");
        set.add("java");
        //不包含重复元素的集合
        set.add("world");
​
        //遍历
        for(String s : set) {
            System.out.println(s);
        }
    }
}

19.2 哈希值

  • 哈希值简介

    是JDK根据对象的地址或者字符串或者数字算出来的int类型的数值

  • 如何获取哈希值

    Object类中的public int hashCode():返回对象的哈希码值

  • 哈希值的特点

    • 同一个对象多次调用hashCode()方法返回的哈希值是相同的

    • 默认情况下,不同对象的哈希值是不同的。而重写hashCode()方法,可以实现让不同对象的哈希值相同

  • 获取哈希值的代码

    • 学生类

    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 int hashCode() {
            return 0;
        }
    }
    • 测试类

    public class HashDemo {
        public static void main(String[] args) {
            //创建学生对象
            Student s1 = new Student("林青霞",30);
    ​
            //同一个对象多次调用hashCode()方法返回的哈希值是相同的
            System.out.println(s1.hashCode()); //1060830840
            System.out.println(s1.hashCode()); //1060830840
            System.out.println("--------");
    ​
            Student s2 = new Student("林青霞",30);
    ​
            //默认情况下,不同对象的哈希值是不相同的
            //通过方法重写,可以实现不同对象的哈希值是相同的
            System.out.println(s2.hashCode()); //2137211482
            System.out.println("--------");
    ​
            System.out.println("hello".hashCode()); //99162322
            System.out.println("world".hashCode()); //113318802
            System.out.println("java".hashCode()); //3254818
    ​
            System.out.println("world".hashCode()); //113318802
            System.out.println("--------");
    ​
            System.out.println("重地".hashCode()); //1179395
            System.out.println("通话".hashCode()); //1179395
        }
    }

19.3 HashSet集合概述和特点

  • HashSet集合的特点

    • 底层数据结构是哈希表

    • 对集合的迭代顺序不作任何保证,也就是说不保证存储和取出的元素顺序一致

    • 没有带索引的方法,所以不能使用普通for循环遍历

    • 由于是Set集合,所以是不包含重复元素的集合

  • HashSet集合的基本使用

    public class HashSetDemo01 {
        public static void main(String[] args) {
            //创建集合对象
            HashSet<String> hs = new HashSet<String>();
    ​
            //添加元素
            hs.add("hello");
            hs.add("world");
            hs.add("java");
    ​
            hs.add("world");
    ​
            //遍历
            for(String s : hs) {
                System.out.println(s);
            }
        }
    }

19.4 HashSet集合保证元素唯一性源码分析

  • HashSet集合保证元素唯一性的原理

    1.根据对象的哈希值计算存储位置

    如果当前位置没有元素则直接存入

    如果当前位置有元素存在,则进入第二步

    2.当前元素的元素和已经存在的元素比较哈希值

    如果哈希值不同,则将当前元素进行存储

    如果哈希值相同,则进入第三步

    3.通过equals()方法比较两个元素的内容

    如果内容不相同,则将当前元素进行存储

    如果内容相同,则不存储当前元素

  • HashSet集合保证元素唯一性的图解

19.5 常见数据结构之哈希表

19.6 HashSet集合存储学生对象并遍历

  • 案例需求

    • 创建一个存储学生对象的集合,存储多个学生对象,使用程序实现在控制台遍历该集合

    • 要求:学生对象的成员变量值相同,我们就认为是同一个对象

  • 代码实现

    • 学生类

      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;
      ​
              if (age != student.age) return false;
              return name != null ? name.equals(student.name) : student.name == null;
          }
      ​
          @Override
          public int hashCode() {
              int result = name != null ? name.hashCode() : 0;
              result = 31 * result + age;
              return result;
          }
      }

    • 测试类

      public class HashSetDemo02 {
          public static void main(String[] args) {
              //创建HashSet集合对象
              HashSet<Student> hs = new HashSet<Student>();
      ​
              //创建学生对象
              Student s1 = new Student("林青霞", 30);
              Student s2 = new Student("张曼玉", 35);
              Student s3 = new Student("王祖贤", 33);
      ​
              Student s4 = new Student("王祖贤", 33);
      ​
              //把学生添加到集合
              hs.add(s1);
              hs.add(s2);
              hs.add(s3);
              hs.add(s4);
      ​
              //遍历集合(增强for)
              for (Student s : hs) {
                  System.out.println(s.getName() + "," + s.getAge());
              }
          }
      }

19.7 LinkedHashSet集合概述和特点

  • LinkedHashSet集合特点

    • 哈希表和链表实现的Set接口,具有可预测的迭代次序

    • 由链表保证元素有序,也就是说元素的存储和取出顺序是一致的

    • 由哈希表保证元素唯一,也就是说没有重复的元素

  • LinkedHashSet集合基本使用

    public class LinkedHashSetDemo {
        public static void main(String[] args) {
            //创建集合对象
            LinkedHashSet<String> linkedHashSet = new LinkedHashSet<String>();
    ​
            //添加元素
            linkedHashSet.add("hello");
            linkedHashSet.add("world");
            linkedHashSet.add("java");
    ​
            linkedHashSet.add("world");
    ​
            //遍历集合
            for(String s : linkedHashSet) {
                System.out.println(s);
            }
        }
    }

20. Set集合排序

20.1 TreeSet集合概述和特点

  • TreeSet集合概述

    • 元素有序,可以按照一定的规则进行排序,具体排序方式取决于构造方法

      • TreeSet():根据其元素的自然排序进行排序

      • TreeSet(Comparator comparator) :根据指定的比较器进行排序

    • 没有带索引的方法,所以不能使用普通for循环遍历

    • 由于是Set集合,所以不包含重复元素的集合

  • TreeSet集合基本使用

    public class TreeSetDemo01 {
        public static void main(String[] args) {
            //创建集合对象
            TreeSet<Integer> ts = new TreeSet<Integer>();
    ​
            //添加元素
            ts.add(10);
            ts.add(40);
            ts.add(30);
            ts.add(50);
            ts.add(20);
    ​
            ts.add(30);
    ​
            //遍历集合
            for(Integer i : ts) {
                System.out.println(i);
            }
        }
    }

20.2 自然排序Comparable的使用

  • 案例需求

    • 存储学生对象并遍历,创建TreeSet集合使用无参构造方法

    • 要求:按照年龄从小到大排序,年龄相同时,按照姓名的字母顺序排序

  • 实现步骤

    • 用TreeSet集合存储自定义对象,无参构造方法使用的是自然排序对元素进行排序的

    • 自然排序,就是让元素所属的类实现Comparable接口,重写compareTo(T o)方法

    • 重写方法时,一定要注意排序规则必须按照要求的主要条件和次要条件来写

  • 代码实现

    • 学生类

      public class Student implements Comparable<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 int compareTo(Student s) {
      //        return 0;
      //        return 1;
      //        return -1;
              //按照年龄从小到大排序
             int num = this.age - s.age;
      //        int num = s.age - this.age;
              //年龄相同时,按照姓名的字母顺序排序
             int num2 = num==0?this.name.compareTo(s.name):num;
              return num2;
          }
      }

    • 测试类

      public class TreeSetDemo02 {
          public static void main(String[] args) {
              //创建集合对象
              TreeSet<Student> ts = new TreeSet<Student>();
      
              //创建学生对象
              Student s1 = new Student("xishi", 29);
              Student s2 = new Student("wangzhaojun", 28);
              Student s3 = new Student("diaochan", 30);
              Student s4 = new Student("yangyuhuan", 33);
      
              Student s5 = new Student("linqingxia",33);
              Student s6 = new Student("linqingxia",33);
      
              //把学生添加到集合
              ts.add(s1);
              ts.add(s2);
              ts.add(s3);
              ts.add(s4);
              ts.add(s5);
              ts.add(s6);
      
              //遍历集合
              for (Student s : ts) {
                  System.out.println(s.getName() + "," + s.getAge());
              }
          }
      }

20.3 比较器排序Comparator的使用

  • 案例需求

    • 存储学生对象并遍历,创建TreeSet集合使用带参构造方法

    • 要求:按照年龄从小到大排序,年龄相同时,按照姓名的字母顺序排序

  • 实现步骤

    • 用TreeSet集合存储自定义对象,带参构造方法使用的是比较器排序对元素进行排序的

    • 比较器排序,就是让集合构造方法接收Comparator的实现类对象,重写compare(T o1,T o2)方法

    • 重写方法时,一定要注意排序规则必须按照要求的主要条件和次要条件来写

  • 代码实现

    • 学生类

      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 class TreeSetDemo {
          public static void main(String[] args) {
              //创建集合对象
              TreeSet<Student> ts = new TreeSet<Student>(new Comparator<Student>() {
                  @Override
                  public int compare(Student s1, Student s2) {
                      //this.age - s.age
                      //s1,s2
                      int num = s1.getAge() - s2.getAge();
                      int num2 = num == 0 ? s1.getName().compareTo(s2.getName()) : num;
                      return num2;
                  }
              });
      
              //创建学生对象
              Student s1 = new Student("xishi", 29);
              Student s2 = new Student("wangzhaojun", 28);
              Student s3 = new Student("diaochan", 30);
              Student s4 = new Student("yangyuhuan", 33);
      
              Student s5 = new Student("linqingxia",33);
              Student s6 = new Student("linqingxia",33);
      
              //把学生添加到集合
              ts.add(s1);
              ts.add(s2);
              ts.add(s3);
              ts.add(s4);
              ts.add(s5);
              ts.add(s6);
      
              //遍历集合
              for (Student s : ts) {
                  System.out.println(s.getName() + "," + s.getAge());
              }
          }
      }

20.4成绩排序案例

  • 案例需求

    • 用TreeSet集合存储多个学生信息(姓名,语文成绩,数学成绩),并遍历该集合

    • 要求:按照总分从高到低出现

  • 代码实现

    • 学生类

      public class Student {
          private String name;
          private int chinese;
          private int math;
      
          public Student() {
          }
      
          public Student(String name, int chinese, int math) {
              this.name = name;
              this.chinese = chinese;
              this.math = math;
          }
      
          public String getName() {
              return name;
          }
      
          public void setName(String name) {
              this.name = name;
          }
      
          public int getChinese() {
              return chinese;
          }
      
          public void setChinese(int chinese) {
              this.chinese = chinese;
          }
      
          public int getMath() {
              return math;
          }
      
          public void setMath(int math) {
              this.math = math;
          }
      
          public int getSum() {
              return this.chinese + this.math;
          }
      }

    • 测试类

      public class TreeSetDemo {
          public static void main(String[] args) {
              //创建TreeSet集合对象,通过比较器排序进行排序
              TreeSet<Student> ts = new TreeSet<Student>(new Comparator<Student>() {
                  @Override
                  public int compare(Student s1, Student s2) {
      //                int num = (s2.getChinese()+s2.getMath())-(s1.getChinese()+s1.getMath());
                      //主要条件
                      int num = s2.getSum() - s1.getSum();
                      //次要条件
                      int num2 = num == 0 ? s1.getChinese() - s2.getChinese() : num;
                      int num3 = num2 == 0 ? s1.getName().compareTo(s2.getName()) : num2;
                      return num3;
                  }
              });
      
              //创建学生对象
              Student s1 = new Student("林青霞", 98, 100);
              Student s2 = new Student("张曼玉", 95, 95);
              Student s3 = new Student("王祖贤", 100, 93);
              Student s4 = new Student("柳岩", 100, 97);
              Student s5 = new Student("风清扬", 98, 98);
      
              Student s6 = new Student("左冷禅", 97, 99);
      //        Student s7 = new Student("左冷禅", 97, 99);
              Student s7 = new Student("赵云", 97, 99);
      
              //把学生对象添加到集合
              ts.add(s1);
              ts.add(s2);
              ts.add(s3);
              ts.add(s4);
              ts.add(s5);
              ts.add(s6);
              ts.add(s7);
      
              //遍历集合
              for (Student s : ts) {
                  System.out.println(s.getName() + "," + s.getChinese() + "," + s.getMath() + "," + s.getSum());
              }
          }
      }

20.5不重复的随机数案例

  • 案例需求

    • 编写一个程序,获取10个1-20之间的随机数,要求随机数不能重复,并在控制台输出

  • 代码实现

    public class SetDemo {
        public static void main(String[] args) {
            //创建Set集合对象
    //        Set<Integer> set = new HashSet<Integer>();
            Set<Integer> set = new TreeSet<Integer>();
    
            //创建随机数对象
            Random r = new Random();
    
            //判断集合的长度是不是小于10
            while (set.size()<10) {
                //产生一个随机数,添加到集合
                int number = r.nextInt(20) + 1;
                set.add(number);
            }
    
            //遍历集合
            for(Integer i : set) {
                System.out.println(i);
            }
        }
    }

21. 泛型

21.1 泛型概述和好处

  • 泛型概述

    是JDK5中引入的特性,它提供了编译时类型安全检测机制,该机制允许在编译时检测到非法的类型

    它的本质是参数化类型,也就是说所操作的数据类型被指定为一个参数。一提到参数,最熟悉的就是定义方法时有形参,然后调用此方法时传递实参。那么参数化类型怎么理解呢?顾名思义,就是将类型由原来的具体的类型参数化,然后在使用/调用时传入具体的类型。这种参数类型可以用在类、方法和接口中,分别被称为泛型类、泛型方法、泛型接口

  • 泛型定义格式

    • <类型>:指定一种类型的格式。这里的类型可以看成是形参

    • <类型1,类型2…>:指定多种类型的格式,多种类型之间用逗号隔开。这里的类型可以看成是形参

    • 将来具体调用时候给定的类型可以看成是实参,并且实参的类型只能是引用数据类型

  • 泛型的好处

    • 把运行时期的问题提前到了编译期间

    • 避免了强制类型转换

21.2 泛型类

  • 定义格式

    修饰符 class 类名<类型> {  }
  • 示例代码

    • 泛型类

      public class Generic<T> {
          private T t;
      
          public T getT() {
              return t;
          }
      
          public void setT(T t) {
              this.t = t;
          }
      }

    • 测试类

      public class GenericDemo {
          public static void main(String[] args) {
              Generic<String> g1 = new Generic<String>();
              g1.setT("林青霞");
              System.out.println(g1.getT());
      
              Generic<Integer> g2 = new Generic<Integer>();
              g2.setT(30);
              System.out.println(g2.getT());
      
              Generic<Boolean> g3 = new Generic<Boolean>();
              g3.setT(true);
              System.out.println(g3.getT());
          }
      }

21.3 泛型方法

  • 定义格式

    修饰符 <类型> 返回值类型 方法名(类型 变量名) {  }
  • 示例代码

    • 带有泛型方法的类

      public class Generic {
          public <T> void show(T t) {
              System.out.println(t);
          }
      }

    • 测试类

      public class GenericDemo {
          public static void main(String[] args) {
      		Generic g = new Generic();
              g.show("林青霞");
              g.show(30);
              g.show(true);
              g.show(12.34);
          }
      }

21.4 泛型接口

  • 定义格式

    修饰符 interface 接口名<类型> {  }
  • 示例代码

    • 泛型接口

      public interface Generic<T> {
          void show(T t);
      }

    • 泛型接口实现类

      public class GenericImpl<T> implements Generic<T> {
          @Override
          public void show(T t) {
              System.out.println(t);
          }
      }

    • 测试类

      public class GenericDemo {
          public static void main(String[] args) {
              Generic<String> g1 = new GenericImpl<String>();
              g1.show("林青霞");
      
              Generic<Integer> g2 = new GenericImpl<Integer>();
              g2.show(30);
          }
      }

21.5 类型通配符

  • 类型通配符的作用

    为了表示各种泛型List的父类,可以使用类型通配符

  • 类型通配符的分类

    • 类型通配符:<?>

      • List<?>:表示元素类型未知的List,它的元素可以匹配任何的类型

      • 这种带通配符的List仅表示它是各种泛型List的父类,并不能把元素添加到其中

    • 类型通配符上限:<? extends 类型>

      • List<? extends Number>:它表示的类型是Number或者其子类型

    • 类型通配符下限:<? super 类型>

      • List<? super Number>:它表示的类型是Number或者其父类型

  • 类型通配符的基本使用

    public class GenericDemo {
        public static void main(String[] args) {
            //类型通配符:<?>
            List<?> list1 = new ArrayList<Object>();
            List<?> list2 = new ArrayList<Number>();
            List<?> list3 = new ArrayList<Integer>();
            System.out.println("--------");
    
            //类型通配符上限:<? extends 类型>
    //        List<? extends Number> list4 = new ArrayList<Object>();
            List<? extends Number> list5 = new ArrayList<Number>();
            List<? extends Number> list6 = new ArrayList<Integer>();
            System.out.println("--------");
    
            //类型通配符下限:<? super 类型>
            List<? super Number> list7 = new ArrayList<Object>();
            List<? super Number> list8 = new ArrayList<Number>();
    //        List<? super Number> list9 = new ArrayList<Integer>();
    
        }
    }

22. 可变参数

22.1 可变参数

  • 可变参数介绍

    可变参数又称参数个数可变,用作方法的形参出现,那么方法参数个数就是可变的了

  • 可变参数定义格式

    修饰符 返回值类型 方法名(数据类型… 变量名) {  }
  • 可变参数的注意事项

    • 这里的变量其实是一个数组

    • 如果一个方法有多个参数,包含可变参数,可变参数要放在最后

  • 可变参数的基本使用

    public class ArgsDemo01 {
        public static void main(String[] args) {
            System.out.println(sum(10, 20));
            System.out.println(sum(10, 20, 30));
            System.out.println(sum(10, 20, 30, 40));
    
            System.out.println(sum(10,20,30,40,50));
            System.out.println(sum(10,20,30,40,50,60));
            System.out.println(sum(10,20,30,40,50,60,70));
            System.out.println(sum(10,20,30,40,50,60,70,80,90,100));
        }
    
    //    public static int sum(int b,int... a) {
    //        return 0;
    //    }
    
        public static int sum(int... a) {
            int sum = 0;
            for(int i : a) {
                sum += i;
            }
            return sum;
        }
    }

22.2 可变参数的使用

23.2 Map集合的基本功能

23.3 Map集合的获取功能

23.4 Map集合的遍历(方式1)

23.5 Map集合的遍历(方式2)

23.6 Map集合的案例

23.6.1 HashMap集合练习之键是String值是Student

23.6.2 HashMap集合练习之键是Student值是String

23.6.3 集合嵌套之ArrayList嵌套HashMap

23.6.4 集合嵌套之HashMap嵌套ArrayList

23.6.5 统计字符串中每个字符出现的次数

27. Collections集合工具类

27.1 Collections概述和使用

27.2 ArrayList集合存储学生并排序

28. 斗地主案例

28.1 模拟斗地主案例-普通版本

28.2 模拟斗地主案例-升级版本

  • Arrays工具类中有一个静态方法:

    • public static <T> List<T> asList(T... a):返回由指定数组支持的固定大小的列表

    • 返回的集合不能做增删操作,可以做修改操作

  • List接口中有一个静态方法:

    • public static <E> List<E> of(E... elements):返回包含任意数量元素的不可变列表

    • 返回的集合不能做增删改操作

  • Set接口中有一个静态方法:

    • public static <E> Set<E> of(E... elements) :返回一个包含任意数量元素的不可变集合

    • 在给元素的时候,不能给重复的元素

    • 返回的集合不能做增删操作,没有修改的方法

  • 示例代码

    public class ArgsDemo02 {
        public static void main(String[] args) {
            //public static <T> List<T> asList(T... a):返回由指定数组支持的固定大小的列表
    //        List<String> list = Arrays.asList("hello", "world", "java");
    //
            list.add("javaee"); //UnsupportedOperationException
            list.remove("world"); //UnsupportedOperationException
    //        list.set(1,"javaee");
    //
    //        System.out.println(list);
    ​
            //public static <E> List<E> of(E... elements):返回包含任意数量元素的不可变列表
    //        List<String> list = List.of("hello", "world", "java", "world");
    //
            list.add("javaee");//UnsupportedOperationException
            list.remove("java");//UnsupportedOperationException
            list.set(1,"javaee");//UnsupportedOperationException
    //
    //        System.out.println(list);
    ​
            //public static <E> Set<E> of(E... elements) :返回一个包含任意数量元素的不可变集合
    //        Set<String> set = Set.of("hello", "world", "java","world"); //IllegalArgumentException
            //Set<String> set = Set.of("hello", "world", "java");
    ​
    //        set.add("javaee");//UnsupportedOperationException
    //        set.remove("world");//UnsupportedOperationException
    ​
            //System.out.println(set);
        }
    }

    23. Map集合

    23.1 Map集合概述和特点

  • Map集合概述

    interface Map<K,V>  K:键的类型;V:值的类型
  • Map集合的特点

    • 键值对映射关系

    • 一个键对应一个值

    • 键不能重复,值可以重复

    • 元素存取无序

  • Map集合的基本使用

    public class MapDemo01 {
        public static void main(String[] args) {
            //创建集合对象
            Map<String,String> map = new HashMap<String,String>();
    ​
            //V put(K key, V value) 将指定的值与该映射中的指定键相关联
            map.put("itheima001","林青霞");
            map.put("itheima002","张曼玉");
            map.put("itheima003","王祖贤");
            map.put("itheima003","柳岩");
    ​
            //输出集合对象
            System.out.println(map);
        }
    }

  • 方法介绍

    方法名说明
    V put(K key,V value)添加元素
    V remove(Object key)根据键删除键值对元素
    void clear()移除所有的键值对元素
    boolean containsKey(Object key)判断集合是否包含指定的键
    boolean containsValue(Object value)判断集合是否包含指定的值
    boolean isEmpty()判断集合是否为空
    int size()集合的长度,也就是集合中键值对的个数
  • 示例代码

    public class MapDemo02 {
        public static void main(String[] args) {
            //创建集合对象
            Map<String,String> map = new HashMap<String,String>();
    ​
            //V put(K key,V value):添加元素
            map.put("张无忌","赵敏");
            map.put("郭靖","黄蓉");
            map.put("杨过","小龙女");
    ​
            //V remove(Object key):根据键删除键值对元素
    //        System.out.println(map.remove("郭靖"));
    //        System.out.println(map.remove("郭襄"));
    ​
            //void clear():移除所有的键值对元素
    //        map.clear();
    ​
            //boolean containsKey(Object key):判断集合是否包含指定的键
    //        System.out.println(map.containsKey("郭靖"));
    //        System.out.println(map.containsKey("郭襄"));
    ​
            //boolean isEmpty():判断集合是否为空
    //        System.out.println(map.isEmpty());
    ​
            //int size():集合的长度,也就是集合中键值对的个数
            System.out.println(map.size());
    ​
    ​
            //输出集合对象
            System.out.println(map);
        }
    }

  • 方法介绍

    方法名说明
    V get(Object key)根据键获取值
    Set<K> keySet()获取所有键的集合
    Collection<V> values()获取所有值的集合
    Set<Map.Entry<K,V>> entrySet()获取所有键值对对象的集合
  • 示例代码

    public class MapDemo03 {
        public static void main(String[] args) {
            //创建集合对象
            Map<String, String> map = new HashMap<String, String>();
    ​
            //添加元素
            map.put("张无忌", "赵敏");
            map.put("郭靖", "黄蓉");
            map.put("杨过", "小龙女");
    ​
            //V get(Object key):根据键获取值
    //        System.out.println(map.get("张无忌"));
    //        System.out.println(map.get("张三丰"));
    ​
            //Set<K> keySet():获取所有键的集合
    //        Set<String> keySet = map.keySet();
    //        for(String key : keySet) {
    //            System.out.println(key);
    //        }
    ​
            //Collection<V> values():获取所有值的集合
            Collection<String> values = map.values();
            for(String value : values) {
                System.out.println(value);
            }
        }
    }

  • 遍历思路

    • 我们刚才存储的元素都是成对出现的,所以我们把Map看成是一个夫妻对的集合

      • 把所有的丈夫给集中起来

      • 遍历丈夫的集合,获取到每一个丈夫

      • 根据丈夫去找对应的妻子

  • 步骤分析

    • 获取所有键的集合。用keySet()方法实现

    • 遍历键的集合,获取到每一个键。用增强for实现

    • 根据键去找值。用get(Object key)方法实现

  • 代码实现

    public class MapDemo01 {
        public static void main(String[] args) {
            //创建集合对象
            Map<String, String> map = new HashMap<String, String>();
    ​
            //添加元素
            map.put("张无忌", "赵敏");
            map.put("郭靖", "黄蓉");
            map.put("杨过", "小龙女");
    ​
            //获取所有键的集合。用keySet()方法实现
            Set<String> keySet = map.keySet();
            //遍历键的集合,获取到每一个键。用增强for实现
            for (String key : keySet) {
                //根据键去找值。用get(Object key)方法实现
                String value = map.get(key);
                System.out.println(key + "," + value);
            }
        }
    }

  • 遍历思路

    • 我们刚才存储的元素都是成对出现的,所以我们把Map看成是一个夫妻对的集合

      • 获取所有结婚证的集合

      • 遍历结婚证的集合,得到每一个结婚证

      • 根据结婚证获取丈夫和妻子

  • 步骤分析

    • 获取所有键值对对象的集合

      • Set<Map.Entry<K,V>> entrySet():获取所有键值对对象的集合

    • 遍历键值对对象的集合,得到每一个键值对对象

      • 用增强for实现,得到每一个Map.Entry

    • 根据键值对对象获取键和值

      • 用getKey()得到键

      • 用getValue()得到值

  • 代码实现

    public class MapDemo02 {
        public static void main(String[] args) {
            //创建集合对象
            Map<String, String> map = new HashMap<String, String>();
    ​
            //添加元素
            map.put("张无忌", "赵敏");
            map.put("郭靖", "黄蓉");
            map.put("杨过", "小龙女");
    ​
            //获取所有键值对对象的集合
            Set<Map.Entry<String, String>> entrySet = map.entrySet();
            //遍历键值对对象的集合,得到每一个键值对对象
            for (Map.Entry<String, String> me : entrySet) {
                //根据键值对对象获取键和值
                String key = me.getKey();
                String value = me.getValue();
                System.out.println(key + "," + value);
            }
        }
    }

  • 案例需求

    创建一个HashMap集合,键是学号(String),值是学生对象(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;
          }
      }

    • 测试类

      /*
          需求:
              创建一个HashMap集合,键是学号(String),值是学生对象(Student)。存储三个键值对元素,并遍历
      ​
          思路:
              1:定义学生类
              2:创建HashMap集合对象
              3:创建学生对象
              4:把学生添加到集合
              5:遍历集合
                  方式1:键找值
                  方式2:键值对对象找键和值
       */
      public class HashMapDemo {
          public static void main(String[] args) {
              //创建HashMap集合对象
              HashMap<String, Student> hm = new HashMap<String, Student>();
      ​
              //创建学生对象
              Student s1 = new Student("林青霞", 30);
              Student s2 = new Student("张曼玉", 35);
              Student s3 = new Student("王祖贤", 33);
      ​
              //把学生添加到集合
              hm.put("itheima001", s1);
              hm.put("itheima002", s2);
              hm.put("itheima003", s3);
      ​
              //方式1:键找值
              Set<String> keySet = hm.keySet();
              for (String key : keySet) {
                  Student value = hm.get(key);
                  System.out.println(key + "," + value.getName() + "," + value.getAge());
              }
              System.out.println("--------");
      ​
              //方式2:键值对对象找键和值
              Set<Map.Entry<String, Student>> entrySet = hm.entrySet();
              for (Map.Entry<String, Student> me : entrySet) {
                  String key = me.getKey();
                  Student value = me.getValue();
                  System.out.println(key + "," + value.getName() + "," + value.getAge());
              }
          }
      }

  • 案例需求

    • 创建一个HashMap集合,键是学生对象(Student),值是居住地 (String)。存储多个元素,并遍历。

    • 要求保证键的唯一性:如果学生对象的成员变量值相同,我们就认为是同一个对象

  • 代码实现

    • 学生类

      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;
      
              if (age != student.age) return false;
              return name != null ? name.equals(student.name) : student.name == null;
          }
      
          @Override
          public int hashCode() {
              int result = name != null ? name.hashCode() : 0;
              result = 31 * result + age;
              return result;
          }
      }

    • 测试类

      public class HashMapDemo {
          public static void main(String[] args) {
              //创建HashMap集合对象
              HashMap<Student, String> hm = new HashMap<Student, String>();
      
              //创建学生对象
              Student s1 = new Student("林青霞", 30);
              Student s2 = new Student("张曼玉", 35);
              Student s3 = new Student("王祖贤", 33);
              Student s4 = new Student("王祖贤", 33);
      
              //把学生添加到集合
              hm.put(s1, "西安");
              hm.put(s2, "武汉");
              hm.put(s3, "郑州");
              hm.put(s4, "北京");
      
              //遍历集合
              Set<Student> keySet = hm.keySet();
              for (Student key : keySet) {
                  String value = hm.get(key);
                  System.out.println(key.getName() + "," + key.getAge() + "," + value);
              }
          }
      }

  • 案例需求

    • 创建一个ArrayList集合,存储三个元素,每一个元素都是HashMap

    • 每一个HashMap的键和值都是String,并遍历。

  • 代码实现

    public class ArrayListIncludeHashMapDemo {
        public static void main(String[] args) {
            //创建ArrayList集合
            ArrayList<HashMap<String, String>> array = new ArrayList<HashMap<String, String>>();
    
            //创建HashMap集合,并添加键值对元素
            HashMap<String, String> hm1 = new HashMap<String, String>();
            hm1.put("孙策", "大乔");
            hm1.put("周瑜", "小乔");
            //把HashMap作为元素添加到ArrayList集合
            array.add(hm1);
    
            HashMap<String, String> hm2 = new HashMap<String, String>();
            hm2.put("郭靖", "黄蓉");
            hm2.put("杨过", "小龙女");
            //把HashMap作为元素添加到ArrayList集合
            array.add(hm2);
    
            HashMap<String, String> hm3 = new HashMap<String, String>();
            hm3.put("令狐冲", "任盈盈");
            hm3.put("林平之", "岳灵珊");
            //把HashMap作为元素添加到ArrayList集合
            array.add(hm3);
    
            //遍历ArrayList集合
            for (HashMap<String, String> hm : array) {
                Set<String> keySet = hm.keySet();
                for (String key : keySet) {
                    String value = hm.get(key);
                    System.out.println(key + "," + value);
                }
            }
        }
    }

  • 案例需求

    • 创建一个HashMap集合,存储三个键值对元素,每一个键值对元素的键是String,值是ArrayList

    • 每一个ArrayList的元素是String,并遍历。

  • 代码实现

    public class HashMapIncludeArrayListDemo {
        public static void main(String[] args) {
            //创建HashMap集合
            HashMap<String, ArrayList<String>> hm = new HashMap<String, ArrayList<String>>();
    
            //创建ArrayList集合,并添加元素
            ArrayList<String> sgyy = new ArrayList<String>();
            sgyy.add("诸葛亮");
            sgyy.add("赵云");
            //把ArrayList作为元素添加到HashMap集合
            hm.put("三国演义",sgyy);
    
            ArrayList<String> xyj = new ArrayList<String>();
            xyj.add("唐僧");
            xyj.add("孙悟空");
            //把ArrayList作为元素添加到HashMap集合
            hm.put("西游记",xyj);
    
            ArrayList<String> shz = new ArrayList<String>();
            shz.add("武松");
            shz.add("鲁智深");
            //把ArrayList作为元素添加到HashMap集合
            hm.put("水浒传",shz);
    
            //遍历HashMap集合
            Set<String> keySet = hm.keySet();
            for(String key : keySet) {
                System.out.println(key);
                ArrayList<String> value = hm.get(key);
                for(String s : value) {
                    System.out.println("\t" + s);
                }
            }
        }
    }
  • 案例需求

    • 键盘录入一个字符串,要求统计字符串中每个字符串出现的次数。

    • 举例:键盘录入“aababcabcdabcde” 在控制台输出:“a(5)b(4)c(3)d(2)e(1)”

  • Collections类的作用

    是针对集合操作的工具类

  • Collections类常用方法

    方法名说明
    public static void sort(List<T> list)将指定的列表按升序排序
    public static void reverse(List<?> list)反转指定列表中元素的顺序
    public static void shuffle(List<?> list)使用默认的随机源随机排列指定的列表
  • 示例代码

    public class CollectionsDemo01 {
        public static void main(String[] args) {
            //创建集合对象
            List<Integer> list = new ArrayList<Integer>();
    
            //添加元素
            list.add(30);
            list.add(20);
            list.add(50);
            list.add(10);
            list.add(40);
    
            //public static <T extends Comparable<? super T>> void sort(List<T> list):将指定的列表按升序排序
    //        Collections.sort(list);
    
            //public static void reverse(List<?> list):反转指定列表中元素的顺序
    //        Collections.reverse(list);
    
            //public static void shuffle(List<?> list):使用默认的随机源随机排列指定的列表
            Collections.shuffle(list);
    
            System.out.println(list);
        }
    }

  • 案例需求

    • ArrayList存储学生对象,使用Collections对ArrayList进行排序

    • 要求:按照年龄从小到大排序,年龄相同时,按照姓名的字母顺序排序

  • 代码实现

    • 学生类

      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 class CollectionsDemo02 {
          public static void main(String[] args) {
              //创建ArrayList集合对象
              ArrayList<Student> array = new ArrayList<Student>();
      
              //创建学生对象
              Student s1 = new Student("linqingxia", 30);
              Student s2 = new Student("zhangmanyu", 35);
              Student s3 = new Student("wangzuxian", 33);
              Student s4 = new Student("liuyan", 33);
      
              //把学生添加到集合
              array.add(s1);
              array.add(s2);
              array.add(s3);
              array.add(s4);
      
              //使用Collections对ArrayList集合排序
              //sort(List<T> list, Comparator<? super T> c)
              Collections.sort(array, new Comparator<Student>() {
                  @Override
                  public int compare(Student s1, Student s2) {
                      //按照年龄从小到大排序,年龄相同时,按照姓名的字母顺序排序
                      int num = s1.getAge() - s2.getAge();
                      int num2 = num == 0 ? s1.getName().compareTo(s2.getName()) : num;
                      return num2;
                  }
              });
      
              //遍历集合
              for (Student s : array) {
                  System.out.println(s.getName() + "," + s.getAge());
              }
          }
      }

  • 案例需求

    通过程序实现斗地主过程中的洗牌,发牌和看牌

  • 代码实现

    public class PokerDemo {
        public static void main(String[] args) {
            //创建一个牌盒,也就是定义一个集合对象,用ArrayList集合实现
            ArrayList<String> array = new ArrayList<String>();
    
            //往牌盒里面装牌
            /*
                ♦2,♦3,♦4...♦K,♦A
                ♣2,...
                ♥2,...
                ♠2,...
                小王,大王
             */
            //定义花色数组
            String[] colors = {"♦", "♣", "♥", "♠"};
            //定义点数数组
            String[] numbers = {"2", "3", "4", "5", "6", "7", "8", "9", "10", "J", "Q", "K", "A"};
            for (String color : colors) {
                for (String number : numbers) {
                    array.add(color + number);
                }
            }
            array.add("小王");
            array.add("大王");
    
            //洗牌,也就是把牌打撒,用Collections的shuffle()方法实现
            Collections.shuffle(array);
    
    //        System.out.println(array);
    
            //发牌,也就是遍历集合,给三个玩家发牌
            ArrayList<String> lqxArray = new ArrayList<String>();
            ArrayList<String> lyArray = new ArrayList<String>();
            ArrayList<String> fqyArray = new ArrayList<String>();
            ArrayList<String> dpArray = new ArrayList<String>();
    
            for (int i = 0; i < array.size(); i++) {
                String poker = array.get(i);
                if (i >= array.size() - 3) {
                    dpArray.add(poker);
                } else if (i % 3 == 0) {
                    lqxArray.add(poker);
                } else if (i % 3 == 1) {
                    lyArray.add(poker);
                } else if (i % 3 == 2) {
                    fqyArray.add(poker);
                }
            }
    
            //看牌,也就是三个玩家分别遍历自己的牌
            lookPoker("林青霞", lqxArray);
            lookPoker("柳岩", lyArray);
            lookPoker("风清扬", fqyArray);
            lookPoker("底牌", dpArray);
        }
    
        //看牌的方法
        public static void lookPoker(String name, ArrayList<String> array) {
            System.out.print(name + "的牌是:");
            for (String poker : array) {
                System.out.print(poker + " ");
            }
            System.out.println();
        }
    }

  • 案例需求

    通过程序实现斗地主过程中的洗牌,发牌和看牌。要求:对牌进行排序

    代码实现

     
    public class PokerDemo {
        public static void main(String[] args) {
            //创建HashMap,键是编号,值是牌
            HashMap<Integer, String> hm = new HashMap<Integer, String>();
    
            //创建ArrayList,存储编号
            ArrayList<Integer> array = new ArrayList<Integer>();
    
            //创建花色数组和点数数组
            String[] colors = {"♦", "♣", "♥", "♠"};
            String[] numbers = {"3", "4", "5", "6", "7", "8", "9", "10", "J", "Q", "K", "A", "2"};
    
            //从0开始往HashMap里面存储编号,并存储对应的牌。同时往ArrayList里面存储编号
            int index = 0;
    
            for (String number : numbers) {
                for (String color : colors) {
                    hm.put(index, color + number);
                    array.add(index);
                    index++;
                }
            }
            hm.put(index, "小王");
            array.add(index);
            index++;
            hm.put(index, "大王");
            array.add(index);
    
            //洗牌(洗的是编号),用Collections的shuffle()方法实现
            Collections.shuffle(array);
    
            //发牌(发的也是编号,为了保证编号是排序的,创建TreeSet集合接收)
            TreeSet<Integer> lqxSet = new TreeSet<Integer>();
            TreeSet<Integer> lySet = new TreeSet<Integer>();
            TreeSet<Integer> fqySet = new TreeSet<Integer>();
            TreeSet<Integer> dpSet = new TreeSet<Integer>();
    
            for (int i = 0; i < array.size(); i++) {
                int x = array.get(i);
                if (i >= array.size() - 3) {
                    dpSet.add(x);
                } else if (i % 3 == 0) {
                    lqxSet.add(x);
                } else if (i % 3 == 1) {
                    lySet.add(x);
                } else if (i % 3 == 2) {
                    fqySet.add(x);
                }
            }
    
            //调用看牌方法
            lookPoker("林青霞", lqxSet, hm);
            lookPoker("柳岩", lySet, hm);
            lookPoker("风清扬", fqySet, hm);
            lookPoker("底牌", dpSet, hm);
        }
    
        //定义方法看牌(遍历TreeSet集合,获取编号,到HashMap集合找对应的牌)
        public static void lookPoker(String name, TreeSet<Integer> ts, HashMap<Integer, String> hm) {
            System.out.print(name + "的牌是:");
            for (Integer key : ts) {
                String poker = hm.get(key);
                System.out.print(poker + " ");
            }
            System.out.println();
        }
    }
    
    
    

    • 代码实现

      public class HashMapDemo {
          public static void main(String[] args) {
              //键盘录入一个字符串
              Scanner sc = new Scanner(System.in);
              System.out.println("请输入一个字符串:");
              String line = sc.nextLine();
      
              //创建HashMap集合,键是Character,值是Integer
      //        HashMap<Character, Integer> hm = new HashMap<Character, Integer>();
              TreeMap<Character, Integer> hm = new TreeMap<Character, Integer>();
      
              //遍历字符串,得到每一个字符
              for (int i = 0; i < line.length(); i++) {
                  char key = line.charAt(i);
      
                  //拿得到的每一个字符作为键到HashMap集合中去找对应的值,看其返回值
                  Integer value = hm.get(key);
      
                  if (value == null) {
                      //如果返回值是null:说明该字符在HashMap集合中不存在,就把该字符作为键,1作为值存储
                      hm.put(key,1);
                  } else {
                      //如果返回值不是null:说明该字符在HashMap集合中存在,把该值加1,然后重新存储该字符和对应的值
                      value++;
                      hm.put(key,value);
                  }
              }
      
              //遍历HashMap集合,得到键和值,按照要求进行拼接
              StringBuilder sb = new StringBuilder();
      
              Set<Character> keySet = hm.keySet();
              for(Character key : keySet) {
                  Integer value = hm.get(key);
                  sb.append(key).append("(").append(value).append(")");
              }
      
              String result = sb.toString();
      
              //输出结果
              System.out.println(result);
          }
      }

  • 20
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

ubanXia

您的鼓励是我最大的创作动力!

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值