Java面试被问了几个简单的问题,却回答的不是很好

作者:逍遥Sean

简介:一个主修Java的Web网站\游戏服务器后端开发者

主页:https://blog.csdn.net/Ureliable

觉得博主文章不错的话,可以三连支持一下~ 如有需要我的支持,请私信或评论留言!

前言

前几天参加了一个做web开发的面试,被问了几个问题,虽然有些题目比较偏,但是确实是Java开发必须了解的内容。我觉得比较简单的问题,却回答的不是很好,事后总结一下~

问题

说一下finally吧

Java的finally关键字是用于定义在try/catch语句块中必须执行的代码块。不论是否有异常抛出,finally块都会被执行。通常在finally块中释放资源,如关闭文件、释放数据库连接等。finally块也可以用于判断try块中的异常是否被捕获和处理了,从而调用其他方法或抛出异常。finally块可以在try块和catch块之后添加,但只能有一个finally块。例如:

java 复制代码
try {
  // 执行代码
} catch(Exception e) {
  // 处理异常
} finally {
  // 释放资源
}

说一下public吧

  1. 在Java中,public是一个访问修饰符,它用于指定一个类、方法或变量可以从任何其他类或代码中访问。
  2. 使用public修饰的类、方法或变量可以被任何其他的类或代码访问,而不限于同一个包。
  3. 对于面向对象编程来说,public是最常用的访问修饰符之一。
  4. Java一个源程序只能有一个public类存在,且类名与文件名相同。
  5. Java程序是从main方法开始执行的,public为类加载器提供入口,然后找到public类中的main方法开始执行。如果存在多个public类,程序将不知道该从哪里执行。
  6. 注意,内部类可以是public的,因为内部类是作为外部类的成员存在的。

静态成员和静态方法是什么

简单来讲:静态成员和静态方法,可以直接通过类名进行调用;其他的成员和方法则需要进行实例化成对象之后,通过对象来调用。

Java的静态成员和静态方法都是属于类而不是对象的,因此不需要实例化类就可以直接访问它们。静态成员通常用于保存所有实例共享的数据,而静态方法通常用于提供不依赖于对象状态的功能。

静态成员可以通过以下方式声明:

java 复制代码
public class MyClass {
    public static int staticVariable;
    public static void staticMethod() {
        // do something
    }
}

静态成员可以通过类名直接访问,如下所示:

java 复制代码
int i = MyClass.staticVariable;
MyClass.staticMethod();

注意到静态方法中不能访问非静态成员,因为非静态成员必须依赖于对象状态,而静态方法不依赖于对象状态。

说一下abstract

Java中的abstract是一个关键字,用于修饰类、方法或者成员变量。用abstract修饰的类称为抽象类,用abstract修饰的方法称为抽象方法,用abstract修饰的成员变量称为抽象成员变量。

抽象类是一种特殊的类,不能被实例化,只能被继承。抽象类中可以包含抽象方法和非抽象方法,抽象方法是没有实现的方法,需要子类去实现。

抽象方法必须在抽象类中声明,不能在普通类中声明。子类继承抽象类时,必须实现抽象方法,否则子类也必须是抽象类。

抽象成员变量必须被子类实现,否则子类也必须是抽象类。抽象成员变量必须以分号结尾,不可定义为private、static、final或native类型。
使用abstract应注意:

  • abstract不能与final并列修饰同一个类 对的;
  • abstract类中不应该有private的成员 对的 :abstract类中可以有private 但是不应该有;
  • abstract方法必须在abstract类或接口中 对的 : 若类中方法有abstract修饰的,该类必须abstract修改。接口方法默认public abstract;
  • static方法中能处理非static的属性 错误 :在JVM中static方法在静态区,静态区无法调用非静态区属性。

java的内存模型

Java的内存模型(Java Memory Model,JMM)指定了Java虚拟机如何管理内存和线程之间的交互。它定义了在多线程环境下共享变量的可见性和顺序性保证,以及线程之间的同步和互斥机制。

