当前位置: 首页 > article >正文

小黑子—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 文字版格斗游戏=

在这里插入图片描述
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;
            }
        }
    }
}

在这里插入图片描述

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

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

在这里插入图片描述

关于printf和print和println的区别

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

1.2 对象数组练习

1.2.1 练习一

在这里插入图片描述
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());
        }
    }
}

在这里插入图片描述

1.2.2 练习二

在这里插入图片描述
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());
        }
    }
}

在这里插入图片描述

1.2.3 练习三

在这里插入图片描述
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);
    }
}

在这里插入图片描述

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中出现空格时,可会给下一个键盘的数据接受,就不会做键盘录入
在这里插入图片描述
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);
    }

在这里插入图片描述

第二套体系:

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

在这里插入图片描述
但是重要的是,键盘录入的两套体系不能混用
弊端:

  • 先用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);//录入不了,就结束了
    }

在这里插入图片描述

1.4 复杂对象数组练习

1.4.1 复杂练习一

在这里插入图片描述
思考要求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());
            }
        }
    }
}

在这里插入图片描述
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());
            }
        }
    }

}

在这里插入图片描述

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

在这里插入图片描述
例子:
其他的API都是存储在JDK-API帮助文档.CHM
在这里插入图片描述
在这里插入图片描述

2.1 使用帮助文档

在这里插入图片描述
API使用步骤
在这里插入图片描述

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

可以寻找关键字
在这里插入图片描述
在这里插入图片描述
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);
    }

在这里插入图片描述

3. 字符串String

常见情况:
在这里插入图片描述
字符串概述:
在这里插入图片描述
注意:
在这里插入图片描述
总结:
在这里插入图片描述

3.1 创建String对象的两种方式

其有两种:
直接赋值和用new去构造一个方法
在这里插入图片描述

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

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

在这里插入图片描述

字符串常量池
在这里插入图片描述

只有直接赋值的字符串才会在这个空间中 在堆内存中
在这里插入图片描述

当串池中已经存在一个abc字符串时,再次给字符串变量赋值相同的值时,会直接复用之前相同字符串的地址。
在这里插入图片描述

在这里插入图片描述
每new一次,就会在堆空间创建一个新的空间,可能会造成内存的浪费
所以,还是推荐使用直接赋值创建字符串。
在这里插入图片描述

3.2 字符串的比较

在这里插入图片描述
==号比较的原理
在这里插入图片描述
字符串常见比较错误:
在这里插入图片描述
对于不同方式字符串的内容比较:
在这里插入图片描述
例如:
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 练习一:用户登录

在这里插入图片描述

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)+"次机会");//
                }
            }
        }
    }

在这里插入图片描述

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

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

在这里插入图片描述

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

在这里插入图片描述
2.
在这里插入图片描述

   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+"个");
    }

在这里插入图片描述

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

在这里插入图片描述

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

在这里插入图片描述
2.
在这里插入图片描述

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

在这里插入图片描述

3.3.4 练习四

3.3.5 练习五

3.4 StringBuilder

使用StringBuilder的场景:

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

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

在这里插入图片描述

3.4.1 StringBuilder构造方法

在这里插入图片描述

3.4.2 StringBuilder常用方法

在这里插入图片描述
1.append 添加方法

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

    }

所以它没有返回一个地址值
在这里插入图片描述

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();

在这里插入图片描述

3.length 获取长度方法

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

在这里插入图片描述

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

在这里插入图片描述
2.
将上方3.4.2内容的第4点:

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

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

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

练习:
1.
在这里插入图片描述
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("当前字符串不是对称字符串");
        }
    }
}

在这里插入图片描述
2.
在这里插入图片描述

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

在这里插入图片描述

3.4.4 StringJoiner

对于有时候StringBuilder按照数组拼接字符串的时候就比较麻烦了,中间有的时候拼,有的时候不拼
在这里插入图片描述
StringJoiner概述:
在这里插入图片描述
StringJoiner对象的创建
在这里插入图片描述

StringJoiner的成员方法
在这里插入图片描述

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

在这里插入图片描述
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);//字符串的类型
    }

