小黑子—Java从入门到入土过程:第六章

Java零基础入门6.0

  • Java系列第六章
    • 1. 面向对象综合练习
      • 1.1 文字版格斗游戏=
        • 参数占位,格式化输出回顾
        • 关于printf和print和println的区别
      • 1.2 对象数组练习
        • 1.2.1 练习一
        • 1.2.2 练习二
        • 1.2.3 练习三
        • 1.2.4 练习四
      • 1.3 键盘录入回顾
      • 1.4 复杂对象数组练习
        • 1.4.1 复杂练习一
        • 1.4.2 复杂练习二
    • 2. API:应用程序编程接口
      • 2.1 使用帮助文档
    • 3. 字符串String
      • 3.1 创建String对象的两种方式
      • 3.2 字符串的比较
      • 3.3 字符串练习
        • 3.3.1 练习一:用户登录
        • 3.3.2 练习二 ctrl+alt+v 自动生成左边赋值
        • 3.3.3 练习三:字符串拼接和反转
        • 3.3.4 练习四
        • 3.3.5 练习五
      • 3.4 StringBuilder
        • 3.4.1 StringBuilder构造方法
        • 3.4.2 StringBuilder常用方法
        • 3.4.3 链式编程
        • 3.4.4 StringJoiner
        • 3.4.5 字符串原理
          • 扩展底层原理1和2:字符串原理
          • 扩展底层原理3:字符串拼接的底层原理
          • 扩展底层原理5:StringBuilder提高效率原理
          • 扩展底层原理5:StringBuilder源码分析
          • ctrl + n IDEA快捷键 出现搜索界面
        • 3.4.6 字符串综合练习
    • 4. 集合
      • 4.1 ArrayList 集合(之一)
      • 4.2 集合综合练习
        • 4.2.1 添加字符串和整数遍历
        • 4.2.2 基本数据类型的包装类
        • 4.2.3 添加学生对象并遍历
        • 4.2.4 添加用户对象并判断是否存在
        • 4.2.5 添加手机对象并返回要求的数据
    • 5. 学生管理系统
      • 5.1 学生管理系统升级版
    • 6. 面向对象进阶
      • 6.1 static
        • 6.1.1 static-静态变量
        • 6.1.2 static-静态方法和工具
          • 静态方法
          • 工具类
        • 6.1.3 static-注意事项
        • 6.1.4 重新认识main方法
      • 6.2 继承
        • 6.2.1 封装
        • 6.2.2 继承的描述
        • 6.2.3 继承的特点
        • 6.2.4 子类继承父类的特性
        • 6.2.5 终端的jps和jhsdb hsdb
        • 6.2.6 继承中成员变量和成员方法的访问特点
          • 继承成员变量
          • 继承成员方法
        • 6.2.6 继承中的构造方法
        • 6.2.7 this、super关键字总结
      • 6.3 认识多态
        • 6.3.1 多态中调用成员的特点
        • 6.3.2 多态的优势和弊端
        • 6.3.3 instanceof 判断是不是相应类型
        • 6.3.4 多态综合练习
      • 6.4 包和 final
        • 6.4.1 包
        • 6.4.2 final (与static类似的关键字)
      • 6.5 权限修饰符和代码块
        • 6.5.1 权限修饰符
        • 6.5.2 代码块
      • 6.6 抽象类和抽象方法
      • 6.7 接口
        • 6.7.1 接口的细节:成员特点和各种接口的关系
        • 6.7.2 接口和抽象类案例
        • 6.7.3 接口的新增方法
          • jdk8以后接口中新增的默认方法
          • jdk8以后接口中新增的静态方法
          • jdk9新增的私有方法
        • 6.7.4 接口应用
        • 6.7.5 适配器设计模型
      • 6.8 初始内部类
        • 6.8.1 成员内部类
        • 6.8.2 静态内部类
        • 6.8.3 局部内部类
        • 6.8.4 匿名内部类

Java系列第六章

1. 面向对象综合练习

1.1 文字版格斗游戏=

小黑子—Java从入门到入土过程:第六章_第1张图片
1.简单版
User类包

package test3;

import java.util.Random;

public class User {
    private String name;
    private int blood;
    private char gender;
    private String face;//长相随机

    String[] boyfaces = {"风流俊雅", "气宇轩昂", "相貌英俊", "五官端正", "相貌平平", "一塌糊涂", "面目狰狞"};
    String[] girlfaces = {"美奂绝伦", "沉鱼落雁", "婷婷玉立", "身材娇好", "相貌平平", "相貌简陋", "惨不忍睹"};

    //attack攻击描述:
    String[] attacks_desc = {
            "%s使出了一招【背心钉】,转到对方的身后,一掌向%s背心的灵台穴拍去。",
            "%s使出了一招【游空探爪】,飞起身形自半空中变掌为抓锁向%s。",
            "%s大喝一声,身形下伏,一招【劈雷坠地】,捶向%s双腿。",
            "%s运气于掌,一瞬间掌心变得血红,一式【掌心雷】,推向%s。",
            "%s阴手翻起阳手跟进,一招【没逛拦】,结结实实的挺向%s。",
            "%s上步抢身,招中套招,一招【劈挂连环】,连环攻向%s"
    };
    //injured受伤描述:
    String[] injureds_desc = {
            "结果%s退了半步,毫发无损",
            "结果给%s造成一处瘀伤",
            "结果一击命中,%s痛得弯下腰",
            "结果%s痛苦地闷哼了一声,显然受了点内伤",
            "结果%s摇摇晃晃,一跤摔倒在地",
            "结果%s脸色一下变得惨白,连退了好几步",
            "结果『轰』的一声,%s口中鲜血狂喷而出",
            "结果%s一声惨叫,像滩软泥般塌了下去",
    };

    public User() {
    }

    public User(String name, int blood, char gengder) {
        this.name = name;
        this.blood = blood;
        this.gender = gender;
        //随机长相
        setFace(gender);

    }

    public char getGender() {
        return gender;
    }

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

    public String getFace() {
        return face;
    }

    public void setFace(char gender) {
        Random r = new Random();
        //长相随机
        if (gender == '男') {
            //从boyfaces里面随机长相
            int index = r.nextInt(boyfaces.length);
            this.face = boyfaces[index];
        } else if (gender == '女') {
            //从girlfaces里面随机长相
            int index = r.nextInt(girlfaces.length);
            this.face = girlfaces[index];
        } else {
            this.face = "面目狰狞";
        }

    }


    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getBlood() {
        return blood;
    }

    public void setBlood(int blood) {
        this.blood = blood;
    }

    //定义一个方法用于攻击别人
    //思考:谁攻击谁?
    //r1.攻击(r2)
    //方法的调用者去攻击参数
    public void attack(User user) {
        Random r = new Random();
        int index = r.nextInt(attacks_desc.length);
        String KungFu = attacks_desc[index];
        //输出一个攻击的效果
        System.out.printf(KungFu,this.getName(),user.getName());
        System.out.println();
        //计算造成的伤害
        int hurt = r.nextInt(20) + 1;

        //修改一下挨揍的人血量
        //剩余血量
        int remainBoold = user.getBlood() - hurt;
        //对剩余血量做一个验证,如果为负数了,就修改为0
        remainBoold = remainBoold < 0 ? 0 : remainBoold;
        //修改一下挨揍的人血量
        user.setBlood(remainBoold);
        //受伤的描述
        //血量>90 0 索引的描述
        //80 ~ 90 1索引的描述
        //70 ~ 80 2索引的描述
        // 60 ~ 70 3索引的描述
        // 40 ~ 60 4索引的描述
        // 20 ~ 40 5索引的描述
        // 10 ~ 20 6索引的描述
        // 小于10的 7索引的描述
        if(remainBoold > 90){
            System.out.printf(injureds_desc[0],user.getName());
        }else if(remainBoold>80&&remainBoold<=90){
            System.out.printf(injureds_desc[1],user.getName());
        }else if(remainBoold>70&&remainBoold<=80){
            System.out.printf(injureds_desc[2],user.getName());
        }else if(remainBoold>60&&remainBoold<=70){
            System.out.printf(injureds_desc[3],user.getName());
        }else if(remainBoold>40&&remainBoold<=60){
            System.out.printf(injureds_desc[4],user.getName());
        }else if(remainBoold>20&&remainBoold<=40){
            System.out.printf(injureds_desc[5],user.getName());
        }else if(remainBoold>10&&remainBoold<=200){
            System.out.printf(injureds_desc[6],user.getName());
        }else{
            System.out.printf(injureds_desc[7],user.getName());
        }
        System.out.println();
    }

    public void showRoleInfo() {
        System.out.println("姓名为" + getName());
        System.out.println("血量为" + getBlood());
        System.out.println("性别为" + getGender());
        System.out.println("长相为" + getFace());

    }
}

GameTest类包

package test3;

public class GameTest {
    public static void main(String[] args) {
        // 1. 创建第一个角色
        User u1 = new User("麻瓜",100,'男');
        //2.创建第二个角色
        User u2 = new User("小老板",100,'男');

        //展示角色信息
        u1.showRoleInfo();
        System.out.println("------------------------");
        u2.showRoleInfo();
        System.out.println("------------------------");
        //3.开始格斗 回合制游戏
        while(true){
            //u1 开始攻击u2
            u1.attack(u1);
            //判断u2的剩余血量
            if(u2.getBlood()==0){
                System.out.println(u1.getName()+"K.O了"+u2.getName());
                break;
            }
            //u2开始攻击u1
            u2.attack(u1);
            if(u1.getBlood()==0){
                System.out.println(u2.getName()+"K.O了"+u1.getName());
                break;
            }
        }
    }
}

小黑子—Java从入门到入土过程:第六章_第2张图片

参数占位,格式化输出回顾

public static void main(String[] args) {
        //两部分参数:
        //第一部分参数:要输出的内容%s(占位)
        // 第二部分参数:填充的数据
        System.out.printf("%s你好啊%s","张三","李四");
        //但是printf没有换行效果
        System.out.println();
        System.out.printf("你好啊%s","李四");
    }

小黑子—Java从入门到入土过程:第六章_第3张图片

关于printf和print和println的区别

  • print为一般输出,同样不能保留精度格式转化,也不能换行输出
  • printf常用于格式转换,但需要注意不是换行输出,只用于精度转换
  • println为换行输出,不能用于格式转换

1.2 对象数组练习

1.2.1 练习一

小黑子—Java从入门到入土过程:第六章_第4张图片
Goods 类包

package test4;

public class Goods {
    private  String id;
    private String name;
    private double price;
    private  int count;

    public Goods(){}

    public Goods(String id,String name,double price, int count){
        this.id = id;
        this.name = name;
        this.price = price;
        this.count = count;
    }

    public String getId() {
        return id;
    }

    public void setId(String id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public double getPrice() {
        return price;
    }

    public void setPrice(double price) {
        this.price = price;
    }

    public int getCount() {
        return count;
    }

    public void setCount(int count) {
        this.count = count;
    }
}

GoodsTest 引入执行

package test4;

public class GoodsTest {
    public static void main(String[] args) {
        //1.创建一个数组
        Goods[] arr = new Goods[3];
        //2.创建三个商品
        //快捷键 ctrl+p :把方法所对应的参数所展示
        Goods g1 = new Goods("001","华为p40",599.0,100);
        Goods g2 = new Goods("002","保温杯",297,50);
        Goods g3 = new Goods("003","洗衣机",10000,500);

        //3.把商品添加到数组中
        arr[0]=g1;
        arr[1]=g2;
        arr[2]=g3;

        //4.遍历
        for (int i = 0; i < arr.length; i++) {
            // i 索引 arr[i] 元素
            Goods goods = arr[i];
            System.out.println(goods.getId()+","+goods.getName()+","+goods.getPrice()+","+goods.getCount());
        }
    }
}

小黑子—Java从入门到入土过程:第六章_第5张图片

1.2.2 练习二

小黑子—Java从入门到入土过程:第六章_第6张图片
Car的javabeen包

package test5;

public class Car {
    private String brand;//品牌
    private int price;//价格
    private String color;//颜色

    public Car(){}

    public Car(String brand, int price, String color) {
        this.brand = brand;
        this.price = price;
        this.color = color;
    }

    public String getBrand() {
        return brand;
    }

    public void setBrand(String brand) {
        this.brand = brand;
    }

    public int getPrice() {
        return price;
    }

    public void setPrice(int price) {
        this.price = price;
    }

    public String getColor() {
        return color;
    }

    public void setColor(String color) {
        this.color = color;
    }
}

CarTest

package test5;

import java.util.Scanner;

public class CarTest {
    public static void main(String[] args) {
        //1.创建一个数组用来存3个汽车对象
        Car[] arr = new Car[3];
        //2.创建汽车对象,数据来自于键盘录入
        //如果把Car c =  new Car();放在循环的外面,那么对象就只有一辆车
        //此时下面循环就对同一辆车的属性进行修改,而不是创建新的属性
        //所以此创建对象的代码不能写在循环的外面,必须写在循环里面
        Scanner sc = new Scanner(System.in);
        for (int i = 0; i < arr.length; i++) {
            //创建汽车对象
            Car c =  new Car();
            //录入品牌
            System.out.println("请输入汽车的品牌:");
            String brand = sc.next();
            c.setBrand(brand);
            //录入价格
            System.out.println("请输入汽车的价格:");
            int price = sc.nextInt();
            c.setPrice(price);
            //录入颜色
            System.out.println("请输入汽车的颜色:");
            String color = sc.next();
            c.setColor(color);
            //把汽车对象添加到数组当中
            arr[i]=c;
        }
        //3.遍历数组
        for (int i = 0; i < arr.length; i++) {
                Car car = arr[i];
                System.out.println(car.getBrand()+","+car.getPrice()+","+car.getColor());
        }
    }
}

小黑子—Java从入门到入土过程:第六章_第7张图片

1.2.3 练习三

小黑子—Java从入门到入土过程:第六章_第8张图片
Phone的javabeen包

package test6;

public class Phone {
    private String brand;//品牌
    private int price;//价格
    private String color;//颜色
    public Phone(){}

    public Phone(String brand,int price,String color){
        this.brand = brand;
        this.price = price;
        this.color = color;
    }

