Java开发面试必备
(一)java基础
1.面向对象的特性有那些? 封装、继承和多态。 封装:对该类的成员变量的访问做出一些限定,不允许外界随意访问。 继承:从已有的类中派生出新的类,子类可以继承父类的某些方法和属性,也可以进行改写。 多态:不同类的对象在调用同一个方法时所呈现出来的多种不同行为。 2.Java中的重写和重载区别是啥? 重写(Override)是指子类对父类方法的一种重写,只能比父类抛出更少的异常,访问权限不能比父类的小。被覆盖的方法不能是 private 的,否则只是在子类中重新定义了一个方法。 重载(Overload)表示同一个类中可以有多个名称相同的方法,但这些方法的参数列表各不相同。 构成重载的条件:参数类型不同、参数个数不同、参数顺序不同。 函数的返回值不同不能构成重载:有些方法不需要返回值。 3.抽象类和接口的区别有哪些? 1)抽象类中可以没有抽象方法,接口中的方法必须是抽象方法; 2)抽象类中可以有普通的成员变量,接口中只有常量,没有变量; 3)抽象类只能单继承,接口可以实现多个父接口; 4)Java 8 中接口中会有 default 方法,即方法可以被实现。 如何选择是接口还是抽象类: ?如果要创建不带任何方法定义和成员变量的基类,那么就应该选择接口而不是抽象类; 如果知道某个类应该是基类,那么第一个选择的应该是让它成为一个接口,只有在必须要有方法定义和成员变量的时候,才应该选择抽象类,因为抽象类中允许存在一个或多个被具体实现的方法,只要方法没有被全部实现该类就仍是抽象类。 4.java、C和C++的区别是啥? C是面向过程,C++和java是面向对象 是面向对象的语言,都支持封装、继承和多态 指针,Java 不提供指针来直接访问内存,程序更加安全 继承,Java 的类是单继承的,C++ 支持多重继承;Java 通过一个类实现多个接口来实现 C++中的多重继承;Java 中类不可以多继承,但是接口可以多继承 内存:Java 有自动内存管理机制,不需要程序员手动释放无用内存 5.Java值传递和对象传递? 值传递是指对象被值传递,意味着传递了对象的一个副本,即使副本被改变,也不会影响源对象。 引用传递是指对象被引用传递,意味着传递的并不是实际的对象,而是对象的引用。因此,外部对引用对象的改变会反映到所有的对象上。 6.JDK、JRE和JVM的联系和区别有哪些? JDK 是 Java 开发工具包,是 Java 开发环境的核心组件,并提供编译、调试和运行一个 Java 程序所需要的所有工具,可执行文件和二进制文件,是一个平台特定的软件。 JRE 是 Java 运行时环境,是 JVM 的实施实现,提供了运行 Java 程序的平台,JRE 包含了 JVM,但是不包含 Java 编译器/调试器之类的开发工具。 JVM 是 Java 虚拟机,当我们运行一个程序时,JVM 负责将字节码转换为特定机器代码,JVM 提供了内存管理/垃圾回收和安全机制等。这种独立于硬件和操作系统,正是 Java 程序可以一次编写多处执行的原因。 区别: JDK 用于开发,JRE 用于运行 Java 程序 JDK 和 JRE 中都包含 JVM JVM 是 Java 编程语言的核心并且具有平台独立性 7.Jdk中常用的包有哪些?(问过) java.lang(Java语言的核心类)、java.util(大量的工具类、集合类,如List、Set)、http://java.io(输入输出)、http://java.net(网络编程相关)、java.awt(GUI相关类和接口)java.sql。 8.说说常用的排序算法?(问过) 9.如何判断一个字符串是否为null? null表示的是一个对象的值,而并不是一个字符串。例如声明一个对象的引用,String a = null ; ""表示的是一个空字符串,也就是说它的长度为0。例如声明一个字符串String str = “” ;
public class StringTest {
public static void main(String[] args) {
String str1=null;
String str2="";
System.out.println(str1);
System.out.println(str1==null||str1=="");
System.out.println(str1==null||str1.equals(""));
System.out.println(str1==null||str1.length()==0);
System.out.println(str1==null||str1.isEmpty());
System.out.println("--------");
System.out.println(str2==null||str2=="");
System.out.println(str2==null||str2.equals(""));
System.out.println(str2==null||str2.length()==0);
System.out.println(str2==null||str2.isEmpty());
}
}
10.访问控制级别有哪些? 四种依次由小到大: private(同一类中):类访问级别 default(同一包中):类访问级别 protected(子类中):子类访问级别 public(全局范围):公共访问级别 11.String和StringBuffer的区别? String: (1)是对象不是原始类型。 (2)为不可变对象,一旦被创建,就不能修改它的值。 (3)对于已经存在的String对象的修改都是重新创建一个新的对象,然后把新的值保存进去。 (4)String是final类,即不能被继承。 StringBuffer: (1)内容和长度都是可以改变的。 (2)它只能通过构造函数来建立,StringBuffer subffer=new StringBuffer(); (3)对象被建立以后,在内存中就会分配内存空间,并初始保存一个null,通过它的append方法向其赋值 subffer.append(“hello word”); 12.Stringbuffer和StringBuilder区别? StringBuffer多线程安全的,StringBuilder多线程不安全 13.包装类都有那些? 基本数据类型:byte、char、int、short、long、float、double、boolean 对应的包装类:Byte、Character、Integer、Short、Long、Float、Double、Boolean 装箱:将基本数据类型的值转为引用数据类型; 拆箱:将引用数据类型的值转为基本数据类型; 注意: Java在设计之初有一个基本原则:一切皆对象,一切的操作都要求用对象的形式进行描述,想要对基本类型数据进行更多的操作,最方便的方式就是将其封装成对象。为啥呢?因为在对象描述中就可以定义更多的属性和行为对该基本数据类型进行操作。 基本数据类型的包装类是为了解决基本数据类型有些操作不方便带来的问题。 14.基本类型和包装类型的区别? (1)包装类型可以为 null,而基本类型不可以 (2)包装类型可用于泛型,而基本类型不可以 (3)基本类型比包装类型更高效 (4)两个包装类型的值可以相同,但却不相等
**
(二)java中常见的集合
** 1.java中常见的集合: 答:Map 接口和 Collection 接口是所有集合框架的父接口。 Collection 接口的子接口包括:Set 接口和 List 接口。 Map 接口的实现类主要有:HashMap、TreeMap、Hashtable、ConcurrentHashMap 及 Properties 等。 Set 接口的实现类主要有:HashSet、TreeSet 及 LinkedHashSet 等。 List 接口的实现类主要有:ArrayList、LinkedList、Stack 及 Vector 等。 2.HashMap 和 HashTable 的区别有哪些?(必问) 答:HashMap 没有考虑同步,是线程不安全的;HashTable 使用了 synchronized 关键字,是线程安全的;前者允许Key为null;后者不允许Key为null。 3.HashMap 的底层实现你知道吗? 在 Java 8 之前,其底层实现是数组 + 链表实现,Java 8 使用了数组 + 链表 + 红黑树实现 4.ConcurrentHashMap 和 HashTable 的区别? (必问) ConcurrentHashMap 结合了 HashMap 和 HashTable 二者的优势。HashMap 没有考虑同步,HashTable 考虑了同步的问题,但是 HashTable 在每次同步执行时都要锁住整个结构。ConcurrentHashMap 锁的方式是稍微细粒度的,同时将 Hash 表分为 16 个桶(默认值),诸如 get、put、remove 等常用操作只锁当前需要用到的桶。 5.List和Set的区别有哪些? List 元素是有序、可重复;Set 元素是无序、不重复。 6.ArrayList和LinkedList有什么区别?(问过) ArrayList底层数据结构是数组,增删慢(会导致创建新的数组),查询快(数组允许使用下标访问元素) LinkenList底层数据结构是双向链表,增删快(只需要修改元素之间的引用关系),查询慢(从链表头开始查询) 7.HashSet和TreeSet区别有哪些? HashSet: 不能保证元素的排列顺序,顺序有可能发生变化 集合元素可以是null,但只能放入一个null HashSet底层是采用HashMap实现的 HashSet底层是哈希表实现的 TreeSet: Treeset中的数据是排好序的,不允许放入null值。 TreeSet是通过TreeMap实现的,只不过Set用的只是Map的key。 TreeSet的底层实现是采用二叉树(红-黑树)的数据结构。
** (三)高并发编程—JUC包 **
1.进程和线程的区别和联系有哪些? 进程是一个“正在执行的应用程序”,是系统进行资源分配和调度的一个独立单位; 线程是进程的一个实体,一个进程中拥有多个线程,线程之间共享地址空间和其他资源(因此通信和同步等操作线程比进程更加容易); 线程上下文的切换比进程上下文切换要快很多: 例子:打开qq是开启进程,打开微信是开启进程,qq聊天是线程,qq电话是线程。 2.多线程和单线程的区别和联系 在单核 CPU 中,将 CPU 分为很小的时间片,在每一时刻只能有一个线程在执行,是一种微观上轮流占用 CPU 的机制。 多线程会存在线程上下文切换,会导致程序执行速度变慢,即采用一个拥有两个线程的进程执行所需要的时间比一个线程的进程执行两次所需要的时间要多一些。 结论:即采用多线程不会提高程序的执行速度,反而会降低速度,但是对于用户来说,可以减少用户的响应时间。 3.如何指定多个线程的执行顺序? 设定一个 orderNum,每个线程执行结束之后,更新 orderNum,指明下一个要执行的线程,并且唤醒所有的等待线程。 在每一个线程的开始,要 while 判断 orderNum 是否等于自己的要求值!不是,则 wait,是则执行本线程。 4.多线程产生死锁的四个必要条件 互斥条件:一个资源每次只能被一个线程使用 请求与保持条件:一个线程因请求资源而阻塞时,对已获得的资源保持不放 不剥夺条件:进程已经获得的资源,在未使用完之前,不能强行剥夺 循环等待条件:若干线程之间形成一种头尾相接的循环等待资源关系 如何避免死锁?(经常问) 指定获取锁的顺序 5.线程的创建方式有哪些? 继承Thread类、实现Runnable接口(推荐) 6.线程的生命周期? 新建、就绪、运行、阻塞、死亡 7.sleep和wait的区别? 最主要是sleep方法没有释放锁,而wait方法释放了锁,使得其他线程可以使用同步控制块或者方法(锁代码块和方法锁)。 **
(四)JVM工作机制
** 1.堆(heap)和栈(stack) 堆: (1)Java的堆是一个运行时数据区,类的对象从堆中分配空间。这些对象通过new等指令建立,通过垃圾回收器来销毁。 (2)堆的优势是可以动态地分配内存空间,需要多少内存空间不必事先告诉编译器,因为它是在运行时动态分配的。但缺点是,由于需要在运行时动态分配内存,所以存取速度较慢。 栈: (1)栈中主要存放一些基本数据类型的变量(byte,short,int,long,float,double,boolean,char)和对象的引用。 (2)栈的优势是,存取速度比堆快,栈数据可以共享。但缺点是,存放在栈中的数据占用多少内存空间需要在编译时确定下来,缺乏灵活性。
2.垃圾回收算法有哪些? 引用计数:原理是此对象有一个引用,即增加一个计数,删除一个引用则减少一个计数。垃圾回收时,只用收集计数为 0 的对象,此算法最致命的是无法处理循环引用的问题。 标记-清除:此算法执行分两阶段,第一阶段从引用根节点开始标记所有被引用的对象;第二阶段遍历整个堆,把未标记的对象清除,此算法需要暂停整个应用,同时会产生内存碎片。 复制算法:此算法把内存空间划为两个相等的区域,每次只使用其中一个区域。垃圾回收时,遍历当前使用区域,把正在使用中的对象复制到另外一个区域中,此算法每次只处理正在使用中的对象,因此复制成本比较小,同时复制过去以后还能进行相应的内存整理,不会出现“碎片”问题。当然,此算法的缺点也是很明显的,就是需要两倍内存空间。 标记-整理:此算法结合了“标记-清除”和“复制”两个算法的优点,也是分两阶段,第一阶段从根节点开始标记所有被引用对象;第二阶段遍历整个堆,把清除未标记对象并且把存活对象“压缩”到堆的其中一块,按顺序排放,此算法避免了“标记-清除”的碎片问题,同时也避免了“复制”算法的空间问题。 ** (五)JDK 8新知识点 ** 1.lambda表达式: Lambda 表达式(也称为闭包),允许我们将函数当成参数传递给某个方法,或者把代码本身当做数据处理。 2.函数式接口: 函式接口(Functional Interface)就是一个有且仅有一个抽象方法,但是可以有多个非抽象方法的接口。 **
(六)网络协议
** 1.TCP建立连接时的三次握手: 三次握手: TCP协议中,在发送数据的准备阶段,客户端与服务器之间的三次交互,以保证连接的可靠 第一-次握手,客户端向服务器端发出连接请求,等待服务器确认 第二次握手,服务器端向客户端回送一个响应, 通知客户端收到了连接请求 第三次握手,客户端再次向服务器端发送确认信息,确认连接 2.TCP断开连接四次握手: 第一次: 当主机A完成数据传输后,将控制位FIN置1,提出停止TCP连接的请求 ; 第二次: 主机B收到FIN后对其作出响应,确认这一方向上的TCP连接将关闭,将ACK置1; 第三次: 由B 端再提出反方向的关闭请求,将FIN置1 ; 第四次: 主机A对主机B的请求进行确认,将ACK置1,双方向的关闭结束.。 3.TCP 和 UDP 的区别: · TCP 过确认机制,丢包可以重发,保证数据的正确性;UDP 不保证正确性,只是单纯的负责发送数据包。 · UDP 是面向报文的。发送方的 UDP 对应用程序交下来的报文,在添加首部后就向下交付给 IP 层,既不拆分,也不合并,而是保留这些报文的边界,因此,应用程序需要选择合适的报文大小。 ** (七)数据库知识点 ** 1.听说过事务吗?(必考) 作为单个逻辑工作单元执行的一系列操作,满足四大特性: 原子性(Atomicity),事务作为一个整体被执行 ,要么全部执行,要么全部不执行; 一致性(Consistency),保证数据库状态从一个一致状态转变为另一个一致状态; 隔离性(Isolation),多个事务并发执行时,一个事务的执行不应影响其他事务的执行; 持久性(Durability),一个事务一旦提交,对数据库的修改应该永久保存。 2.事务的并发问题有哪几种? 答:丢失更新、脏读、不可重复读和幻读 3.数据库中的锁有哪几种? 答:独占锁、排他锁和更新锁。 4.事务的隔离级别有哪几种? 答:读未提交、读已提交、可重复读和序列化。 5.数据库的索引有什么作用?(必考)底层数据结构是什么,为什么使用这种数据结构? 答: 索引是对数据库表中一列或多列的值进行排序的一种结构,使用索引可快速访问数据库表中的特定信息。 底层数据结构是 B+ 树。 使用 B+ 树的原因:查找速度快、效率高,在查找的过程中,每次都能抛弃掉一部分节点,减少遍历个数(此时,你应该在白纸上画出什么是 B+ 树)。 **
(八)spring相关知识
** JavaWeb 开发经典的 3 层框架:Web 层、Service 层(业务逻辑层)和 Dao 层(数据访问层)。 Web 层:包含 JSP 和 Servlet 等与 Web 相关的内容 业务层:只关心业务逻辑 数据层:封装了对数据库的访问细节 1.Spring 的 IoC 和 AOP 有了解吗? 答: IoC:控制反转,(解耦合)将对象间的依赖关系交给 Spring 容器,使用配置文件来创建所依赖的对象,由主动创建对象改为了被动方式。 AOP:面向切面编程,将功能代码从业务逻辑代码中分离出来。 2.AOP 的实现方式有哪几种?如何选择?(必考) 答:JDK 动态代理实现和 cglib 实现。 选择: 如果目标对象实现了接口,默认情况下会采用 JDK 的动态代理实现 AOP,也可以强制使用 cglib 实现 AOP。 如果目标对象没有实现接口,必须采用 cglib 库,Spring 会自动在 JDK 动态代理和 cglib 之间转换。 扩展:JDK 动态代理如何实现?(加分点) 答:JDK 动态代理,只能对实现了接口的类生成代理,而不是针对类,该目标类型实现的接口都将被代理。原理是通过在运行期间创建一个接口的实现类来完成对目标对象的代理。 定义一个实现接口 InvocationHandler 的类 通过构造函数,注入被代理类 实现 invoke(Object proxy、Method method、Object[] args)方法 在主函数中获得被代理类的类加载器 使用 Proxy.newProxyInstance( ) 产生一个代理对象 通过代理对象调用各种方法
3.什么是myBatis? MyBatis 是一款优秀的持久层框架,一个半 ORM(对象关系映射)框架,它支持定制化 SQL、存储过程以及高级映射。 4.JDBC编程有哪些不足之处,MyBatis是如何解决这些问题的? (1)数据库链接创建、释放频繁造成系统资源浪费从而影响系统性能,如果使用数据库连接池可解决此问题。 解决:在mybatis-config.xml中配置数据链接池,使用连接池管理数据库连接。 (2)Sql语句写在代码中造成代码不易维护,实际应用sql变化的可能较大,sql变动需要改变java代码。 解决:将Sql语句配置在XXXXmapper.xml文件中与java代码分离。 (3)向sql语句传参数麻烦,因为sql语句的where条件不一定,可能多也可能少,占位符需要和参数一一对应。 解决: Mybatis自动将java对象映射至sql语句。 (4)对结果集解析麻烦,sql变化导致解析代码变化,且解析前需要遍历,如果能将数据库记录封装成pojo对象解析比较方便。 解决:Mybatis自动将sql执行结果映射至java对象。 5.#{}和KaTeX parse error: Expected 'EOF', got '#' at position 7: {}的区别 #?{}是占位符,预编译处理;{}是拼接符,字符串替换,没有预编译处理。 #{} 可以有效的防止SQL注入,提高系统安全性;KaTeX parse error: Expected 'EOF', got '#' at position 15: {} 不能防止SQL 注入 #?{} 的变量替换是在DBMS …{} 的变量替换是在 DBMS 外
**
(九)微服务知识点
** 1.简单介绍redis? 答:Redis是C语言开发的一个开源的(遵从BSD协议)高性能键值对nosql数据库,可以用作数据库、缓存、消息中间件等。 1)读写速度非常快; 2)单进程单线程,是线程安全的,采用IO多路复用机制; 3)丰富的数据类型,支持字符串(strings)、散列(hashes)、列表(lists)、集合(sets)、有序集合(sorted sets)等; 4)支持数据持久化。将内存中数据保存在磁盘中,重启时加载; 5)主从复制,哨兵,高可用; 6)可以作为消息中间件使用。 Redis缓存如何使用? 结合spring boot使用的,一般有两种方式,一种是直接通过RedisTemplate来使用,另一种是使用spring cache集成Redis(也就是注解的方式) 2.介绍一下redis主从复制? 持久化保证了即使redis服务重启也不会丢失数据,因为redis服务重启后会将硬盘上持久化的数据恢复到内存中,但是当redis服务器的硬盘损坏了可能会导致数据丢失,如果通过redis的主从复制机制就可以避免这种单点故障。 3.RabbitMQ是什么? RabbitMQ是一个消息中间价,消息队列就是一个使用队列来通信的组件 4.说说生产者Producer和消费者Consumer? 生产者: 消息生产者,就是投递消息的一方。 消息一般包含两个部分:消息体(payload)和标签(Label)。 消费者: 消费消息,也就是接收消息的一方。 消费者连接到RabbitMQ服务器,并订阅到队列上。消费消息时只消费消息体,丢弃标签。 5.为什么需要消息队列? 本质上来说是因为互联网的快速发展,业务不断扩张,促使技术架构需要不断的演进。 消息队列用于异步处理、服务解耦、流量控制(削峰)
|