在这里插入图片描述

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

3.4.5 字符串原理

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

在这里插入图片描述

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

在这里插入图片描述
1.当等号的右边没有变量时:
在这里插入图片描述
在编译的时候,就会将"a"+ “b” +“c"拼接为"abc”

2.当等号的右边有变量时:
在这里插入图片描述

在这里插入图片描述

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

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

在这里插入图片描述
面试练习题:

在这里插入图片描述
2.

在这里插入图片描述

那就采用StringBuilder 和StringJoiner 进行优化

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

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

在这里插入图片描述
3、4原理小结:
在这里插入图片描述

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

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

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

在所有位置里寻找,搜索界面默认在当前项目文件里找不到
在这里插入图片描述

--------->
在这里插入图片描述
ctrl + f12 ---->寻找toString
在这里插入图片描述

3.4.6 字符串综合练习

在这里插入图片描述
2.
在这里插入图片描述
3.

4. 集合

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

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

在这里插入图片描述
在这里插入图片描述

4.1 ArrayList 集合(之一)

ArrayList集合的创建:

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

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

ArrayList成员方法
在这里插入图片描述

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

在这里插入图片描述

4.2 集合综合练习

4.2.1 添加字符串和整数遍历

在这里插入图片描述

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("]");

    }

在这里插入图片描述
2.
在这里插入图片描述
下方遍历代码一样,中间改变

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 基本数据类型的包装类

这里的包装类实际上就是泛型里的关键字
在这里插入图片描述
jdk5以后int Intleger 之间是可以互相转化的

4.2.3 添加学生对象并遍历

在这里插入图片描述

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.
在这里插入图片描述
遍历思路:
在这里插入图片描述

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

在这里插入图片描述

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

在这里插入图片描述
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;
    }
}

在这里插入图片描述

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;
        //返回的是集合,函数的返回值类型就得是集合
    }

在这里插入图片描述

5. 学生管理系统

学会阅读需求文档,在了解需求文档后,自己画出需求的结构流程图(业务流程图)
在这里插入图片描述
流程图:
在这里插入图片描述
Ctrl + alt + t 全选中内容后,快捷生成结构环绕方式
在这里插入图片描述
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<Student> 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;
    }
}


在这里插入图片描述

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

5.1 学生管理系统升级版

需求图:
在这里插入图片描述在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
流程图:
在这里插入图片描述

1.注册
在这里插入图片描述
2.登录
在这里插入图片描述
3.忘记密码

在这里插入图片描述

6. 面向对象进阶

6.1 static

6.1.1 static-静态变量

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

在这里插入图片描述
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();

    }

在这里插入图片描述
当这里的teacherName被赋值后,static会被Student类里所有对象共享(公共的一个属性)

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

示意图:
在这里插入图片描述
静态区里的变量是对象共享的,在内存中只有一份,谁用谁拿,非静态的变量是每一个对象所独有的,每一个对象里的非静态的变量都是单独存放的。

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

6.1.2 static-静态方法和工具

静态方法

在这里插入图片描述

工具类

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

目前一共学习了三种类
在这里插入图片描述
工具类的要求:
在这里插入图片描述

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

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

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

练习:
1.
在这里插入图片描述
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.
在这里插入图片描述
工具类:

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

在这里插入图片描述

6.1.3 static-注意事项

在这里插入图片描述
在非静态方法中,有一个隐藏的this,这个this就表示当前方法调用者的地址值
在这里插入图片描述
在第一次调用show()方法时,虚拟机就会把第一次调用者的地址赋值给方法中的this,就像图中所示
第二次同理,虚拟机会把第二次调用者的地址赋值给方法中的this

在这里插入图片描述
this的值

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

在这里插入图片描述

上面sout里的this可以省略

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

示意图:
在这里插入图片描述
在这里插入图片描述

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

在这里插入图片描述

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

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

在这里插入图片描述

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

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

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

在这里插入图片描述

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

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

6.1.4 重新认识main方法

JVM:虚拟机
在这里插入图片描述例子:
在这里插入图片描述