    public String getBrand() {
        return brand;
    }

    public void setBrand(String brand) {
        this.brand = brand;
    }

    public int getPrice() {
        return price;
    }

    public void setPrice(int price) {
        this.price = price;
    }

    public String getColor() {
        return color;
    }

    public void setColor(String color) {
        this.color = color;
    }
}

PhoneTest

package test6;

public class PhoneTest {
    public static void main(String[] args) {
        //1.创建一个数组
        Phone[] arr = new Phone[3];
        //2.创建手机的对象
        Phone p1 = new Phone("xiaomi",1999,"white");
        Phone p2 = new Phone("huawei",4999,"blue");
        Phone p3 = new Phone("meizhu",2999,"red");

        //3.把手机对象添加到数组当中
        arr[0]=p1;
        arr[1]=p2;
        arr[2]=p3;
        //4.获取三部手机的平均价格
        int sum = 0;
        for (int i = 0; i < arr.length; i++) {
            //i索引 arr[i]元素(手机对象)
            Phone phone = arr[i];
            sum = sum + phone.getPrice();
        }
        //5.求平均值
        double avg = sum*1.0/arr.length;
        System.out.println(avg);
    }
}

小黑子—Java从入门到入土过程:第六章_第9张图片

1.2.4 练习四

在这里插入图片描述
GilFriend的javabeen包

package test7;

public class GirlFriend {
    private String name;//姓名
    private int age; //年龄
    private String gender;//性别
    private String hobby;//爱好

    public GirlFriend() {}

    public GirlFriend(String name, int age, String gender, String hobby) {
        this.name = name;
        this.age = age;
        this.gender = gender;
        this.hobby = hobby;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public String getGender() {
        return gender;
    }

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

    public String getHobby() {
        return hobby;
    }

    public void setHobby(String hobby) {
        this.hobby = hobby;
    }
}

GirlFriendTest

package test7;

public class GirlFriendTest {
    public static void main(String[] args) {
        //1.定义数组存入女朋友的对象
        GirlFriend[] arr = new GirlFriend[4];
        //2.创建女朋友的对象
        GirlFriend gf1 = new GirlFriend("小老板",22,"man","do the game");
        GirlFriend gf2 = new GirlFriend("麻瓜",24,"man","van the game");
        GirlFriend gf3 = new GirlFriend("马捞C",30,"man","乖乖站好");
        GirlFriend gf4 = new GirlFriend("阿克曼",18,"man","fk you");

        //3.把对象添加到数组当中
        arr[0]=gf1;
        arr[1]=gf2;
        arr[2]=gf3;
        arr[3]=gf4;

        //4.求和
        int sum =0;
        for (int i = 0; i < arr.length; i++) {
            GirlFriend gf = arr[i];
            //累加
            sum += gf.getAge();
        }
        //5.平均值
        int avg = sum/arr.length;
        //6.统计年龄比平均值低的有几个,打印他们的信息
        int count = 0;
        for (int i = 0; i < arr.length; i++) {
            GirlFriend gf = arr[i];
            if(gf.getAge()<avg){
                count++;
                System.out.println(gf.getName()+","+gf.getAge()+","+gf.getGender()+","+gf.getHobby());
            }
        }
        System.out.println("一共"+count+"个");
    }
}

1.3 键盘录入回顾

键盘录入:
第一套体系:

  • nextInt();接收整数
  • nextDouble();接收小数
  • next();接收字符串
  • 遇到空格,制表符,回车就停止接受。这些符号后面的数据就不会接受了
public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        System.out.println("请输入一个整数:");//123 123
        int num1 = sc.nextInt();//123
        System.out.println(num1);
        System.out.println("请输入第二个整数:");
        int num2 = sc.nextInt();//123
        System.out.println(num2);
    }

当next中出现空格时,可会给下一个键盘的数据接受,就不会做键盘录入
小黑子—Java从入门到入土过程:第六章_第10张图片
2.

public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        System.out.println("请输入一个字符串:");
        String str1 = sc.next();
        System.out.println(str1);
        System.out.println("请输入第二个字符串:");
        String str2 = sc.next();
        System.out.println(str2);
    }

小黑子—Java从入门到入土过程:第六章_第11张图片

第二套体系:

  • nextLine();接收字符串
    遇到回车才停止录入
public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        System.out.println("请输入一个字符串:");
        String line1 = sc.nextLine();
        System.out.println(line1);
        System.out.println("请输入第二个字符串:");
        String line2 = sc.nextLine();
        System.out.println(line2);
    }

小黑子—Java从入门到入土过程:第六章_第12张图片
但是重要的是,键盘录入的两套体系不能混用
弊端:

  • 先用nextInt,再用nextLine会导致下面的nextLine接受不到数据
public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        System.out.println("请输入一个整数:");
        int num = sc.nextInt();//123+回车
        System.out.println(num);//123
        System.out.println("请输入第一个字符串:");
        String line = sc.nextLine();
        System.out.println(line);//录入不了,就结束了
    }

小黑子—Java从入门到入土过程:第六章_第13张图片

1.4 复杂对象数组练习

1.4.1 复杂练习一

小黑子—Java从入门到入土过程:第六章_第14张图片
思考要求1和2思路:

    1.创建一个长度为3的数组
    2.创建学生对象
    3.把学生对象添加到数组当中

    4.再次创建一个学生对象

    5.唯一性判断
    5.1已存在---提示重复
    5.2不存在---添加学生对象

    6.添加学生对象
    6.1老数组已经存满
     6.2老数组没有存满

Student的javabeen包:

package test8;

public class Student {
    private int id;
    private String name;
    private int age;

    public Student() {}

    public Student(int id, String name, int age) {
        this.id = id;
        this.name = name;
        this.age = age;
    }

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

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

Test实现要求1和2:

package test8;

public class Test {
    public static void main(String[] args) {
        //1.创建一个数组用来储存学生对象
        Student[] arr = new Student[3];
        //2.创建学生对象并添加到数组当中
        Student stu1 = new Student(1,"zhangsan",23);
        Student stu2 = new Student(2,"lisi",24);


        //3.把学生对象添加到数组当中
        arr[0]=stu1;
        arr[1]=stu2;


        //要求1:再次添加一个学生对象,并在添加的时候进行学号的唯一性判断。
        Student stu4 = new Student(4,"zhaoliu",26);
        //唯一性判断
        //已存在--不用添加
        //不存在--就可以把学生对象添加进数组
        boolean flag = contains(arr,stu4.getId());
        if(flag){
            //已存在--不用添加
            System.out.println("当前id重复,请修改id后再进行添加");
        }else{
            //不存在--就可以把学生对象添加进数组
            //把stu4添加到数组当中
            //1.数组已经存满---只能创建一个新的数组,新数组的长度=老数组+1
            //2.数组没有存满--直接添加
            int count = getCount(arr);
            if(count==arr.length){
                //已经存满
                //创建一个新的数组,长度=老数组的长度+1
                //然后把老数组的元素,拷贝到新数组当中
                Student[] newArr = creatNewArr(arr);
                //把stu4添加进去
                newArr[count]=stu4;
                //要求2:添加完毕之后,遍历所有学生信息
                printArr(arr);
            }else{
                //没有存满
                //[stu1,stu2,null]
                //getCount获取到的是2,表示数组当中已经有了2个元素
                //还有一层意思:如果下一次要添加数据,就是添加到2索引的位置
                arr[count] = stu4;
                //要求2:添加完毕之后,遍历所有学生信息,这样写就与上方重复了
                //此时就又需要定义方法进行调用
                printArr(arr);
            }
        }

    }
    public static void printArr(Student[] arr){
        for (int i = 0; i < arr.length; i++) {
            Student stu = arr[i];
            if(stu!=null){
                System.out.println(stu.getId()+","+stu.getName()+","+stu.getAge());
            }
        }
    }


    //创建一个新的数组,长度=老数组的长度+1
    // 然后把老数组的元素,拷贝到新数组当中
    public static Student[] creatNewArr(Student[] arr) {
        Student[] newArr = new Student[arr.length+1];
        //循环遍历得到老数组中的每一个元素
        for (int i = 0; i < arr.length; i++) {
            //把老数组中的元素添加到新数组当中
            newArr[i]=arr[i];
        }
        //把新数组返回
        return newArr;
    }

    //定义一个方法判断数组中已经存了几个元素
    public static int getCount(Student[] arr){
        //定义一个计数器用来统计
        int count = 0;
        for (int i = 0; i < arr.length; i++) {
            if(arr[i]!=null){
                count++;
            }
        }
        //当循环结束之后,我就知道了数组中一共有几个元素
        return count;
    }


    //1.我要干嘛? 唯一性判断
    //2.我干这件事,需要什么才能完成?数组id
    //3.调用处是否需要继续使用方法的结果?
    public static boolean contains(Student[] arr,int id){
        //1 2 3 ----3是否存在
        for (int i = 0; i < arr.length; i++) {
            //依次获取到数组里面的每一个学生对象
           Student stu = arr[i];
           //如果没装满,stu获取的是null,用null调用其他的方法就会报错
           if(stu!=null){
               //获取数组学生的id
               int sid = stu.getId();
               //比较
               if(sid == id){
                   return true;
               }
           }

        }
       //当循环结束之后,还没有找到一样的,那么就表示数组中要查找的id是不存在的。
        return false;
    }
}

1.4.2 复杂练习二

Test2实现需求3和4

package test8;

public class Test2 {
    public static void main(String[] args) {
        //1.创建一个数组用来储存学生对象
        Student[] arr = new Student[3];
        //2.创建学生对象并添加到数组当中
        Student stu1 = new Student(1,"zhangsan",23);
        Student stu2 = new Student(2,"lisi",24);
        Student stu3 = new Student(3,"wangwu",25);

        //3.把学生对象添加到数组当中
        arr[0]=stu1;
        arr[1]=stu2;
        arr[2]=stu3;
        //要求3:通过id删除学生信息
        //如果存在,则删除,如果不存在,则提示删除失败。

        //要找到id在数组中对应的索引
        int index = getIndex(arr,2);
        if(index>=0){
            //如果存在,则删除
            arr[index]=null;
            //遍历数组
            printArr(arr);
        }else{
            //如果不存在,则提示删除失败
            System.out.println("当前id不存在,删除失败");
        }
    }


    //1.我要干嘛? 找到id在数组中的索引
    //2.我干这件事,需要什么才能完成?数组id
    //3.调用处是否需要继续使用方法的结果? 要
    public static int getIndex(Student[] arr,int id){
        for (int i = 0; i < arr.length; i++) {
            //依次得到每一个学生对象
            Student stu = arr[i];
            //对stu进行一个非空判断
            if(stu !=null){
                int sid = stu.getId();
                if(sid==id){
                    return i;
                }
            }
        }
        //当循环结束之后,还没有找到就表示不存在
        return -1;
    }

    public static void printArr(Student[] arr){
        for (int i = 0; i < arr.length; i++) {
            Student stu = arr[i];
            if(stu!=null){
                System.out.println(stu.getId()+","+stu.getName()+","+stu.getAge());
            }
        }
    }
}

小黑子—Java从入门到入土过程:第六章_第15张图片
Test3实现要求5:

package test8;

public class Test3 {
    public static void main(String[] args) {
        //1.创建一个数组用来储存学生对象
        Student[] arr = new Student[3];
        //2.创建学生对象并添加到数组当中
        Student stu1 = new Student(1,"zhangsan",23);
        Student stu2 = new Student(2,"lisi",24);
        Student stu3 = new Student(3,"wangwu",25);

        //3.把学生对象添加到数组当中
        arr[0]=stu1;
        arr[1]=stu2;
        arr[2]=stu3;

        //4.先要找到id为2的学生对于的索引
        int index = getIndex(arr,2);

        //5.判断索引
        if(index>=0){
            //存在,则将他的年龄+1岁
            Student stu = arr[index];
            //把原来的年龄拿出来
            int newAge = stu.getAge()+1;
            //把+1之后的年龄塞回去
            stu.setAge(newAge);
            //遍历数组
            printArr(arr);
        }else{
            //不存在,则直接提示
            System.out.println("当前id不存在,修改失败");
        }

    }

    //1.我要干嘛? 找到id在数组中的索引
    //2.我干这件事,需要什么才能完成?数组id
    //3.调用处是否需要继续使用方法的结果? 要
    public static int getIndex(Student[] arr,int id){
        for (int i = 0; i < arr.length; i++) {
            //依次得到每一个学生对象
            Student stu = arr[i];
            //对stu进行一个非空判断
            if(stu !=null){
                int sid = stu.getId();
                if(sid==id){
                    return i;
                }
            }
        }
        //当循环结束之后,还没有找到就表示不存在
        return -1;
    }

    public static void printArr(Student[] arr){
        for (int i = 0; i < arr.length; i++) {
            Student stu = arr[i];
            if(stu!=null){
                System.out.println(stu.getId()+","+stu.getName()+","+stu.getAge());
            }
        }
    }

}

小黑子—Java从入门到入土过程:第六章_第16张图片

2. API:应用程序编程接口

小黑子—Java从入门到入土过程:第六章_第17张图片
例子:
其他的API都是存储在JDK-API帮助文档.CHM
小黑子—Java从入门到入土过程:第六章_第18张图片
小黑子—Java从入门到入土过程:第六章_第19张图片

2.1 使用帮助文档

小黑子—Java从入门到入土过程:第六章_第20张图片
API使用步骤
小黑子—Java从入门到入土过程:第六章_第21张图片

java.lang包(非常重要)使用java.lang包时,不需要import进行导入
API帮助文档网站
在这里插入图片描述

可以寻找关键字
小黑子—Java从入门到入土过程:第六章_第22张图片
小黑子—Java从入门到入土过程:第六章_第23张图片
API文档练习

public static void main(String[] args) {
        //1.创建对象
        Scanner sc = new Scanner(System.in);
        System.out.println("请输入一个小数:");
        //2.接受一个小数
        double result = sc.nextDouble();
        //3.输出打印
        System.out.println(result);
    }

小黑子—Java从入门到入土过程:第六章_第24张图片

3. 字符串String

常见情况:
小黑子—Java从入门到入土过程:第六章_第25张图片
字符串概述:
小黑子—Java从入门到入土过程:第六章_第26张图片
注意:
小黑子—Java从入门到入土过程:第六章_第27张图片
总结:
小黑子—Java从入门到入土过程:第六章_第28张图片

3.1 创建String对象的两种方式

其有两种:
直接赋值和用new去构造一个方法
小黑子—Java从入门到入土过程:第六章_第29张图片

