【学习日记2023.3.26】之包_多态_抽象类_接口

1. 包

1.1 什么是包?

  • 包是用来分门别类的管理各种不同类(java文件)的,类似于文件夹、建包利于程序的管理和维护

  • 建包的语法格式:package 公司域名倒写.技术名称。包名建议全部英文小写,且具备意义

  • package com.itheima.domain; // 存储Javabean 起名字叫domain
    public class Student{}
    
  • 建包语句必须在第一行, 一般IDEA工具会帮助创建

1.2 导包

  • 相同包下的类可以直接访问, 不同包下的类必须导包,才可以使用!(java.lang包的除外)
  • 格式: import 包名.类名;
  • 假如一个类中需要用到不同的类,而这两个类的名称是一样的,那么默认只能导入一个类,另一个类要带包名访问

请添加图片描述

2. 多态

2.1 多态的概述

  • 什么是多态
    • 在继承/实现关系中, 不同子类的对象会展现各自的行为.这种现象叫多态
  • 前提
    • 有继承/实现关系
    • 有方法的重写
    • 有父类的引用指向子类的对象: (父类的类型可以记录任意子类的对象)
      • 格式: 父类名 变量名 = new 子类名();
      • 示例: Fu f = new Zi();
  • 注意: 成员变量没有多态
  • 代码演示
    • 父类: 人(Person)的类
      • 成员变量: 年龄(age)
      • 方法: 跑(run)
    • 子类: 老师类(Teacher)
      • 成员变量: 年龄(age)
      • 方法:
        • 跑(run): 老师跑的慢
        • 教学(teach): 老师在上课
    • 子类: 学生类(Student)
      • 成员变量: 年龄(age)
      • 方法:
        • 跑(run): 学生跑的快
        • 学习(study): 学生在学习
public class Person {
    public int age = 10;
    public void run(){
        System.out.println("跑");
    }
}
public class Student extends Person{
    public int age = 23;
    @Override
    public void run() {
        System.out.println("学生跑的快~~~");
    }
    public void study() {
        System.out.println("好好学习~~~");
    }
}
public class Teacher extends Person{
    public int age = 40;
    @Override
    public void run() {
        System.out.println("老师跑的慢~~~~~");
    }
    public void teach() {
        System.out.println("好好上课~~~");
    }
}

public class Demo1 {
    /*
        在继承/实现关系中 不同子类的对象会展现各自的行为.这种现象就是多态

        前提:
            1.要有继承/实现关系
            2.要有方法的重写
            3.父类的引用指向子类的对象(父类类型的变量可以记录任意子类的对象)
                父类类型 变量名 = 子类的对象
                Fu f = new Zi();

        不同子类会展现各自的行为
            Person p = new Teacher();  p.run() 执行Teacher中的run方法
            Person p = new Student();  p.run() 执行Student中的run方法

        注意: 成员变量没有多态现象
     */
    public static void main(String[] args) {
        Person p = new Student();
//        Person p = new Teacher();
        p.run();
        System.out.println(p.age); // 成员变量没有多态现象
    }
}

1.2 多态的好处和弊端

好处:多态形势下,右边的对象是解耦合的,便于扩展和维护

People p = new Teacher()/new Student() ....;
p.run();

常见的使用场景: 定义方法时,使用父类类型的参数,可以接收一切子类的对象,提高扩展性

public class Demo2 {

    public static void main(String[] args) {
        Student s = new Student();
        show(s);

        Teacher t = new Teacher();
        show(t);
    }

    // 多态的好处: 定义方法时,使用父类类型的参数,可以接受一切子类的对象,提高扩展性
    public static void show(Person p){ // Person p = ?
        p.run();
    }
}

弊端:不能使用子类特有的方法

public class Demo2 {
    public static void main(String[] args) {
        Student s = new Student();
        show(s);

        Teacher t = new Teacher();
        show(t);
    }


    public static void show(Person p){ // Person p = ?
        p.run();
        // 多态的弊端: 不能使用子类特有的方法
                // p.study(); // 编译错误
        // p.teach(); // 编译错误
    }
}

