Java后端面试题

目录

Java基础

一、面向对象、面向过程的定义

二、Java的四个基本特性

三、重载、重写的区别

四、String、StringBuffer、StringBuilder的区别

五、hashCode、equals

六、hashSet如何检查重复(可以说明为什么要有hashCode)

七、抽象类、接口的区别是什么

七、volatile关键字

八、static关键字

九、静态变量、实例变量

十、get和post的区别

十一、final关键字

十二、HashMap和Hashtable的区别

十三、数据类型

十四、String

十五、异常

十六、Java和C++的区别

十七、List、Set

十八、ArrayList、LinkedList

十九、HashMap的底层实现

线程、并发相关

一、使用线程的方法

二、线程的生命周期

三、sleep、wait的区别

四、并发的三大特性

五、Synchronized的原理

六、什么是CAS

Spring Boot

一、什么是Spring Boot

二、Spring Boot有哪些优缺点

三、什么是Swagger

Dubbo

一、Dubbo中zookeeper做注册中心,如果集群都挂掉,发布者跟订阅者之间还能通信吗?

二、Dubbo服务负载均衡策略


Java基础

一、面向对象、面向过程的定义

  • 面向对象更注重事情的参与者(即对象)、以及各自需要做些什么;

  • 面向过程的优点是性能比面向对象高,因为类调用时需要实例化,开销比较大,更消耗资源;缺点是没有面向对象易维护、易复用、易扩展;

  • 面向对象的优点是易维护、易复用、易扩展,由于面向对象的四个特性,可以设计出低耦合的系统,使得系统更灵活、更易于维护;缺点是性能比面向过程低。

二、Java的四个基本特性

  • 抽象:把生活中的某一类东西提取出来,通常称为类或者接口,包括数据抽象(对象属性)和过程抽象(对象行为特征);
  • 封装:将客观事物封装成抽象的类,并且类可以将自己的数据和方法对不可信的类或者对象封装隐藏,分为属性的封装和方法的封装;
  • 继承:对有着共同特性的多类事物进行再抽象成一个类,这个类就是多类事物的父类,父类的意义在于抽取多类事物的共性;
  • 多态:允许不同类的对象对同一消息做出响应。

三、重载、重写的区别

  • 重载:发送在同一个类中,方法名必须相同,参数类型不同、个数不同、顺序不同,返回值和访问修饰符可以不同;
  • 重写:发送在父子类中,方法名、参数列表必须相同,返回值、抛出的异常小于等于父类,访问修饰符大于等于父类。如果父类访问修饰符是private,则子类中不是重写。重写使用@Override注解,可以让编译器帮忙检查是否满足条件。

四、String、StringBuffer、StringBuilder的区别

  • 可变性:String类中使用字符数组保存字符串,private final char value[ ],所以string对象是不可变的;StringBuilder与StringBuffer都继承自AbstractStringBuilder类,在AbstractStringBuilder中也是使用字符数组保存字符串,char[ ] value,这两种对象是可变的;
  • 线程安全性:String中的对象是不可变的,也就可以理解为常量,所以线程安全。AbstractStringBuilder是StringBuilder和StringBuffer的公共父类,定义了一些字符串的基本操作,例如append、insert、indexOf等公共方法。StringBuffer对方法加了同步锁或者对调用的方法加了同步锁,所以线程安全;StringBuilder没有对方法加同步锁,所以是非线程安全的;
  • 在性能方面,StringBuilder优于StringBuffer,StringBuffer优于String;
  • 经常需要改变字符串内容时使用StringBuilder,多线程使用共享变量时使用StringBuffer。

五、hashCode、equals

  • equals相等,hashCode必定相等;hashCode相等,equals可能不相等;
  • equals方法被覆盖过,则hashCode方法也必须被覆盖。

六、hashSet如何检查重复(可以说明为什么要有hashCode)

  • 对象加入hashSet时,会先计算对象的hashCode值,判断对象加入的位置,看对应的位置是否有值,如果没有,hashSet会假定对象没有重复出现,如果有,会调用equals来检查两个对象是否真的相同。如果相同,hashSet就不会让加入操作成功;如果不同,就会重新散列到其他位置,大大减少equals的次数,提高了执行速度。