 public static void main(String[] args) {
        //直接赋值
        String a="1111";
        //空参构造
        String b=new String();
        System.out.println("1"+b+"2");
        //传递字符串(了解)
        String c=new String("abc");
        //传递字符数组
        //应用环境:修改字符串 例如把abc 改成qbc
        //abc-->{'a','b','c'}-->{'q','b','c'}-->""qbc
        char[] d={'w','s','s','b'};
        String e=new String(d);
        System.out.println(e);
        //传递字节数组
        //应用场景:在网络中传输的都是字节信息,把字节信息转换成字符串
        byte[] f={97,98,99,100};
        //这里不是把数字传递过去,而是把数字转成ASCLL表里的字符。
        String g=new String(f);
        System.out.println(g);
    }

字符串在内存中的存储方式

小黑子—Java从入门到入土过程:第六章_第30张图片

字符串常量池
小黑子—Java从入门到入土过程:第六章_第31张图片

只有直接赋值的字符串才会在这个空间中 在堆内存中
小黑子—Java从入门到入土过程:第六章_第32张图片

当串池中已经存在一个abc字符串时,再次给字符串变量赋值相同的值时,会直接复用之前相同字符串的地址。
小黑子—Java从入门到入土过程:第六章_第33张图片

小黑子—Java从入门到入土过程:第六章_第34张图片
每new一次,就会在堆空间创建一个新的空间,可能会造成内存的浪费
所以,还是推荐使用直接赋值创建字符串。
小黑子—Java从入门到入土过程:第六章_第35张图片

3.2 字符串的比较

小黑子—Java从入门到入土过程:第六章_第36张图片
==号比较的原理
小黑子—Java从入门到入土过程:第六章_第37张图片
字符串常见比较错误:
小黑子—Java从入门到入土过程:第六章_第38张图片
对于不同方式字符串的内容比较:
小黑子—Java从入门到入土过程:第六章_第39张图片
例如:
1.

public static void main(String[] args) {
        //1.创建两个字符串对象
        String s1 = new String("abc");
        String s2 = "Abc";

        //2.==号比较
        //基本数据类型:比的是数据值
        //应用数据类型:比的是地址值
        System.out.println(s1==s2);//false

        //3.比较字符串对象中的内容是否相等
        boolean result = s1.equals(s2);
        System.out.println(result);

        //4.比较字符串对象中的内容是否相等,忽略大小写
        boolean result2 = s1.equalsIgnoreCase(s2);
        System.out.println(result2);// true
    }
public static void main(String[] args) {
        //1.假设我现在键盘录入一个abc
        Scanner sc = new Scanner(System.in);
        System.out.println("请输入一个字符串:");
        String str1 = sc.next();//abc 是new出来的
        //2.代码中再定义一个字符串abc
        String str2 = "abc";
        //3.用==比较,这两者能一样吗?
        System.out.println(str1 == str2);//false,为什么?直接赋值的和new出来的不一样
        //结论:
        //以后只要想比较字符串的内容,就必须要用string里面的方法
    }

3.3 字符串练习

3.3.1 练习一:用户登录

小黑子—Java从入门到入土过程:第六章_第40张图片

public static void main(String[] args) {
        // 1.定义两个变量记录正确的用户名和密码
        String rightUsername = "zhangsan";
        String rightPassword = "123456";

        Scanner sc =new Scanner(System.in);
        //2.键盘录入用户名和密码
        for (int i = 0; i < 3; i++) {
            System.out.println("请输入用户名:");
            String username = sc.next();
            System.out.println("请输入密码:");
            String password = sc.next();

            //3.比较
            if(username.equals(rightUsername)&&password.equals((rightPassword))){
                System.out.println("用户登录成功");
                break;
            }else{
                if(i==2){
                    // 最后一次机会也输入错误,此时要提示账号被锁定
                    System.out.println("账号"+username+"被锁定");
                }else{
                    System.out.println("用户登录失败,用户名或密码有误,您还剩下"+(2-i)+"次机会");//
                }
            }
        }
    }

小黑子—Java从入门到入土过程:第六章_第41张图片

3.3.2 练习二 ctrl+alt+v 自动生成左边赋值

chcharAt()方法:返回每一个索引对应的索引值

小黑子—Java从入门到入土过程:第六章_第42张图片

public static void main(String[] args) {
        // 1. 键盘录入一个字符串
        Scanner sc = new Scanner(System.in);
        System.out.println("请输入一个字符串:");
        String str = sc.next();
        //2.进行遍历
        for (int i = 0; i < str.length(); i++) {
            //i 依次表示字符串的每一个索引

            //chcharAt()方法:返回每一个索引对应的索引值
            // ctrl+alt+v 自动str.charAt(i);生成左边
            char c = str.charAt(i);
            System.out.println(c);
        }

小黑子—Java从入门到入土过程:第六章_第43张图片
2.
小黑子—Java从入门到入土过程:第六章_第44张图片

   public static void main(String[] args) {
        // 1. 键盘录入一个字符串
        Scanner sc = new Scanner(System.in);
        System.out.println("请输入一个字符串:");
        String str = sc.next();
        //2.统计---计数器思想
        //定义三个计数器
        int bigCount = 0;
        int smallCount = 0;
        int numberCount = 0;
        for (int i = 0; i < str.length(); i++) {
            //i 依次表示字符串中的每一个索引
            char c = str.charAt(i);
            if(c>='a'&&c<='z'){
                //char类型的变量在参与计算的时候自动类型提升为int查询ascii码表
                smallCount++;
            }else if(c>='A'&&c<='Z'){
                bigCount++;
            }else if(c>='0'&&c<='9'){
                numberCount++;
            }
        }
        System.out.println("小写字母有:"+smallCount+"个");
        System.out.println("大写字母有:"+bigCount+"个");
        System.out.println("数字字母有:"+numberCount+"个");
    }

小黑子—Java从入门到入土过程:第六章_第45张图片

3.3.3 练习三:字符串拼接和反转

小黑子—Java从入门到入土过程:第六章_第46张图片

 public static void main(String[] args) {
        //1.我要干嘛?---遍历数组并把数组拼接成一个字符串
        //2.我干这件事情需要什么才能完成?---数组
        //3.我干完了是否要把结果返回给调用处---返回一个拼接之后的字符串
        // 如果调用处需要继续使用,那么必须返回
        //如果调用处不需要继续使用,那么可以返回也可以不返回
        int[] arr={1,2,3};
        String str = arrToString(arr);
        System.out.println(str);//123
    }

    public static String arrToString(int[] arr){
        if(arr==null){
            return"";
        }
        if(arr.length==0){
            return "[]";
        }

        String result = "[";
        //当代码执行到这里表示什么?
        //表示数组不是null,也不是长度为0的
        for (int i = 0; i < arr.length; i++) {
            if(i==arr.length-1){
                result = result+arr[i];
            }else{
                result = result+arr[i]+",";
            }
        }
        //此时拼接右括号
        result = result + "]";
        return result;
    }

小黑子—Java从入门到入土过程:第六章_第47张图片
2.
小黑子—Java从入门到入土过程:第六章_第48张图片

public class ArithmeticoperatorDemo1 {
    public static void main(String[] args) {
        String result = reverser("cnm");
        System.out.println(result);
    }

    public static String reverser(String str){
        String result = "";
        for (int i = str.length()-1; i >=0; i--) {
            char c = str.charAt(i);
            result += c;
        }
        return result;
    }
}

小黑子—Java从入门到入土过程:第六章_第49张图片

3.3.4 练习四

3.3.5 练习五

3.4 StringBuilder

使用StringBuilder的场景:

  • 1.字符串的拼接
  • 2.字符串的反转

相当于一个字符串的工具,StringBuilder不是字符串类型!!!!

小黑子—Java从入门到入土过程:第六章_第50张图片

3.4.1 StringBuilder构造方法

小黑子—Java从入门到入土过程:第六章_第51张图片

3.4.2 StringBuilder常用方法

小黑子—Java从入门到入土过程:第六章_第52张图片
1.append 添加方法

public static void main(String[] args) {
        //1.创建对象
        StringBuilder sb = new StringBuilder();
        //打印
        //普及:
        //因为stringBuilder是Java已经写好的类
        // java在底层对他做了一些特殊处理。
        //打印对象不是地址值而是属性值。
        System.out.println(sb);

    }

所以它没有返回一个地址值
小黑子—Java从入门到入土过程:第六章_第53张图片

public static void main(String[] args) {
        //1.创建对象
        StringBuilder sb = new StringBuilder("abc");
        //2.添加元素
        sb.append(1);
        sb.append(2.3);
        sb.append(true);
        System.out.println(sb);

    }

在这里插入图片描述
2.reverse 反转方法

sb.reverse();

小黑子—Java从入门到入土过程:第六章_第54张图片

3.length 获取长度方法

        int len = sb.length();
        System.out.println(len);

小黑子—Java从入门到入土过程:第六章_第55张图片

4.toString

public static void main(String[] args) {
        //1.创建对象
        StringBuilder sb = new StringBuilder("abc");
        //2.添加字符串
        sb.append("aaa");
        sb.append("wwww");
        sb.append("xxxx");

        System.out.println(sb);//abcaaawwwwxxxx只是在一个容器里面
        //3.再把StringBuilder变回字符串类型
        String str = sb.toString();
        System.out.println(str);//现在的abcaaawwwwxxxx才是字符串类型
    }

3.4.3 链式编程

当我们在调用一个方法的时候,不需要用变量接收他的结果,可以继续调用其他方法
1.

public static void main(String[] args) {
       String len = getString().substring(1).replace('b','w');
       System.out.println(len);
       int len2 = len.length();
       System.out.println(len2);
    }

    public static String getString(){
        Scanner sc = new Scanner(System.in);
        System.out.println("请输入一个字符串:");
        String str = sc.next();
        return str;
    }

小黑子—Java从入门到入土过程:第六章_第56张图片
2.
将上方3.4.2内容的第4点:

        sb.append("aaa");
        sb.append("wwww");
        sb.append("xxxx");

可写成->一条链子,效果相同

sb.append("aaa").append("wwww").append("xxxx");

练习:
1.
小黑子—Java从入门到入土过程:第六章_第57张图片
equals() 方法用于比较两个字符串的内容是否相等。

package com.itheima.demo1;

import java.util.Scanner;

public class ArithmeticoperatorDemo1 {
    public static void main(String[] args) {
        // 1.键盘录入字符串
        Scanner sc = new Scanner(System.in);
        System.out.println("请输入一个字符串:");
        String str = sc.next();

        //2.反转键盘录入的字符串
       String result =  new StringBuilder().append(str).reverse().toString();
       //.3比较
        if(str.equals(result)){
            System.out.println("当前字符串是对称字符串");
        }else{
            System.out.println("当前字符串不是对称字符串");
        }
    }
}

小黑子—Java从入门到入土过程:第六章_第58张图片
2.
小黑子—Java从入门到入土过程:第六章_第59张图片

package com.itheima.demo1;

public class ArithmeticoperatorDemo1 {
    public static void main(String[] args) {
        //1.定义数组
        int[] arr = {1, 2, 3, 4};
        //2.定义一个接受字符数组的子函数,把arr放进去
        String str = arrString(arr);
        System.out.println(str);
    }

    public static String arrString(int[] arr) {
        //3. new一个StringBuilder容器,用来存放字符串
        StringBuilder sb = new StringBuilder();
        sb.append("[");//将 [ 先加入到容器中
        //4.循环遍历分割数组
        for (int i = 0; i < arr.length; i++) {
            //5.采用判断语句,如果加入到了最后一个字时,就i=length-1,才会不打印 , 逗号
            //其他加入的时候,就带 ,逗号一加入进容器
            if (i == arr.length - 1) {
                sb.append(arr[i]);
            } else {
                sb.append(arr[i]).append(",");
            }
        }
        //循环结束之后,填右边括号
        sb.append("]");
        //6.完成后返回sb的字符串类型
        return sb.toString();
    }
}

小黑子—Java从入门到入土过程:第六章_第60张图片

3.4.4 StringJoiner

对于有时候StringBuilder按照数组拼接字符串的时候就比较麻烦了,中间有的时候拼,有的时候不拼
小黑子—Java从入门到入土过程:第六章_第61张图片
StringJoiner概述:
小黑子—Java从入门到入土过程:第六章_第62张图片
StringJoiner对象的创建
小黑子—Java从入门到入土过程:第六章_第63张图片

StringJoiner的成员方法
小黑子—Java从入门到入土过程:第六章_第64张图片

1.add() 添加内容

delimiter:中间间隔的符号,prefix:开始的符合,suffix:结尾的符号

public static void main(String[] args) {
        StringJoiner sj = new StringJoiner("-----");
        //2.添加元素
        sj.add("aaa").add("bbbb").add("ccc");
        //3.打印结果
        System.out.println(sj);
    }

小黑子—Java从入门到入土过程:第六章_第65张图片
2.

public static void main(String[] args) {
        StringJoiner sj = new StringJoiner(",","[","]");
        //2.添加元素
        sj.add("aaa").add("bbbb").add("ccc");

        int len = sj.length();
        System.out.println(len);//14
        //3.打印结果
        System.out.println(sj);//容器的类型

        String str = sj.toString();
        System.out.println(str);//字符串的类型
    }

小黑子—Java从入门到入土过程:第六章_第66张图片

总结:
小黑子—Java从入门到入土过程:第六章_第67张图片

3.4.5 字符串原理

扩展底层原理1和2:字符串原理

在这里插入图片描述

扩展底层原理3:字符串拼接的底层原理

在这里插入图片描述
1.当等号的右边没有变量时:
小黑子—Java从入门到入土过程:第六章_第68张图片
在编译的时候,就会将"a"+ “b” +“c"拼接为"abc”

2.当等号的右边有变量时:
小黑子—Java从入门到入土过程:第六章_第69张图片

小黑子—Java从入门到入土过程:第六章_第70张图片

  • 在jdk8以前:系统底层会自动创建一个StringBuilder对象,然后再调用其append方法完成拼接。
    拼接后,再调用其toString方法转换为String类型,而toString方法的底层是直接new了一个字符串对象。

  • 在jdk8之后:在编译时,会先预估字符串的长度并创建一个数组,再把数组变成一个字符串,这样就消耗性能了。

小黑子—Java从入门到入土过程:第六章_第71张图片
面试练习题:

小黑子—Java从入门到入土过程:第六章_第72张图片
2.

小黑子—Java从入门到入土过程:第六章_第73张图片

那就采用StringBuilder 和StringJoiner 进行优化

扩展底层原理5:StringBuilder提高效率原理

stringBuilder是一个内容可变的容器,所有要拼接的内容都会往StringBuilder中放,不会创建很多无用的空间,节约内存

小黑子—Java从入门到入土过程:第六章_第74张图片
3、4原理小结:
小黑子—Java从入门到入土过程:第六章_第75张图片

扩展底层原理5:StringBuilder源码分析

小黑子—Java从入门到入土过程:第六章_第76张图片
小黑子—Java从入门到入土过程:第六章_第77张图片
总结:
小黑子—Java从入门到入土过程:第六章_第78张图片

ctrl + n IDEA快捷键 出现搜索界面

在所有位置里寻找,搜索界面默认在当前项目文件里找不到
小黑子—Java从入门到入土过程:第六章_第79张图片

--------->

ctrl + f12 ---->寻找toString
小黑子—Java从入门到入土过程:第六章_第80张图片

3.4.6 字符串综合练习

小黑子—Java从入门到入土过程:第六章_第81张图片
2.
小黑子—Java从入门到入土过程:第六章_第82张图片
3.

4. 集合

集合是一个容器,可以用来存储数据,和数组不同的是,集合的长度可以发生变化。当添加元素时,会自动扩容。

  • 集合可以存储引用数据类型,不能直接存储基本数据类型,要把基本数据类型变成其对应的包装类才能存储。

小黑子—Java从入门到入土过程:第六章_第83张图片
小黑子—Java从入门到入土过程:第六章_第84张图片

4.1 ArrayList 集合(之一)

ArrayList集合的创建:

   public static void main(String[] args) {
        //1.创建集合的对象
        //泛型:指限定集合中存储数据的类型,就是 <里面的>
        //ArrayList list = new ArrayList();
        // jDK7之后:
        ArrayList<String> list = new ArrayList<>();
        System.out.println(list);

        //此时我们创建的是ArrayList的对象,
        //这个类在底层做了一些处理
        //打印对象不是地址值,而是集合中存储数据内容 也就是[]
        //在展示的时候会拿[]把所有的数据进行包裹
    }

ArrayList成员方法
小黑子—Java从入门到入土过程:第六章_第85张图片

  • add()和remove的返回值都是布尔值,add默认返回true,不用管,而remove在删除成功时返回true,失败时返回false
    同时,remove还可以根据索引进行删除,返回值是被删除的元素
  • set是修改指定索引上的值,返回被覆盖的值。
  • get就是获取相应索引的元素
  • size就是集合的长度,类似于length
public static void main(String[] args) {
        //1.创建集合的对象
        ArrayList<String> list = new ArrayList<>();
        //2.添加元素
        list.add("aaa");
        list.add("aaa");
        list.add("www");
        list.add("ddd");

        System.out.println("2:"+list);

        //3.删除元素
        boolean result1 = list.remove("aaa");
        System.out.println("3:"+result1);//当要删除的元素不存在时,就会false
        System.out.println("3:"+list);

        //把被删除的元素进行返回
        String str = list.remove(2);
        System.out.println("3:"+str);
        System.out.println("3:"+list);

        //4.修改元素
        String res = list.set(1, "cccc");//把替换的元素进行返回
        System.out.println("4:"+res);
        System.out.println("4:"+list);

        //5.查询元素
        String s = list.get(0);
        System.out.println("5:"+s);
        System.out.println("5:"+list);
        
        //6.遍历元素 list.fori
        for (int i = 0; i < list.size(); i++) {
            //list.get(i) 元素
            String s1 = list.get(i);
            System.out.println("6:"+s1);
            System.out.println("6:"+list);
        }
    }

小黑子—Java从入门到入土过程:第六章_第86张图片

4.2 集合综合练习

4.2.1 添加字符串和整数遍历

小黑子—Java从入门到入土过程:第六章_第87张图片

public static void main(String[] args) {
        ArrayList<String> list = new ArrayList<>();

        list.add("aaa");
        list.add("bbb");
        list.add("ccc");
        list.add("ddd");

        //遍历
        System.out.print("[");
        for (int i = 0; i < list.size(); i++) {
            if(i==list.size()-1){
                System.out.print(list.get(i));
            }else{
                System.out.print(list.get(i)+",");
            }
        }
        System.out.println("]");

    }

小黑子—Java从入门到入土过程:第六章_第88张图片
2.
小黑子—Java从入门到入土过程:第六章_第89张图片
下方遍历代码一样,中间改变

ArrayList<Integer> list = new ArrayList<>();

        list.add(1);
        list.add(2);
        list.add(3);
        list.add(4);
        list.add(5);

在这里插入图片描述

添加字符类型遍历也是同理

        ArrayList<Character> list = new ArrayList<>();

        list.add('a');
        list.add('b');
        list.add('c');
        list.add('d');

4.2.2 基本数据类型的包装类

这里的包装类实际上就是泛型里的关键字
小黑子—Java从入门到入土过程:第六章_第90张图片
jdk5以后int Intleger 之间是可以互相转化的

4.2.3 添加学生对象并遍历

小黑子—Java从入门到入土过程:第六章_第91张图片

public static void main(String[] args) {
      ArrayList<Student> list = new ArrayList<>();
      //2.创建学生对象
      Student s1 = new Student("zhangsan",23);
      Student s2 = new Student("magua",24);
      Student s3 = new Student("xiaolaoban",25);

      //3.添加元素
      list.add(s1);
      list.add(s2);
      list.add(s3);

      //4.遍历集合
      for (int i = 0; i < list.size(); i++) {
         Student stu = list.get(i);
         System.out.println(stu.getName()+","+stu.getAge());
      }
   }

在这里插入图片描述
2.
小黑子—Java从入门到入土过程:第六章_第92张图片
遍历思路:
小黑子—Java从入门到入土过程:第六章_第93张图片

public static void main(String[] args) {
        ArrayList<Student> list = new ArrayList<>();
        // 长度为0
        //2.键盘录入学生的信息并添加到集合当中
        Scanner sc = new Scanner(System.in);
        for (int i = 0; i < 3; i++) {
            Student s = new Student();
            System.out.println("请输入学生的姓名:");
            String name = sc.next();
            System.out.println("请输入学生的年龄:");
            int age = sc.nextInt();

            //把name和age赋值给学生对象
            s.setName(name);
            s.setAge(age);
            //把学生对象添加到集合当中
            list.add(s);
        }
        //集合里面是否有学生对象
        //有? 没有?
        System.out.println(list.size());//3
        for (int i = 0; i < list.size(); i++) {
            Student stu = list.get(i);
            System.out.println(stu.getName()+","+stu.getAge());
        }
    }

小黑子—Java从入门到入土过程:第六章_第94张图片

4.2.4 添加用户对象并判断是否存在

小黑子—Java从入门到入土过程:第六章_第95张图片
javabean部分:

package test10;

public class User {
    private String id;
    private String username;
    private String password;

    public User() {
    }

    public User(String id, String username, String password) {
        this.id = id;
        this.username = username;
        this.password = password;
    }

    public String getId() {
        return id;
    }

    public void setId(String id) {
        this.id = id;
    }

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }
}

Test部分:

package test10;

import java.util.ArrayList;

public class test {
    public static void main(String[] args) {
        //1.创建集合
        ArrayList<User> list = new ArrayList<>();
        //2.创建三个用户对象
       User u1 = new User("magua001","zhangsan","12345");
       User u2 = new User("magua002","lisi","12345678");
       User u3 = new User("magua003","wangwu","12345asd");

       //3.把用户对象添加到集合当中
        list.add(u1);
        list.add(u2);
        list.add(u3);
        
        //4.调用方法查看id是否存在
        boolean flag = contains(list, "magua001");
        System.out.println(flag);
    }
    public static boolean contains(ArrayList<User> list,String id){
//        for (int i = 0; i < list.size(); i++) {
//           User u = list.get(i);
//          String uid = u.getId();
//          if(uid.equals(id)){
//              //如果找到了直接返回true
//              return true;
//          }
//        }
//        //当循环结束表示集合里面所有的元素都比较完毕还没有一样的
//        //那么就返回false
//        return false;
       return getIndex(list,id)>=0;
    }
    public static int getIndex(ArrayList<User>list,String id){
        for (int i = 0; i < list.size(); i++) {
            User u = list.get(i);
            String uid = u.getId();
            if(uid.equals(id)){
                return i;
            }
        }
        return -1;
    }
}

小黑子—Java从入门到入土过程:第六章_第96张图片

4.2.5 添加手机对象并返回要求的数据

在这里插入图片描述
phone的javabean:

package test11;

public class Phone {
    private String brand;
    private int price;

