java面试基础部分

2021/6/13 20:25:03

本文主要是介绍java面试基础部分,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!

基础知识部分
基础数据类型:byte、char、short、int、long 、float、double、boolean
Static:被static修饰的变量属于类变量,被static修饰的方法属于类方法,可以通过类名调用。static代码块在类中是独立于成员变量和成员函数的代码块的。注意: 这些static代码块只会被执行一次
final、finally、finalize 有什么区别?
(1)final可以修饰类、变量、方法,修饰类表示该类不能被继承、修饰方法表示该方法不能被重写、修饰变量表示该变量是一个常量不能被重新赋值。
(2)finally一般作用在try-catch代码块中,在处理异常的时候,通常我们将一定要执行的代码方法finally代码块中,表示不管是否出现异常,该代码块都会执行,一般用来存放一些关闭资源的代码。
(3)finalize是一个方法,属于Object类的一个方法,而Object类是所有类的父类,该方法一般由垃圾回收器来调用,当我们调用System的gc()方法的时候,由垃圾回收器调用finalize(),回收垃圾。
throw 和 throws 的区别?
throws是用来声明一个方法可能抛出的所有异常信息,throws是将异常声明但是不处理,而是将异常往上传,谁调用我就交给谁处理。而throw则是指抛出的一个具体的异常类型。

try-catch-finally 中,如果 catch 中 return 了,finally 还会执行吗?
会执行,在 return 前执行。
常见的异常类有哪些?
NullPointerException:当应用程序试图访问空对象时,则抛出该异常。
SQLException:提供关于数据库访问错误或其他错误信息的异常。
IndexOutOfBoundsException:指示某排序索引(例如对数组、字符串或向量的排序)超出范围时抛出。
NumberFormatException:当应用程序试图将字符串转换成一种数值类型,但该字符串不能转换为适当格式时,抛出该异常。
FileNotFoundException:当试图打开指定路径名表示的文件失败时,抛出此异常。
IOException:当发生某种I/O异常时,抛出此异常。此类是失败或中断的I/O操作生成的异常的通用类。
ClassCastException:当试图将对象强制转换为不是实例的子类时,抛出该异常。
==和equal()的区别
基本类型:比较的是值是否相同;
引用类型:比较的是引用是否相同;
equals 本质上就是 ==,只不过 String 和 Integer 等重写了 equals 方法

String、StringBuffer、StringBuilder的区别
String 和 StringBuffer、StringBuilder 的区别在于 String 声明的是不可变的对象,每次操作都会生成新的 String 对象,然后将指针指向新的 String 对象,而 StringBuffer、StringBuilder 可以在原有对象的基础上进行操作,所以在经常改变字符串内容的情况下最好不要使用 String。
StringBuffer 和 StringBuilder 最大的区别在于,StringBuffer 是线程安全的,而 StringBuilder 是非线程安全的,但 StringBuilder 的性能却高于 StringBuffer,所以在单线程环境下推荐使用 StringBuilder,多线程环境下推荐使用 StringBuffer。
String 类的常用方法都有那些?
indexOf():返回指定字符的索引。
charAt():返回指定索引处的字符。
replace():字符串替换。
trim():去除字符串两端空白。
split():分割字符串,返回一个分割后的字符串数组。
getBytes():返回字符串的 byte 类型数组。
length():返回字符串长度。
toLowerCase():将字符串转成小写字母。
toUpperCase():将字符串转成大写字符。
substring():截取字符串。
equals():字符串比较。
String s1=”abcd” 与String s2=new String(”abcd”)的区别

抽象类和接口的区别:
抽象类是被继承(extends)接口是被实现(implement) 一个类可以实现多个接口,但只能继承一个抽象类。
抽象类可以有构造方法,接口中不能有构造方法。
抽象类中可以有普通成员变量,接口中没有普通成员变量
抽象类中可以包含非抽象的普通方法,接口中的所有方法必须都是抽象的,不能有非抽象的普通方法。

堆和栈的区别:
栈内存存储的是局部变量而堆内存存储的是实体;
申请效率的不同。栈由系统自动分配,速度较快,而堆一般速度比较慢;
栈是连续的空间,而堆是不连续的空间。
一般情况下堆的空间比栈大
栈内存存放的变量生命周期一旦结束就会被释放,而堆内存存放的实体会被垃圾回收机制不定时的回收。