七、抽象类、接口的区别是什么

  • 抽象类是对整个类进行抽象,包括属性、行为,是自底向上抽象而来的;接口是对行为抽象,是自顶向下设计的;
  • 抽象类可以存在普通成员函数;接口只能存在抽象方法,jdk1.8之后可以添加默认方法;
  • 抽象类中的成员变量可以是各种类型的;接口中的成员变量时public static final类型的;
  • 抽象类只能继承一个;接口可以实现多个;
  • 抽象类的设计目的是代码的复用,不同类具有某些相同行为且其中一部分行为实现方式一致时,可以让这些类派生于一个抽象类;接口的设计目的是对类的行为进行约束,约束行为的有无但是不对如何实现行为进行限制;
  • 抽象类是对类本质的抽象,表达的是is a的关系,包含并实现了子类的通用特性,将子类存在差异化的特性进行抽象,交由子类去实现;接口是对行为抽象,表达的是like a的关系,其核心是定义行为,即实现类可以做什么,至于实现类主体是谁、是如何实现的,接口不关心;
  • 关注事物的本质时,用抽象类;关注操作时,用接口;
  • 抽象类不能被实例化,只能被继承。

七、volatile关键字

  • 处理器为了提高程序运行效率,可能会对输入代码进行优化,但是不能保证程序中的各个与的执行先后顺序同代码中一致,但是会保证程序最终执行结果和代码顺序执行的结果一致;
  • volatile可以保证可见性:当一条线程修改了这个变量的值,新值对于其他线程是可以立即得知的;
  • volatile可以禁止指令重排:volatile修饰的变量,可以保证变量赋值操作的顺序与程序代码中的执行顺序一致;
  • 基于volatile变量的运算在并发下不一定是安全的。

八、static关键字

  • 可以修饰内部类、方法、变量、代码块;
  • 修饰的类是静态内部类,可以访问外部类所有的静态变量和方法,即使是private也一样,可以定义静态变量、方法、构造方法等;
  • 修饰的方式是静态方法,表示该方法属于当前类,而不属于某个对象,静态方法不能被重写,可以直接使用类名来调用static方法中不能使用this或者super关键字;
  • 修饰的变量是静态变量(类变量),静态变量被所有实例共享,不会依赖于对象,在内存中只有一份拷贝,在JVM加载类的时候,只为静态分配一次内存;
  • 修饰的代码块是静态代码块,通常用来做程序优化,整个静态代码块中的代码只会在整个类加载的时候执行一次,静态代码块可以有多个,按先后顺序执行。

九、静态变量、实例变量

  • 静态变量也称为类变量,类的所有实例都共享静态变量,可通过类名直接访问,静态变量在内存中只存在一份;
  • 实例变量必须依存于某一个实例,只能通过对象才能进行访问,与实例同生共死。

十、get和post的区别

  • get是用来从服务器上获取数据,而post是用来向服务器上传递数据;
  • get将表单中的数据按照variable=value的形式,添加到action所指向的URL后,并且两者使用“?”连接,各变量之间用“&”连接;post是将表单中的数据放在form数据体中,按照变量和值相对应的方式传递到action所指向URL;
  • get是不安全的,在传输过程中,数据被放在请求的URL中;post的所有操作对用户来说不可见;
  • get的传输的数据量小,主要是受URL长度限制;post可以传输大量数据,所以上传文件只能使用post;
  • get限制form表单的数据集必须是ASCII字符;post支持整个ISO10646字符集;
  • get是form的默认方式。

十一、final关键字

  • final修饰的类不可以被继承;
  • final修饰的方法不可以被重写;
  • final修饰的变量不可以被改变,如果修饰引用,那么表示引用不可变,引用指向的内容可变;
  • final修饰的方法,JVM会尝试将其内联,提高运行效率;
  • final修饰的常量,在编译期会存入常量池。

十二、HashMap和Hashtable的区别

  • 二者都实现了Map接口;
  • HashMap没有排序,允许null键(一个)和null值(多个),Hashtable不允许;
  • HashTable继承自Dictionary类,HashMap是Map接口的实现类;
  • HashTable的方法是Synchronize的,而HashMap不是,在多个线程访问HashTable时,不需要实现同步,而HashMap需要提供;
  • HashMap把HashTable的contains方法去掉了,改成了containsvalue和containsKey;
  • HashTable和HashMap采用的hash/rehash算法大致一样,所以性能没有很大差异。