1.3 类型转换

  • 多态的弊端: 无法使用子类特有的方法
  • 如何解决? 强制类型转换

1.4 类型转换语法

  • 自动类型转换
    • 父类名 变量名 = new 子类();
    • Person p = new Teacher();
  • 强制类型转换
    • 子类 变量名 = (子类) 父类变量
    • Teacher t = (Teacher)p;
Student s = (Student) p;
s.study();

ClassCastException

  • 强制类型转换,有可能出现类型转换异常ClassCastException
  • 原因: 运行时,变量记录的真实类型与强转后的类型不同
Person p = new Teacher(); // p变量记录的真实类型为Teacher
Student s = (Student)p; // 与强转后Student的类型不一致,ClassCastException

instanceof

  • 作用: 判断真实类型,避免类型转换异常
  • p instanceof Student
    • 涵义: 判断p变量记录的真实类型 是否为 Student
      • 如果是: 结果为true
      • 如果不是: 结果为false
if(p instanceof Student){
    // 如果p记录的真实类型是Student,再强转
    Student s = (Student) p;
    s.study();
}
if(p instanceof Teacher){
    // 如果p记录的真实类型是Teacher,再强转
    Teacher t = (Teacher) p;
    t.teach();
}

1.5 练习

  • 定义动物类(Animal)
    • 成员变量:昵称(nickname),年龄(age)
    • 构造方法:无参,带参
    • 成员方法:
      • get/set
      • 吃东西(eat)
        • 打印=> 动物吃东西
  • 定义猫类(Cat),继承Animal
    • 构造方法:无参,带参
    • 成员方法:
      • 重写吃(eat) , 打印 => 猫吃鱼
      • 捉老鼠(catchMouse), 打印=> 猫会捉老鼠
  • 定义狗类(Dog),继承Animal
    • 构造方法:无参,带参
    • 成员方法:
      • 重写吃(eat) , 打印 => 狗吃肉
      • 看门(watch), 打印=> 狗会看门
  • 定义测试类(Demo),写代码测试
    • 在main方法平级的位置 定义 静态方法show
      • 参数: (Animal a)
      • 代码
        • 调用a.eat();
        • 使用instanceof关键字判断 a 记录的真实类型
          • 如果a 记录的是Dog, 调用看门(watch)方法
          • 如果a 记录的是Cat,调用捉老鼠(catchMouse)方法
    • 在main方法中调用show方法,传递不同的对象,观察程序运行结果
public class Animal {
    private String nickname;
    private int age;

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

    public Animal() {
    }

    public String getNickname() {
        return nickname;
    }

    public void setNickname(String nickname) {
        this.nickname = nickname;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }
    public void eat(){
        System.out.println("动物吃东西");
    }
}
public class Dog extends Animal{
    public Dog(String nickname, int age) {
        super(nickname, age);
    }

    public Dog() {
    }

    @Override
    public void eat() {
        System.out.println(getNickname() + "吃肉");
    }

    public void watch(){
        System.out.println(getNickname() + "看门");
    }
}
public class Cat extends Animal{
    public Cat(String nickname, int age) {
        super(nickname, age);
    }

    public Cat() {
    }

    @Override
    public void eat() {
        System.out.println(getNickname() + "吃鱼");
    }

    public void catchMouse(){
        System.out.println(getNickname() +"捉老鼠");
    }
}
public class Demo {
    public static void main(String[] args) {
//        show(new Cat("加菲猫",3));
        show(new Dog("哈士奇",4));
    }

    public static void show(Animal a){
        a.eat();
        if (a instanceof Dog){
            Dog d = (Dog) a;
            d.watch();
        } else if (a instanceof Cat){
            Cat c = (Cat) a;
            c.catchMouse();
        }
    }
}

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-yzVoBw2K-1681896245356)(E:\itcast\images\summarize\Image1.png)]

3.抽象类

3.1 认识抽象方法和抽象类

  • 多态中案例中子父类存在的问题?
  • 图示
    请添加图片描述