Java内存模型规定了所有的变量都存储在主内存中,但是每个线程会有自己的工作内存,线程的工作内存保存了该线程中使用了的变量(从主内存中拷贝的),线程对变量的操作都必须在工作内存中进行,不同线程之间无法直接访问对方工作内存中的变量,线程间变量值从传递都要经过主内存完成

Java内存模型中的主要概念包括:

  1. 主内存:Java虚拟机中所有线程所共享的内存区域,用于存储所有变量的值。
  2. 工作内存:每个线程独立拥有的内存区域,用于读写变量的值。线程之间不能直接访问对方的工作内存,所有的变量值都要先从主内存中读取到工作内存中,再进行操作。
  3. 内存屏障:Java虚拟机提供的一种同步机制,用于保证内存操作的可见性和顺序性。

Java内存模型中规定了以下规则:

  1. 原子性:对于基本数据类型如int和long,读写操作具有原子性。对于引用类型和一些复合操作,如i++,并不具有原子性。
  2. 可见性:一个线程修改了变量的值,另一个线程必须能够看到变量的最新值。JMM通过内存屏障来保证可见性。
  3. 顺序性:在没有使用同步机制的情况下,JMM不能保证代码的执行顺序,可能会出现指令重排等情况。使用volatile和synchronized等机制可以保证代码的顺序性。
  4. 原则上不保证读线程能够获得写线程的最新值。使用volatile保证了变量的可见性和顺序性。
  5. 线程操作内存必须先将内存中的数据拷贝到线程的本地内存中,线程之间的共享变量只能通过主内存来传递。

什么是原子性

简单讲:一个操作是不可中断的,要么全部执行成功要么全部执行失败,比如银行转账

原子性是指一组操作要么全部完成,要么全部不完成,不会出现部分完成的情况,保证操作的完整性和一致性。在多线程编程中,如果一个操作需要被多个线程同时访问,为了保证正确性,必须保证操作的原子性。可以使用同步机制如锁或原子变量等来实现原子性。

什么是可见性

当多个线程访问同一变量时,一个线程修改了这个变量的值,其他线程就能够立即看到修改的值

可见性指的是一个程序中变量在多线程环境下的可见性。当一个变量被一个线程修改后,其他线程是否能够立即看到修改的结果就是可见性问题。如果一个变量的值被修改后,其他线程不能立即看到变量的修改结果,那么就会出现数据不一致的问题。在并发编程中,保证可见性是非常重要的一项技术。常见的解决可见性问题的方式包括使用volatile关键字、synchronized关键字、Lock对象等。

什么是有序性

程序执行的顺序按照代码的先后顺序执行
int a = 0; //1
int b = 2; //2

像这2句代码1会比2先执行,但是jvm在正真执行时不一定是1在2之前,这里涉及一个概念叫做指令重排,处理器为了提高程序运行效率,可能会对输入代码进行优化,它不保证程序中各个语句的执行先后顺序同代码中的顺序一致,但是它会保证程序最终执行结果和代码顺序执行的结果是一致的。比如上面的代码语句1和语句2谁先执行对最终的程序结果并没有影响,那么就有可能在执行过程中,语句2先执行而语句1后执行。

在指令重排时会考虑指令之间的数据依赖性,比如2依赖了1的数值,那么处理器会保证1在2之前执行。

但是在多线程的情况下,指令重排就会有影响了。

volatile到底做了什么

在 Java 中,volatile 是一种关键字,用于修饰变量。当一个变量被声明为 volatile

时,它的值可能会被并发修改,因此多个线程之间对该变量的读写操作是相互可见的。 具体来说,当一个线程对一个 volatile

变量进行写操作时,它会强制刷新该变量的值到主内存中,并通知其他线程该变量的值已经发生改变。同理,当一个线程对一个 volatile

变量进行读操作时,它会从主内存中读取最新的值而不是寄存器缓存中的值。因此,volatile 变量的读写操作具有原子性,可以保证线程安全。

需要注意的是,volatile 变量不能保证多个线程对该变量的复合操作(例如 i++)是原子性的,因此对于这类操作,仍然需要使用

synchronized 或者使用原子类来保证线程安全。

