Java基础面试题——【Java语言特性】

🤔思考题:

什么是面向对象编程,什么是面向过程编程

题目:

面向对象三大特性是什么?为什么Java是平台无关性的?

解答:

1、三大特性

  • 封装:访问修饰符(private/protected/public/default)的作用域
  • 继承:extends实现、方法重写规则(两同两小一大原则)
  • 多态:编译时多态(方法重载) vs 运行时多态(方法重写+父类引用指向子类对象)

2、平台无关性

JVM工作机制:.java → .class → 机器码

字节码验证过程(类加载时的4次验证)


详解:

Java 中的访问修饰符(Access Modifiers)用于控制类、方法、变量等成员的可见性可访问性。它们决定了这些成员在哪些范围内可以被访问或使用。

Java 有四种访问修饰符:

修饰符 作用域(Scope) 可见性说明
public 所有包(All Packages) 任何地方都可以访问
protected 当前类、子类、同一包 子类和同包内可访问
default(默认,不写修饰符) 同一包(Same Package) 仅限于当前包内
private 当前类(Current Class) 仅限于定义它的类内部

一、详细说明

1. public

  • 作用范围:所有类、包、子类。
  • 适用对象:类、接口、方法、变量。
  • 特点
    • 最宽松的访问权限。
    • 可以被其他任何类访问,无论是否在同一包中。
java 复制代码
public class MyClass {
    public int publicVar;
    public void publicMethod() { ... }
}

2. protected

  • 作用范围:当前类、子类、同一包。
  • 适用对象:方法、变量。
  • 特点
    • 允许子类继承并访问。
    • 在同一包中的其他类也可以访问。
    • 不允许跨包访问(除非是子类)。
java 复制代码
class Parent {
    protected int protectedVar;
    protected void protectedMethod() { ... }
}

class Child extends Parent {
    void accessProtected() {
        System.out.println(protectedVar); // 可以访问
    }
}

⚠️ 注意:protected 不能用于类(即不能声明一个 protected class)。

3. default(默认,不写修饰符)

  • 作用范围:同一包(Same Package)。
  • 适用对象:类、方法、变量。
  • 特点
    • 如果不写任何修饰符,则默认为 default
    • 仅限于当前包内的类访问。
java 复制代码
class DefaultClass {
    int defaultVar;
    void defaultMethod() { ... }
}

✅ 示例:如果另一个类在同一个包中,就可以访问 defaultVardefaultMethod()

4. private

  • 作用范围:当前类(Current Class)。
  • 适用对象:方法、变量。
  • 特点
    • 最严格的访问权限。
    • 只能在定义它的类内部访问。
    • 不能被子类继承或访问。
java 复制代码
class MyClass {
    private int privateVar;
    private void privateMethod() { ... }

    void accessPrivate() {
        System.out.println(privateVar); // 可以访问
    }
}

❌ 示例:在其他类中无法直接访问 privateVarprivateMethod()


二、访问修饰符的作用域对比表

修饰符 同类 同包 子类 其他包
public
protected
default
private

三、使用建议

  • 使用 public:当需要对外公开接口或数据时。
  • 使用 protected:当希望子类能访问但不希望外部直接访问时。
  • 使用 default:当只需要在本包内使用时。
  • 使用 private:当希望完全隐藏实现细节时。

四、总结

Java 的访问修饰符通过控制成员的可见性和可访问性,实现了对代码的封装和模块化管理。合理使用这些修饰符有助于提高程序的安全性、可维护性和可扩展性。


继承:

