java面试-java基础

java基础

java面向对象有哪些特征

继承 封装 多态

封装:封装是将数据和相关操作封装在一个单元内,对外界来说他内部的细节是隐藏的,暴露给外界的是他的访问方法。

继承:允许一个类(子类/派生类)继承另一个类(父类/基类)的属性和方法。通过继承,子类可以重用父类的代码,并在其基础上进行扩展或修改。继承有助于实现代码的层次结构和代码重用,提高了代码的可扩展性。

多态:多态性就是同一个方法名可以被不同的对象用不同的方式调用。从而提高了代码的灵活性和可扩展性。多态可以通过方法的重写(覆盖)和方法的重载来实现。

多态的三要素

多态三要素:继承、重写和向上转型
1. 继承 2. 方法重写 3. 向上转型:父类引用接收子类对象(默认,隐式转型)
多态表现:父类引用指向子类对象(向上转型),父类引用调用方法执行的是子类重写的方法​

重载和重写的区别

作用范围:重写的作用范围是父类和子类之间;重载是发生在一个类里面

参数列表:重载必须不同;重写不能修改

返回类型:重载可修改;重写方法返回相同类型或子类

访问权限:重载可修改;重写一定不能做更严格的限制

ArrayList和LinkedList有什么区别?

可以从它们的底层数据结构、效率、开销进行阐述哈

ArrayList是数组的数据结构,LinkedList是链表的数据结构。

随机访问的时候,ArrayList的效率比较高,因为LinkedList要移动指针,而ArrayList是基于索引(index)的数据结构,可以直接映射到。

插入、删除数据时,LinkedList的效率比较高,因为ArrayList要移动数据。

LinkedList比ArrayList开销更大,因为LinkedList的节点除了存储数据,还需要存储引用。

静态代理和动态代理的区别?

静态代理中代理类在编译期就已经确定,而动态代理则是JVM运行时动态生成,静态代理的效 率相对动态代理来说相对高一些,但是静态代理代码冗余大,一单需要修改接口,代理类和委 托类都需要修改

Java 语言有哪些特点

  • 面向对象(封装,继承,多态);
  • 平台无关性( Java 虚拟机实现平台无关性);
  • 支持多线程( C++ 语言没有内置的多线程机制,因此必须调用操作系统的多线程功能来进行多线程程序设计,而 Java语言却提供了多线程支持);
  • 可靠性(具备异常处理和自动内存管理机制)

什么是字节码?采用字节码的好处是什么?

在 Java 中,JVM 可以理解的代码就叫做字节码(即扩展名为 .class 的文件),它不面向任何特定的处理器,只面向虚拟机。Java 语言通过字节码的方式,在一定程度上解决了传统解释型语言执行效率低的问题,同时又保留了解释型语言可移植的特点

char 变量能不能存贮一个中文汉字?为什么?

char 变量可以存贮一个汉字,因为 Java 中使用的默认编码是 Unicode ,一个 char 类型占 2 个字节(16 bit),一个汉字是2个字节,所以放一个中文是没问题的。

jdk与jre的区别是什么?

jdk是java开发包,提供了java的开发环境和运行环境。而jre仅是java的运行环境,jdk包含jre以及其他编译工具和分析调试工具

接口和抽象类的区别

接口和抽象类是面向对象编程中的两种不同的概念,它们都用于定义类的结构和行为,但有一些关键区别。以下是一个简单的表格,用于概述它们之间的区别:

特点接口抽象类
定义方式使用 interface 关键字定义使用 abstract 关键字定义
多继承支持多重接口继承不支持多重类继承
构造函数不允许定义构造函数允许定义构造函数
方法实现所有方法都是抽象的,需要被实现可以包含抽象方法和具体方法
变量不允许定义实例变量可以定义实例变量
继承关系类可以同时实现多个接口子类只能继承一个抽象类

