# 第 08 章:随堂复习与企业真题(面向对象 - 高级)


# 一、随堂复习

# 1. 关键字:static

  • static:静态的,随着类的加载而加载、执行

  • static 用来修饰:属性、方法、代码块、内部类

  • 熟悉:static 修饰的类变量、类方法与不使用 static 修饰的区别。

    • 类变量:类的生命周期内,只有一个。被类的多个实例共享。
  • 掌握:我们遇到属性或方法时,需要考虑是否声明为 static 的。

# 2. 单例模式(或单子模式)

  • 经典的设计模式有 23 种
  • 解决的问题:在整个软件系统中,只存在当前类的唯一实例
  • 实现方式:饿汉式、懒汉式、枚举类等
    • 私有化构造器
    • 提供一个当前类的实例,必须是静态的
    • 提供一个获取当前类实例的方法,必须是静态的
  • 对比饿汉式和懒汉式
    • 饿汉式“立即加载”线程安全的。
    • 懒汉式"延迟加载"线程不安全
  • 需要会手写饿汉式和懒汉式

# 3. 理解 main () 方法

  • public static void main(String[] args){}
  • 理解 1:作为程序的入口;普通的静态方法
  • 理解 2:如何使用 main () 与控制台进行数据的交互。
    • 命令行:java 类名 "Tom" "Jerry" "123"

# 4. 类的成员之四:代码块

  • 分类:静态代码块、非静态代码块
  • 使用频率上来讲:用的比较少。
  • 静态代码块:随着的加载而执行
  • 非静态代码块:随着对象的创建而执行

总结:对象的实例变量可以赋值的位置及先后顺序

① 默认初始化
② 显式初始化 或 ⑤ 代码块中初始化
构造器中初始化

④ 有了对象以后,通过 "对象。属性" 或 "对象。方法" 的方法进行赋值

执行的先后顺序:
① - ②/⑤ - ③ - ④

# 5. 关键字:final

  • 最终的

  • 用来修饰:类、方法、变量(成员变量、局部变量)

    • 类:不能被继承
    • 方法:不能被重写
    • 变量:是一个 “常量”,一旦赋值不能修改。

# 6. 关键字:abstract

  • 抽象的
  • 用来修饰:类、方法
    • 类:抽象类:不能实例化。
    • 方法:抽象方法:没有方法体,必须由子类实现此方法。

# 7. 关键字:interface

  • interface:接口,用来定义一组规范、一种标准。

  • 掌握:接口中可以声明的结构。

    • 属性:使用 public static final 修饰,可忽略

      公共静态常量

    • 方法:

      • jdk8 之前:只能声明抽象方法,使用 public abstract 修饰

        公共抽象方法

      • jdk8 中:声明 static 方法、default 方法。

        公共静态方法、公共默认方法

      • jdk9 中:声明 private 方法。

        私有方法

  • 笔试题:抽象类、接口的对比。

# 8. 类的成员之五:内部类

> 成员内部类的理解
> 如何创建成员内部类的实例
> 如何在成员内部类中调用外部类的结构
> 局部内部类的基本使用(关注:如何在方法内创建匿名局部内部类的对象)

# 9. 枚举类:enum

  • 掌握:使用 enum 关键字定义枚举类即可。

# 10. 注解:Annotation

  • 框架 = 注解 + 反射 + 设计模式

  • Java 基础阶段:简单。

    • @Override:重写
    • @Deprecated:标记过时
    • @SuppressWarnings:抑制编译器警告
  • 元注解:描述注解的注解。

    • @Target:描述注解的使用范围
    • @Retation:描述注解的生命周期
    • @Documented:描述注解被 javadoc 工具记录
    • @Inherited:描述注解被子类继承
  • 如何自定义注解。

# 11. 包装类的使用

  • 掌握:基本数据类型对应的包装类都有哪些?

image-20230331160011510

  • 掌握:基本数据类型、包装类、String 三者之间的转换

    省流

    • 基本数据类型 / 包装类 ---> String 类

      • String.valueOf(xxx)
    • String 类 ---> 基本数据类型 / 包装类

      • 包装类.parseXxx(str)

        如果 str 的内容无法正确转换为对应的基本类型,可能会抛出异常 NumberFormatException