Image2
  • abstract关键字
    • 修饰方法: 抽象方法,不写方法体
    • 修饰类: 抽象类, 有抽象方法的类,必须是抽象类
public abstract class Person {
     public abstract void run();
}

3.2 抽象类的特点

  • 抽象类可以没有抽象方法,有抽象方法的类必须是抽象类
  • 抽象类中的成员(成员变量,构造方法,成员方法)都可以有
  • 和普通的类最主要的区别: 不能创建对象,作为一种特殊的父类,让子类继承并实现
  • 抽象类的子类
    • 要么重写所有的抽象方法
    • 要么子类也定义为抽象类
public abstract class A {
    private String name;
    public abstract void test();
    
    public A(){
        
    }

    public void show() {
        System.out.println("show方法执行了 ....");
    }
    
    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}
public class B extends A{
    @Override
    public void test(){
        System.out.println("重写的test方法执行了")
    }
}
public class Demo {
    public static void main(String[] args) {
                // A a = new A(); // 编译错误 抽象类不能创建对象
        B b = new B();
        b.show();
        System.out.println(b.getName());
        b.test();
    }
}

3.3 抽象方法关键字使用冲突

  • private: private 修饰的方法,子类不能重写 - abstract 要求子类必须重写
  • final: final 修饰的方法,子类不能重写 - abstract 要求子类必须重写
  • static: static 修饰的方法,子类不能重写 - abstract 要求子类必须重写

3.4 模板方法设计模式

  • 解决什么问题: 子类中重复的代码
public class A{
    public void sing(){
        System.out.println("下面给大家带来一首攒劲的歌曲: ");
        System.out.println("我是一只小小鸟,想要飞却怎么样也飞不高~~~~~~~~");
        System.out.println("....小小鸟歌词....");
        System.out.println("....小小鸟歌词....");
        System.out.println("....小小鸟歌词....");
        System.out.println("谢谢!");
    }
}

public class B{
    public void sing(){
        System.out.println("下面给大家带来一首攒劲的歌曲: ");
        System.out.println("我们一起学猫叫,一起喵喵喵喵喵~~~~~~~~~~");
        System.out.println("....学猫叫歌词....");
        System.out.println("....学猫叫歌词....");
        System.out.println("....学猫叫歌词....");
        System.out.println("谢谢!");
    }
}
  • 思路
    • 问题: 所有的功能都挤在同一个方法中,过于臃肿.
      • 封装的思想,将代码抽取到方法中,按照功能进行分类管理
      • 将歌词的部分抽取成方法song(歌曲)
    • 两个类中共性的内容(sing和song)抽取到父类(Fu)中
      • sing方法中的内容子类中都是相同的,所以子类不需要重写
      • song方法中的歌词子类中是不同的,子类需要重写,父类中的song方法可以定义成抽象方法
    • 编写测试类
      • 在main方法平级的位置定义show方法,参数为父类类型(Fu f)
      • 在show方法中调用模板方法f.sing
      • 在main方法中调用show方法 传递不同的子类对象观察效果
public abstract class Fu {
    public void sing(){
        System.out.println("下面给大家带来一首攒劲的歌曲: ");
        song();
        System.out.println("谢谢!");
    }

    public abstract void song() ;
}
public class A extends Fu{
    @Override
    public void song() {
        System.out.println("我是一只小小鸟,想要飞却怎么样也飞不高~~~~~~~~");
        System.out.println("....小小鸟歌词....");
        System.out.println("....小小鸟歌词....");
        System.out.println("....小小鸟歌词....");
    }
}
public class B extends Fu{
    @Override
    public void song() {
        System.out.println("我们一起学猫叫,一起喵喵喵喵喵~~~~~~~~~~");
        System.out.println("....学猫叫歌词....");
        System.out.println("....学猫叫歌词....");
        System.out.println("....学猫叫歌词....");
    }
}
public class Demo {
    public static void main(String[] args) {
        show(new B());
    }
    public static void show(Fu f){
        f.sing();
    }
}

4. 接口

4.1 概述

  • 现实生活中的规则
    • 笔记本电脑规定USB插口形状
    • 其他设备必须按照这个形状做USB插头