总的来说,接口更适合用于定义类之间的契约和多态性,而抽象类更适合用于共享通用行为和结构,并且可以包含一些已实现的方法。选择接口还是抽象类取决于您的设计需求和类之间的关系。有时,它们也可以一起使用,以实现更复杂的继承和多态结构。

Comparable 和 Comparator 有哪些区别?

当比较 Java 中的 Comparable 和 Comparator 时,有一些关键区别需要考虑:

  • 位置

    • Comparable 位于 java.lang 包下。
    • Comparator 位于 java.util 包下。
  • 实现方式

    • Comparable 在排序类的内部实现,定义对象自身的排序规则。
    • Comparator 在排序类的外部实现,允许外部定义多个不同的排序规则。
  • 方法

    • Comparable 需要重写 compareTo() 方法,用于定义对象之间的自然排序规则。
    • Comparator 需要重写 compare() 方法,用于定义不同的排序规则。

这些区别可以帮助您选择何时使用 Comparable 和 Comparator,具体取决于您的需求和设计。

== 和 equals 的区别是什么?

双等于号对于基本类型,两者比较的是值,而对于引用类型,对比的是,其引用是否相同
equals 本质上就是 ==,只不过 String 和 Integer 等重写了 equals 方法,把它变成了值比较

final 在 java 中有什么作用??

final 修饰类,类不可以被继承。
final 修饰的方法不可以被重写
final 修饰的量是常量。必须初始化且不能被修改

String 属于基础的数据类型吗??

String 不属于基础类型,基础类型有 8 种:byte、boolean、char、short、int、float、long、double,而
String 属于对象

String 类能被继承吗,为什么。

首先,String 是一个 final 修饰的类,final 修饰的类不可以被继承。

  • 效率性,String 类作为最常用的类之一,禁止被继承和重写,可以提高效率。
  • 安全性,String 类中有很多调用底层的本地方法,调用了操作系统的 API,如果 方法可以重写,可能被植入恶意代码,破坏程序。

为什么 string 要设计成不可变??

(1) 节省空间:在 java 中,将字符串常量存储在字符串常量池中,这样这些字符串方便被共享,可以节省空间,同时防止其他线程修改该字符串,string 设计为不可变
(2) 提高效率,线程安全:正是由于 string 会被不同用户共享,在多线程编程时,在多线程共享string 时,因为 string 不可变所以 string 是线程安全且省略了同步的过程会显著提高效率。

String、StringBuffer、StringBuilder 的区别?

可变性: String 为字符串常量是不可变对象,StringBuffer 与 StringBuilder 为字符串变量是可变对象;
性能: String 它的底层是一个用 final 修饰的字符数组,每次修改相当于生成一个新对象,因此性能最低;StringBuffer 和 StringBuilder 底层使用的是没有用 final 修饰的字符数组 char[],所以在做字符串拼接的时候就在原来的内存上进行拼接,不会浪费内存空间。但是 StringBuffer 不同与StringBuilder 使用 synchronized 来保证线程安全,但两者性能均优于 String。;

int 和 Integer 有什么区别

 int 是基本数据类型,interger 是 int 的封装类
 int 默认值为 0 ,而 interger 默认值为 null, Interger 使用需要判空处理

int和Integer有什么区别,为什么要使用包装类?

答:为了能够将这些基本数据类型当成对象操作,Java为每一个基本数据类型都引入了对应的包装类型,比如int的包装类就是Integer,Java 为每个原始类型提供了包装类型:

java 中 IO 流分为几种?

主要分为输入输出流。字节流和字符流。字节流按八位传输。以字节为单位。进行输入输出。字符流按
16 位进行传输。以字符为单位进行输入输出。分别来看字符流(Reader、Writer)和字节流(InputStream、OutputStream)的使用。