image-20230331160048147

# 12. IDEA: 快捷键和 debug

# 二、企业真题

# 2.1 static 关键字

# 1. 实例变量和静态变量的区别?(保 * 丰、* 软国际、* 软华 *、北京明 ** 信)

  • 个数

    • 实例变量:类的每一个实例都存有一份;
    • 静态变量:在内存空间中只有一份,被的所有实例所共享;
  • 内存位置

    • 实例变量:堆空间的实例实体中;
    • 静态变量:
      • JDK6 及之前,存放在方法区;
      • JDK7 及之后,存放在堆空间
  • 加载 / 消亡时机

    • 实例变量:随着实例的创建而加载;随着实例的消失而消失;
    • 静态变量:随着类的加载而加载,而类只会加载一次;随着类的卸载而消失;
  • 调用者

    • 实例变量:实例对象
    • 静态变量:类 / 实例对象
  • 判断是否可以调用(从生命周期的角度解释)

    静态变量实例变量
    ×
    实例对象
  • 使用场景

    • 静态变量:类的所有实例能共享此成员变量,开发中常常将一些常量声明为静态的,如 Math.PI

# 2. 静态属性和静态方法是否可以被继承?是否可以被重写?以及原因?(* 度)

类似问题:
> 在java中,可以重载一个static方法吗?可以覆盖一个static方法吗?(Vi*o)

静态属性、静态方法可以被继承

静态方法可以被重载(overload)

静态方法不能被重写(override),不存在多态性。

当父类、子类中出现同名同参数的方法时,只允许两种情况(否则编译报错):

  • 都没用 static修饰:重写(override)
  • 都用了 static修饰:仅仅是同名而已,不存在多态性
public class StaticTest {
 public static void main(String[] args) {
     // 尝试重写父类的静态方法:
     Father father = new Son();
     father.method(); // 根据阿里巴巴 Java 开发手册,应该避免通过一个类的对象引用访问此类的静态变量或静态方法,应该直接通过类名来访问。
     // 通过类名访问静态方法
     Father.method();
 }
}
class Father {
 public static void method() {
     System.out.println("Father");
 }
}
class Son extends Father {
 public static void method() {
     System.out.println("Son");
 }
}

# 3. 是否可以从一个 static 方法内部发出对非 static 方法的调用?(同 * 顺)

不能直接调用非静态方法只能通过对象来对非静态方法的调用

# 4. 被 static 修饰的成员 (类、方法、成员变量) 能否再使用 private 进行修饰?(联 * 优势)

完全可以。

除了代码块。

因为代码块本身不能用权限修饰符来修饰

# 2.2 设计模式

# 1. 知道哪些设计模式?(* 通快递、蚂 ** 服)

  • 单例模式

    • 饿汉式
    • 懒汉式
  • 模板方法

    • 抽象类
  • 享元设计模式

    • 包装类中缓存的常量对象

# 2. 开发中都用到了那些设计模式?用在什么场合?(久 * 国际物流)

# 2.3 main()

# 1. main () 方法的 public 能不能换成 private,为什么(凡 * 科技、顺 *)

可以改。但是改完以后就不是程序入口了

# 2. main () 方法中是否可以调用非静态方法?(浩 * 科技)

能通过对象来对非静态方法的调用

# 2.4 代码块

# 1. 类的组成和属性赋值执行顺序?(航 * 拓普)

类似问题:
> Java中类的变量初始化的顺序?(*壳)

实例变量可以赋值的位置及先后顺序:

① 默认初始化
② 显式初始化 或 ⑤ 代码块中初始化
构造器中初始化

④ 有了对象以后,通过 "对象。属性" 或 "对象。方法" 的方法进行赋值

执行的先后顺序:① - ②/⑤ - ③ - ④

# 2. 静态代码块,普通代码块,构造方法,从类加载开始的执行顺序?(恒 * 电子)

类似问题:
> 类加载成员变量、静态代码块、构造器的加载顺序(*科软、软**力、同*顺)
> static代码块(静态代码块)是否在类的构造函数之前被执行(联*优势)

静态代码块 --> 普通代码块 --> 构造器

# 2.5 final 关键字