字节流和字符流的区别
字节流操作(读写)的基本单元为字节;字符流操作的基本单元为Unicode码元。
字节流默认不使用缓冲区;字符流使用缓冲区。
一般纯文本文件使用字符流,其他使用字节流。

数组和集合的区别:
数组声明了它容纳的元素的类型,而集合不声明。
数组是静态的,一个数组实例具有固定的大小,一旦创建了就无法改变容量了。而集合是可以动态扩展容量,可以根据需要动态改变大小,集合提供更多的成员方法,能满足更多的需求。
数组的存放的类型只能是一种(基本类型/引用类型),集合存放的类型可以不是一种(不加泛型时添加的类型是Object)。
数组是java语言中内置的数据类型,是线性排列的,执行效率或者类型检查都是最快的。

Collection和Collections的区别
java.util.Collection 是一个集合接口(集合类的一个顶级接口)。它提供了对集合对象进行基本操作的通用接口方法。Collection接口在Java 类库中有很多具体的实现。Collection接口的意义是为各种具体的集合提供了最大化的统一操作方式,其直接继承接口有List与Set。
Collections则是集合类的一个工具类/帮助类,其中提供了一系列静态方法,用于对集合中元素进行排序、搜索以及线程安全等各种操作。

List(有序集合,允许相同元素和null)
ArrayList (非同步,允许相同元素和null,实现了动态大小的数组,遍历效率高,用的多)
LinkedList (非同步,允许相同元素和null,遍历效率低插入和删除效率高,双向链表)
Vector(同步,允许相同元素和null,效率低)
ArrayList和LindedList的区别:
1.ArrayList是实现了基于动态数组的数据结构,LinkedList基于链表的数据结构。
2.对于随机访问get和set,ArrayList觉得优于LinkedList,因为LinkedList要移动指针。
3.对于新增和删除操作add和remove,LinedList比较占优势,因为ArrayList要移动数据。
4.ArrayList 的时间复杂度是 O(1),而 LinkedList 是 O(n)

Map(没有实现collection接口,key不能重复,value可以重复,一个key映射一个value)
Hashtable (实现Map接口,同步,不允许null作为key和value,用自定义的类当作key的话要复写hashCode和eques方法,)
HashMap (实现Map接口,非同步,允许null作为key和value,用的多)

HashMap 和 Hashtable 有什么区别?
hashMap去掉了HashTable 的contains方法,但是加上了containsValue()和containsKey()方法。
hashTable同步的,而HashMap是非同步的,效率上比hashTable要高。
hashMap允许空键值,而hashTable不允许。
HashSet 不是线程安全的, 如果多个线程尝试同时修改 HashSet,则最终结果是不确定的。
HashMap具有很快的访问速度,最多允许一条记录的键为 null,不支持线程同步 是无序的

HashMap 的实现原理是什么?
HashMap概述: HashMap是基于哈希表的Map接口的非同步实现。此实现提供所有可选的映射操作,并允许使用null值和null键。此类不保证映射的顺序,特别是它不保证该顺序恒久不变。
HashMap的数据结构: 在java编程语言中,最基本的结构就是两种,一个是数组,另外一个是模拟指针(引用),所有的数据结构都可以用这两个基本结构来构造的,HashMap也不例外。HashMap实际上是一个“链表散列”的数据结构,即数组和链表的结合体。
当我们往Hashmap中put元素时,首先根据key的hashcode重新计算hash值,根绝hash值得到这个元素在数组中的位置(下标),如果该数组在该位置上已经存放了其他元素,那么在这个位置上的元素将以链表的形式存放,新加入的放在链头,最先加入的放入链尾.如果数组中该位置没有元素,就直接将该元素放到数组的该位置上。
需要注意Jdk 1.8中对HashMap的实现做了优化,当链表中的节点数据超过八个之后,该链表会转为红黑树来提高查询效率,从原来的O(n)到O(logn)

Set(无序集合,不允许相同元素,最多有一个null元素)
HashSet(无序集合,不允许相同元素,最多有一个null元素)
说一下 HashSet 的实现原理?
HashSet底层由HashMap实现
HashSet的值存放于HashMap的key上
HashMap的value统一为PRESENT

反射
反射机制是在运行时,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意个对象,都能够调用它的任意一个方法。在java中,只要给定类的名字,就可以通过反射机制来获得类的所有信息。这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制。
优点:提高系统的灵活性和扩展性,降低耦合性,提高自适应能力。它允许程序创建和控制任何类的对象。