Writer 使用
	Writer 可用来写入文件,请参考以下代码:
	// 给指定目录下的文件追加信息
	Writer writer = new FileWriter("d:\\io.txt",true);
	writer.append("老王");
	writer.close();
	这几行简单的代码就可以实现把信息 老王 追加到 d:\\io.txt 的文件下,参数二表示的是覆盖文字还是追加文字。
	
	② Reader 使用
	Reader 可用来读取文件,请参考以下代码:
	Reader reader = new FileReader("d:\\io.txt");
	BufferedReader bufferedReader = new BufferedReader(reader);
	String str = null;
	// 逐行读取信息
	while (null != (str = bufferedReader.readLine())) {
		System.out.println(str);
	}
	bufferedReader.close();
	reader.close();InputStream 使用
	InputStream 可用来读取文件,请参考以下代码:
	InputStream inputStream = new FileInputStream(new File("d:\\io.txt"));
	byte[] bytes = new byte[inputStream.available()];
	// 读取到 byte 数组
	inputStream.read(bytes);
	// 内容转换为字符串
	String content = new String(bytes, "UTF-8");
	inputStream.close();OutputStream 使用
	OutputStream 可用来写入文件,请参考以下代码:
	OutputStream outputStream = new FileOutputStream(new File("d:\\io.txt"),true);
	outputStream.write("老王".getBytes());
	outputStream.close();

同步与异步,阻塞与非阻塞

  • 同步和异步指的是:当前线程是否需要等待方法调用执行完毕。
    比如你调用一个搬运一百块石头的方法:
    同步指的是调用这个方法,你的线程需要等待这一百块石头搬完,然后得到搬完了的结果,接着
    再继续执行剩下的代码逻辑。
    异步指的是调用这个方法,立马就直接返回,不必等候这一百块石头还未搬完,可以立马执行后
    面的代码逻辑,然后利用回调(这里也能体现了回调函数的应用场景)或者事件通知的方式得到
    石头已经搬完的结果
  • 阻塞和非阻塞指的是:当前接口数据还未准备就绪时,线程是否被阻塞挂起。
    何为阻塞挂起?就是当前线程还处于 CPU 时间片当中,调用了阻塞的方法,由于数据未准备就
    绪,则时间片还未到就让出 CPU。
    所以阻塞和同步看起来都是等,但是本质上它们不一样,同步的时候可没有让出 CPU。
    而非阻塞就是当前接口数据还未准备就绪时,线程不会被阻塞挂起,可以不断轮询请求接口,看
    看数据是否已经准备就绪。
  • 至此我们可以得到一个结论:
    同步, 异步指:当数据还未处理完成时,代码的逻辑处理方式不同。
    阻塞, 非阻塞指:当数据还未处理完成时 (未就绪),线程的状态。所以同步, 异步其实是处于框架
    这种高层次维度来看待的,而阻塞与非阻塞往往针对底层的系统调用方面来抉择,也就是说两者
    是从不同维度来考虑的。

同步与异步,阻塞与非阻塞 IO

  • 前提:程序和硬件之间隔了个操作系统,而为了安全考虑,Linux 系统分了:用户态和内核态
    在这个前提下,我们再明确 I/O 操作有两个步骤:1.发起 I/O 请求 2.实际 I/O 读写(即数据从内核缓存拷贝到用户空间).

  • 阻塞 I/O 和非阻塞 I/O。按照上文,其实指的就是用户线程是否被阻塞,这里指代的步骤 1
    (发起 I/O 请求)。

  • 阻塞 I/O,指用户线程发起 I/O 请求的时候,如果数据还未准备就绪(例如暂无网络数据接 收),就会阻塞当前线程,让出 CPU。

  • 非阻塞 I/O,指用户线程发起 I/O 请求的时候,如果数据还未准备就绪(例如暂无网络数据
    接收),也不会阻塞当前线程,可以继续执行后续的任务。可以发现,这里的阻塞和非阻塞其实 是指用户线程是否会被阻塞。

  • 同步 I/O 和异步 I/O。按照上文,我们可以得知这就是根据 I/O 响应方式不同而划分的。

  • 同步 I/O,指用户线程发起 I/O 请求的时候,数据是有的,那么将进行步骤 2(实际 I/O 读
    写,即数据从内核缓存拷贝到用户空间),这个过程用户线程是要等待着拷贝完成。

  • 异步 I/O,指用户线程发起 I/O 请求的时候,数据是有的,那么将进行步骤 2(实际 I/O 读
    写,即数据从内核缓存拷贝到用户空间),拷贝的过程中不需要用户线程等待,用户线程可以去
    执行其它逻辑,等内核将数据从内核空间拷贝到用户空间后,用户线程会得到一个“通知”。再 仔细思考下,在 I/O场景下同步和异步说的其实是内核的实现,因为拷贝的执行者是内核,一种是同步将数据拷贝到用户空间,用户线程是需要等着的。一个是通过异步的方式,用户线程不 用等,在拷贝完之后,内核会调用指定的回调函数。

