【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 实现自旋锁的原理?
本文详解自旋锁的概念、优缺点、使用场景及Java实现。关注【mikechen的互联网架构】,10年+BAT架构经验倾囊相授。
大厂面试高频:什么是自旋锁?Java 实现自旋锁的原理?
|
6天前
|
存储 缓存 Oracle
Java I/O流面试之道
NIO的出现在于提高IO的速度,它相比传统的输入/输出流速度更快。NIO通过管道Channel和缓冲器Buffer来处理数据,可以把管道当成一个矿藏,缓冲器就是矿藏里的卡车。程序通过管道里的缓冲器进行数据交互,而不直接处理数据。程序要么从缓冲器获取数据,要么输入数据到缓冲器。
Java I/O流面试之道
|
2天前
|
存储 缓存 Java
大厂面试必看!Java基本数据类型和包装类的那些坑
本文介绍了Java中的基本数据类型和包装类,包括整数类型、浮点数类型、字符类型和布尔类型。详细讲解了每种类型的特性和应用场景,并探讨了包装类的引入原因、装箱与拆箱机制以及缓存机制。最后总结了面试中常见的相关考点,帮助读者更好地理解和应对面试中的问题。
18 4
|
3天前
|
存储 Java 程序员
Java基础的灵魂——Object类方法详解(社招面试不踩坑)
本文介绍了Java中`Object`类的几个重要方法,包括`toString`、`equals`、`hashCode`、`finalize`、`clone`、`getClass`、`notify`和`wait`。这些方法是面试中的常考点,掌握它们有助于理解Java对象的行为和实现多线程编程。作者通过具体示例和应用场景,详细解析了每个方法的作用和重写技巧,帮助读者更好地应对面试和技术开发。
28 4
|
27天前
|
存储 安全 算法
Java面试题之Java集合面试题 50道(带答案)
这篇文章提供了50道Java集合框架的面试题及其答案,涵盖了集合的基础知识、底层数据结构、不同集合类的特点和用法,以及一些高级主题如并发集合的使用。
78 1
Java面试题之Java集合面试题 50道(带答案)
|
10天前
|
Java 关系型数据库 数据库
面向对象设计原则在Java中的实现与案例分析
【10月更文挑战第25天】本文通过Java语言的具体实现和案例分析,详细介绍了面向对象设计的五大核心原则:单一职责原则、开闭原则、里氏替换原则、接口隔离原则和依赖倒置原则。这些原则帮助开发者构建更加灵活、可维护和可扩展的系统,不仅适用于Java,也适用于其他面向对象编程语言。
10 2
|
16天前
|
存储 Java 程序员
Java面试加分点!一文读懂HashMap底层实现与扩容机制
本文详细解析了Java中经典的HashMap数据结构,包括其底层实现、扩容机制、put和查找过程、哈希函数以及JDK 1.7与1.8的差异。通过数组、链表和红黑树的组合,HashMap实现了高效的键值对存储与检索。文章还介绍了HashMap在不同版本中的优化,帮助读者更好地理解和应用这一重要工具。
39 5
|
14天前
|
存储 Java
[Java]面试官:你对异常处理了解多少,例如,finally中可以有return吗?
本文介绍了Java中`try...catch...finally`语句的使用细节及返回值问题,并探讨了JDK1.7引入的`try...with...resources`新特性,强调了异常处理机制及资源自动关闭的优势。
16 1
|
24天前
|
Java 程序员
Java 面试高频考点:static 和 final 深度剖析
本文介绍了 Java 中的 `static` 和 `final` 关键字。`static` 修饰的属性和方法属于类而非对象,所有实例共享;`final` 用于变量、方法和类,确保其不可修改或继承。两者结合可用于定义常量。文章通过具体示例详细解析了它们的用法和应用场景。
25 3
|
27天前
|
Java
Java面试题之cpu占用率100%,进行定位和解决
这篇文章介绍了如何定位和解决Java服务中CPU占用率过高的问题,包括使用top命令找到高CPU占用的进程和线程,以及使用jstack工具获取堆栈信息来确定问题代码位置的步骤。
76 0
Java面试题之cpu占用率100%,进行定位和解决
下一篇
无影云桌面