反射的实现方式都有什么?
获取Class对象,有4种方法:(1)Class.forName(“类的路径”);(2)类名.class;(3)对象名.getClass();(4)基本类型的包装类,可以调用包装类的Type属性来获得该包装类的Class对象。
什么是线程,与进程的区分?
线程是操作系统(cpu调度)能够进行运算调度的最小单位。它被包含在进程之中,是进程中的实际运作单位。
1.一个线程只能属于一个进程,而一个进程可以有多个线程,但至少有一个线程;
2.资源分配给进程,同一进程的所有线程共享该进程的所有资源;
3.处理机分给线程,即真正在处理机上运行的是线程;
4.线程在执行过程中,需要协作同步。不同进程的线程间要利用消息通信的办法实现同步。
什么是多线程,多线程的优点?
优点:提高cpu的利用率,可以提高程序的效率。
提高程序的响应速度,可以分别设置各个任务的优先级以优化性能
缺点:是很耗系统资源,因为线程需要开辟内存。更多线程需要更多内存。
影响系统性能,因为操作系统需要在线程之间来回切换。
.需要考虑线程操作对程序的影响,如线程挂起,中止等操作对程序的影响。
什么是线程安全?
当多个线程访问某一个类(对象或方法)时,对象对应的公共数据区始终都能表现正确,那么这个类(对象或方法)就是线程安全的
创建线程的方式
继承Thread类创建线程类
通过Runnable接口创建线程类
通过Callable和Future创建线程
runnable 和 callable 有什么区别?
Runnable接口中的run()方法的返回值是void,它做的事情只是纯粹地去执行run()方法中的代码而已;
Callable接口中的call()方法是有返回值的,是一个泛型,和Future、FutureTask配合可以用来获取异步执行的结果。
线程有哪些状态:
线程通常都有五种状态,创建、就绪、运行、阻塞和死亡。
Run()和Start()的区别
start()方法来启动线程,真正实现了多线程运行,通过调用Thread类的start()方法来启动一个线程,这时此线程是处于就绪状态,并没有运行。然后通过此Thread类调用方法run()来完成其运行操作的,这里方法run()称为线程体。
例子:start()为排队 run()为排到你了。

Sleep()和wait()的区别

Sleep()和yield()方法的区别
sleep给其他线程运行机会时不考虑线程的优先级,yield只会给相同优先级或更高优先级的线程运行的机会
线程执行sleep()方法后转入阻塞状态,所以,执行sleep()方法的线程在指定的时间内不会被执行,而yield()方法只是使当前线程重新回到可执行状态,所以执行yield()方法的线程可能在进入可执行状态后马上又被执行
Lock和synchronize的区别
两者所处层面不同
synchronized是Java中的一个关键字,在jvm层面
Lock是Java中的一个接口,
解锁操作
synchronized:不能指定解锁操作,执行完代码块的对象会自动释放锁,自动解锁。
Lock:可调用ulock方法去释放锁比synchronized更灵活,手动释放锁。
应用
Lock锁适合大量同步的代码的同步问题,synchronized锁适合代码少量的同步问题
乐观锁和悲观锁的区别
悲观锁, 顾名思义,就是很悲观,每次去拿数据的时候都认为别人会修改,所以每次在拿数据的时候都会上锁,这样别人想拿这个数据就会block直到它拿到锁。传统的关系型数据库里边就用到了很多这种锁机制,比如行锁,表锁等,读锁,写锁等,都是在做操作之前先上锁。
乐观锁(Optimistic Lock), 顾名思义,就是很乐观,每次去拿数据的时候都认为别人不会修改,所以不会上锁,但是在更新的时候会判断一下在此期间别人有没有去更新这个数据,可以使用版本号等机制。乐观锁适用于多读的应用类型,这样可以提高吞吐量。

