【Java 面向对象,2021最后一次Java面试 下

简介: 【Java 面向对象,2021最后一次Java面试

public class Person {

private int age;
private static int count = 1;
private static void run() {
  System.out.println("Person - run");
}
public static class Car { // 静态嵌套类
  public void test() {
    Person person = new Person();
    // 静态嵌套类可以直接访问外部类中的成员(包括 private)
    System.out.println(person.age); // 0
    Person.count = 1;
    Person.run(); // Person - run
    System.out.println(count); // 1
    run(); // Person - run
  }
}

}

public static void main(String[] args) {
  Person p = new Person();
  // 静态嵌套类的使用
  Person.Car c = new Person.Car(); 
  // 如果之前 import Person.Car; 可以直接使用;
  // Car c = new Car();
  c.test();
} 
```
[](https://gitee.com/vip204888/java-p7)什么情况使用嵌套类?
-----------------------------------------------------------------------------
如果类 A 只用在类 C 内部,可以考虑将类 A 嵌套到类 C 中;
*   封装性更好
*   程序包更加简化
*   增强可读性、维护性
如果类 A 需要经常访问类 C 的**非公共成员**,可以考虑将类 A嵌套到类 C 中;
*   另外也可以根据需要将类 A 隐藏起来,不对外暴露
如果需要**经常访问非公共的实例成员**,设计成内部类(非静态嵌套类),否则设计成静态嵌套类;
*   如果必须先有 C 实例,才能创建 A 实例,那么可以将 A 设计为 C 的内部类
[](https://gitee.com/vip204888/java-p7)局部类(Local Class)
===================================================================================
**局部类**:定义在**代码块**中的类(可以定义在方法中、for 循环中、if 语句中等)
局部类不能定义除**编译时常量**以外的任何 `static` 成员;
局部类只能访问 `final` 或者 **有效`final`** 的局部变量;
*   从 Java 8 开始,如果**局部变量没有被第二次赋值**,就认定为是**有效`final`**
局部类可以直接访问外部类中的所有成员(即使被声明为 `private`)
*   局部类只有定义在实例相关的代码块中,才能直接访问外部类中的实例成员(实例变量、实例方法)
局部类示例:
```
public class TestLocalClass {
  private int a = 1;
  private static int b = 2;
  private static void test1() {}
  private void test2() {}
  public void test3() {
    int c = 2;
    class LocalClass {
      static final int d = 4;
      void test4() {
        System.out.println(a + b + c  + d);
        test1();
        test2();
      }
    }
    new LocalClass().test4();
  }
} 
```
[](https://gitee.com/vip204888/java-p7)抽象类(Abstract Class)与接口(Interface)
====================================================================================================
[](https://gitee.com/vip204888/java-p7)抽象类
----------------------------------------------------------------------
**抽象方法**:被 `abstract` 修饰的实例方法
*   只有方法声明,没有方法实现(参数列表后面没有大括号,而是分号)
*   不能是 `private` 权限(因为定义抽象方法的目的让子类去实现)
*   只能定义在抽象类、接口中
**抽象类**:被 `abstract` 修饰的类
*   可以定义抽象方法
*   不能实例化,但可以自定义构造方法
*   子类必须实现抽象父类中的所有抽象方法(除非子类也是一个抽象类)
*   可以像非抽象类一样定义成员变量、常量、嵌套类型、初始化块、非抽象方法等  
    也就说,**抽象类也可以完全不定义抽象方法**
常见使用场景:
*   抽取子类的公共实现到抽象父类中,要求子类必须要单独实现的定义成抽象方法
实例:
```
public abstract class Shape {
  protected double area;
  protected double girth;
  public double getArea() {
    return area;
  }
  public double getGirth() {
    return girth;
  }
  public void show() {
    calculate();
    System.out.println(area + "_" + girth);
  }
  protected abstract void calculate();
} 