Image3
  • 代码层面
    • 如果抽象类中只有抽象方法,那么我们就可以将这个抽象类改写为接口
    • 接口主要是对行为制定规则
public abstract class A{
    public abstract void method1();
    public abstract void method2();
}

public interface A{
    public abstract void method1();
    public abstract void method2();
}
  • 接口的特点
    • 接口使用关键字interface来定义:
      • public interface 接口名{}
    • 接口不能实例化
    • 接口和类之间是实现关系,通过implements关键字表示
      • public class 类名 implements 接口名{}
    • 接口的实现类
      • 要么重写所有的抽象方法
      • 要么是抽象类
public interface A {
    public abstract void method1();
    public abstract void method2();
}
/*
    B类称为实现类
    实现类:
        要么重写所有的抽象方法
        要么将实现类变成抽象类
 */
public class B implements A{ // 实现关系,B类实现了A接口
    @Override
    public void method1() {

    }

    @Override
    public void method2() {

    }
}
public class Demo {
    public static void main(String[] args) {
//        A a = new A(); // 接口不能实例化
    }
}

4.2 接口中成员的特点

  • 构造方法: 没有
  • 成员变量: 只能是常量(final)
    • 默认修饰符: public final static
  • 成员方法: 只能是抽象方法
    • 默认修饰符: public abstract
    • 接口中的方法JDK8和JDK9有一些新特性
/*
    接口中成员的特点
        构造方法: 没有
        成员变量: 都是常量
            默认修饰符 public final static
        成员方法: 只能是抽象方法
            默认修饰符 public abstract
            接口中的方法,在JDK8和JDK9增加了新的方法
 */
public interface A {
     public static final  int a = 10;
     public abstract void show();
}
public class Demo {
    public static void main(String[] args) {
        System.out.println(A.a);

    }
}

4.3 类和接口的各种关系

  • 类和类的关系
    • 继承关系,只能是单继承,支持多层继承
  • 类和接口的关系
    • 实现关系,可以单实现,也可以多实现,还可以在继承一个类的同时实现多个接口
  • 接口和接口的关系
    • 继承关系,可以单继承,也可以多继承
public interface Inter1 {}
public interface Inter2 {}
public class Fu{}
public class InterImpl extends Fu implements Inter1,Inter2 {}
public interface C {
}
public interface D {
}
public interface E extends D,C {
}

4.4 案例

  • 木门和电动报警门
  • ①木门
    • 成员变量:宽,高,品牌
    • 成员方法:开门,关门
  • ②电动报警门:
    • 成员变量:宽,高,品牌
    • 成员方法:开门,关门,报警
Image4

分析

Image5

实现

  • ①定义报警 (Alarm)接口
    • 成员方法:报警
  • ②定义门 (Door)抽象类
    • 成员变量:宽,高,品牌
    • 构造方法:无参,带参
    • 成员方法:get/set方法,开门,关门
  • ③定义木门类(WoodDoor),继承门类
    • 构造方法:无参,带参
    • 成员方法:开门,关门
  • ④定义电动报警门类(ElectricAlarmDoor),继承门类,实现报警接口
    • 构造方法:无参,带参
    • 成员方法:开门,关门,报警
  • ⑤测试类中创建对象进行测试
public interface Alarm {
    void alarm();
}
public abstract class Door {
    private double weight;
    private double height;
    private String brand;

    public double getWeight() {
        return weight;
    }

    public void setWeight(double weight) {
        this.weight = weight;
    }

    public double getHeight() {
        return height;
    }

    public void setHeight(double height) {
        this.height = height;
    }

    public String getBrand() {
        return brand;
    }

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

    public Door(double weight, double height, String brand) {
        this.weight = weight;
        this.height = height;
        this.brand = brand;
    }

    public Door() {
    }

    public abstract void open();
    public abstract void close();
}
public class WoodDoor extends Door{
    public WoodDoor(double weight, double height, String brand) {
        super(weight, height, brand);
    }

    public WoodDoor() {
    }

    @Override
    public void open() {
        System.out.println("手动开门");
    }