两种锁各有优缺点,不可认为一种好于另一种,像乐观锁适用于写比较少的情况下,即冲突真的很少发生的时候,这样可以省去了锁的开销,加大了系统的整个吞吐量。但如果经常产生冲突,上层应用会不断的进行retry,这样反倒是降低了性能,所以这种情况下用悲观锁就比较合适。
线程池
线程池是一种多线程处理形式,处理过程中将任务添加到队列,然后在创建线程后自动启动这些任务。线程池线程都是后台线程。
降低资源消耗。通过重复利用已创建的线程降低线程创建和销毁造成的消耗。
提高响应速度。当任务到达时,任务可以不需要等到线程创建就能立即执行。
提高线程的可管理性。
一个线程池包括以下四个基本组成部分:
1、线程池管理器(ThreadPool):用于创建并管理线程池,包括 创建线程池,销毁线程池,添加新任务;
2、工作线程(PoolWorker):线程池中线程,在没有任务时处于等待状态,可以循环的执行任务;
3、任务接口(Task):每个任务必须实现的接口,以供工作线程调度任务的执行,它主要规定了任务的入口,任务执行完后的收尾工作,任务的执行状态等;
4、任务队列(taskQueue):用于存放没有处理的任务。提供一种缓冲机制。
常用的线程池
①newSingleThreadExecutor
单个线程的线程池,即线程池中每次只有一个线程工作,单线程串行执行任务
②newFixedThreadExecutor(n)
固定数量的线程池,没提交一个任务就是一个线程,直到达到线程池的最大数量,然后后面进入等待队列直到前面的任务完成才继续执行
③newCacheThreadExecutor(推荐使用)
可缓存线程池,当线程池大小超过了处理任务所需的线程,那么就会回收部分空闲(一般是60秒无执行)的线程,当有任务来时,又智能的添加新线程来执行。
④newScheduleThreadExecutor
大小无限制的线程池,支持定时和周期性的执行线程

Web部分
Servlet 生命周期:
加载阶段、实例化阶段、初始化阶段、服务阶段、销毁阶段

Jsp的九大内置对象和四大域对象:
pageContext page request response session application out config exception(绿色为4个域对象)
Post请求和get请求的区别:
get请求比post请求速度快
get是从服务器上获取数据,post是向服务器传送数据。
post请求比get请求安全性高
post请求比get请求传送的数据量较大(get不能大于2KB,post为100KB)
session 和 cookie 有什么区别?
1、cookie数据存放在客户的浏览器上,session数据放在服务器上
2、cookie不是很安全,别人可以分析存放在本地的COOKIE并进行
3、session会在一定时间内保存在服务器上。当访问增多,会比较占用你服务器的性能
4、单个cookie在客户端的限制是3K,就是说一个站点在客户端存放的COOKIE不能大于3K。对于session来说并没有上限,但出于对服务器端的性能考虑,session内不要存放过多的东西
5、cookie支持跨域名访问。session不支持跨域名访问。

http协议
超文本传输协议,他是由w3c制定的一种应用层协议,用来定义浏览器和web服务器之间如何通信以及通信的数据格式。
HTTP协议传输的数据都是未加密的,也就是明文的,
HTTPS是对HTTP协议传输的数据进行加密,比HTTPS更加安全。

重定向和请求转发的区别?
请求次数:重定向为2次,转发为1次
重定向地址栏会变化,请求转发地址栏不会变化。
重定向可以跨域访问,而转发是在web服务器内部进行的,不能跨域访问。
重定向两次请求不共享数据,转发共享数据。
重定向是客户端行为,转发是服务器端行为。
拦截器和过滤器的区别
过滤器依赖于servlet容器,基于函数回调实现,可以对所有请求进行过滤,过滤器实例只在容器初始化时调用一次,
拦截器依赖于web框架,基于Java的反射机制实现,属于AOP的一种运用。只能对controller请求进行拦截,可以多次调用。可以获取IOC容器中的各个bean。
Ajax请求
AJAX = 异步 JavaScript 和 XML。 通过在后台与服务器进行少量数据交换,AJAX 可以使网页实现异步更新.,局部刷新。
请求的五个步骤
1.创建一个XMLHttpRequest异步对象
2.设置请求方式和请求地址
3.接着,用send发送请求
4.监听状态变化
5.最后,接收返回的数据
Json
JSON 是轻量级的文本数据交换格式
JSON 独立于语言:JSON 使用 Javascript语法来描述数据对象,但是 JSON 仍然独立于语言和平台。
Json对象
{ “name”:“老姚” , “url”:“www.yaonutao.com” }
json数组:
var sites = [ { “name”:“runoob” , “url”:“www.runoob.com” }, { “name”:“google” , “url”:“www.google.com” }, { “name”:“微博” , “url”:“www.weibo.com” } ];
JDBC链接数据库步骤
加载JDBC驱动程序
创建数据库连接
创建statement对象
执行sql
处理返回结果
关闭资源