    public Phone() {
    }

    public Phone(String brand, int price) {
        this.brand = brand;
        this.price = price;
    }

    public String getBrand() {
        return brand;
    }

    public void setBrand(String brand) {
        this.brand = brand;
    }

    public int getPrice() {
        return price;
    }

    public void setPrice(int price) {
        this.price = price;
    }
}

test部分:

public static void main(String[] args) {
        //1.创建集合
        ArrayList<Phone> list = new ArrayList<>();
        //2.创建三个用户对象
        Phone p1 = new Phone("xiaomi",1000);
        Phone p2 = new Phone("iphone",4000);
        Phone p3 = new Phone("cuizi",2000);

        //3.把用户对象添加到集合当中
        list.add(p1);
        list.add(p2);
        list.add(p3);
        //4.调用方法
        ArrayList<Phone> phoneInfoList  = getPhoneInfo(list);
        //5.遍历集合
        for (int i = 0; i < phoneInfoList.size(); i++) {
            Phone phone = phoneInfoList.get(i);
            System.out.println(phone.getBrand()+","+phone.getPrice());
        }
    }
    //1.我要干嘛?查询手机信息
    //2.我干这件事情,需要什么才能完成?集合
    //3.我干完了,方法的调用处是否需要继续使用结果?返回

    //技巧:
    //如果我们要返回多个数据,可以把这些数据先放到一个容器当中,再把容器返回/集合数组
    public static ArrayList<Phone> getPhoneInfo(ArrayList<Phone> list){
        //定义一个集合用于存储价格低于3000的手机对象
        ArrayList<Phone> resultList = new ArrayList<>();
        //遍历集合
        for (int i = 0; i < list.size(); i++) {
           Phone p = list.get(i);
            int price = p.getPrice();
            //如果当前手机的价格低于3000,
            if(price<3000){
                resultList.add(p);
            }
        }
        return resultList;
        //返回的是集合,函数的返回值类型就得是集合
    }

小黑子—Java从入门到入土过程:第六章_第97张图片

5. 学生管理系统

学会阅读需求文档,在了解需求文档后,自己画出需求的结构流程图(业务流程图)
小黑子—Java从入门到入土过程:第六章_第98张图片
流程图:
小黑子—Java从入门到入土过程:第六章_第99张图片
Ctrl + alt + t 全选中内容后,快捷生成结构环绕方式
小黑子—Java从入门到入土过程:第六章_第100张图片
StudentTest第一部分:

package test1;

import java.util.ArrayList;
import java.util.Scanner;

public class StudentTest {
    public static void main(String[] args) {
        ArrayList<Student> list = new ArrayList<>();
        while (true) {
            //不要把ArrayList list = new ArrayList<>();
            //放在循环内部,这样在添加学生到list后,再循环一次,list又变成了0,这样查询的时候就总是无法查到
            System.out.println("----------------欢迎来到小黑子的学生管理系统----------------");
            System.out.println("1:添加学生");
            System.out.println("2:删除学生");
            System.out.println("3:修改学生");
            System.out.println("4:查询学生");
            System.out.println("5:退出");
            System.out.println("请输入您的选择:");
            Scanner sc = new Scanner(System.in);
            //定义一个字符串来接收
            String choose = sc.next();
            switch (choose) {
                case "1" -> addStudnet(list);
                case "2" -> deleteStudnet(list);

                case "3" -> updateStudnet(list);

                case "4" -> queryStudnet(list);
                case "5" -> {
                    System.out.println("退出");
                    System.exit(0);//停止虚拟机运行
                }
                default -> System.out.println("没有这个选项");
            }
        }
    }

    //添加学生
    public static void addStudnet(ArrayList<Student> list) {
        //利用空参构造先创建学生对象
        Student s = new Student();

        Scanner sc = new Scanner(System.in);
        String id = null;

        while (true) {
            System.out.println("请输入学生的id:");
            id = sc.next();
            boolean flag = contains(list, id);
            if (flag) {
                //true 表示id已经存在,需要重新录入
                System.out.println("id已经存在,请重新录入");
            } else {
                //表示id不存在,唯一
                s.setId(id);
                break;
            }
        }

        System.out.println("请输入学生的姓名:");
        String name = sc.next();
        s.setName(name);

        System.out.println("请输入学生的年龄:");
        int age = sc.nextInt();
        s.setAge(age);

        System.out.println("请输入学生的家庭住址:");
        String address = sc.next();
        s.setAddress(address);

        //把学生对象添加到集合当中
        list.add(s);

        //提示用户
        System.out.println("学生信息添加成功");
        System.out.println(list.size());
    }

    //删除学生
    public static void deleteStudnet(ArrayList<Student> list) {
        Scanner sc = new Scanner(System.in);
        System.out.println("请输入要删除的id:");
        String id = sc.next();
        //查询id在集合中的索引
        int index = getIndex(list, id);
        //对index进行判断
        //如果-1,就表示索引不存在,结束方法,返回初始菜单
        if (index >= 0) {
            //如果大于等于0的,表示存在,直接删除
            list.remove(index);
            System.out.println("id为:" + id + "的学生删除成功");
        } else {
            System.out.println("id不存在,删除失败");
        }
    }