在 Java 中,继承(extends 是面向对象编程的重要特性之一,它允许一个类(子类)继承另一个类(父类)的属性和方法。通过继承,可以实现代码复用、扩展功能等。


一、extends 实现

1. 基本语法

java 复制代码
class 子类名 extends 父类名 {
    // 子类的成员变量和方法
}

2. 特点

  • Java 不支持多继承(即一个类不能同时继承多个类),但可以通过接口实现多继承。
  • Object 是所有类的默认父类。
  • 子类可以访问父类的 非私有 成员(包括 publicprotected)。

3. 示例

java 复制代码
// 父类
class Animal {
    public void eat() {
        System.out.println("Animal is eating.");
    }
}

// 子类
class Dog extends Animal {
    public void bark() {
        System.out.println("Dog is barking.");
    }
}

public class Main {
    public static void main(String[] args) {
        Dog dog = new Dog();
        dog.eat();   // 继承自 Animal
        dog.bark();  // 子类自己的方法
    }
}

二、方法重写(Override)

1. 定义

方法重写是指在子类中重新定义从父类继承来的方法。目的是为了改变或扩展父类的行为

注意:重写必须与父类方法具有相同的签名(方法名、参数列表、返回类型)


三、方法重写的规则(两同两小一大原则)

这是 Java 方法重写的核心规则,也称为 "两同两小一大"原则

规则 说明
两同 - 方法名相同 - 参数列表相同
两小 - 返回值类型要小于等于父类方法的返回值类型(协变返回) - 异常抛出范围要小于等于父类方法的异常范围
一大 - 访问权限要大于或等于父类方法的访问权限

1. 两同(Same Name, Same Parameters)

  • 方法名相同:子类方法名必须与父类方法名一致。
  • 参数列表相同:参数的数量、类型、顺序必须完全一致。
java 复制代码
class Parent {
    public void show(int x) {
        System.out.println("Parent: " + x);
    }
}

class Child extends Parent {
    @Override
    public void show(int x) {  // 符合"两同"
        System.out.println("Child: " + x);
    }
}

2. 两小(Smaller Return Type, Smaller Exception)

  • 返回值类型要小于等于父类方法的返回值类型 (协变返回):
    • 允许子类方法返回更具体的类型(如 String 可以覆盖 Object)。
    • 但不能是更宽泛的类型(如 Object 不能覆盖 String)。
java 复制代码
class Parent {
    public Object getObject() {
        return new Object();
    }
}

class Child extends Parent {
    @Override
    public String getObject() {  // 协变返回(合法)
        return "Hello";
    }
}
  • 异常抛出范围要小于等于父类方法的异常范围
    • 子类方法可以不抛出异常,也可以抛出比父类更少或更具体的异常。
    • 不能抛出父类没有声明的检查型异常。
java 复制代码
class Parent {
    public void method() throws IOException {
        // ...
    }
}

class Child extends Parent {
    @Override
    public void method() throws FileNotFoundException {  // 合法(更具体)
        // ...
    }
}

3. 一大(Larger Access Modifier)

  • 访问权限要大于或等于父类方法的访问权限
    • 父类方法是 private,子类不能重写(因为无法访问)。
    • 父类方法是 default(包访问),子类方法可以是 protectedpublic
    • 父类方法是 protected,子类方法可以是 public
    • 父类方法是 public,子类方法只能是 public
java 复制代码
class Parent {
    protected void display() {
        System.out.println("Parent's display");
    }
}

class Child extends Parent {
    @Override
    public void display() {  // 更大的访问权限(合法)
        System.out.println("Child's display");
    }
}

四、注意事项

  • final 方法不能被重写
  • static 方法不能被重写(只能被隐藏)。
  • private 方法不能被重写(因为无法访问)。
  • 使用 @Override 注解可以帮助编译器验证是否为正确重写。

五、总结

规则 说明
两同 方法名相同,参数列表相同
两小 返回值类型更小/相同,异常范围更小/相同
一大 访问权限更大或相同

合理使用方法重写可以增强程序的灵活性和可维护性,是面向对象设计中的重要手段。


多态:

在 Java 中,多态(Polymorphism) 是面向对象编程的三大特性之一,它允许不同类的对象对同一消息做出不同的响应。根据实现方式的不同,多态可以分为 编译时多态运行时多态


一、编译时多态:方法重载(Overloading)

1. 定义

方法重载 (Method Overloading)是指在同一个类中,方法名相同,但参数列表不同(参数类型、数量或顺序不同),从而实现不同的功能。

2. 特点

  • 发生在编译阶段,由编译器决定调用哪个方法。
  • 不涉及继承关系,是类内部的方法定义。
  • 返回值类型可以不同,但不能仅靠返回值类型来区分重载方法(否则会报错)。

3. 示例

java 复制代码
public class Calculator {
    public int add(int a, int b) {
        return a + b;
    }

    public double add(double a, double b) {
        return a + b;
    }

    public int add(int a, int b, int c) {
        return a + b + c;
    }
}

4. 调用示例

java 复制代码
public class Main {
    public static void main(String[] args) {
        Calculator calc = new Calculator();
        System.out.println(calc.add(2, 3));       // 输出 5
        System.out.println(calc.add(2.5, 3.5));   // 输出 6.0
        System.out.println(calc.add(1, 2, 3));    // 输出 6
    }
}

5. 优点

  • 提高代码可读性和灵活性。
  • 减少重复代码。

二、运行时多态:方法重写 + 父类引用指向子类对象

1. 定义

运行时多态 (Runtime Polymorphism)是通过 方法重写(Override)父类引用指向子类对象 实现的。它在程序运行时才确定具体调用哪个方法。

2. 核心要素

  • 方法重写:子类重新定义从父类继承的方法。
  • 父类引用指向子类对象:使用父类变量引用子类对象,通过该变量调用方法时,实际执行的是子类的方法。

3. 示例

java 复制代码
// 父类
class Animal {
    public void sound() {
        System.out.println("Animal makes a sound");
    }
}

// 子类
class Dog extends Animal {
    @Override
    public void sound() {
        System.out.println("Dog barks");
    }
}

class Cat extends Animal {
    @Override
    public void sound() {
        System.out.println("Cat meows");
    }
}

4. 调用示例

java 复制代码
public class Main {
    public static void main(String[] args) {
        Animal animal1 = new Dog();     // 父类引用指向子类对象
        Animal animal2 = new Cat();

        animal1.sound();  // 输出 "Dog barks"
        animal2.sound();  // 输出 "Cat meows"
    }
}

5. 原理说明

  • 在编译时,编译器只知道 animal1Animal 类型,无法确定具体是哪个子类。
  • 在运行时,JVM 会根据实际对象的类型来调用对应的方法,这就是 动态绑定(Dynamic Binding)。

三、编译时多态 vs 运行时多态 对比

特性 编译时多态(方法重载) 运行时多态(方法重写 + 父类引用)
实现方式 同一类中方法名相同,参数不同 不同类中方法名相同,参数相同
决定时间 编译时 运行时
是否需要继承 无需继承 需要继承
方法修饰符 可以不同 必须满足"两同两小一大"原则
调用方式 通过参数不同调用 通过父类引用调用
典型应用 重载操作符、统一接口 多态行为、接口实现

四、总结

多态类型 实现方式 特点 应用场景
编译时多态 方法重载 编译时确定 提供统一接口,增强可读性
运行时多态 方法重写 + 父类引用 运行时确定 实现灵活的行为扩展,支持接口和抽象类设计

五、补充说明

  • 方法重写 是实现 运行时多态 的核心机制。
  • 父类引用指向子类对象 是实现运行时多态的关键手段。
  • 多态 是面向对象设计的重要思想,有助于提高代码的可扩展性、可维护性和灵活性。

思考题:

面向对象编程(Object-Oriented Programming,简称 OOP)和面向过程编程(Procedural Programming)是两种不同的编程范式,它们在设计思想、代码组织方式以及解决问题的思维方式上存在显著差异。


一、面向过程编程(Procedural Programming)

1. 定义

面向过程编程是一种以过程/函数 为中心的编程方式。程序被看作是一系列操作步骤的集合,通过调用一系列函数来完成任务。

2. 核心特点

  • 以函数为核心:程序由多个函数组成,每个函数完成特定的功能。
  • 数据与操作分离:数据和处理数据的函数是分开的。
  • 强调流程控制:关注"怎么做",即如何一步步执行操作。

3. 示例(C语言)

cpp 复制代码
#include <stdio.h>

// 函数:计算两个数的和
int add(int a, int b) {
    return a + b;
}

int main() {
    int x = 5;
    int y = 10;
    int result = add(x, y);
    printf("Result: %d\n", result);
    return 0;
}

4. 优点

  • 简单直观,适合小型项目。
  • 执行效率高,适合底层开发。

5. 缺点

  • 数据与功能分离,难以维护和扩展。
  • 重复代码多,不利于复用。

二、面向对象编程(Object-Oriented Programming,OOP)

1. 定义

面向对象编程是一种以对象 为核心的编程方式。程序被看作是由多个对象 组成的系统,每个对象包含数据(属性)行为(方法)

2. 核心特点

  • 以对象为核心:程序由多个对象构成,每个对象具有自己的状态和行为。
  • 封装性:将数据和操作封装在一起,对外隐藏实现细节。
  • 继承性:子类可以继承父类的属性和方法。
  • 多态性:同一操作在不同对象上有不同的表现形式。

3. 示例(Java)

java 复制代码
// 定义一个类:Person
class Person {
    // 属性(数据)
    String name;
    int age;

    // 方法(行为)
    void speak() {
        System.out.println("My name is " + name + ", I am " + age + " years old.");
    }
}

public class Main {
    public static void main(String[] args) {
        // 创建对象
        Person person = new Person();
        person.name = "Alice";
        person.age = 25;
        person.speak(); // 调用方法
    }
}

4. 优点

  • 更符合现实世界的建模方式,易于理解和维护。
  • 代码复用性强,便于扩展和维护。
  • 支持模块化开发,提高团队协作效率。

5. 缺点

  • 学习曲线较陡,需要理解类、对象、继承等概念。
  • 对于简单任务可能显得复杂。

三、面向过程 vs 面向对象

特性 面向过程编程 面向对象编程
核心 函数/过程 对象
数据与操作 分离 封装在一起
重点 如何做 什么对象做什么
可维护性 较低 较高
复用性 一般
适用场景 小型程序、底层开发 中大型系统、复杂应用

四、总结

  • 面向过程 更注重步骤和流程,适合简单的逻辑处理。
  • 面向对象 更注重对象和关系,适合复杂系统的构建和维护。

在实际开发中,现代编程语言(如 Java、C++、Python)普遍采用面向对象的方式进行开发,因为其更符合软件工程的需求。不过,面向过程的思想仍然在某些场景下有其价值,比如嵌入式系统或性能敏感的代码中。

相关推荐
choke2331 小时前
[特殊字符] Python 文件与路径操作
java·前端·javascript
Swift社区2 小时前
Gunicorn 与 Uvicorn 部署 Python 后端详解
开发语言·python·gunicorn
choke2332 小时前
Python 基础语法精讲:数据类型、运算符与输入输出
java·linux·服务器
码农阿豪2 小时前
Python Flask应用中文件处理与异常处理的实践指南
开发语言·python·flask
岁岁种桃花儿2 小时前
CentOS7 彻底卸载所有JDK/JRE + 重新安装JDK8(实操完整版,解决kafka/jps报错)
java·开发语言·kafka
csbysj20202 小时前
AngularJS 模块
开发语言
独好紫罗兰2 小时前
对python的再认识-基于数据结构进行-a003-列表-排序
开发语言·数据结构·python
wuhen_n2 小时前
JavaScript内置数据结构
开发语言·前端·javascript·数据结构
不会代码的小测试2 小时前
UI自动化-POM封装
开发语言·python·selenium·自动化