Tomcat

Tomcat主要组件:服务器Server,服务Service,连接器Connector、容器Container。连接器Connector和容器Container是Tomcat的核心。
一个Container容器和一个或多个Connector组合在一起,加上其他一些支持的组件共同组成一个Service服务,有了Service服务便可以对外提供能力了,但是Service服务的生存需要一个环境,这个环境便是Server,Server组件为Service服务的正常使用提供了生存环境,Server组件可以同时管理一个或多个Service服务。
两大组件
1、Connector

一个Connecter将在某个指定的端口上侦听客户请求,接收浏览器的发过来的 tcp 连接请求,创建一个 Request 和 Response 对象分别用于和请求端交换数据,然后会产生一个线程来处理这个请求并把产生的 Request 和 Response 对象传给处理Engine(Container中的一部分),从Engine出获得响应并返回客户。

2、Container

Container是容器的父接口,该容器的设计用的是典型的责任链的设计模式,它由四个自容器组件构成,分别是Engine、Host、Context、Wrapper。这四个组件是负责关系,存在包含关系。通常一个Servlet class对应一个Wrapper,如果有多个Servlet定义多个Wrapper,如果有多个Wrapper就要定义一个更高的Container,如Context。
Context 还可以定义在父容器 Host 中,Host 不是必须的,但是要运行 war 程序,就必须要 Host,因为 war 中必有 web.xml 文件,这个文件的解析就需要 Host 了,如果要有多个 Host 就要定义一个 top 容器 Engine 了。而 Engine 没有父容器了,一个 Engine 代表一个完整的 Servlet 引擎。

Engine 容器
Engine 容器比较简单,它只定义了一些基本的关联关系
Host 容器
Host 是 Engine 的子容器,一个 Host 在 Engine 中代表一个虚拟主机,这个虚拟主机的作用就是运行多个应用,它负责安装和展开这些应用,并且标识这个应用以便能够区分它们。它的子容器通常是 Context,它除了关联子容器外,还有就是保存一个主机应该有的信息。
Context 容器
Context 代表 Servlet 的 Context,它具备了 Servlet 运行的基本环境,理论上只要有 Context 就能运行 Servlet 了。简单的 Tomcat 可以没有 Engine 和 Host。Context 最重要的功能就是管理它里面的 Servlet 实例,Servlet 实例在 Context 中是以 Wrapper 出现的,还有一点就是 Context 如何才能找到正确的 Servlet 来执行它呢? Tomcat5 以前是通过一个 Mapper 类来管理的,Tomcat5 以后这个功能被移到了 request 中,在前面的时序图中就可以发现获取子容器都是通过 request 来分配的。
Wrapper 容器
Wrapper 代表一个 Servlet,它负责管理一个 Servlet,包括的 Servlet 的装载、初始化、执行以及资源回收。Wrapper 是最底层的容器,它没有子容器了,所以调用它的 addChild 将会报错。
Wrapper 的实现类是 StandardWrapper,StandardWrapper 还实现了拥有一个 Servlet 初始化信息的 ServletConfig,由此看出 StandardWrapper 将直接和 Servlet 的各种信息打交道。
网址:(42条消息) Tomcat(一):简介_水滴的博客-CSDN博客_tomcat

热部署和热加载的区别
热加载:服务器会监听 class 文件改变,包括class,lib,web.xml等文件,若发生更改,则局部进行加载,不清空session ,不释放内存。开发中用的多,但是要考虑内存溢出的情况。
热部署:整个项目从新部署,包括你从新打上.war 文件。 会清空session ,释放内存。
热加载:在运行时重新加载class,主要使用的是类加载机制,在实现方式上就是在容器启动的时候起一条后台线程,定时的检测类文件的时间戳变化,如果类的时间戳发生变化,则将类重新载入。
热部署:直接重新加载整个应用,这种方式会释放内存,比热加载更加干净,但是它比热加载更加的浪费时间。
热部署:更多的是在生产环境中使用,就是适用于频繁的部署并且启动耗时长的应用、无法停止服务的应用等。
热加载:更多的是在开发环境中使用,用于开发,debug中,可以大大的提高开发效率。



这篇关于java面试基础部分的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!


扫一扫关注最新编程教程