    //修改学生
    public static void updateStudnet(ArrayList<Student> list) {
        Scanner sc = new Scanner(System.in);
        System.out.println("请输入要修改学生的id:");
        String id = sc.next();

        int index = getIndex(list,id);

        if(index == -1){
            System.out.println("要修改的id:"+id+"不存在,请重新输入");
            return;
        }
        //当代码执行到这里,表示什么?表示当前id是存在的
        //获取要修改的学生对象
        Student stu = list.get(index);

        //输入其他的信息并修改
        System.out.println("请输入修改的学生姓名:");
        String newName = sc.next();
        stu.setName(newName);

        System.out.println("情输入修改的学生年龄:");
        String newAge = sc.next();
        stu.setName(newAge);

        System.out.println("情输入修改的学生家庭住址:");
        String newAddress = sc.next();
        stu.setName(newAddress);

        System.out.println("学生信息修改完成");
    }

    //查询学生
    public static void queryStudnet(ArrayList<Student> list) {
        System.out.println(list.size());
        if (list.size() == 0) {
            System.out.println("当前无学生信息,请添加后再查询");
            return;
        }
        //打印表头信息
        System.out.println("id\t\t姓名\t年龄\t家庭住址");
        //当代码执行到这里时表示集合是有数据的,遍历集合的每个数据
        for (int i = 0; i < list.size(); i++) {
            Student stu = list.get(i);
            System.out.println(stu.getId() + "\t" + stu.getName() + "\t" + stu.getAge() + "\t" + stu.getAddress());
        }
    }

    //判断id 的方法
    public static boolean contains(ArrayList<Student> list, String id) {
//        //循环遍历每一个学生对象
//        for (int i = 0; i < list.size(); i++) {
//            //拿到学生对象后,获取id并进行判断
//            Student stu = list.get(i);
//            String sid = stu.getId();
//            if(sid.equals(id)){
//                //存在,true
//                return true;
//            }
//        }
//        //不存在方法就返回false
//        return false;
        return getIndex(list, id) >= 0;
    }

    //通过id获取索引的方法
    public static int getIndex(ArrayList<Student> list, String id) {
        //遍历集合
        for (int i = 0; i < list.size(); i++) {
            //得到每一个学生对象
            Student stu = list.get(i);
            //得到每一个学生对象的id
            String sid = stu.getId();
            //拿着集合中的学生id跟要查询的id进行比较
            if (sid.equals(id)) {
                //如果一样,那么就返回索引
                return i;
            }
        }
        return -1;
    }
}


小黑子—Java从入门到入土过程:第六章_第101张图片

swich语句不能用箭头表达式,java版本换成jdk17以上行了。

5.1 学生管理系统升级版

需求图:
小黑子—Java从入门到入土过程:第六章_第102张图片小黑子—Java从入门到入土过程:第六章_第103张图片
小黑子—Java从入门到入土过程:第六章_第104张图片
小黑子—Java从入门到入土过程:第六章_第105张图片
流程图:
小黑子—Java从入门到入土过程:第六章_第106张图片

1.注册
小黑子—Java从入门到入土过程:第六章_第107张图片
2.登录
小黑子—Java从入门到入土过程:第六章_第108张图片
3.忘记密码

小黑子—Java从入门到入土过程:第六章_第109张图片

6. 面向对象进阶

6.1 static

6.1.1 static-静态变量

static(静态变量)(静态变量被该类所有对象共享),是Java中的一个修饰符,可以修饰成员方法,成员变量

小黑子—Java从入门到入土过程:第六章_第110张图片
javabean类:

public class Student {
    private String name;
    private int age;
    private  String gender;
    public static String teacherName;

    public Student() {
    }