# 1. 描述一下对 final 理解(华 ** 博普)

用来修饰:类、方法、变量(成员变量、局部变量)

  • 类:不能被继承
  • 方法:不能被重写
  • 变量:是一个 “常量”,一旦赋值不能修改。

# 2. 判断题:使用 final 修饰一个变量时,是引用不能改变,引用指向的对象可以改变?(* 米)

引用不能改变。

引用指向的对象实体中的属性,如果没有使用 final 修饰,则可以改变

# 3. 判断题:final 不能用于修饰构造方法?(联 * 优势)

是的。无意义

# 4. final 或 static final 修饰成员变量,能不能进行 ++ 操作?(佳 * 贸易)

不能。因为赋值后不能再修改了

# 2.6 抽象类与接口

# 1. 什么是抽象类?如何识别一个抽象类?(易 * 支付)

使用 abstract 修饰。

可能有抽象方法。

# 2. 为什么不能用 abstract 修饰属性、私有方法、构造器、静态方法、final 的方法?(止 ** 善)

为了语言的自洽:

  • 不能用 abstract 修饰属性、代码块、构造器

    1. 属性:被 abstract 修饰的内容都是暂未被实现的,比如类、方法。而属性不存在 "尚未被实现" 的状态,因为在声明属性时会默认初始化
    2. 代码块:“尚未被实现” 的状态?那直接删掉代码块不就好了嘛...
    3. 构造器:abstract 在修饰方法时,要求方法体为空,要求在子类中实现该方法。而构造方法不能被子类继承,与之矛盾
  • 不能用 abstract 修饰私有方法、静态方法、final 的方法、final 的类

    1. 私有方法:子类无法访问到父类的私有方法,因此无法被子类 override,而 abstract 方法必须要被子类实现,矛盾!
    2. 静态方法:静态方法可以通过类名直接调用,而 abstract 方法是没有方法体的,不能被调用,矛盾
    3. final 方法:final 方法不能被子类 override,同 1
    4. final 类:final 类不能被继承,同 1

# 3. 接口与抽象类的区别?(字 * 跳动、阿 * 校招、* 度校招、** 计算机技术及应用研究所、航 * 拓普、纬 *、招 ** 晟、汇 * 云通、数信 ** 科技、北京永 * 鼎力、上海 * 连科技)

image-20230331160132667

在开发中,常看到一个类不是去继承一个已经实现好的类,而是要么继承抽象类,要么实现接口

# 4. 接口是否可继承接口?抽象类是否可实现(implements)接口?抽象类是否可继承实现类(concrete class)?(航 * 拓普、* 蝶、深圳德 * 科技)

类似问题:
> 接口A可以继承接口B吗?接口A可以实现接口B吗?(久*国际物流)

是;

而且接口之间的继承关系是多继承

是;

一个类实现了某接口(有两个公共抽象方法),但该类只实现了其中一个抽象方法,那么该类也就是抽象类。

是;

Object 类是所有类的父类,它本身就是实现类。

# 5. 接口可以有自己属性吗?(华 * 中盛)

可以。必须是 public static final

公共静态常量

# 6. 访问接口的默认方法如何使用 (上海 * 思)

使用实现类的对象进行调用。

而且实现还可以重写此默认方法

# 2.7 内部类

# 1. 内部类有哪几种?(华油 ** 普、来 * 科技)

  • 成员内部类

    • 静态的
    • 非静态的
  • 局部内部类

    • 匿名的
    • 非匿名的

# 2. 内部类的特点说一下(招通 **)

类似问题:
> 说一下内部类的好处(北京楚*龙)
> 使用过内部类编程吗,有什么作用(软**力)