    @Override
    public void close() {
        System.out.println("手动关门");
    }
}
public class ElectricAlarmDoor extends Door implements Alarm{
    public ElectricAlarmDoor(double weight, double height, String brand) {
        super(weight, height, brand);
    }

    public ElectricAlarmDoor() {
    }

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

    @Override
    public void open() {
        System.out.println("自动开门");
    }

    @Override
    public void close() {
        System.out.println("自动关门");
    }
}
public class Demo {
    public static void main(String[] args) {
        WoodDoor w = new WoodDoor(1.2,2.2,"TATA");
        showDoor(w);
        System.out.println("==================");


        ElectricAlarmDoor e = new ElectricAlarmDoor(6.0,3.0,"盼盼");
        showDoor(e);
        showAlarm(e);
    }

    // 定义方法 参数类型为门,接收一切子类对象
    public static void showDoor(Door d){
        System.out.println("宽: " + d.getWeight() + ",高: " + d.getHeight() + ", 品牌: " + d.getBrand());
        d.open();
        d.close();
    }
    // 定义方法 参数为警报器,接收一切实现类对象
    public static void showAlarm(Alarm a){ // 接收一切实现类对象    接口名 变量名 = new 实现类名()
        a.alarm();
    }
}

目标

  • 理解接口制定了行为的规则: 实现Alarm接口,就必须具备alarm功能
  • 理解继承一个类的同时,继续实现接口,可以实现功能的扩展

4.5 接口中新增的方法[了解]

  • 默认方法: JDK8
    • 使用default关键字修饰,默认public修饰
    • 注意: 只能由接口的实现类对象调用
    • 实现类可以直接使用,也可以重写
  • 静态方法: JDK8
    • 使用static修饰,默认public修饰
    • 注意: 只能用接口名调用
  • 私有方法: JDK9
    • 只能用private修饰
  • 作用: 增强了接口的能力,便于项目维护和扩展
public interface A {
    public default void show1(){
        System.out.println("我是show1方法");
        show3();
    }