volatile实现了以下工作:

  • 禁止了指令重排
  • 保证了不同线程对这个变量进行操作时的可见性,即一个线程修改了某个变量值,这个新值对其他线程是立即可见的
  • 不保证原子性(线程不安全)

基本数据类型

Java基本数据类型包括八种:

  1. byte(字节型):8位有符号二进制数,取值范围为-128~127。

  2. short(短整型):16位有符号二进制数,取值范围为-32768~32767。

  3. int(整型):32位有符号二进制数,取值范围为-2147483648~2147483647。

  4. long(长整型):64位有符号二进制数,取值范围为-9223372036854775808~9223372036854775807。

  5. float(单精度浮点型):32位IEEE-754标准浮点数。

  6. double(双精度浮点型):64位IEEE-754标准浮点数。

  7. char(字符型):16位Unicode字符,取值范围为0~65535。

  8. boolean(布尔型):true或false。

除了基本数据类型,Java还有引用数据类型,如类、接口、数组等。

什么是内部类

内部类是一个定义在另一个类中的类。它可以访问外部类的成员(包括私有成员),并且可以用来实现一些特定的功能,如事件处理、回调等。内部类的作用主要是为了增强可读性、安全性和封装性。内部类分为成员内部类、局部内部类、匿名内部类和静态内部类等几种类型。

静态内部类里面一定是静态方法吗

不是必须的。静态内部类可以声明静态方法,但也可以声明非静态方法。另外,非静态内部类则不能声明静态方法,因为它已经默认包含了外部类的实例,而静态方法不能访问任何实例变量和实例方法。

静态方法可以不可以使用非静态变量

静态方法不能直接使用非静态变量,因为非静态变量是属于对象实例的,而静态方法是独立于对象实例的。如果要在静态方法中使用非静态变量,需要通过实例化对象来访问非静态变量。或者将非静态变量作为参数传递给静态方法。

抽象方法可以不可以有函数体

抽象方法不能有函数体。抽象方法是一种特殊的方法声明,它没有具体的实现,只有方法名、参数和返回值类型。在Java中,抽象方法必须声明在抽象类中,并且抽象类必须用"abstract"关键字修饰。子类必须覆盖重写所有抽象方法才能被实例化,否则子类也必须是一个抽象类。因此,抽象方法不能有函数体,否则它就不再是一个抽象方法,而是一个普通的方法。

说一下抽象类和接口

  • 一个子类只能继承一个抽象类(虚类),但能实现多个接口;
  • 一个抽象类可以有构造方法,接口没有构造方法;
  • 一个抽象类中的方法不一定是抽象方法,即其中的方法可以有实现(有方法体),接口中的方法都是抽象方法,不能有方法体,只有声明;
  • 一个抽象类可以是public、private、protected、default, 接口只有public;
  • 一个抽象类中的方法可以是public、private、protected、default, 接口中的方法只能是public和default。

从使用上来说,抽象类适合用于创建一些共性较强的类和方法,而接口则适合用于实现某些特定的行为,以及在不同类之间进行统一的操作。通常情况下,如果需要更好的扩展性和灵活性,应该优先使用接口,如果需要提供一些默认的实现或是定义某些共有的行为,应该优先使用抽象类。

相关推荐
xcl09255 小时前
北京24小时自助健身房系统软件开发实战:从架构到部署全流程指南
java·spring boot·架构
一 乐7 小时前
动漫书销售商城|基于springboot + vue动漫书销售商城(源码+数据库+文档)
java·数据库·vue.js·spring boot·毕业设计
卓怡学长7 小时前
w214基于jsp知道特产网
java·intellij-idea
步行cgn7 小时前
Spring 注解使用详解
java·spring
一条小小yu8 小时前
Spring IoC的理解
java·后端·spring
落魄实习生8 小时前
Agent Scope Java 2.x 系列【7】工具使用
java·开发语言·ai
旺仔学长 哈哈8 小时前
springboot钓鱼爱好者交流平台APP设计与实现
java·spring boot·mysql·充电桩管理系统
自强的小白10 小时前
核心功能(Service接口)
java·mybatis
财情双生教练易和中10 小时前
“找矿大会战”产业链,量化统计研究报告
职场和发展·职业发展·创业创新·程序员创富