我再简单的总结一下,关于 I/O 的阻塞、非阻塞、同步、异步:
阻塞和非阻塞指的是发起 I/O 请求后,用户线程状态的不同,阻塞 I/O 在数据未准备就绪的
时候会阻塞当前用户线程,而非阻塞 I/O 会立马返回一个错误,不会阻塞当前用户线程。同步和
异步是指,内核的 I/O 拷贝实现,当数据准备就绪后,需要将内核空间的数据拷贝至用户空间,
如果是同步 I/O 那么用户线程会等待拷贝的完成,而异步 I/O 则这个拷贝过程用户线程该干嘛可
以去干吗,当内核拷贝完毕之后会“通知”用户线程。

BIO,NIO,AIO

BIO: 同步阻塞
NIO:同步非阻塞
AIO:异步非阻塞

异常处理

throw 和 throws 的区别?

throws 用来声明一个方法可能抛出的所有异常,表示谁调用都要使用 try-catch 进行异常处理而
throw 则是直接抛出一个具体异常

final、finally、finalize 有什么区别?

final 可以修饰类、变量、方法,修饰类表示该类不能被继承、修饰方法表示该方法不能被
重写、修饰变量表示该变量是一个常量不能被重新赋值。
在 try-catch 中不管有没有异常都要执行 finally 中的内容
finalize 属于所有类父类 Object 类的方法,该方法一般由垃圾回收器执行,当调用 system.gc()
时由垃圾回收器调用 finalize 执行

try-catch-finally 中哪个部分可以省略??

可以省略 catch 或者 finally。catch 和 finally 不可以同时省略。

原因:try 可以自己处理运行异常,try+catch 可以处理运行时 + 普通异常,当我们处理普通异常
省略 catch 编译不通过会报错但是当我们处理运行时异常则可以直接使用 try.

注:如果 catch 中 return 了,finally 会在 return 前执行

java 泛型

使用了迭代器就可以不用关注容器的内部细节,用同样的方式遍历不同类型的容器。(泛型可以修饰
类、方法、接口、变量。)

在这里插入图片描述

List<Object> 和 List<?> 有什么区别?

答:List<?> 可以容纳任意类型,只不过 List<?> 被赋值之后,就不允许添加和修改操作了;而
List<Object> 和 List<?> 不同的是它在赋值之后,可以进行添加和修改操作

List 和 List<Object> 的区别是什么?

答:List 和 List<Object> 都能存储任意类型的数据,但 List 和 List<Object> 的唯一区别就是,List不会触发编译器的类型安全检查,比如把 List<String> 赋值给 List 是没有任何问题的,但赋值给List<Object> 就不行

泛型的工作原理是什么?为什么要有类型擦除??

答:泛型是通过类型擦除来实现的,类型擦除指的是编译器在编译时,会擦除了所有类型相关的信息,比如 List 在编译后就会变成 List 类型,这样做的目的就是确保能和 Java 5 之前的版本(二进制类库)进行兼容。

说说反射的用途及实现原理,Java 获取反射的三种方法

