Java基础高频面试题汇总

        一、面向对象

封装

继承

多态

二、JDK、JRE、JVM之间的区别

三、==和equals方法之间的区别

四、final关键字的作用是什么?

五、String、StringBuffer、StringBuilder的区别

六、重载和重写的区别

七、接口和抽象类的区别(重点)

详细说明(深入说明)

使用场景


一、面向对象

相较于面向过程,是两种不同的处理问题的角度

面向过程更注重事情的每⼀个步骤及顺序。

面向对象更注重事情有哪些参与者(对象)、及各自需要什么。

例如:洗衣机洗衣服

(1)站在面向过程的角度,会将任务拆解成⼀系列的步骤。

打开洗衣机----->放衣服----->放洗衣粉----->清洗----->烘干衣服

(2)站在面向对象的角度,会拆出人和洗衣机两个对象,然后分析两个对象分别要做什么事。

a. 人:打开洗衣机 放衣服 放洗衣粉

b. 洗衣机:清洗 烘干

从以上例子能看出,面向过程比较直接高效,而面向对象更易于复用、扩展和维护

封装

明确标识允许外部使用的所有成员函数和数据项,内部细节对外部调用透明,外部调用无需修改或者关心内部实现

(1)JavaBean

JavaBean的属性私有,提供了getter,setter方法进行访问,这样属性的赋值or获取逻辑只能由JavaBean本身决定,而不能由外部胡乱修改。

private String name;
public void setName(String name) {
    this.name = "Harmony_" + name;
}

例如我们规定设置值的时候,必须以“Harmony_”为前缀,如果我们不用private加以限制,让外部使用属性名.name的方式,就可能会违背这一规则。

(2)ORM框架

我们不关心链接怎么建立,SQL怎么写,只要引入MyBatis,调用方法即可。

继承

继承基类的方法,并做出自己的改变or扩展。

子类共性的方法或者属性直接使用父类的,而不需要自己再定义(达到代码复用的效果),只需扩展自己个性化的。

多态

基于对象所属类的不同,外部对同⼀个方法的调用,实际执行的逻辑不同。

前提:继承、方法重写、父类引用指向子类对象

父类类型 变量名 = new 子类对象();
变量名.方法名();  //调用的实际上是子类的方法

但是无法调用子类对象特有的方法。 

二、JDK、JRE、JVM之间的区别

JDK:Java Develpment Kit  Java开发工具

JRE:Java Runtime Environment Java运行时环境

JVM:java Virtual Machine Java虚拟机

JRE = JVM + lib库

JDK = JRE + Java工具

Java是跨平台的,通过javac编译的.class文件可以“到处运行”,.class文件再由JVM进行解释。

三、==和equals方法之间的区别

"==":

如果是基本数据类型,比较两者的是否相等。
如果是引用数据类型,不仅要比较两者的值是否相等,而且还要比较两者的引用是否指向同一个对象(同一个内存地址)。

"equals()":

仅仅比较数值是否相等。

public class test {
    public static void main(String[] args) {
        String a = new String("foo");
        String b = new String("foo");
        System.out.println("==:" + (a == b));
        // false;
        System.out.println("equals:" + a.equals(b));
        // true;
    }
}

四、final关键字的作用是什么?

修饰类:表示类不可被继承,final类中的一切方法都是final。

修饰方法:表示方法不可被子类覆盖,但是可以重载

修饰变量:表示变量⼀旦被赋值就不可以更改它的值

  • (1) 修饰成员变量

如果final修饰的是类变量,只能在静态初始化块中指定初始值 或者 声明该类变量时赋值(2处)。

如果final修饰的是成员变量,可以在非静态初始化块声明该变量构造器中赋值(3处)。

  • (2) 修饰局部变量