    public Student(String name, int age, String gender) {
        this.name = name;
        this.age = age;
        this.gender = gender;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public String getGender() {
        return gender;
    }

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

    //行为
    public void study(){
        System.out.println(name+"正在学习");
    }

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

测试类:

 public static void main(String[] args) {
        //1.创建学生对象
        Student s1 = new Student();
        s1.setName("张三");
        s1.setAge(23);
        s1.setGender("man");
        s1.teacherName = "麻瓜";

        s1.study();
        s1.show();

        //2.创建第二个学生对象
        Student s2 = new Student();
        s2.setName("李四");
        s2.setAge(25);
        s2.setGender("man");

        s2.study();
        s2.show();

    }

小黑子—Java从入门到入土过程:第六章_第111张图片
当这里的teacherName被赋值后,static会被Student类里所有对象共享(公共的一个属性)

静态变量是随着类的加载而加载的,优先于对象出现,被赋值是单独存储再堆内存中的静态区域

示意图:
小黑子—Java从入门到入土过程:第六章_第112张图片
静态区里的变量是对象共享的,在内存中只有一份,谁用谁拿,非静态的变量是每一个对象所独有的,每一个对象里的非静态的变量都是单独存放的。

判断一个变量是否是静态变量,主要就是两个字,共享
需要共享的变量就是静态变量

6.1.2 static-静态方法和工具

静态方法

在这里插入图片描述

工具类

工具类:帮助我们做一些事情的,但是不描述任何事物的类

目前一共学习了三种类
小黑子—Java从入门到入土过程:第六章_第113张图片
工具类的要求:
小黑子—Java从入门到入土过程:第六章_第114张图片

这里的第2个私有化构造方法就是

public class Student {
    private public Student() {
    }
}

一个类一旦被私有化构造方法后,就不能创建这个类的对象了。

练习:
1.
小黑子—Java从入门到入土过程:第六章_第115张图片
javabean类:

public class ArrayUtil {
    //私有化构造方法
    //目的:为了不让外界创建他的对象
    private ArrayUtil(){}

    public static String printArr(int[] arr){
        //一到字符串的拼接,就一定要想到StringBuilde
        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("]");
        return sb.toString();
    }

    public static double getAverage(double[] arr){
        double sum =0;
        for (int i = 0; i < arr.length; i++) {
            sum = sum + arr[i];
        }
        return sum/arr.length;
    }
}

测试类:

public class TestDemo {
    public static void main(String[] args) {
        //测试工具类的两个方法是否正确
        int[] arr1 = {1, 2, 3, 4, 5};
        String str = ArrayUtil.printArr(arr1);
        System.out.println(str);

        double[] arr2 ={1.5,23.43,654.43,1.23,23.3};
        double avg = ArrayUtil.getAverage(arr2);
        System.out.println(avg);

    }
}

在这里插入图片描述
2.
小黑子—Java从入门到入土过程:第六章_第116张图片
工具类:

import java.util.ArrayList;

public class StudentUtil {
    private StudentUtil(){}
    
    //静态方法
    public static int getMaxAgeStudent(ArrayList<Student> list){
        //1.定义一个参照物
       int max = list.get(0).getAge();
       //2.循环遍历集合
        for (int i = 0; i < list.size(); i++) {
            //i  索引  list.get(i)元素/学生对象  我们还需要getAge获取到年龄之后再进行比较
            int tempAge = list.get(i).getAge();
            if(tempAge>max){
                max = tempAge;
            }
        }
        //3.直接返回
        return max;
    }
}

Test部分调用工具类方法:

        //4.调用工具类方法
        int maxAgeStudent = StudentUtil.getMaxAgeStudent(list);
        System.out.println(maxAgeStudent);

小黑子—Java从入门到入土过程:第六章_第117张图片

6.1.3 static-注意事项

小黑子—Java从入门到入土过程:第六章_第118张图片
在非静态方法中,有一个隐藏的this,这个this就表示当前方法调用者的地址值
小黑子—Java从入门到入土过程:第六章_第119张图片
在第一次调用show()方法时,虚拟机就会把第一次调用者的地址赋值给方法中的this,就像图中所示
第二次同理,虚拟机会把第二次调用者的地址赋值给方法中的this

小黑子—Java从入门到入土过程:第六章_第120张图片
this的值

this的这一特性就是区分不同对象的 即在调用成员变量时,变量前面有隐含的this,从而显示出不同变量的结果

在这里插入图片描述

上面sout里的this可以省略

  • 而在static静态方法中,是没有这个this关键字的
  • 原因就是静态方法是公用的,而this一般是独立的对象进行使用,不符合公用的理念。

示意图:
小黑子—Java从入门到入土过程:第六章_第121张图片
小黑子—Java从入门到入土过程:第六章_第122张图片

  1. 静态方法不能访问非静态成员变量(也就是实例变量即对象)

小黑子—Java从入门到入土过程:第六章_第123张图片

因为在使用静态方法时,通过类名调用会直接到静态存储位置去找变量,而非静态的变量是随着对象的创建而创建的,在静态存储位置找不到,所以静态方法不能调用非静态成员变量

  1. 静态方法不能访问非静态的成员方法

小黑子—Java从入门到入土过程:第六章_第124张图片

因为非静态的方法需要调用者,而在静态方法中是没有this的,也就没有调用者,自然就不能使用了

综上,静态方法只能调用静态的内容

  1. 非静态方法可以访问所有

小黑子—Java从入门到入土过程:第六章_第125张图片

因为静态的是公用的,所以非静态既可以访问到静态,也可以访问非静态

小结:
小黑子—Java从入门到入土过程:第六章_第126张图片

6.1.4 重新认识main方法

JVM:虚拟机
小黑子—Java从入门到入土过程:第六章_第127张图片例子:

点击IDEA右上角的锤子旁边的按钮
小黑子—Java从入门到入土过程:第六章_第128张图片
在程序参数里填写,args即可返回值
小黑子—Java从入门到入土过程:第六章_第129张图片
小黑子—Java从入门到入土过程:第六章_第130张图片

6.2 继承

6.2.1 封装

封装:

对象代表什么,就得封装对应的数据,并提供数据对应的行为

像这种相同的行为太多了,这时候就需要用到封装
小黑子—Java从入门到入土过程:第六章_第131张图片
小黑子—Java从入门到入土过程:第六章_第132张图片
封装完行为方法之后,就要用到继承了
小黑子—Java从入门到入土过程:第六章_第133张图片

6.2.2 继承的描述

继承实际上就是类跟类之间的父子关系
小黑子—Java从入门到入土过程:第六章_第134张图片
什么时候用继承?
小黑子—Java从入门到入土过程:第六章_第135张图片
小结:
在这里插入图片描述
继承需要学习的点:
小黑子—Java从入门到入土过程:第六章_第136张图片

6.2.3 继承的特点

小黑子—Java从入门到入土过程:第六章_第137张图片
即儿子继承父亲,父亲继承爷爷
小黑子—Java从入门到入土过程:第六章_第138张图片
即子类的父类是直接父类,父类的父类是子类的间接父类

java中有一个祖宗类就是Object,每一个类都直接或间接继承于Object

小黑子—Java从入门到入土过程:第六章_第139张图片
小黑子—Java从入门到入土过程:第六章_第140张图片
小结:
小黑子—Java从入门到入土过程:第六章_第141张图片

练习:
小黑子—Java从入门到入土过程:第六章_第142张图片
设计继承体系时,尽量先搞清楚体系逻辑,画一张图,从子类到父类
设计的核心就是:共性的内容抽取,子类是父类的一种
书写代码时,从父类到子类

小黑子—Java从入门到入土过程:第六章_第143张图片

小结:
小黑子—Java从入门到入土过程:第六章_第144张图片

6.2.4 子类继承父类的特性

小黑子—Java从入门到入土过程:第六章_第145张图片

  1. 构造方法:不论私有(private)还是非私有(像public等)的构造方法,子类都是不能继承的
    小黑子—Java从入门到入土过程:第六章_第146张图片
    例子:
    小黑子—Java从入门到入土过程:第六章_第147张图片

  2. 成员变量:不论私有(private,不能直接调用)还是非私有(像public等)的成员变量,子类都是可以继承的(相当于从父类哪里copy了一份过来)

1.没有用private修饰的继承成员变量的内存图:
小黑子—Java从入门到入土过程:第六章_第148张图片
2.有用private修饰的继承成员变量的内存图:
小黑子—Java从入门到入土过程:第六章_第149张图片

  • 这里new出来一个子类后,会把堆内存中开辟出来的空间分为两部分,第一部分是继承父类的成员变量,第二类是子类自己的成员变量
  • 如果父类的成员变量使用private修饰后,子类对象在堆内存中就无法使用继承父类的成员变量。

父类会把非private,非static和非final的方法(这些方法统称为虚方法)抽取出来,放到虚方法表里,在继承的时候,父类会把虚方法表交给子类复制,子类可以添加新的虚方法加入到子类的虚方法表中,使后代继续复制

  • 成员方法:非私有的成员方法(虚方法)可以被继承,私有的成员方法就不能被继承下来

运行效率低下:
小黑子—Java从入门到入土过程:第六章_第150张图片
以下如此可以大大提高性能:
小黑子—Java从入门到入土过程:第六章_第151张图片
例子:
小黑子—Java从入门到入土过程:第六章_第152张图片

6.2.5 终端的jps和jhsdb hsdb

在终端中输入jps,得到类中获得的id
小黑子—Java从入门到入土过程:第六章_第153张图片
输入jhsdb hsdb 打开HotSpot Debugger

  • (HSDB(Hotspot Debugger) ,是一款内置于 SA 中的 GUI 调试工具,可用于调试 JVM运行时数据,从而进行故障排除。)

小黑子—Java从入门到入土过程:第六章_第154张图片
在file中寻找到第一个点击进入
小黑子—Java从入门到入土过程:第六章_第155张图片
从jps中获得的id输入,ok

小黑子—Java从入门到入土过程:第六章_第156张图片
之后显示
小黑子—Java从入门到入土过程:第六章_第157张图片

在tools里找到Memory Viewer
小黑子—Java从入门到入土过程:第六章_第158张图片
在tools里找到Inspector
小黑子—Java从入门到入土过程:第六章_第159张图片
在这里插入图片描述

6.2.6 继承中成员变量和成员方法的访问特点

继承成员变量
  • 继承的成员变量的访问特点: 就近原则:谁离我近,我就用谁 即优先级为: 方法内的成员变量>子类的成员变量>父类的成员变量
    在使用一个成员变量时,会先在局部的方法内找,如果方法内没有,就会到本类(子类)中去找,本类中再没有,就会到父类中去找

小黑子—Java从入门到入土过程:第六章_第160张图片
在上述代码中,name就是“ziShow”,如果“ziShow”没有,name就是“Zi”,如果“Zi”再没有,那么name就是“Fu”
当然,也可以同时访问这三个成员变量

例子:
1.

public class Test {
    public static void main(String[] args) {
        Zi zi=new Zi();
        zi.ziShow();
    }
}
class Fu{
    String name="Fu";
}
class Zi extends Fu{
    String name="Zi";
    public void ziShow(){
        String name="ziShow";
        System.out.println(name);
        System.out.println(this.name);
        System.out.println(super.name);
    }
}

小黑子—Java从入门到入土过程:第六章_第161张图片
2.
小黑子—Java从入门到入土过程:第六章_第162张图片
即使用this关键字可以访问本类的成员变量,使用super关键字可以访问父类的成员变量。
语法:

  • this.变量名
  • super.变量名

注:在子类中最多使用一个super

小结:
小黑子—Java从入门到入土过程:第六章_第163张图片

继承成员方法

继承的成员方法的访问特点:

  1. 直接调用:满足就近原则,谁近调用谁
  2. super调用:直接访问父类

与上面成员变量的特点一样,都是就近原则,都是this,super

public class Test {
    public static void main(String[] args) {
        Zi zi=new Zi();
        zi.show();
    }
}
class Fu{
    String name="Fu";
    public void eat(){
        System.out.println("chifan,父类被调用");
    }
}
class Zi extends Fu{
    String name="Zi";
    //这里进行了方法的重写,由于父类的方法不能满足子类的需求,从而进行了方法的重写
    @Override
    public void eat(){
        System.out.println("heshui,子类被调用");
    }
    public void show(){
        eat();
        this.eat();
        super.eat();
    }
}

小黑子—Java从入门到入土过程:第六章_第164张图片
小黑子—Java从入门到入土过程:第六章_第165张图片
方法重写的本质:

新的方法覆盖旧的方法(虚方法表)
小黑子—Java从入门到入土过程:第六章_第166张图片

小黑子—Java从入门到入土过程:第六章_第167张图片
方法重写注意事项和要求:
小黑子—Java从入门到入土过程:第六章_第168张图片
私有方法不能进行重写,重写方法时也可以调用父类的方法

练习:
小黑子—Java从入门到入土过程:第六章_第169张图片
小黑子—Java从入门到入土过程:第六章_第170张图片

总结:
在这里插入图片描述

6.2.6 继承中的构造方法

  • 特点
    1.父类中的构造方法不会被子类继承
    2.子类中所有的构造方法默认先访问父类中的无参构造,再执行自己
    小黑子—Java从入门到入土过程:第六章_第171张图片
    第二条出现的原因
    在这里插入图片描述
    例子:
    小黑子—Java从入门到入土过程:第六章_第172张图片

所以,子类的构造方法的第一句都会是super(),即使不写也会存在于第一行。 这里的super()就是调用父类的空参构造方法
如果想调用父类的有参构造,就必须手动写super进行调用

小结:
小黑子—Java从入门到入土过程:第六章_第173张图片

6.2.7 this、super关键字总结

  • this 就相当于一个局部变量,表示当前方法调用者的地址值

小黑子—Java从入门到入土过程:第六章_第174张图片

  • super 就代表父类的存储空间

this与super的区别

关键字 访问成员变量 访问成员方法 访问构造方法
this this.成员变量 访问本类成员变量 this.成员方法访问本类成员方法 this(…)访问本类构造方法
super super.成员变量 访问父类成员变量 super. 访问父类成员方法 super(…)访问父类构造方法

当使用this方法来访问本类构造方法:

public class Person {
    String name;
    int age;

    String gender;

    public Person() {
        this(null,0,"男");
    }
    public Person(String name,int age,String gender){
        this.name=name;
        this.age=age;
        this.gender=gender;
    }
}

这里空参构造里的this(null,0,"男");就是使用this来访问构造方法,并赋予初始值
且,使用this()后,虚拟机就不会自动添加super()
练习:
小黑子—Java从入门到入土过程:第六章_第175张图片

Employeer:
public class Employee {
    //1.类名见名知意
    //2.所有的成员变量都需要私有
    //3.构造方法(空参带全部参数的构造)
    //4.get/ set
    private String id;
    private String name;
    private double salary;

    public Employee(){}

    public Employee(String id, String name, double salary) {
        this.id = id;
        this.name = name;
        this.salary = salary;
    }

    public String getId() {
        return id;
    }

    public void setId(String id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public double getSalary() {
        return salary;
    }

    public void setSalary(double salary) {
        this.salary = salary;
    }

    //工作
    public void work(){
        System.out.println("员工在工作");
    }

    //吃饭
    public void eat(){
        System.out.println("吃米饭");
    }
}

Manager:
public class Manager extends Employee{
    private double bouns;

    //空参构造
    public Manager(double bouns) {
        this.bouns = bouns;
    }

    //带全部参数的构造
    //父类+子类
    public Manager(String id, String name, double salary, double bouns) {
        super(id, name, salary);
        this.bouns = bouns;
    }

    public double getBouns() {
        return bouns;
    }

    public void setBouns(double bouns) {
        this.bouns = bouns;
    }

    @Override
    public void work() {
        System.out.println("管理其他人");
    }
}

Cook:
public class Cook extends Employee{
    public Cook(){}

    public Cook(String id, String name, double salary) {
        super(id, name, salary);
    }

    @Override
    public void work() {
        System.out.println("厨师正在炒菜");
    }
}

Test:
public class Test {
    public static void main(String[] args) {
        //创建对象并赋值调用
        Manager m = new Manager("magua001","小笼包",15000,8000);
        System.out.println(m.getId()+","+m.getName()+
                ","+m.getSalary()+","+m.getBouns());
        m.work();
        m.eat();

        Cook c = new Cook();
        c.setId("magua002");
        c.setName("lisi");
        c.setSalary(8000);
        System.out.println(c.getId()+","+c.getName()+","+c.getSalary());
        c.work();
        c.eat();
    }
}

小黑子—Java从入门到入土过程:第六章_第176张图片

6.3 认识多态

小黑子—Java从入门到入土过程:第六章_第177张图片
多态的概念:
封装是多态的必要条件,继承是多态的前提条件

小黑子—Java从入门到入土过程:第六章_第178张图片
多态的应用场景:
小黑子—Java从入门到入土过程:第六章_第179张图片
不同的用户对象,采用同样的代码模块会出现冗余
小黑子—Java从入门到入土过程:第六章_第180张图片
解决方案:
小黑子—Java从入门到入土过程:第六章_第181张图片
多态的含义

多种形态,同种类型的对象表现出的不同形态 可以以父类来创建子类对象,即使用父类型作为参数,可以接收所有子类对象

多态语法
父类类型 对象名称=子类对象
多态可以根据调用对象的不同,使用对应的方法

例如 Person man=new Student(),这里Person是父类,Student是子类 但是多态的使用要满足以下前提

小黑子—Java从入门到入土过程:第六章_第182张图片
例子:

Person:
public class Person {
    private String name;
    private int age;

    public Person() {
    }

    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

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

Student:
public class Person {
    private String name;
    private int age;

    public Person() {
    }

    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

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

Teacher:
public class Teacher extends Person{
    @Override
    public void show() {
        System.out.println("老师的信息为:"+getName()+","+getAge());
    }
}

Adminnistrator类:
public class Administrator extends Person{
    @Override
    public void show() {
        System.out.println("管理员的信息为:"+getName()+","+getAge());
    }
}

测试类:
public class Test {
    public static void main(String[] args) {
        //创建三个对象,并调用register方法
        Student s =new Student();
        s.setName("张三");
        s.setAge(18);

        Teacher t = new Teacher();
        t.setName("麻瓜");
        t.setAge(30);

        Administrator admin = new Administrator();
        admin.setName("管理员");
        admin.setAge(35);

        //不管传递什么对象,都可以被下方Person接收
        //这就是多态的原因
        register(s);
        register(t);
        register(admin);
    }

    //这个方法既能接收老师,又能接收学生,还能接收管理员
    // 只能把参数写成这三个类型的父类
    public static void register(Person p){
        p.show();
    }
}

小黑子—Java从入门到入土过程:第六章_第183张图片
总结:
小黑子—Java从入门到入土过程:第六章_第184张图片

6.3.1 多态中调用成员的特点

父类 对象名=new 子类()
小黑子—Java从入门到入土过程:第六章_第185张图片
遵循两个口诀:

  1. 编译看左边的解释: javac编译代码时,会看左边的父类有没有这个变量或方法,如果有,编译成功,如果没有,编译失败,即必须要有父类的方法
    在这里插入图片描述
    小黑子—Java从入门到入土过程:第六章_第186张图片

  2. 运行也看左边的解释: javac运行代码的时候,实际获取的就是左边父类中成员变量的值。
    小黑子—Java从入门到入土过程:第六章_第187张图片
    小黑子—Java从入门到入土过程:第六章_第188张图片
    即对象调用遵循以上两个规则。
    同理,方法调用也是如此,只不过在运行时会运行子类的方法,即 右边

内存图解:
小黑子—Java从入门到入土过程:第六章_第189张图片
例子:

//父类Person
package com.inherit.study;

public class Person {
    String name="人";
    int age;

    String gender;

    public Person() {

    }
    public Person(String name,int age,String gender){
        this.name=name;
        this.age=age;
        this.gender=gender;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public String getGender() {
        return gender;
    }

    public void setGender(String gender) {
        this.gender = gender;
    }
    public void show(){
        System.out.println(name+" "+age);
    }
}
//子类Student
package com.inherit.study;

public class Student extends Person {
    String name="学生";
    @Override
    public void show(){
        System.out.println("学生的信息为:"+getName()+" "+getAge());
    }
}
//测试类
package com.inherit.study;

public class test3 {
    public static void main(String[] args) {
        Person pr=new Student();
        System.out.println(pr.name);
        pr.show();
    }

}

在这里插入图片描述
可以看到,父类的成员变量显示出来,子类的成员变量没有显示,并且子类的方法被运行,父类的方法没有运行

子类的方法能运行的原因是子类重写的方法是虚方法,在虚方法表里覆盖了父类的虚方法。
如果是子类 对象名=子类()这种形式调用成员变量时,会先在子类的内存空间寻找成员变量,子类的内存空间没有时,才会到父类的内存空间去找,这是继承的特性,而在多态中,父类 对象名=new 子类()如果父类里没有相应的成员变量,会直接报错。

6.3.2 多态的优势和弊端

优势
小黑子—Java从入门到入土过程:第六章_第190张图片
即只需把后面标红的代码修改就可以了

弊端:

  • 不能调用子类的特有功能
  • 因为子类的特有方法不是重写的,是子类独有的,父类里没有,所以不能调用,会报错。

解决方案:
用强制类型转换把父类型转换为子类型,不能随便转换,要对应着转换
例子:

public class Test {
    public static void main(String[] args) {
        //创建对象
        Animal a =new Dog();
        a.eat();
        //多态的弊端
        //不能调用子类的特有功能很错的原因?
        //当调用成员方法的时候,编译看左边,运行看右边
        //那么在编译的时候会先检查左边的父类中有没有这个方法,如果没有直接报错。
        //a.lookHome();Animal没有lookHome() 报错

        //解决方案:
        //变回子类就可以了
        //Dog d =(Dog) a;
        //d.lookHome();

        //细节:转换的时候不能瞎转,如果转成其他类的类型,就会报错
        //Cat c = (Cat) a;
        //c.CatchMouse(); 已经new成狗了,就不能再变成猫
        
    }
}

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

class Dog extends Animal{
    @Override
    public void eat() {
        System.out.println("狗吃骨头");
    }
    public void lookHome(){
        System.out.println("狗看家");
    }
}

class Cat extends Animal{
    @Override
    public void eat() {
        System.out.println("猫吃小鱼干");
    }
    public void CatchMouse(){
        System.out.println("猫抓老鼠");
    }
}

6.3.3 instanceof 判断是不是相应类型

可以用instanceof关键字来判断是不是相应类型
对象名 instanceof
如果是相应类型,会返回true,否则返回false

//可以利用判断语句进行判断类型是否转换
        if(a instanceof Dog){
            Dog d =(Dog) a;
            d.lookHome();
        } else if(a instanceof Cat){
            Cat c = (Cat) a;
            c.CatchMouse();
        }else{
            System.out.println("没有这个类型,无法转换");
        }

java14的新特性
对象名 instanceof 类 变量名
如果是相应类型,会直接变成相应类型的变量,否则结果是false

if(a instanceof Dog d){
            d.lookHome();
        } else if(a instanceof Cat c){
            c.CatchMouse();
        }else{
            System.out.println("没有这个类型,无法转换");
        }

小结:
小黑子—Java从入门到入土过程:第六章_第191张图片

6.3.4 多态综合练习

小黑子—Java从入门到入土过程:第六章_第192张图片

Animal类:
public class Animal {
    private int age;
    private String color;

    public Animal() {
    }

    public Animal(int age, String color) {
        this.age = age;
        this.color = color;
    }

    public void eat(String something){
        System.out.println("动物在吃"+something);
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public String getColor() {
        return color;
    }

    public void setColor(String color) {
        this.color = color;
    }
}

Dog类:
public class Dog extends Animal{
    public Dog(){}
    public Dog(int age,String color){
        super(age,color);
    }
    //行为
    //eat(String something ) (something表示吃的东西)
    //看家lookHome方法(无参数)

    @Override
    public void eat(String something) {
        System.out.println(getAge()+"岁的"+getColor()+"黑颜色的狗两只前腿死死的抱住"+something+"骨头猛吃");
    }

    public void lookHome(){
        System.out.println("狗在看家");
    }
}

Cat类:
public class Cat extends Animal{
    public Cat() {
    }

    public Cat(int age, String color) {
        super(age, color);
    }

    @Override
    public void eat(String something) {
        System.out.println(getAge()+"岁的"+getColor()+"黑颜色的狗两只前腿死死的抱住"+something+"骨头猛吃");
    }

    public void catchMouse(){
        System.out.println("猫抓老鼠");
    }
}

Person类:
public class Person {
    private String name;
    private int age;

    public Person() {
    }

    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

//    //饲养狗
//    public void keePet(Dog dog,String something){
//        System.out.println("年龄为"+age+"岁的"+name+"养了一只"+dog.getColor()+"颜色的"+dog.getAge()+"岁的狗");
//        dog.eat(something);
//    }
//    //饲养猫
//    public void keePet(Cat cat,String something){
//        System.out.println("年龄为"+age+"岁的"+name+"养了一只"+cat.getColor()+"颜色的"+cat.getAge()+"岁的猫");
//        cat.eat(something);
//    }

    //想要一个方法,能接收所有的动物,包括猫,包括狗
    //方法的形参,可以写这些类的父类 Animal
    public void keepPet(Animal a,String something){
        if(a instanceof Dog d){
            System.out.println("年龄为"+age+"岁的"+name+"养了一只"+a.getColor()+"颜色的"+a.getAge()+"岁的狗");
            d.eat(something);
        }else if(a instanceof Cat c){
            System.out.println("年龄为"+age+"岁的"+name+"养了一只"+c.getColor()+"颜色的"+c.getAge()+"岁的猫");
            c.eat(something);
        }else{
            System.out.println("没有这种动物");
        }
    }

}

测试类:
public class Test {
    public static void main(String[] args) {
        //创建对象并调用方法
//        Person p = new Person("老王",30);
//        Dog d = new Dog(2,"墨");
//        p.keePet(d,"骨头");
//
//        Person p2 = new Person("老李",25);
//        Cat c = new Cat(4,"灰");
//        p2.keePet(c,"鱼");
        Person p = new Person("老王",30);
        Dog d = new Dog(2,"黑");
        Cat c =new Cat(3,"灰");
        p.keepPet(d,"骨头");
        p.keepPet(c,"鱼");

    }
}

小黑子—Java从入门到入土过程:第六章_第193张图片

6.4 包和 final

6.4.1 包

包的起名规则:
公司域名反写+包的作用
小黑子—Java从入门到入土过程:第六章_第194张图片
包名加上类名才是全部的类名,下面的名字太长了
小黑子—Java从入门到入土过程:第六章_第195张图片
改进:如果想在一个包里使用其他包的类名,就需要引用使用的那个包的名字加上类名
import 包名.类名
小黑子—Java从入门到入土过程:第六章_第196张图片
这样就可以使用其他包的类了
注意事项:
使用两个包的同名类时,不需要导包了,直接使用同名类
小黑子—Java从入门到入土过程:第六章_第197张图片

在这里插入图片描述
小结:
在这里插入图片描述

6.4.2 final (与static类似的关键字)

在代码中,一旦被final修饰,就表示被修饰的内容不能改变了,有点像JavaScript的const。
final可以修饰方法,类,和变量
小黑子—Java从入门到入土过程:第六章_第198张图片

  1. 修饰方法时: 表示该方法是最终方法,不能被重写
  2. 修饰类时: 表示该类是最终类,不能被继承
  3. 修饰变量时: 这个变量就会变为一个常量,只能被赋值一次

小黑子—Java从入门到入土过程:第六章_第199张图片
使用final的场景:

如果定义的方法是一种规则时,可以用final 主要还是用final来修饰变量

常量:
小黑子—Java从入门到入土过程:第六章_第200张图片
主要是第二点,对象的内部可以改变。

字符串不可变的原因就是final和private

ieda快捷键 crtl+shift+u可以让字母变成大写

小结:
小黑子—Java从入门到入土过程:第六章_第201张图片

6.5 权限修饰符和代码块

6.5.1 权限修饰符

小黑子—Java从入门到入土过程:第六章_第202张图片
权限修饰符的分类:
有四种类,被访问的范围从小到大分为:private<空着不写(默认情况)

修饰符 同一个类中的作用范围 同一个包里的其他类的作用范围 不同包下的子类的作用范围 不同包下的无关类的作用范围
private 可以 不行 不行 不行
空着不写(默认) 可以 可以 不行 不行
protected 可以 可以 可以 不行
public 可以 可以 可以 可以

小黑子—Java从入门到入土过程:第六章_第203张图片

实际开发中,一般来讲,只会用private和public,且遵守以下规则:

小黑子—Java从入门到入土过程:第六章_第204张图片

6.5.2 代码块

小黑子—Java从入门到入土过程:第六章_第205张图片
代码块可以分为三类

局部代码块,构造代码块,静态代码块

  • 局部代码块
    小黑子—Java从入门到入土过程:第六章_第206张图片

作用:提前结束变量的生命周期(例如上面的a,代码块结束后,a就会消失)
这个技术现在已经用不到了

  • 构造代码块(了解)
    1.就是写在成员位置的代码块,可以优先于构造方法执行
    2.作用:可以把多个构造方法中重复的代码抽取出来。
    3.执行时机:我们在创建本类对象的时候会先执行构造代码块,再执行构造方法

小黑子—Java从入门到入土过程:第六章_第207张图片
这个技术现在也渐渐淘汰了
可以将重复的代码抽取成一个方法,构造方法需要使用时直接调用方法就行了。
小黑子—Java从入门到入土过程:第六章_第208张图片

  • 静态代码块(重点)
    就是在构造代码块的基础上加上static

小黑子—Java从入门到入土过程:第六章_第209张图片
小结:
小黑子—Java从入门到入土过程:第六章_第210张图片

6.6 抽象类和抽象方法

抽象类
下面每个子类的工作内容是不一样的,解决方法就是在子类中随便写一个方法乙,让子类再去重写。

但是有一个小弊端,下面的子类是别人写的代码,别人在写子类的时候忘了重写,那就没办法了。

所以,抽象关键字就来进行强制重写,否则代码就直接报错,抽象方法所在的类就叫抽象类。
小黑子—Java从入门到入土过程:第六章_第211张图片

抽象关键字:abstract

抽象类:
如果一个类中存在抽象方法,那么该类就必须声明为抽象类。(由方法推向类,不是由类推向方法)

抽象方法
在这里插入图片描述
抽象方法的定义格式:
public abstract 返回值类型 方法名(参数列表);
没有方法体

抽象类的定义同理:public abstract class 类名{}

抽象类和抽象方法的注意事项
小黑子—Java从入门到入土过程:第六章_第212张图片
1.抽象类不能创建对象

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

3.抽象类可以有构造方法(作用:当创建子类对象时给子类的属性进行赋值)

4.抽象类的子类分两种情况:

  • 如果子类不是抽象类,则需要重写抽象类中的所有方法
  • 如果子类是抽象类,则没事

ieda便捷键 alt+回车 可以查看报错的内容并且快速修改
小黑子—Java从入门到入土过程:第六章_第213张图片
小黑子—Java从入门到入土过程:第六章_第214张图片

练习:
小黑子—Java从入门到入土过程:第六章_第215张图片
小黑子—Java从入门到入土过程:第六章_第216张图片

Animal类:
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 void drink(){
        System.out.println("动物在喝水");
    }

    public abstract void  eat();
}

Frog类:
public class Frog extends Animal{
    public Frog() {
    }

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

    @Override
    public void eat() {
        System.out.println("青蛙在吃虫子");
    }
}

Dog类:
public class Dog extends Animal{
    public Dog(){}

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

    @Override
    public void eat() {
        System.out.println("狗吃骨头");
    }
}

Sheep类:
public class Sheep extends Animal{

    public Sheep() {
    }

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

    @Override
    public void eat() {
        System.out.println("山羊在吃草");
    }
}

测试类:
public class Test {
    public static void main(String[] args) {
        //创建对象
        Frog f =new Frog("mauga",1);
        System.out.println(f.getName()+","+f.getAge());
        f.drink();
        f.eat();
    }
}

小黑子—Java从入门到入土过程:第六章_第217张图片
抽象类和抽象方法的意义:
在这里插入图片描述
当每个关于同一个行为的代码不统一时,调用时就会非常痛苦
小黑子—Java从入门到入土过程:第六章_第218张图片
用抽象类进行重写
小黑子—Java从入门到入土过程:第六章_第219张图片
总结:
小黑子—Java从入门到入土过程:第六章_第220张图片

6.7 接口

接口就是一种规则,是指父类与子类之间的关系。
下述图片很好的说明了为什么要有接口:
在这里插入图片描述
小黑子—Java从入门到入土过程:第六章_第221张图片

接口的应用:
接口不代表一类事务,他代表一种规则,是对行为的抽象
接口与抽象的区别:
抽象更多是表示一类事物,而接口更多表示行为
小黑子—Java从入门到入土过程:第六章_第222张图片
小黑子—Java从入门到入土过程:第六章_第223张图片
接口的定义和使用:
1.接口用关键字interface定义
public interface 接口名{}

2.接口不能创建对象

3.接口和类是实现关系,通过inplements关键字表示
public class 类名 inplements 接口名{}

4.接口的子类(接口的实现类)
分两种情况:

  • 不是抽象类直接重写所有抽象方法(更多用这种)
  • 是抽象类没事

5.接口里的方法都是抽象方法
小黑子—Java从入门到入土过程:第六章_第224张图片
练习:
小黑子—Java从入门到入土过程:第六章_第225张图片
创建新的类时选择接口的选项
在这里插入图片描述

Animal类:
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 Swim {
    public abstract void swim();
}

Rabbit类:
public class Rabbit extends Animal{
    public Rabbit() {
    }

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

    @Override
    public void eat() {
        System.out.println("兔子在吃胡萝卜");
    }
}

Frog类:
public class Frog extends Animal implements Swim{

    public Frog() {
    }

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

    @Override
    public void eat() {
        System.out.println("青蛙在吃虫子");
    }

    @Override
    public void swim() {
        System.out.println("青蛙在蛙泳");
    }
}

Dog类:
public class Dog extends Animal implements Swim{

    public Dog() {
    }

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

    @Override
    public void eat() {
        System.out.println("狗吃骨头");
    }

    @Override
    public void swim() {
        System.out.println("狗刨式");
    }
}

测试类:
public class Test {
    public static void main(String[] args) {
        Frog f = new Frog("青蛙",1);
        System.out.println(f.getName()+","+ f.getAge());

        f.eat();
        f.swim();


        Rabbit r = new Rabbit("兔子",2);
        System.out.println(r.getName()+","+r.getAge());
        r.eat();

    }
}

小黑子—Java从入门到入土过程:第六章_第226张图片

6.7.1 接口的细节:成员特点和各种接口的关系

接口中成员的特点:
小黑子—Java从入门到入土过程:第六章_第227张图片

inter接口:
public interface Inter {
    //public static final
    int a =10;

    //public abstract
    void method();
}

InterImp1类:
public class InterImp1 implements Inter{

    @Override
    public void method() {
        System.out.println("method");
    }
}

测试类:
import java.util.Scanner;

public class Test {
    public static void main(String[] args) {
        //创建实现对象并调用方法
        InterImp1 li = new InterImp1();
        li.method();

        Scanner sc = new Scanner(System.in);
        sc.next();
        //防止程序运行过快,无法反应
    }
}

在这里插入图片描述
接口和类之间的关系:

  1. 类和类之间的关系
    继承关系,只能单继承,不能多继承,但是可以多重继承
  2. 类和接口的关系
    实现关系,可以单实现,也可以多实现,还可以在继承一个类的同时实现多个接口。
    多个接口中有重名的方法,只需在类里重写一次就行了
  3. 接口与接口之间的关系
    继承关系,可以单继承,也可以多继承。
    如果实现类实现了子接口,那么就需要重写所有的抽象方法
//如果实现类实现了子接口,那么就需要重写所有的抽象方法
//接口1
public interface Inter1{
	public abstract void method1();
}
//接口2
public interface Inter2{
	public abstract void method2();	
}
//接口3
public interface Inter3 extends Inter1,Inter2{
	public abstract void method3();		
}
//实现类
public class InterImpl implements Inter3{
	@Override
	public void method1(){
	
	}
	@Override
	public void method2(){
	
	}
	@Override
	public void method3(){
	
	}
}

总结:
小黑子—Java从入门到入土过程:第六章_第228张图片

6.7.2 接口和抽象类案例

小黑子—Java从入门到入土过程:第六章_第229张图片
流程图思路:
1.
小黑子—Java从入门到入土过程:第六章_第230张图片

2.最优流程图
小黑子—Java从入门到入土过程:第六章_第231张图片

//因为直接创建人的对象是没有意义的,所以直接把person创建为抽象类
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;
    }
}
---------------------------------------------------
package com.inherit4.study;

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

    public athletes(String name, int age) {
        super(name, age);
    }
    public abstract void study();
}
---------------------------------------------------
package com.inherit4.study;

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

    public instructor(String name, int age) {
        super(name, age);
    }
    public abstract void teach();
}
---------------------------------------------------
package com.inherit4.study;

public interface English {
    public abstract void eng();
}
---------------------------------------------------
package com.inherit4.study;

public class ppathletes extends athletes implements English{
    public ppathletes() {
    }

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

    @Override
    public void eng() {
        System.out.println("说英语");
    }

    @Override
    public void study() {
        System.out.println("学打乒乓球");
    }
}
---------------------------------------------------
package com.inherit4.study;

public class bkathletes extends athletes{
    public bkathletes() {
    }

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

    @Override
    public void study() {
        System.out.println("学打篮球");
    }
}
---------------------------------------------------
package com.inherit4.study;

public class ppInstuctor extends instructor implements English{
    public ppInstuctor() {
    }

    public ppInstuctor(String name, int age) {
        super(name, age);
    }
    @Override
    public void eng() {
        System.out.println("说英语");
    }

    @Override
    public void teach() {
        System.out.println("教打乒乓球");
    }
}
---------------------------------------------------
package com.inherit4.study;

public class bkInstucttor extends instructor{
    public bkInstucttor() {
    }

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

    @Override
    public void teach() {
        System.out.println("教打篮球");
    }
}
---------------------------------------------------
package com.inherit4.study;

public class test {
    public static void main(String[] args) {
        ppathletes pa=new ppathletes("zhangsan",18);
        System.out.println(pa.getName()+" "+pa.getAge());
        pa.eng();
        pa.study();
        bkathletes ba=new bkathletes("zhangsi",19);
        System.out.println(ba.getName()+" "+ba.getAge());
        ba.study();
        ppInstuctor pi=new ppInstuctor("lisi",30);
        System.out.println(pi.getName()+" "+pi.getAge());
        pi.eng();
        pi.teach();
        bkInstucttor bi=new bkInstucttor("zhangliu",36);
        System.out.println(bi.getName()+" "+bi.getAge());
        bi.teach();
    }
}

6.7.3 接口的新增方法

jdk7以前,接口中只能定义抽象方法
jdk8以后,接口中可以定义有方法体的方法(默认,静态)
jdk9以后,接口中可以定义私有方法
即jdk8之后,接口里的方法可以有方法体了

小黑子—Java从入门到入土过程:第六章_第232张图片
我又想加新的规则;又想让他们的代码不报错怎么办呢?
小黑子—Java从入门到入土过程:第六章_第233张图片

小黑子—Java从入门到入土过程:第六章_第234张图片

jdk8以后接口中新增的默认方法

允许在接口中定义默认方法,需要使用关键字default修饰
作用:解决接口升级的问题

接口默认方法的定义格式:
public default 返回值类型 方法名(参数列表){方法体}
例如:

public default void show(){}

接口中默认方法的注意事项:

  1. 接口中的默认方法不是抽象方法,所以不强制重写。如果被重写,重写时去掉default 关键字。
  2. public可以省略,default不能省略
  3. 如果实现了多个接口,多个接口中存在相同名字的默认方法,子类就必须对该方法进行重写。
    小黑子—Java从入门到入土过程:第六章_第235张图片
接口A:
public interface InterA {
    public abstract void method();
    public default void show(){
        System.out.println("InterA接口中的默认方法----show");
    }
}

接口Bpublic interface InterB {
    public default void show(){
        System.out.println("InterB接口中的默认方法----show");
    }
}

InterImpl:
public class InterImpl implements InterA,InterB{

    @Override
    public void method() {

    }

    @Override
    public void show() {
        InterA.super.show();
    }
}

测试类:
public class Test {
    public static void main(String[] args) {
        InterImpl ii = new InterImpl();

        ii.show();
    }
}

小黑子—Java从入门到入土过程:第六章_第236张图片

jdk8以后接口中新增的静态方法

jdk8以后接口中新增的方法(静态方法)
静态方法不能重写。
允许在接口中定义静态方法,需要使用关键字static修饰

接口静态方法的定义格式:
public static 返回值类型 方法名(参数列表){方法体}
例如

public static void show(){}

接口中静态方法的注意事项:

  1. 接口中的静态方法只能通过接口名调用,不能通过实现类名或者对象名调用
  2. public可以省略,static不能省略
    小黑子—Java从入门到入土过程:第六章_第237张图片

重写的概念:
小黑子—Java从入门到入土过程:第六章_第238张图片

jdk9新增的私有方法

小黑子—Java从入门到入土过程:第六章_第239张图片

为什么在接口中增加私有方法?

对于一些重复代码,是对单独一个接口中其他方法去服务的,不想被外类去访问,因为外类访问是没有意义的,因此在接口中出现了私有方法

接口中私有方法的定义格式:
格式1:private 返回值类型 方法名(参数列表){}(不加default关键字,给默认方法服务,即默认方法中的重复代码)
例如:

private void show(){}

格式2:private static 返回值类型 方法名(参数列表){}(给静态方法服务,即静态方法中的重复代码)
例如:

private static void method(){}

小黑子—Java从入门到入土过程:第六章_第240张图片

小结:
小黑子—Java从入门到入土过程:第六章_第241张图片

6.7.4 接口应用

小黑子—Java从入门到入土过程:第六章_第242张图片

  1. 把多个类都有可能用到的规则定义成接口,对实现类来讲,想要要实现类拥有什么样的功能,就实现对应的接口就行了。
    即接口代表规则,是行为的抽象。想要让哪个类拥有一个行为,就让这个类实现对应的接口就行了
  2. 当一个方法的参数是接口时,可以传递接口所有实现类的对象,这种方式称之为接口多态。

在这里插入图片描述
小结:

小黑子—Java从入门到入土过程:第六章_第243张图片

6.7.5 适配器设计模型

设计模式:

设计模式是一套被反复利用,多数人知晓的,经过分类编目的,代码设计经验的总结。使用设计模式是为了可重用代码,让代码更容易被他人理解,保证代码可靠性,程序的重用性。

简单理解:设计模式就是各种套路

适配器设计模式:

  • 解决接口与接口实现类之间的矛盾问题
    就是在接口和实现类中间加上一个单独的类,这个类把接口里的所有方法重写(空着),然后,实现类使用时只需要重写需要的方法就行了

注意,中间类的名字是XXXAdapder

接口:
小黑子—Java从入门到入土过程:第六章_第244张图片

中间类:
小黑子—Java从入门到入土过程:第六章_第245张图片

实现类:继承中间的适配器,不让外界创建它的对象
小黑子—Java从入门到入土过程:第六章_第246张图片

总结:
小黑子—Java从入门到入土过程:第六章_第247张图片

6.8 初始内部类

类的五大成员:
属性,方法,构造方法,代码块,内部类
内部类就是在一个类里再定义的类
例如:

public class Person{
	public class Student{

	}
}

小黑子—Java从入门到入土过程:第六章_第248张图片
为什么要学习内部类?
小黑子—Java从入门到入土过程:第六章_第249张图片
代码实现:
小黑子—Java从入门到入土过程:第六章_第250张图片

内部类的分类
分为:

  1. 成员内部类
  2. 静态内部类
  3. 局部内部类
  4. 匿名内部类

前三种了解一下哎,写代码时能看懂,会用就行,最后一种匿名内部类需要掌握

person类里的student就是内部类,person就是外部类
跟这两个类无关的其他所有类就是外部其他类

  1. 定义内部类的规则: 内部类表示的事物是外部类的一部分 内部类单独出现没有任何意义
  2. 内部类的访问特点: 内部类可以直接访问外部类的成员,包括私有的 外部类要访问内部类的成员,必须在外部类里创建对象

案例:

总结:
小黑子—Java从入门到入土过程:第六章_第251张图片

6.8.1 成员内部类

写在成员位置的内部类就是成员内部类
小黑子—Java从入门到入土过程:第六章_第252张图片

public class Car {
    private String carName;
    private int carAge;
    private String carColor;
    eng neng=new eng();
    public void show2(){
        System.out.println(neng.engAge+" "+neng.engName+" "+neng.engColor);
    }

    class eng{//这里就是成员内部类
        String engName;
        int engAge;
        String engColor;
        public void show1(){
            System.out.println(carName+" "+carAge+" "+carColor);
        }
    }
}

小黑子—Java从入门到入土过程:第六章_第253张图片

  • 成员内部类代码的书写
    1.写在成员位置的,属于外部类的成员,有着成员的性质
    2.成员内部类可以被一些修饰符所修饰,比如:private,默认,protected,public,static(用static修饰的内部类就不是成员内部类了,是静态内部类)
    3.成员内部类里可以定义静态变量(jdk16以后)

成员内部类的创建

  • 方式1:(private修饰时会使用)
    在外部类中编写方法,对外提供内部类的对象,可以用Object创建一个先对象来接收内部类对象的返回值,也可以直接使用

注意版本要匹配:
小黑子—Java从入门到入土过程:第六章_第254张图片

方式1的例子:

public class Outer {
	private String name;
    private class Inner{
       
        }
    public Inner getInner(){//创建方法
		return new Inner();
	}
}
Outer o=new Outer();
o.getInner();//调用方法
  • 方式2: 直接创建格式:外部类名.内部类名 对象名=外部类对象(new 对象).内部类对象(new 对象);
//这里相当于内部类是外部类的成员,创建外部类对象后调用
Outer.Inner duixiang= new Outer().new Inner();
//这里Outer是外部类名,Inner是内部类名

成员内部类获取外部类的成员变量(使用Outer.this.变量,Outer是外部类名)

练习:
小黑子—Java从入门到入土过程:第六章_第255张图片
内存图解析:
小黑子—Java从入门到入土过程:第六章_第256张图片

Outer类:
public class Outer {
    private int a =10;

    class Inner{
        private int a =20;
        public void show(){
            int a = 30;
            System.out.println(Outer.this.a);
            System.out.println(this.a);
            System.out.println(a);
        }
    }
}

测试类:
public class Test {
    public static void main(String[] args) {
        //创建内部类的对象,并调用show方法
        Outer.Inner oi = new Outer().new Inner();
        oi.show();
    }
}

小黑子—Java从入门到入土过程:第六章_第257张图片
小结:
小黑子—Java从入门到入土过程:第六章_第258张图片

6.8.2 静态内部类

小黑子—Java从入门到入土过程:第六章_第259张图片
例子:

public class Outer {
	int a=10;
	static String name="111";
	//静态内部类
    static class Inner{
   		public void show1(){
   			Outer oi=new Outer();
   			sout(oi.a);//外部类的非静态对象需要创建对象才能访问
			sout(name);//外部类的静态变量可以直接访问
		}
		public static void show2(){
   			Outer oi=new Outer();
   			sout(oi.a);//外部类的非静态对象需要创建对象才能访问
			sout(name);//外部类的静态变量可以直接访问
		}    
   }
}
  • 创建静态内部类的语法: 外部类名.内部类名 对象名=new 外部类名.内部类名();
    例如: Outer.Inner oi=new Outer.Inner();(这里new的是Inner)
  • 用静态内部类对象调用静态内部类中的非静态方法:
    先创建对象,用对象调用
  • 调用静态内部类中的静态方法:
    直接调用:Outer.Inner.方法名()

案例:

public class Outer {
	//静态内部类
    static class Inner{
   		public void show1(){
			sout(非静态的方法被调用了);
		}
		public static void show2(){
			sout(静态的方法被调用了);
		}    
   }
}
//调用
//调用静态内部类里的非静态的方法,需要先创建一个静态内部类对象,然后用对象调用
Outer.Inner oi=new Outer.Inner();
oi.show1();
//调用静态内部类里的静态的方法,可以直接通过 外部类.内部类.方法名() 调用
Outer.Inner.show2();

小结:
小黑子—Java从入门到入土过程:第六章_第260张图片

6.8.3 局部内部类

小黑子—Java从入门到入土过程:第六章_第261张图片
案例:

Outer类:
public class Outer {
    int b=20;
    public void show(){
        int a=10;
        //局部内部类
        class Inner{
            String name;
            int age;

            public void method1(){
                System.out.println(a);
                System.out.println(b);
                System.out.println("局部内部类中的method1方法");
            }
            public static void method2(){
                System.out.println("局部内部类中的method2静态方法");
            }
        }

        //创建局部内部类的对象
        Inner i = new Inner();
        System.out.println(i.name);//null
        System.out.println(i.age);//0
        i.method1();
        Inner.method2();
    }
}

测试类:
public class Test {
    public static void main(String[] args) {
        Outer o = new Outer();
        o.show();
    }
}

小黑子—Java从入门到入土过程:第六章_第262张图片

6.8.4 匿名内部类

匿名内部类的本质就是隐藏了名字的内部类,可以写在成员位置,也可以写在局部位置

小黑子—Java从入门到入土过程:第六章_第263张图片
匿名内部类有三个特点:
1.实现或继承关系
2.方法的重写
3.创建对象

匿名内部类的语法:

new 类名或接口名(){
	重写方法();//类或接口的抽象方法的重写
};
//这一段代码的返回值是一个对象,可以被对象变量接收

例如:

new Inter(){
	public void show(){

	}
};

小黑子—Java从入门到入土过程:第六章_第264张图片
在这里插入图片描述

即:

new Swim(){//这里的new创建的是后面没有名字的类的对象
	@Override
	public void swim(){
		sout("重写的游泳方法");
	}
};
/*这一部分从语法上来解释,应该叫做匿名内部类的对象
new Swim(){
	@Override
	public void swim(){
		sout("重写的游泳方法");
	}
};
*/
/*这一部分才是没有名字类的主体,即匿名内部类,实现了Swim这个接口
{
	@Override
	public void swim(){
		sout("重写的游泳方法");
	}
};*/

以上代码有三个特点

  • 1.实现关系
  • 2.方法的重写
  • 3.创建对象

同理,当Swim换成一个类名时,特点就变为了

1.继承关系
2.方法的重写
3.创建对象

此时匿名内部类的主题就是父类的子类

new Fulei(){//这里的new创建的是后面没有名字的类的对象
	@Override
	public void show(){
		sout("重写的show方法");
	}
};
/*这一部分从语法上来解释,应该叫做匿名内部类的对象
new Fulei(){
	@Override
	public void show(){
		sout("重写的show方法");
	}
};
*/
/*这一部分才是没有名字类的主体,即匿名内部类,继承了Fulei的子类
{
	@Override
	public void show(){
		sout("重写的show方法");
	}
};*/

应用场景
可以作为方法的实参,不用再写格外的类

比如:

//Animal类(父类)
public abstract class Animal{
	public void eat(){
		sout("吃东西")
	}
}
//Dog类(子类)
public class Dog extends Animal{
	@Override
	public void eat(){
		sout("狗吃骨头")
	}
}
//测试类
psvm(String[] args){
	//以前调用method方法
	Dog d=new Dog();
	method(d);
	//使用匿名内部类调用method方法
	method(
		new Animal(){
		@Override
		public void eat(){
			sout("狗吃骨头")
		}
	}
)
/*
new Animal(){
		@Override
		public void eat(){
			sout("狗吃骨头")
		}
	}
	这个整体就相当于:Animal a=子类对象 ,即多态
*/
	public static void method(Animal a){
		a.eat();
	} 
}

拓展:
可以直接用语法的形式调用对象
小黑子—Java从入门到入土过程:第六章_第265张图片
同理

new Fulei(){//这里的new创建的是后面没有名字的类的对象
	@Override
	public void show(){
		sout("重写的show方法");
	}
}.show();//所以可以调用自己里面的方法

小结:
小黑子—Java从入门到入土过程:第六章_第266张图片

你可能感兴趣的:(java,java,jvm,开发语言)