Java 获取反射的三种方法:
 第一种,使用 Class.forName 静态方法。
 第二种,使用类的.class 方法
 第三种,使用实例对象的 getClass() 方法。

讲讲类的实例化顺序,比如父类静态数据,构造函数,子类静态数据,构造函数。

所以,类实例化顺序为: 父类静态代码块/静态域->子类静态代码块/静态域 -> 父类非静态代码块 -> 父类构造器 -> 子类非静态代码块 -> 子类构造器

Java 创建对象有几种方式

Java 创建对象有 5 种方式
 用 new 语句创建对象。
 使用反射,使用 Class.newInstance()创建对象/调用类对象的构造方法——
Constructor
 调用对象的 clone()方法。
 运用反序列化手段,调用 java.io.ObjectInputStream 对象的 readObject()方法.

谈谈 Java 的异常层次结构

从前从前,有位老人,他的名字叫 Throwable,他生了两个儿子,大儿子叫
Error,二儿子叫 Exception。

Error
表示编译时或者系统错误,如虚拟机相关的错误,OutOfMemoryError 等,
error 是无法处理的。
Exception
代码异常,Java 程序员关心的基类型通常是 Exception。它能被程序本身可以
处理,这也是它跟 Error 的区别。
它可以分为 RuntimeException(运行时异常)和 CheckedException(可
检查的异常)。

静态内部类与非静态内部类有什么区别

 静态内部类可以有静态成员(方法,属性),而非静态内部类则不能有静态成员(方
法,属性)。
 静态内部类只能够访问外部类的静态成员和静态方法,而非静态内部类则可以访问
外部类的所有成员(方法,属性)。
 实例化静态内部类与非静态内部类的方式不同
 调用内部静态类的方法或静态变量,可以通过类名直接调用

String s 与 new String 与有什么区别

String snew String 都用于创建字符串对象,但它们之间有重要的区别:

  1. 字符串池(String Pool)的使用:

    • String s = "Hello";:这种方式会尝试将字符串放入字符串池中。如果字符串池中已经存在相同内容的字符串(例如,“Hello”),则会重用现有的字符串对象,而不会创建新的对象。这可以节省内存并提高性能。
    • String s = new String("Hello");:这种方式会创建一个新的字符串对象,无论字符串池中是否已存在相同内容的字符串。这种方式不利于内存管理,因为它会在堆内存中创建新的对象,即使内容相同。
  2. 可变性:

    • String s 对象是不可变的。一旦创建,它的内容不能被修改。任何修改字符串的操作都会创建一个新的字符串对象。
    • new String 创建的字符串对象是可变的。你可以使用一些方法(如concatsubstring)来修改这个字符串对象的内容。
  3. 内存管理:

    • 使用字符串池中的字符串常常更加节省内存,因为多个字符串变量可以共享相同的字符串对象。
    • 使用 new String 创建的字符串对象会占用更多内存,因为每次都会创建一个新的对象,即使内容相同。

一般来说,推荐使用字符串池中的字符串,因为它们具有更好的性能和内存管理。只有在需要修改字符串内容的情况下才使用 new String 创建的字符串对象。

反射中,Class.forName 和 ClassLoader 的区别

Class.forName 和 ClassLoader 都可以对类进行加载。它们区别在哪里呢?
ClassLoader 负责加载 Java 类的字节代码到 Java 虚拟机中。
Class.forName 其实是调用了 ClassLoader。
在这里插入图片描述
所以,Class.forName 和 ClassLoader 的区别,就是在类加载的时候,
class.forName 有参数控制是否对类进行初始化。

深拷贝和浅拷贝

浅拷贝
复制了对象的引用地址,两个对象指向同一个内存地址,所以修改其中任意的
值,另一个值都会随之变化。

深拷贝
将对象及值复制过来,两个对象修改其中任意的值另一个值不会改变

什么是拆装箱?

拆箱:把包装类型转成基本数据类型

装箱:把基本数据类型转成包装类型

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值