系统不会为局部变量进⾏初始化,局部变量必须由程序员显示初始化。因此使⽤final修饰局部变量时, 即可以在定义时指定默认值(后⾯的代码不能对变量再赋值),也可以不指定默认值,⽽在后⾯的代码 中对final变量赋初值(仅⼀次

public class FinalVar { 
    // 类变量
    final static int a = 0;//在声明的时候就需要赋值 或者静态代码块赋值 

    static { 
        a = 0;
    }  
    
    // 成员变量
    final int b = 0;  //在声明的时候就需要赋值 或者代码块中赋值 或者构造器赋值 
    
    {
        b = 0;
    } 
    public static void main(String[] args) { 
        // 局部变量
        final int localA;
        //局部变量只声明没有初始化,不会报错,与final⽆关。
        localA = 0;
        //在使⽤之前⼀定要赋值 
        //localA = 1; 但是不允许第⼆次赋值
    }
}
  • (3) 修饰基本类型数据和引用类型数据

如果是基本数据类型的变量,则其数值⼀旦在初始化之后便不能更改

如果是引⽤类型的变量,则在对其初始化之后便不能再让其指向另⼀个对象。但是引⽤的值是可变 的

public class Demo{ 
    public static void main() { 
        final int[] iArr={1,2,3,4};
        iArr[2]=-3;//合法 
        iArr=null;//⾮法,对iArr不能重新赋值
        
        final Person p = new Person(25); 
        p.setAge(24);//合法 
        p=null;//⾮法
}

五、String、StringBuffer、StringBuilder的区别

String是由final修饰的,是不可变的,如果尝试去修改,会新生成⼀个字符串对象(导致内存浪费)

StringBuffer和StringBuilder是可变

StringBuffer是线程安全的,StringBuilder是线程不安全的。

StringBuffer方法都是由synchronized关键字修饰的。所以在单线程环境下StringBuilder效率会更高

性能:StringBuilder > StringBuffer > String

使用场景:经常要改变字符串内容的,使用后面两个;优先使用StringBuilder多线程使用共享变量时使用StringBuffer

六、重载和重写的区别

重载:

发生在同⼀个类中,方法名必须相同,参数类型不同、个数不同、顺序不同,方法返回值和访问修饰符可以不同,发生在编译时

重写:

发生在父子类中,方法名、参数列表必须相同。

返回值范围小于等于父类,抛出的异常范围 小于等于父类,访问修饰符范围大于等于父类。

如果父类方法访问修饰符为private、final子类就不能重写该方法。

七、接口和抽象类的区别(重点)

(1)抽象类可以存在普通成员函数,而接口只能存在public abstract 方法(只能有抽象方法)。

(2)抽象类中的成员变量可以是各种类型的,而接⼝中的成员变量只能是public static final类型的。

(3)抽象类只能继承⼀个接口可以实现多个

[public] interface interface_name [extends interface1_name[, interface2_name,…]] {
    // 接口体,其中可以包含定义常量和声明方法
    [public] [static] [final] type constant_name = value;    // 定义常量
    [public] [abstract] returnType method_name(parameter_list);    // 声明方法
}

 public、abstract、static、final都是可以省略的!

详细说明(深入说明)

接口的设计目的,是对类的行为进行约束(更准确的说是⼀种“有”约束,因为接⼝不能规定类不可以有 什么行为),也就是提供⼀种机制,可以强制要求不同的类具有相同的⾏为。它只约束了行为的有无, 但不对如何实现行为进行限制

抽象类的设计目的,是代码复用。当不同的类具有某些相同的行为,可以让这些类都派生出⼀个抽象类。一定是先有子类再有抽象类!将子类中共性的方法抽取出来形成抽象类。抽象类不能被实例化,这是因为抽象类有一些方法是没有被实现!

接口是对行为的抽象,表达的是 like a 的关系。比如: Bird like a Aircraft 。接口的核心是定义行为,即实现类可以做什么,至于实现类主体是谁、是如何实现的,接口并不关心。

抽象类是对类本质的抽象,表达的是 is a 的关系,比如: BMW is a Car 。抽象类包含并实现子类的通用特性,将子类存在差异化的特性进行抽象,交由子类去实现。

使用场景

当你关注⼀个事物的本质的时候,用抽象类;当你关注⼀个操作的时候,用接口

抽象类的功能要远超过接口,但是,定义抽象类的代价高。因为高级语言来说(从实际设计上来说也是)每个类只能继承一个类

在这个类中,你必须继承或编写出其所有子类的所有共性。虽然接口在功能上会弱化许多,但是它只是针对⼀个动作的描述。而且你可以在一个类中同时实现多个接口。在设计阶段会降低难度。

posted @   金鳞踏雨  阅读(28)  评论(0编辑  收藏  举报  
相关博文:
阅读排行:
· 全程不用写代码,我用AI程序员写了一个飞机大战
· DeepSeek 开源周回顾「GitHub 热点速览」
· 记一次.NET内存居高不下排查解决与启示
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· .NET10 - 预览版1新功能体验(一)
点击右上角即可分享
微信分享提示