十三、数据类型

  • byte/8、char/16、short/16、int/32、float/32、long/64、double/64
  • boolean:只有true和false,可以使用1bit存储。

十四、String

  • String被声明为final,不可被继承;
  • String中的常用方法如下:
String中的常用方法
方法名 作用
compareTo(String s) 比较两个字符串
equals(Object obj) 判断内容是否相等
endsWith(String s) 判断字符串是否以s结尾
contains(String s) 判断字符串是否包含s
length() 获取字符串长度
split(String split) 分割字符串
trim() 返回消除空格后的字符串

十五、异常

  • 所有异常的顶级父类是Throwable,Throwable下面有两个子类Exception和Error;
  • Exception分为两类:一类是受检异常,需要用try...catch...语句进行捕获,并且可以从异常中恢复;一类是非受检异常,是程序运行时错误,例如除0;
  • 常见异常如下:

        (1)java.lang.NullPointerException,调用了未经初始化的对象或者是不存在的对象;

        (2)java.lang.ClassNotFoundException,指定的类不存在;

        (3)java.lang.NumberFormatException,字符串转换为数字异常;

        (4)java.lang.IndexOutOfBoundsException,数组下标越界异常;

        (5)java.lang.ArithmeticException,数学运算异常。

十六、Java和C++的区别

  • Java是面向对象,C++为了兼容C,既支持面向对象也支持面向过程;
  • Java通过虚拟机可以实现跨平台,C++依赖于特定平台;
  • Java没有指针,其引用可以理解为安全指针,C++有指针;
  • Java支持自动垃圾回收,C++需要手动回收;
  • Java不支持多继承,只能实现多接口,C++支持多继承。

十七、List、Set

  • List:有序,可重复,允许多个null元素,可以使用Iterator取出所有元素,也可以使用get方法获取指定下标的元素;
  • Set:无序,不可重复,最多允许一个null元素,只能使用Iterator取元素。

十八、ArrayList、LinkedList

  • ArrayList基于动态数组,支持快速随机访问。数组默认大小是10。
  • LinkedList基于链表,适合做数据的插入以及删除操作,但不适合查询,需要逐一遍历。

十九、HashMap的底层实现

  • 底层是数组+链表实现;
  • jdk1.8之后,链表高度达到8、数组长度超过64,链表就会转为红黑树。

        (1)计算key的hash值,二次hash然后对数组长度取模,对应到数组下标;

        (2)如果没有产生hash冲突(下标位置没有元素),直接创建节点存入数组;

        (3)如果产生hash冲突,先进行equal比较,相同则取代,不同,则判断链表高度插入链表,高度达到8,并且数组长度到64,则转变为红黑树,长度低于6则将红黑树转回链表;

        (4)key为null,存在下标为0的位置。

线程、并发相关

一、使用线程的方法

  • 实现Runnable接口;
  • 实现Callable接口;
  • 继承Thread类。

二、线程的生命周期

  • 线程通常有五种状态:创建、就绪、运行、阻塞、死亡;
  • 阻塞态又分为三种:

        (1)等待阻塞:执行wait方法,该线程会释放占用的所有资源,JVM会把该线程放入等待池中,进入这个状态不能被自动唤醒,必须依靠其他线程调用notify或者notifyAll才能唤醒;

        (2)同步阻塞:运行的线程在获取对象的同步锁时,若同步锁被占用,则JVM会把该线程放入锁池中;

        (3)其他阻塞:执行sleep或者join方法,或者发出I/O请求时,JVM就会将该线程置为阻塞态。当sleep状态超时、join等待线程终止或者超时、或者I/O请求处理完毕时,线程重新进入就绪态。

三、sleep、wait的区别

  • sleep是Thread类的静态本地方法,wait是Object类的本地方法;
  • sleep方法不会释放lock,wait会释放lock,并加入到等待队列中;
  • sleep方法不依赖于synchronized,wait需要依赖synchronized;
  • sleep不需要被唤醒,wait需要;
  • sleep一般用于当前线程休眠或者轮循暂停操作,wait则多用于多线程之间的通信;
  • sleepe会让出CPU执行时间且强制上下文切换,wait则不一定。