成员内部类的使用特征,概括来讲有如下两种角色:

  • 成员内部类作为 类的成员 的角色:
    • 和外部类(只能使用 public、缺省)不同,内部类还可以声明为 private 或 protected;
    • 可以调用外部类的结构。(注意:在静态内部类中不能使用外部类的非静态成员
    • 可以声明为 static 的;
  • 成员内部类作为 的角色:
    • 可以在内部定义属性、方法、构造器等结构
    • 可以继承自己的想要继承的父类,实现自己想要实现的父接口们,和外部类的父类和父接口无关
    • 可以声明为 abstract 类 ,因此可以被其它的内部类继承
    • 可以声明为 final 的,表示不能被继承
    • 编译以后生成 OuterClass$InnerClass.class 字节码文件(也适用于局部内部类)

注意点:

  1. 外部类访问成员内部类的成员,需要 “内部类。成员” 或 “内部类对象。成员” 的方式

  2. 成员内部类可以直接使用外部类的所有成员,包括私有的数据

  3. 当想要在外部类的静态成员部分使用内部类时,可以考虑内部类声明为静态的

# 8. 匿名类说一下(阿 * 校招、上海立 * 网络)

匿名类是不能有名字的类,因此不能被引用,只能在创建时用 new 语句来声明它们。

匿名类通常继承一个父类实现一个 / 多个接口

# 2.8 枚举类

# 1. 枚举可以继承吗?(顺 *)

使用 enum 定义的,其父类就是 java.lang.Enum 类,就不要再继承其他的类了。

# 2.9 包装类

# 1. Java 基本类型与包装类的区别(凡 * 科技)

省流:基本类型有默认值,而包装类型初始为 null。然后再根据这两个特性进行分业务使用,在阿里巴巴的规范里所有的 POJO 类必须使用包装类型,而在本地变量推荐使用基本类型

image-20230331160147078

1、在 Java 中,一切皆对象,但八大基本类型却不是对象

2、声明方式的不同,基本类型无需通过 new 关键字来创建,而包装类型需 new 关键字

3、存储方式及位置的不同,基本类型是直接存储变量的值保存在中能高效的存取包装类型需要通过引用指向实例,具体的实例保存在

4、初始值的不同,包装类型的初始值为 null,基本类型的的初始值视具体的类型而定,比如 int 类型的初始值为 0,boolean 类型为 false;

5、使用方式的不同,比如与集合类合作使用时只能使用包装类型

6、什么时候该用包装类,什么时候用基本类型,看基本的业务来定:这个字段允不允许 null 值,如果允许 null 值,则必然要用封装类,否则值类型就可以了,用到比如泛型和反射调用函数.,就需要用包装类!

# 2.10 综合

# 1. 谈谈你对面向对象的理解 (君 * 科技、航 * 拓普、...)

  • 面向对象的两个要素类、对象 ---> 面向对象编程。“万事万物皆对象”。
  • 面向对象的三大特征封装、继承、多态
  • 接口,与类并列的结构,作为一个补充:类可以实现多个接口

# 2. 面向对象的特征有哪些方面? (北京楚 * 龙、深圳德 * 科技、直 * 科技、米 * 奇网络、航 * 拓普)

  • 封装(Encapsulation):将对象的属性和行为封装在一个抽象的类中,对外部隐藏其内部实现细节,只暴露必要的方法接口。这样可以避免外部直接访问和修改对象的属性,保证了对象的安全性和一致性。
  • 继承(Inheritance):通过一个已经存在的类来派生出一个新的类,新的类具有已有类的所有属性和方法,并且可以添加新的属性和方法,从而实现代码的重用和扩展。Java 中支持单继承和多层继承。
  • 多态(Polymorphism):同一种操作作用于不同的对象上面,可以产生不同的效果。
    • 编译时多态:通过方法的重载实现,指在一个类中,有多个方法名相的方法,但是这些方法有着不同的参数列表,在编译期我们就可以确定到底调用哪个方法。
    • 运行时多态:通过方法的重写实现,子类重写父类中的方法(包括接口的实现),父类的引用不仅可以指向父类的对象,而且还可以指向子类的对象。当父类的引用指向子类的引用时,只有在运行时才能确定调用哪个方法。
  • 抽象(Abstraction):抽取对象的共性,将其提取为一个抽象的类或接口,然后具体的对象通过继承或实现来实现这个抽象的类或接口。抽象可以减少代码的重复性,提高代码的复用性和可维护性。
  • 接口(Interface):接口是一种特殊的抽象类,它定义了一组方法的签名,但是没有实现方法的实现。类可以实现一个或多个接口,实现接口的类必须实现接口中定义的所有方法,从而达到了代码重用和灵活性的目的。