点击IDEA右上角的锤子旁边的按钮
在这里插入图片描述
在程序参数里填写,args即可返回值
在这里插入图片描述
在这里插入图片描述

6.2 继承

6.2.1 封装

封装:

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

像这种相同的行为太多了,这时候就需要用到封装
在这里插入图片描述
在这里插入图片描述
封装完行为方法之后,就要用到继承了
在这里插入图片描述

6.2.2 继承的描述

继承实际上就是类跟类之间的父子关系
在这里插入图片描述
什么时候用继承?
在这里插入图片描述
小结:
在这里插入图片描述
继承需要学习的点:
在这里插入图片描述

6.2.3 继承的特点

在这里插入图片描述
即儿子继承父亲,父亲继承爷爷
在这里插入图片描述
即子类的父类是直接父类,父类的父类是子类的间接父类

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

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

练习:
在这里插入图片描述
设计继承体系时,尽量先搞清楚体系逻辑,画一张图,从子类到父类
设计的核心就是:共性的内容抽取,子类是父类的一种
书写代码时,从父类到子类

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

6.2.4 子类继承父类的特性

在这里插入图片描述

  1. 构造方法:不论私有(private)还是非私有(像public等)的构造方法,子类都是不能继承的
    在这里插入图片描述
    例子:
    在这里插入图片描述

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

1.没有用private修饰的继承成员变量的内存图:
在这里插入图片描述
2.有用private修饰的继承成员变量的内存图:
在这里插入图片描述

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

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

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

运行效率低下:
在这里插入图片描述
以下如此可以大大提高性能:
在这里插入图片描述
例子:
在这里插入图片描述

6.2.5 终端的jps和jhsdb hsdb

在终端中输入jps,得到类中获得的id
在这里插入图片描述
输入jhsdb hsdb 打开HotSpot Debugger

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

在这里插入图片描述
在file中寻找到第一个点击进入
在这里插入图片描述
从jps中获得的id输入,ok

在这里插入图片描述
之后显示
在这里插入图片描述

在tools里找到Memory Viewer
在这里插入图片描述
在tools里找到Inspector
在这里插入图片描述
在这里插入图片描述

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

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

在这里插入图片描述
在上述代码中,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);
    }
}

在这里插入图片描述
2.
在这里插入图片描述
即使用this关键字可以访问本类的成员变量,使用super关键字可以访问父类的成员变量。
语法:

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

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

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

继承成员方法

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

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

在这里插入图片描述
在这里插入图片描述
方法重写的本质:

新的方法覆盖旧的方法(虚方法表)
在这里插入图片描述

在这里插入图片描述
方法重写注意事项和要求:
在这里插入图片描述
私有方法不能进行重写,重写方法时也可以调用父类的方法

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

6.2.6 继承中的构造方法

  • 特点
    1.父类中的构造方法不会被子类继承
    2.子类中所有的构造方法默认先访问父类中的无参构造,再执行自己
    在这里插入图片描述
    第二条出现的原因
    在这里插入图片描述
    例子:
    在这里插入图片描述
    在这里插入图片描述

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

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

6.2.7 this、super关键字总结

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

在这里插入图片描述

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

this与super的区别

关键字访问成员变量访问成员方法访问构造方法
thisthis.成员变量 访问本类成员变量this.成员方法访问本类成员方法this(…)访问本类构造方法
supersuper.成员变量 访问父类成员变量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()
练习:
在这里插入图片描述

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

在这里插入图片描述

6.3 认识多态

在这里插入图片描述
多态的概念:
封装是多态的必要条件,继承是多态的前提条件

在这里插入图片描述
多态的应用场景:
在这里插入图片描述
不同的用户对象,采用同样的代码模块会出现冗余
在这里插入图片描述
解决方案:
在这里插入图片描述
多态的含义

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

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

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

在这里插入图片描述
例子:

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

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

6.3.1 多态中调用成员的特点