public class Rectangle extends Shape {

private double width;
private double height;
public Rectangle(double width, double height) {
  super();
  this.width = width;
  this.height = height;
}
@Override
protected void calculate() {
  area = width * height;
  girth = (width + height) * 2;
}

}

public class Circle extends Shape {
  private double radius;
  public Circle(double radius) {
    this.radius = radius;
  }
  @Override
  protected void calculate() {
    double half = Math.PI * radius;
    area = half * radius;
    girth = half * 2;
  }
} 

public static void main(String[] args) {

Rectangle rectangle = new Rectangle(10, 20);
rectangle.show();
Circle circle = new Circle(30);
circle.show();

}

[](https://gitee.com/vip204888/java-p7)接口(Interface)
--------------------------------------------------------------------------------
**API**(Application Programming Interface)
*   **应用编程接口**,提供给开发者调用的一组功能(无须提供源码)
**Java 中的接口**:
*   一系列方法声明的集合
*   用来定义规范、标准
**接口中可以定义的内容**:
*   **抽象方法(可以省略 abstract)**
*   **常量(可以省略 static、final)**
*   **嵌套类型**
*   从 Java 8 开始可以定义:**默认方法(`default`)**、**静态方法**  
    上述可以定义的内容都是隐式 public 的,因此可以省略 public 关键字
*   从 Java 9 开始可以定义:**private 方法**
*   不能自定义构造方法、不能定义(静态)初始化块、不能实例化
**接口的细节**:  
一个类可以通过 `implements` 关键字实现一个或多个接口
*   实现接口的类必须实现接口中定义的所有抽象方法,除非它是个抽象类
*   如果一个类实现的多个接口中有相同的抽象方法,只需要实现此方法一次
*   `extends` 和 i`mplements` 可以一起使用,`implements` 必须写在 `extends` 的后面
*   当父类、接口中的方法签名一样时,那么返回值类型也必须一样
一个接口可以通过 `extends` 关键字继承一个或者多个接口
*   当多个父接口中的方法签名一样时,那么返回值类型也必须一样
[](https://gitee.com/vip204888/java-p7)抽象与接口的对比(如何选择)
---------------------------------------------------------------------------------
抽象类和接口的用途还是有点类似,该如何选择?
何时选择**抽象类**?
*   在**紧密相关的类**之间共享代码
*   需要除 public 之外的访问权限
*   需要定义实例变量、非 final 的静态变量
何时选择**接口**?
*   **不相关的类**实现相同的方法
*   只是**定义行为**,不关心具体是谁实现了行为
*   想实现类型的**多重继承**
[](https://gitee.com/vip204888/java-p7)接口的升级问题(默认方法、静态方法)
=====================================================================================
如果接口需要升级,比如增加新的抽象方法:会导致大幅的代码改动,以前实现接口的类都得改动
若想在不改动以前实现类的前提下进行接口升级,从 Java 8 开始,有 2 种方案:
*   **默认方法**(Default Method)
*   **静态方法**(Static Method)
[](https://gitee.com/vip204888/java-p7)默认方法(Default Method)
---------------------------------------------------------------------------------------
*   用 `default` 修饰默认方法
*   默认方法只能是实例方法
**默认方法的使用**:  
当一个类实现的接口中有默认方法时,这个类可以:
*   **啥也不干**,沿用接口的默认实现
*   重新定义默认方法,**覆盖**默认方法的实现
*   重新声明默认方法,将默认方法声明为抽象方法(此类必须是抽象类)
当一个接口继承的父接口中有默认方法时,这个接口可以:
*   **啥也不干**,沿用接口的默认实现
*   重新定义默认方法,**覆盖**默认方法的实现
*   重新声明默认方法,将默认方法声明为抽象方法
简单示例:`Eatable` 中有默认方法,`Dog`啥也不干,`Cat` 覆盖默认方法。

public interface Eatable {

// 默认方法
default void eat(String name) {
  System.out.println("Eatable - eat - " + name);
}

}

// Eatable接口中新增了方法, 但是没有影响到Dog类
public class Dog implements Eatable {} 

// Eatable接口中新增了方法, Cat类中可以覆盖

public class Cat implements Eatable {

@Override
public void eat(String name) {
  Eatable.super.eat(name);
  System.out.println("Cat - eat - " + name);
}

}

 public static void main(String[] args) {
    Dog dog = new Dog();
    dog.eat("bone"); 
    // Eatable - eat - bone
    Cat cat = new Cat();
    cat.eat("fish");
    // Eatable - eat - fish
    // Cat - eat - fish
  } 
```
如果父类定义的非抽象方法与接口的默认方法相同时,最终将调用父类的方法(**就近原则**):
```
public class Animal {
  public void run() {
    System.out.println("Animal - run");
  }
} 

public interface Runnable {

default void run() {
  System.out.println("Runnable - run");
}

}

public class Dog extends Animal implements Runnable {} 

public static void main(String[] args) {

Dog dog = new Dog();
dog.run(); // 继承的父类、实现的接口中都有 run() 方法, 默认调用父类的
// Animal - run

}

如果父类定义的抽象方法与接口的默认方法相同时,要求子类实现此抽象方法
*   可以通过 `super` 关键字调用接口的默认方法

public interface Runnable {

default void run() {
  System.out.println("Runnable - run");
}

}

public abstract class Animal {
  public void run() {}
} 

public class Dog extends Animal implements Runnable {

@Override
public void run() { // 父类的抽象方法run方法与接口中的run方法相同, 要求实现父类的抽象方法
  Runnable.super.run(); // 可以通过super调用接口的默认方法
  System.out.println("Dog - run");
  // Runnable - run
  // Dog - run
}

}

如果(父)接口定义的默认方法与其他(父)接口定义的方法相同时,要求子类型实现此默认方法:  
例:`Runnable` 和 `Walkable` 两个父接口中定义的**默认方法**都是 `run()`,`Testable` 继承了两个父类,则要求实现默认方法 `run()` ,`Dog` 类同理。

public interface Runnable {

default void run() {
  System.out.println("Runnable - run");
}

}

public interface Walkable {
  default void run() {
    System.out.println("Walkable - run");
  }
} 

// Testable 父接口继承了 Runnable 父接口和 Walkable 父接口

// 他们都有默认方法 run, 要求 Testable 接口实现该默认方法

public interface Testable extends Runnable, Walkable {

@Override
default void run() {
  Runnable.super.run();
  Walkable.super.run();
  System.out.println("Testable - run");
}

}

// Dog 类实现了 Runnable、Walkable 两个接口
// 他们都有默认方法 run, 要求 Dog 类实现该默认方法
public class Dog implements Runnable, Walkable {
  @Override
  public void run() {
    Runnable.super.run();
    Walkable.super.run();
    System.out.println("Dog - run");
  }
} 

public static void main(String[] args) {

Dog dog = new Dog();
dog.run();
// Runnable - run
// Walkable - run
// Dog - run

}

再看一个例子:

public interface Animal {

default String myself() {
  return "I am an animal.";
}

}

public interface Fire extends Animal {} 

public interface Fly extends Animal {

@Override
default String myself() {
  return "I am able to fly.";
}

}

public class Dragon implements Fly, Fire {} 

public static void main(String[] args) {

Dragon dragon = new Dragon();
System.out.println(dragon.myself());
// I am able to fly.

}

[](https://gitee.com/vip204888/java-p7)静态方法(Static Method)
--------------------------------------------------------------------------------------
*   接口中定义的静态方法只能通过接口名调用,**不能被继承**;

public interface Eatable {

static void eat(String name) {
相关文章
|
1月前
|
监控 Java 应用服务中间件
高级java面试---spring.factories文件的解析源码API机制
【11月更文挑战第20天】Spring Boot是一个用于快速构建基于Spring框架的应用程序的开源框架。它通过自动配置、起步依赖和内嵌服务器等特性,极大地简化了Spring应用的开发和部署过程。本文将深入探讨Spring Boot的背景历史、业务场景、功能点以及底层原理,并通过Java代码手写模拟Spring Boot的启动过程,特别是spring.factories文件的解析源码API机制。
71 2
|
20天前
|
Java 程序员
Java社招面试题:& 和 && 的区别,HR的套路险些让我翻车!
小米,29岁程序员,分享了一次面试经历,详细解析了Java中&和&&的区别及应用场景,展示了扎实的基础知识和良好的应变能力,最终成功获得Offer。
53 14
|
1月前
|
存储 缓存 算法
面试官:单核 CPU 支持 Java 多线程吗?为什么?被问懵了!
本文介绍了多线程环境下的几个关键概念,包括时间片、超线程、上下文切换及其影响因素,以及线程调度的两种方式——抢占式调度和协同式调度。文章还讨论了减少上下文切换次数以提高多线程程序效率的方法,如无锁并发编程、使用CAS算法等,并提出了合理的线程数量配置策略,以平衡CPU利用率和线程切换开销。
面试官:单核 CPU 支持 Java 多线程吗?为什么?被问懵了!
|
1月前
|
存储 算法 Java
大厂面试高频:什么是自旋锁?Java 实现自旋锁的原理?
本文详解自旋锁的概念、优缺点、使用场景及Java实现。关注【mikechen的互联网架构】,10年+BAT架构经验倾囊相授。
大厂面试高频:什么是自旋锁?Java 实现自旋锁的原理?
|
16天前
|
Java
java中面向过程和面向对象区别?
java中面向过程和面向对象区别?
19 1
|
1月前
|
存储 缓存 Oracle
Java I/O流面试之道
NIO的出现在于提高IO的速度,它相比传统的输入/输出流速度更快。NIO通过管道Channel和缓冲器Buffer来处理数据,可以把管道当成一个矿藏,缓冲器就是矿藏里的卡车。程序通过管道里的缓冲器进行数据交互,而不直接处理数据。程序要么从缓冲器获取数据,要么输入数据到缓冲器。
Java I/O流面试之道
|
25天前
|
Java 编译器 程序员
Java面试高频题:用最优解法算出2乘以8!
本文探讨了面试中一个看似简单的数学问题——如何高效计算2×8。从直接使用乘法、位运算优化、编译器优化、加法实现到大整数场景下的处理,全面解析了不同方法的原理和适用场景,帮助读者深入理解计算效率优化的重要性。
30 6
|
28天前
|
JavaScript 前端开发 Java
还不明白面向对象? 本文带你彻底搞懂面向对象的三大特征(2024年11月Java版)
欢迎来到我的博客,我是瑞雨溪,一名热爱JavaScript和Vue的大一学生。如果你从我的文章中受益,欢迎关注我,我将持续更新更多优质内容。你的支持是我前进的动力!🎉🎉🎉
24 0
还不明白面向对象? 本文带你彻底搞懂面向对象的三大特征(2024年11月Java版)
|
1月前
|
存储 缓存 Java
大厂面试必看!Java基本数据类型和包装类的那些坑
本文介绍了Java中的基本数据类型和包装类,包括整数类型、浮点数类型、字符类型和布尔类型。详细讲解了每种类型的特性和应用场景,并探讨了包装类的引入原因、装箱与拆箱机制以及缓存机制。最后总结了面试中常见的相关考点,帮助读者更好地理解和应对面试中的问题。
57 4
|
1月前
|
存储 Java 程序员
Java基础的灵魂——Object类方法详解(社招面试不踩坑)
本文介绍了Java中`Object`类的几个重要方法,包括`toString`、`equals`、`hashCode`、`finalize`、`clone`、`getClass`、`notify`和`wait`。这些方法是面试中的常考点,掌握它们有助于理解Java对象的行为和实现多线程编程。作者通过具体示例和应用场景,详细解析了每个方法的作用和重写技巧,帮助读者更好地应对面试和技术开发。
114 4