    public static void show2(){
        System.out.println("我是show2方法");
        show3();
    }
    private static void show3(){
        System.out.println("我是show3方法");
    }
}
public class B implements A{
    @Override
    public void show1() {
        System.out.println("我是实现类中的show1方法");
    }
}
public class Demo {
    public static void main(String[] args) {
        B b = new B();
//        b.show2();
        b.show1();

        A.show2(); // 使用方便
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 好的,以下是一些2023年Java面试题和学习计划建议: Java面试题: 1. 什么是Java虚拟机(JVM)?JVM的组成部分是什么? 2. 什么是Java中的反射?反射的优缺点是什么? 3. 什么是Java中的注解?它们有哪些用途? 4. 什么是Java中的Lambda表达式?如何使用它们? 5. 什么是Java中的异常处理?Java中有哪些类型的异常? 6. 什么是Java中的多线程?如何创建和控制线程? 7. 什么是Java中的集合框架?Java中有哪些集合类? 8. 什么是Java中的IO和NIO?它们有什么区别? 9. 什么是Java中的泛型?如何使用它们? 10. 什么是Java中的类加载器?它们有哪些类型? 学习计划建议: 1. 学习Java基础知识,包括语法、数据类型、运算符等。 2. 深入了解Java中的面向对象编程思想,掌握类、对象、继承、多态等概念。 3. 学习Java中的集合框架,包括List、Set、Map等集合类的使用。 4. 学习Java中的异常处理机制,掌握try-catch-finally结构以及自定义异常的使用。 5. 学习Java中的多线程编程,包括线程的创建、启动、等待和同步等概念。 6. 学习Java中的IO和NIO编程,包括文件读写、网络编程等。 7. 学习Java中的反射和注解机制,了解它们的作用和使用方法。 8. 学习Java中的Lambda表达式和函数式编程思想,掌握Lambda表达式的语法和使用方法。 9. 学习Java中的泛型编程,包括泛型类和泛型方法的使用。 10. 学习Java中的类加载机制,包括类加载器的种类、类加载的顺序等。 以上是一些建议,您可以根据自己的情况进行调整和修改。最重要的是不断练习,多做一些实际的项目或者练习题目,以提高自己的编程能力和实践经验。 ### 回答2: 2023年的Java面试题和学习计划如下: 1. Java核心知识 - Java语言基础:变量、数据类型、运算符、控制结构等 - 面向对象编程:封装、继承、多态抽象类接口等 - 异常处理机制:try-catch-finally、自定义异常等 - 集合框架:List、Set、Map等常用集合操作 - IO操作:文件读写、序列化等 2. Java高级特性 - 多线程和并发:线程生命周期、同步、锁机制、线程池等 - 反射和动态代理:Class类、反射调用、动态代理的概念和用法 - 泛型:泛型类型、泛型方法、通配符等 - 注解:定义和使用注解、元注解等 - Lambda表达式和函数式接口:Lambda表达式的语法和用法、函数式接口定义和使用 3. 数据库相关 - SQL语法和基本操作:增删改查、连接查询、聚合函数等 - JDBC编程:连接数据库、CRUD操作、事务管理等 - ORM框架:例如Hibernate、MyBatis的使用和原理 4. web开发相关 - Servlet和JSP:Servlet生命周期、请求响应过程、Session管理等 - Spring框架:IOC、AOP、MVC等基本概念和使用 - Spring Boot:自动配置、常用注解、项目搭建等 - RESTful API设计和使用:HTTP方法、资源定义、状态码等 学习计划如下: 1. 确定学习目标:了解面试要求和考察重点,制定合理的时间表 2. 学习基础知识:通过阅读相关教材、网上教程等掌握Java的基础语法和核心知识 3. 实践项目:通过完成一些小项目或者任务来巩固理论知识,提高编程能力 4. 阅读原理文档:深入理解Java相关的原理和机制,如JVM、多线程等 5. 练习面试题:刷题、模拟面试,提高解决问题的能力和应对压力的能力 6. 参考书籍和培训班:选择一些经典的Java开发书籍和参加培训班提高自己的学习效果 7. 学习交流:参加技术社区、技术论坛等进行学习交流,与其他Java开发者共同进步 以上是2023年Java面试题的整理和一个较为综合的学习计划,具体根据个人情况进行调整。成功的关键在于持续努力、实践和不断积累经验。祝你在2023年的Java面试中取得好成绩! ### 回答3: 2023年的Java面试题分为三个主要方面:基础知识、核心概念和高级特性。下面是一个学习计划的建议,以帮助你准备面试。 1. 基础知识: - 熟悉Java语言的基本语法、数据类型、运算符和控制流程语句。 - 理解面向对象编程的概念,包括类、对象、继承、多态和封装。 - 学习异常处理机制、输入输出流和Java集合框架。 2. 核心概念: - 理解Java内存管理机制,包括堆和栈的区别、垃圾回收和内存泄漏。 - 学习多线程编程,包括线程的创建、同步、通信和线程池的使用。 - 熟悉Java的反射机制和注解,了解它们在框架和库中的应用。 3. 高级特性: - 学习Java的网络编程,包括Socket编程、HTTP传输和RESTful服务。 - 掌握常用的设计模式,如单例模式、工厂模式和观察者模式。 - 了解Java的新特性,如Lambda表达式、Stream API和模块化系统。 学习计划建议如下: - 设定一个合理的学习时间表,每天定期进行学习,以确保学习的连续性。 - 阅读相关的Java教程和参考资料,例如官方文档和经典的Java编程书籍。 - 实践编写Java代码,通过解决实际问题来加深对知识的理解和记忆。 - 参加Java开发的线上课程、培训或是参与开源项目,积累实践经验。 - 利用在线资源,如编程网站和论坛,与其他学习者交流、分享和提问。 - 制定一个自我评估计划,定期检查自己的学习进度并找出需要加强的领域。 通过系统学习和实践,逐步提升自己的Java编程能力,并不断完善面试题的准备。记住,面试并不仅仅是回答问题,还要展示自己的编程思维和解决问题的能力。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值