父类 对象名=new 子类()
在这里插入图片描述
遵循两个口诀:

  1. 编译看左边的解释: javac编译代码时,会看左边的父类有没有这个变量或方法,如果有,编译成功,如果没有,编译失败,即必须要有父类的方法
    在这里插入图片描述
    在这里插入图片描述

  2. 运行也看左边的解释: javac运行代码的时候,实际获取的就是左边父类中成员变量的值。
    在这里插入图片描述
    在这里插入图片描述
    即对象调用遵循以上两个规则。
    同理,方法调用也是如此,只不过在运行时会运行子类的方法,即 右边

内存图解:
在这里插入图片描述
例子:

//父类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 多态的优势和弊端

优势
在这里插入图片描述
即只需把后面标红的代码修改就可以了

弊端:

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

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

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("没有这个类型,无法转换");
        }

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

6.3.4 多态综合练习

在这里插入图片描述

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,"鱼");

    }
}

在这里插入图片描述

6.4 包和 final

6.4.1 包

包的起名规则:
公司域名反写+包的作用
在这里插入图片描述
包名加上类名才是全部的类名,下面的名字太长了
在这里插入图片描述
改进:如果想在一个包里使用其他包的类名,就需要引用使用的那个包的名字加上类名
import 包名.类名
在这里插入图片描述
这样就可以使用其他包的类了
注意事项:
使用两个包的同名类时,不需要导包了,直接使用同名类
在这里插入图片描述

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

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

在代码中,一旦被final修饰,就表示被修饰的内容不能改变了,有点像JavaScript的const。
final可以修饰方法,类,和变量
在这里插入图片描述

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

在这里插入图片描述
使用final的场景:

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

常量:
在这里插入图片描述
主要是第二点,对象的内部可以改变。

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

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

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

6.5 权限修饰符和代码块

6.5.1 权限修饰符

在这里插入图片描述
权限修饰符的分类:
有四种类,被访问的范围从小到大分为:private<空着不写(默认情况)<protected<public

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

在这里插入图片描述

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

在这里插入图片描述

6.5.2 代码块

在这里插入图片描述
代码块可以分为三类

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

  • 局部代码块
    在这里插入图片描述

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

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

在这里插入图片描述
这个技术现在也渐渐淘汰了
可以将重复的代码抽取成一个方法,构造方法需要使用时直接调用方法就行了。
在这里插入图片描述

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

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

6.6 抽象类和抽象方法

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

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

所以,抽象关键字就来进行强制重写,否则代码就直接报错,抽象方法所在的类就叫抽象类。
在这里插入图片描述

抽象关键字:abstract

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

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

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

抽象类和抽象方法的注意事项
在这里插入图片描述
1.抽象类不能创建对象

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

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

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

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

ieda便捷键 alt+回车 可以查看报错的内容并且快速修改
在这里插入图片描述
在这里插入图片描述

练习:
在这里插入图片描述
在这里插入图片描述

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

在这里插入图片描述
抽象类和抽象方法的意义:
在这里插入图片描述
当每个关于同一个行为的代码不统一时,调用时就会非常痛苦
在这里插入图片描述
用抽象类进行重写
在这里插入图片描述
总结:
在这里插入图片描述

6.7 接口

接口就是一种规则,是指父类与子类之间的关系。
下述图片很好的说明了为什么要有接口:
在这里插入图片描述
在这里插入图片描述

接口的应用:
接口不代表一类事务,他代表一种规则,是对行为的抽象
接口与抽象的区别:
抽象更多是表示一类事物,而接口更多表示行为
在这里插入图片描述
在这里插入图片描述
接口的定义和使用:
1.接口用关键字interface定义
public interface 接口名{}

2.接口不能创建对象

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

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

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

5.接口里的方法都是抽象方法
在这里插入图片描述
练习:
在这里插入图片描述
创建新的类时选择接口的选项
在这里插入图片描述

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();

    }
}

在这里插入图片描述

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

接口中成员的特点:
在这里插入图片描述

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(){
	
	}
}

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

6.7.2 接口和抽象类案例

在这里插入图片描述
流程图思路:
1.
在这里插入图片描述

2.最优流程图
在这里插入图片描述

//因为直接创建人的对象是没有意义的,所以直接把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之后,接口里的方法可以有方法体了

在这里插入图片描述
我又想加新的规则;又想让他们的代码不报错怎么办呢?
在这里插入图片描述