四、并发的三大特性

  • 原子性:指在一个操作中CPU不可以在中途暂停然后再调度,即不被中断操作,要么全部执行,要么都不执行。关键字:synchronized;
  • 可见性:当多个线程访问到同一个变量时,一个线程修改了值,其他线程都能立即看到修改的值。关键字:volatile、synchronized、final;
  • 有序性:虚拟机在进行代码编译时,对于那些改变顺序之后不会对最终结果造成影响的代码,虚拟机不一定会按照写的代码的顺序执行,有可能进行重排序。实际上,有些代码进行重排序之后,虽然对变量的值没有造成影响,但有可能出现线程安全问题。关键词:volatile、synchronized。

五、Synchronized的原理

Synchronized是由JVM实现的一种实现互斥同步的一种方式,查看被Synchronized修饰过的代码块,在编译前后被编译器生成了monitorenter和monitorexit两个字节码指令。在虚拟机执行到monitorenter指令时,首先要尝试获取对象的锁,如果这个对象没有锁定,或者当前线程已经拥有了这个对象的锁,把锁的计数器+1;执行monitorexit指令时将锁计数器-1;当计数器为0时,锁被释放。如果获取对象失败,那么当前线程就要阻塞等待,直到对象锁被另外一个线程释放为止。

Synchronized是通过在对象头设置标记,达到了获取锁和释放锁的目的。

六、什么是CAS

CAS(Compare and Swap,比较并交换),涉及到三个操作数:内存值、预期值、新值。当且仅当预期值和内存值相等时才将内存值修改为新值。

处理逻辑是首先检查某块内存的值是否跟之前读取的一样,如果不一样则表示期间此内存值已经被别的线程修改了,舍弃本次操作,否则说明期间没有其他线程对此内存值操作,可以将新值设置给此块内存。

CAS具有原子性。

Spring Boot

一、什么是Spring Boot

现如今,启动一个新的Spring项目,必须添加构建路径或者添加maven依赖关系,配置应用程序服务器,添加Spring配置,因此开始一个新的Spring项目需要从头开始做所有事情。

Spring Boot建立在现有的Spring框架之上,因此,Spring Boot可以帮助我们以最少的工作量,更健壮地使用现有Spring功能。

二、Spring Boot有哪些优缺点

  • 优点:

        (1)快速构建项目;

        (2)对主流开发框架的无配置集成;

        (3)项目可独立运行,无须外部依赖Servlet容器;

        (4)提供运行时的应用监控;

        (5)极大提高了开发、部署效率;

        (6)与云计算天然集成。

  • 缺点:

        (1)版本迭代速度很快,一些模块改动很大;

        (2)不需要自己做配置,报错时定位困难;

        (3)网上现成解决方案比较少。

三、什么是Swagger

Swagger广泛应用于可视化API,使用Swagger UI为前端开发人员提供在线沙箱。Swagger是用于生成RestFul Web服务的可视化表示的工具,规定和完整框架实现。它使文档能够以与服务器相同的速度更新。当通过Swagger正确定义时,消费者可以使用最少量的实现逻辑来理解远程服务并与其进行交互,因此,Swagger消除了调用服务时的猜测。

Dubbo

一、Dubbo中zookeeper做注册中心,如果集群都挂掉,发布者跟订阅者之间还能通信吗?

可以;启动Dubbo时,消费者会从zookeeper拉取注册的生产者的地址接口等数据,缓存到本地。每次调用时按照本地存储的地址进行调用。注册中心对等集群,任意一台宕机,将会切换到另一台;注册中心全部宕机,仍旧能通过本地缓存进行通信。

二、Dubbo服务负载均衡策略

  • Random LoadBalance:随机;
  • RoundRobin LoadBalance:轮循;
  • LeastActive LoadBalance:最少活跃调用数;
  • ConsistentHash LoadBalance:一致性Hash。

猜你喜欢

转载自blog.csdn.net/qq_44978143/article/details/121937342