更新日志
Java基础
JVM、JRE、JDK三者的区别
JVM:是可运行Java代码的假想计算机,加载 .class 并运行 .class(Java实现跨平台的核心)
JRE:运行Java的最小环境(包含JVM标准实现及Java核心类库)
JDK:Java的开发工具包(Java核心,包括了Java运行环境JRE、Java工具、Java核心类库)
int和Integer有什么区别
int是Java提供的八大基本类型之一。Java为每个基本类型提供了封装类
Integer是Java为int提供的封装类。int的默认是为0,而Integer的默认值为null
重写与重载的区别
重写:发生在父子类中,方法名相同,参数列表相同,方法体不同
重载:发生在一个类中,方法名相同,参数列表不同,方法体不同
String、StringBuilder、StringBuffer的区别
主要区别在于两个方面:执行速度和线程安全
String是字符串常量,即String对象一旦创建不可改变,
StringBuilder 和 StringBuffer 为字符串变量,可以改变
执行速度:StringBuilder > StringBuffer > String
线程安全:StringBuffer 线程安全;StringBuilder 线程不安全
StringBuffer中有很多方法带synchronized锁关键字,所以可以保证线程是安全的
StringBuilder中方法中没有该关键字,所以不能保证线程是安全的
如果要进行的操作是多线程,那么就要使用StringBuffer,如果在单线程的情况下,还是建议速度比较快的StringBuilder
String常用API
String test = " Hello Java ";
//char 返回当前字符串中给定位置处对应的字符
char test1 = test.charAt(7); //J
//int 查找给定字符串在当前字符串中的下标位置,若当前字符串不包返回-1
int test2 = test.indexOf("c"); //-1
//int 该方法返回当前字符串的长度(字符个数)
int test3 = test.length(); //12
//Boolean 判断字符串是否是以给定字符串开始
Boolean test4 = test.startsWith("h"); //false
//Boolean 判断字符串是否是以给定字符串结尾
Boolean test5 = test.endsWith("j"); //false
//String 截取当前字符串中指定范围内的内容("含头不含尾") ;一个参数为从指定位置截取到末尾
String test6 = test.substring(3,7); //llo
//String 将当前字符串中的英文部分转换为全大写
String test7 = test.toUpperCase(); // HELLO JAVA
//String 将当前字符串中的英文部分转换为全小写
String test8 = test.toLowerCase(); // hello java
//String 去除当前字符串两边的空白字符
String test9 = test.trim(); //Hello Java
抽象类与接口的区别?
抽象类:由abstract修饰,包含抽象方法的类必须是抽象类,不能被实例化,只能被继承
接口:由interface修饰,只能包含常量和抽象方法,不能被实例化,一个类可以实现多个接口,接口继承接口
char 型变量中能不能存贮一个中文汉字,为什么?
JDK中常用的类、包、接口
类:String、Integer、Long、File、Date、Thread
包:java.lang.* java.util.* java.awt.* java.io.* java.sql.*
接口:Comparable、Collection、Map、List、Runnable
Obiect类中有哪些方法
toString、equals、getClass
wait、notify、notifyAll
为什么重写toString方法
toString方法是Object类中的,重写toString方法是为了将输出的对象按照字符串的形式输出,如果不重写toString输出的只是对象内存地址
== 与 equals 的区别
==一般用于比较基本类型,比较值是否一样,如果用于引用类型,比较的是两个对象的指向地址
代码示例:
String x = "Hello";
String y = "Hello";
String z = new String("Hello");
System.out.println(x==y); // true
System.out.println(x==z); // false
System.out.println(x.equals(y)); // true
System.out.println(x.equals(z)); // true
equals:默认情况下是引用比较,重写equals方法后比较两个对象的值是否一样,内部利用还是==
代码示例:
String x = new String("Hello"); String y = new String("Hello"); System.out.println(x==y); // false System.out.println(x.equals(y)); // true
数组长度、字符串长度、集合长度
数组:length 集合:size() 字符串:Length()
final 和 finally 的区别
final是修饰符,修饰变量时需要给变量赋初始值并且之后也只能读取不能重新赋值,方法不能被重写,类不能被继承
finally是处理异常操作时用来执行清除操作的,写在try/catch后面表示该内容无论异常是否发生都会被执行
notify 和 notifyAll 的区别
都是在满足某些情况下唤醒线程:
当调用notify()时,只有一个等待线程会被唤醒,但是不能保证哪个等待线程会被唤醒,取决于线程调度器
当调用notifyAll()时,所有的等待线程都会被唤醒,但是在执行剩下的代码时,所有被唤醒的线程都将争夺
throw和throws的区别
try-catch-finally的执行过程
基本执行过程如下:
1: 程序首先执行可能发生异常的try语句块。
2:如果try语句块没有出现异常则执行完后跳至finally语句块执行;
如果try语句出现异常,则中断执行并根据发生的异常类型跳至相应的catch语块执行处理。
3:catch语句块可以有多个,分别捕获不同类型的异常。
4:catch语句块执行完成后程序会继续执行finally语句块。
5:finally语句是可选的,如果有的话,则不管是否发生异常,finally语句都会被执行。
注意: 即使try和catch块中存在return语句,finally语句也会执行。是在执行完finally语句后再通过return退出
XML常用的解析方式有几种,各自的特点是什么
1:DOM是层次结构组织的节点或信息片段的集合,采用建立树型结构的方式访问XML文档,
用DOM解析模型的优点是编程容易,开发人员只需要调用建树的指令,利用navigation APIs访问所需的树节点来完成任务
2:SAX处理的优点类似于流传媒的优点,分析能立即开始,而不是等待所有的数据被处理,采用基于事件的模型
3:JDOM简化与XML的交互并且比使用DOM实现更快,目的是成为Java特定文档模型:
4:DOM4J是JDOM的智能分支.它合并了许多超出基本XML文档表示的功能,包括集成的XPath支持、XML Schema支持
以及用于大文档或流文化档的基于事件的处理。它通过DOM4J API和标准DOM接口具有并行访问功能
比较:DOM4J性能最好,如果不考虑可移植性采用DOM4J
JDOM和DOM在性能测试时表现不佳,适用于小型文档
DOM广泛应用于多种语言编程,它还是许多其他与XML相关的标准的基础
Java内存模型
线程
什么是线程?
线程是操作系统能够进行运算调度最小的单位,它被包含在进程中,是进程中的实际运作单位。程序员可以通过它进行多处理编程
使用多线程可以对运算密集型任务提速。比如:如果一个线程完成一个任务的时间需要100毫秒,那么用十个线程完成该任务只需要10毫秒
进程和线程的关系
1:一个线程只属于一个进程,而一个进程可以有多个线程,但至少有一个线程,线程是操作系统可识别的最小执行和调度单位
2:资源分配给进程,同一进程的所有线程共享该进程的所有资源(同一进程中的多个线程共享代码段(代码和常量)
数据段(全局变量和静态变量),扩展段(堆存储)。但是每个线程拥有自己的栈段,栈段又叫运行时段,用来存放所有局部变量和临时变量)
3:线程在执行过程中,需要协作同步。不同进程的线程间要利用消息通信的办法实现同步
什么是线程安全
一段代码在单线程和多线程下执行获得的结果永远一样,那说明你的代码就是线程安全的
线程安全的级别
创建线程有几种方式
1:继承Thread并重写run方法
2:实现Runnable接口,单独定义线程任务
用Thread还是Runnable创建线程
Java不支持多继承,但支持多实现,如果你要继承其他父类,建议使用Runnable
Thread类中的 start() 方法和 run() 方法有什么区别
start()方法是用来启动新创建的线程,使该线程变为运行状态。
run()方法只是在原来的线程中调用,没有新的线程启动
线程阻塞的几种方法
1:使用Thread的 join() 方法 可以协调线程之间的同步运行
2:睡眠阻塞 sleep() 可以设置该线程处于阻塞状态的毫秒值
3:线程等待Object类中的 wait() 方法
4:线程礼让 Thread.yield() 方法
Java中 sleep 方法和 wait 方法的区别
两者都是用来暂停当前运行的线程,
sleep() 实际上只是短暂停顿,因为它不会释放锁
wait() 意味着条件等待,这就是为什么该方法要释放锁,因为只有这样,其他等待的线程才能在满足条件时获取到该锁
怎么唤醒一个阻塞线程
如果线程是调用了 join()、sleep()、wait() 方法而导致的阻塞,可以中断线程,并且通过 InterruptedException 来唤醒它。
如果线程遇到了IO阻塞,无能为力,因为IO阻塞是操作系统实现的,Java代码并没有办法直接接触到操作系统
怎么终止一个线程
1:使用interrupt()中断线程
2:使用标志位终止线程
3:使用stop()终止线程(已弃用)
一个线程如果出现运行时异常会怎么样
守护线程
创建多少个线程合适
如何在两个线程间共享数据
怎么检测一个线程是否持有对象监听器
如果让你实现一个并发安全的链表,你会怎么做
什么是死锁?导致线程死锁的原因?怎么解除线程死锁?
为什么使用线程池
Java集合
Java集合有哪些
Collection和Collections的区别
如何实现数组与集合之间的转换
数组转集合:Arrays.asList()
集合转数组:toArray()
ArrayList和LinkedList的区别
ArrayList是数组实现、LinkedList是链表实现
对于随机访问(get 和 set),ArrayList优于LinkedList,因为LinkedList要移动指针
对于新增和删除元素,LinkedList优于ArrayList,因为ArrayList要移动数据
HashMap原理
jdk1.7数组+链表实现,jdk1.8数组+链表或红黑树实现
HashMap及基于Hashing的原理,使用put(key,value)把对象存储到HashMap中,使用get(key)从HashMap中获取对象,当我们用put()传递键值
时,先调用hashCode()方法,计算hash值,返回的hash值查找存放位置下标,数组中存在对象,调用equals()比较value是否相等,相等则覆盖,
不相等则形成链表,(jdk1.7会将新元素放在数组中,原始节点作为新节点的后继节点;jdk1.8将元素放在最后)
HashMap的线程安全问题
HashMap是非线程安全的,HashMap的容量是有限的,如果HashMap中的数组容量很小,假如只有2个,那么放入10个key,碰撞会非常频繁
HashMap什么情况下链表会变成红黑树
链表长度为8时,判断数组,数组长度小于MIN_TREEIFY_CAPACITY,会先扩容
说一下HashMap的put()方法
Servlet
Servlet的优缺点
优点:高效、方便、功能强大、可移植性好
缺点:web.xml配置量大,servlet有容器依赖性,不利于单元测试,处理的请求有局限性,页面内用展示差
Servlet的运行原理
1:浏览器根据IP建立与容器的连接
2:浏览器将请求数据包打包
3:容器解析请求数据包,封装request和response对象
4:容器根据请求路径找到servlet创建对象
5:容器将request和response对象作为参数传入service方法,并调用
6:容器将响应数据包打包发送给浏览器
7:浏览器取出结果生成页面
Servlet的生命周期
实例化(创建Servlet实例) 初始化(调用init()方法)
就绪(调用service()方法) 销毁(调用destroy()方法)
JSP的九大内置对象及作用
request:封装客户端的请求,其中包含get和post请求的参数
response:封装服务端对客户端的响应
application:封装服务器运行环境的对象
session:封装用户会话的对象
out:输出服务器响应的输出流对象
config:web应用的配置对象
page:jsp页面本身(相当于Java程序中的this)
pageContext:通过该对象可以获取其他对象
exception:封装页面抛出异常的对象
JSP的四大作用域
page代表与一个页面相关的对象和属性
request代表与web客户机发出的一个请求相关的对象和属性。一个请求可以跨越多个页面,
涉及多个web组件,需要在页面显示的临时数据可以置于此作用域
session代表某个用户与服务器建立的一次会话相关的对象和属性。
application代表与整个web应用程序相关的对象和属性,它实质上是跨越整个web程序,包括多个页面、请求和会话的全局作用域
重定向和转发
重定向是两次请求,转发是一次请求
重定向:服务器通知浏览器向某个地址发送请求,重定向的地址是任意的,重定向之后,浏览器地址栏的地址发生改变
转发:一个web组件将未完成的处理交给另外一个web组件继续做,转发之后浏览器地址栏地址不变,转发是有局限性的,要求同属一个web应用
两种状态管理:cookie 和 session 的区别
cookie:保存在浏览器,只能存放少量的数据,浏览器关闭,cookie被删除
session:保存在服务器,支持更丰富的数据类型、更安全、超时被删除
session的运行原理
session是一种记录客户端状态的机制,因为http是无状态协议,在开发过程中需要记录某些用户的信息,这个时候就用到了session
session的实现:当服务器第一次接收到请求后,会生成一个session对象,针对该用户生成一个sessionID,并将sessionID以cookie
的形式响应给客户端。等下一次客户端请求时,会携带这个sessionID,服务器会根据sessionID去找对应用户信息,
session默认存活时间为30分钟,可以再web.xml中设置时间
框架(Spring、Spring MVC、MyBatis)
谈谈你对Spring的理解
Spring是一个IOC和AOP的容器框架
控制反转(IOC),传统的Java开发模式中,当需要一个对象时,我们会使用自己new或间接调用构造方法创建对象,在Spring开发模式中,
Spring容器使用工厂模式为我们创建了所需要的对象,不需要我们自己创建,直接调用Spring为我们提供的对象就可以了,这是控制反转的思想
面向切面(AOP),在面向对象编程思想中,我们将事物抽象成一个个的对象。而在面向切面编程中,我们将一个个对象某些类似的方面抽象
成一个切面,对这个切面进行一些如权限控制、事物管理、记录日志等共用操作处理的过程就是面向切面编程的思想。
AOP底层是动态代理,接口采用JDK动态代理,类采用CGLIB方式实现动态代理
Spring中用到了哪些设计模式
工厂模式
单例模式(懒汉式、饿汉式)
单例模式的线程安全性
懒汉式 - 线程不安全 缺点:如果多个线程同时进入一个方法,判断语句为true,多个线程会同时执行,导致多次实例化对象
饿汉式 - 线程安全 缺点:直接实例化,资源会浪费
什么是Spring的依赖注入,有哪些依赖注入
依赖注入(DI),Spring使用JavaBean对象的set方法或带参数的构造方法为我们创建所需要的的对象时将其属性自动设置所需要的值的过程
set注入
构造器注入
静态工厂的方法注入
实例工厂的方法注入
Spring支持bean的作用域有几种
Spring框架支持以下五种bean的作用域:
● singleton:bean在每个Springioc容器中只有一个实例。
● prototype:一个bean的定义可以有多个实例。
● request:每次http请求都会创建一个bean,该作用域仅在基于web的SpringApplicationContext情形下有效。
● session:在一个HTTPSession中,一个bean定义对应一个实例。该作用域仅在基于web的SpringApplicationContext情形下有效。
● global-session:在一个全局的HTTPSession中,一个bean定义对应一个实例。该作用域仅在基于web的SpringApplicationContext情形下有效。缺省的Springbean的作用域是Singleton。
简述Bean的生命周期
Bean定义:在配置文件里面用<bean></bean>来进行定义
Bean初始化:有两种初始化方式
1:在配置文件中通过指定init-method属性来完成
2:实现org.springframwork.beans.factory.InitializingBean接口
Bean调用:有三种方式可以得到Bena实例,并进行调用
Bean销毁:销毁方式有两种
1:使用配置文件指定destroy-method属性
2:实现org.springframwork.bean.factory.DisposeableBean接口
SpringMVC的核心组件及含义
-
DispatcherServlet(前端控制器):接收所有请求的Servlet(不包括例如css、js等),并且根据请求路径分发到各控制器;
-
HandlerMapping(映射处理器):记录请求路径与控制器或处理请求的方法之间的映射关系;
-
Controller(处理器):具体处理请求,确定如何响应的组件;
-
ModelAndView(返回的数据和视图名):控制器的返回结果,其中Model表示数据,View表示最终负责响应的视图组件的名称;
-
ViewResolver(视图解析器):根据视图组件名称得到具体的视图组件。
SpringMVC的运行原理
-
客户端请求提交到DispatcherServlet
-
由DispatcherServlet控制器查询一个或多个HandlerMapper,找到处理该请求的Controller
-
在Controller控制器里处理相应的业务逻辑和数据交互,返回ModelAndView,Model是返回的数据对象,View是视图名
-
ViewResolver会根据视图名查找对应的jsp文件
-
DispatcherServlet把返回的Model传给View,发送响应
图解:
MyBatis中的动态SQL是什么意思
MyBatis是怎么解决sql注入的
怎么实现MyBatis的接口绑定
1:注解绑定
2:xml绑定 namespace属性
JDBC有哪些不足之处,MyBatis是如何处理这些问题的
1:数据库连接的创建、释放频繁造成系统资源浪费从而影响了性能,如果使用数据库连接池就可以解决这个问题。当然JDBC同样能够使用数据源
解决:在SQLMapConfig.xml中配置数据连接池,使用数据库连接池管理数据库连接
2:SQL语句在写代码中不容易维护,事件需求中SQL变化的可能性很大,SQL变动需要改变Java代码
解决:将SQL语句配置在mapper.xml文件中与java代码分离
3:向SQL语句传递参数麻烦,因为SQL语句的where条件不一定,可能多,也可能少,占位符需要和参数一一对应。
解决:Mybatis自动将java对象映射到sql语句。
4:对结果集解析麻烦,sql变化导致解析代码变化,且解析前需要遍历,如果能将数据库记录封装成pojo对象解析比较方便。
解决:Mbatis自动将SQL执行结果映射到java对象
使用MyBatis编程要做好:1.设计SQL语句 2.设计抽象方法 3.配置映射
设计抽象方法:如果是增删改操作,返回值固定设计为Integer;如果是查询操作,根据查询结果来决定,例如:List<User>,User,Integer…
关于映射配置:根据所执行的操作选择<insert> <delete> <update> <select> 节点,无论是哪个节点必须配置id,取值为对应的抽象方法的名称
Spring的事务管理有哪些优点
Spring事务的四种隔离级别
1:读未提交(Read Uncommited)
2:读已提交(Read Committed)
3:可重复读(Repeatable Read)
4:串行化(Serialization)
Spring系列常用注解
@Controller 控制层组件
@Service 业务层组件
@Repository 持久层组件
@Autowired 自动装配
@RequestMapping 映射请求路径
@RequestParam 参数
@ResponseBody 返回前端数据
SpringBoot的配置文件格式有几种
1:properties
2:yaml
3:xml
MySQL
Mysql的四种引擎
1:MyISAM
2:InnoDB
3:Memory
4:Merge
JVM
说说类加载过程,什么是双亲委派,可以打破双亲委派吗
JVM内存分代
新生代、老年代
说一下运行时数据区(JVM内存布局
堆、方法区、虚拟机栈、本地方法栈、程序计数器
什么情况下会发生栈溢出?
内存溢出和内存泄漏的区别?
JVM的垃圾回收机制,何时触发MinorGC,何时触发MajorGC
说一下JVM中一次完整的GC(从YGC到FGC)是怎样的?主要说一下对象怎么晋升到老年代
JVM的引用类型有哪些?
垃圾回收器有哪些?