在这里插入图片描述

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

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

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

public default void show(){}

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

  1. 接口中的默认方法不是抽象方法,所以不强制重写。如果被重写,重写时去掉default 关键字。
  2. public可以省略,default不能省略
  3. 如果实现了多个接口,多个接口中存在相同名字的默认方法,子类就必须对该方法进行重写。
    在这里插入图片描述
接口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();
    }
}

在这里插入图片描述

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

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

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

public static void show(){}

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

  1. 接口中的静态方法只能通过接口名调用,不能通过实现类名或者对象名调用
  2. public可以省略,static不能省略
    在这里插入图片描述

重写的概念:
在这里插入图片描述

jdk9新增的私有方法

在这里插入图片描述

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

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

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

private void show(){}

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

private static void method(){}

在这里插入图片描述

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

6.7.4 接口应用

在这里插入图片描述

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

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

在这里插入图片描述

6.7.5 适配器设计模型

设计模式:

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

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

适配器设计模式:

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

注意,中间类的名字是XXXAdapder

接口:
在这里插入图片描述

中间类:
在这里插入图片描述

实现类:继承中间的适配器,不让外界创建它的对象
在这里插入图片描述

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

6.8 初始内部类

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

public class Person{
	public class Student{

	}
}

在这里插入图片描述
为什么要学习内部类?
在这里插入图片描述
代码实现:
在这里插入图片描述

内部类的分类
分为:

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

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

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

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

案例:

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

6.8.1 成员内部类

写在成员位置的内部类就是成员内部类
在这里插入图片描述

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

在这里插入图片描述

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

成员内部类的创建

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

注意版本要匹配:
在这里插入图片描述

方式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是外部类名)

练习:
在这里插入图片描述
内存图解析:
在这里插入图片描述

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

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

6.8.2 静态内部类

在这里插入图片描述
例子:

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();

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

6.8.3 局部内部类

在这里插入图片描述
案例:

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

在这里插入图片描述

6.8.4 匿名内部类

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

在这里插入图片描述
匿名内部类有三个特点:
1.实现或继承关系
2.方法的重写
3.创建对象

匿名内部类的语法:

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

例如:

new Inter(){
	public void show(){

	}
};

在这里插入图片描述
在这里插入图片描述

即:

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

拓展:
可以直接用语法的形式调用对象
在这里插入图片描述
同理

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

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


http://www.kler.cn/a/9767.html

相关文章:

  • 24.11.13 Javascript3
  • 项目集章程program charter
  • C/C++精品项目之图床共享云存储(3):网络缓冲区类和main
  • Openstack7--安装消息队列服务RabbitMQ
  • 【pytorch】常用强化学习算法实现(持续更新)
  • 以色列支付龙头遭DDoS攻击,各地超市加油站等POS机瘫痪
  • 【openAI】调用gpt-xxx模型时显示网络连接错误(Error communicating with openAI...)
  • 封仲淹:OceanBase开源技术生态全景解析
  • Java基础教程之Object类是怎么回事?
  • 采用多种方式实现项目的查询多级缓存(四)
  • Java模拟rank() over()函数获取分组排名的方法设计及实现
  • 书 | 图理论 | 2020年GraphSage提出者William L. Hamilton《图表示学习》
  • Systemverilog中Constrained random value generation的记录
  • linux之pthread_join函数
  • 安全防御 --- APT、密码学
  • 《数据库系统概论》第三章课后习题 (4个表+三建工程项目)
  • JAVA所有版本特性【JAVA 1.0 - JAVA 20】
  • 圣戈班Saint-Gobain EDI需求分析
  • 计算机网络 - TCP的效率与特性
  • 从0到1基于ChatGLM-6B使用LaRA进行参数高效微调 审核中
  • 49.现有移动端开源框架及其特点—MACE( Mobile AI Compute Engine)
  • 3、ThingsBoard使用jar包单机部署
  • cadence allegro学习记录(四)
  • Golang每日一练(leetDay0030)
  • CDH 之 Kerberos 安全认证和 Sentry 权限控制管理(一)
  • 指令系统和寻址方式