1.1 java是什么?
Java是一门面向对象的程序设计语言
1.2 面向对象是什么?它的基本特征是什么?
面向对象是一种编程思想。
面向对象的编程思想是从面向过程的编程思想升华。
面向对象的基本特征:
1.封装----将原本分散的东西聚集在一起,统一处理。
2.继承----与我们生活中所说的继承是用一同概念,孩子可以从父母哪里继承财产。
3.多态----同一类事物在不同的环境下,呈现出不同的状态。
1.3 JDK是什么?由几部分组成?每一部分是什么?
JDK是 Java 语言的软件开发工具包,JDK中包含java开发工具集和JRE,JRE是java运行时环境负责运行java程序,JRE之所以能运行java程序,是因为它包含了JVM,真正负责运行java程序的是JVM。JRE是由java程序开发库和JVM组成,因此上jre只能运行java程序,不能开发。如果只是想运行一下java程序,那么只安装一个jre就足够了,当然安装一个jdk也可以运行java程序。
JDK 和 JRE 有什么区别?
JDK:Java Development Kit 的简称,Java 开发工具包,提供了 Java 的开发环境和运行环境。
JRE:Java Runtime Environment 的简称,Java 运行环境,为 Java 的运行提供了所需环境。
具体来说 JDK 其实包含了 JRE,同时还包含了编译 Java 源码的编译器 Javac,还包含了很多 Java 程序调试和分析的工具。简单来说:如果你需要运行 Java 程序,只需安装 JRE 就可以了,如果你需要编写 Java 程序,需要安装 JDK。
1.4 java程序的执行原理?
1.源文件(.java源代码)通过编译器(javac.exe)编译成字节码文件class。
2.通过JVM中的解释器将字节码文件生成对应的可执行文件,运行。
3.将编译后的程序加载到方法区,存储类信息。
4.运行时,JVM创建线程来执行代码,在虚拟机栈和程序计数器分配独占的空间。根据方法区里的指令码,在虚拟机栈对线程进行操作,程序计数器保存线程代码执行到哪个位置。
在这里插入图片描述
- JVM的结构基本上由5部分组成:
类加载器:在 JVM 启动时或者类运行时将需要的 class 加载到 JVM 中
执行引擎:执行引擎的任务是负责执行 class 文件中包含的字节码指令,相当于实际机器上的 CPU
内存区:将内存划分成若干个区以模拟实际机器上的存储、记录和调度功能模块,如实际机器上的各种功能的寄存器或者 PC 指针的记录器等
本地方法调用:调用 C 或 C++ 实现的本地方法的代码返回结果
垃圾回收系统:是java虚拟机的重要组成部分,垃圾回收器可以对方法区、java堆和直接内存进行回收。其中,java堆是垃圾收集器的工作重点。和C/C++不同,java中所有的对象空间释放都是隐式的,也就是说,java中没有类似free()或者delete()这样的函数释放指定的内存区域。对于不再使用的垃圾对象,垃圾回收系统会在后台默默工作,默默查找、标识并释放垃圾对象,完成包括java堆、方法区和直接内存中的全自动化管理。、 - JVM的几个运行时数据区:
1.方法区
用于存储已被JVM加载的类信息,常量,静态变量,即时编译器编译后的代码,线程共享。
2.运行时常量池
方法区一部分。存放编译期生成的各种字面量和符号引用。
3.虚拟机栈
内部创建栈帧,来存放局部变量表,操作数栈,动态链接,方法出口等,线程私有。
4.本地方法栈(HotSpot不区分虚拟机栈和本地方法栈)
类似虚拟机栈,但是只为Native方法服务。
5.堆
存放实例对象和数组,线程共享。
6.程序计数器
存放当前线程执行的字节码的行号。
1.5 java语言的特点?
1.面向对象
Java语言是支持封装,继承,多态和面向对象的编程语言,这使得程序只有很少的耦合,能够更具凝聚力。每个模块都执行自己的功能,不会通过公共接口相互干扰。
2.异常处理机制
所谓异常处理,就是指程序在出现问题时依然可以正确的执行完。
Java是采用面向对象的方式来处理异常的。处理过程:
- 抛出异常:在执行一个方法时,如果发生异常,则这个方法生成代表该异常的一个对象,停止当前执行路径,并把异常对象提交给JRE。
- 捕获异常:JRE得到该异常后,寻找相应的代码来处理该异常。JRE在方法的调用栈中查找,从生成异常的方法开始回溯,直到找到相应的异常处理代码为止。
3.多线程【处理并发】
进程是操作系统中分配的最小内存资源单元。每个进程可以同时拥有两个或多个线程,允许它们同时执行。并且它提供了Rannable接口及其实现类Thread,提供了许多控制线程操作的方法,以及线程同步控制。
4.跨平台【操作系统】
在Java语言中,最大的优点就是具有与平台无关,这样在使用的时候能够进行跨平台使用。大多数编程语言都不是跨平台的。所谓的平台,我们可以理解为操作系统,在其他的操作系统下不可以运行其他文件。但是Java语言不一样,Java程序不是直接运行在操作系统上面,而是在JVM中进行运行。
5.自动垃圾回收机制
java做的一大改进是将复杂的内存管理抽离出来交给jvm去处理,让程序员不再时刻盯着内存泄漏的问题,可以更专注于业务逻辑的开发,不要求程序员显示地分配内存和释放内存,Java在创建对象的时候会自动分配内存,并在该对象不再使用时自动释放对象所使用的内存。
2.1 什么是注释?注释的作用是什么?注释的分类以及具体的表现形式?
注释就是解释说明自己编写的java代码是什么意思,为了以后能够知道自己当时所写的java代码的功能或者含义,方便别人能够看懂自己的java程序
2.2 标识符是什么?标识符的具体规则?
标识符是编写java代码时给java中的元素起名字的字符串。
【java中的元素–类,方法/函数,变量,数组…】
标识符规则:
1.可以用数字,字母,_下划线,$美元符号 组成,数字不能开头。
Hello_world$110 [错误]100_Hello
2.不能有空格
3.区分大小写 Hello hello
4.不能是关键字
Java中各元素的基本命名规范:
类—符合标识符规则,类名的首字母要大写 例如:Hello HelloWorld
方法—符合标识符规则,方法的名称首字母小写,从第二个单词开始首字母大写
例如:get getName getMyName
变量—符合标识符规则,变量的名称所有字母小写,可以使用_分割
例如:name my_name my_name_number
2.3 什么是关键字?Java中常用的关键字?
关键字是java中为一些单词赋予了特殊含义,这些被赋予特殊含义的单词就是关键。标识符不能用关键字。
2.4 什么是变量?变量的作用?变量的组成?
变量是在程序运行的时候随时可能发生变化的数据。
变量的作用:保存具体的数据值,限制了数据值在内存中的位置和大小。
变量的组成部分:
- 数据类型—决定内存空间
- 变量名称—自定义的,只要符合标识符的规则
- 初始值—默认值
- 作用域—有效范围
2.5 Java中的基本数据类型有几种?如何表示,取值范围,注意事项?
Java中基础数据类型【原生数据类型】有 8 种:byte、boolean、char、short、int、float、long、double,分为4大类8种
整数类:byte、short、int、long
浮点型:float、double
字符型:char
布尔型:boolean
2.6 基本数据类型之间的转换?注意事项?
- 基本数据类型的分类:
boolean为布尔类型;
byte,short,int,long为整型;
float,double为实型;
char为字符型 - boolean类型不可以转换为其他的数据类型
- 表示范围从小到大:byte->short->char=int–>long–>float–>double
- 基本数据类型有两种转换方式:自动类型转换、强制类型转换,表示范围小的数据类型可以自动转换为表示范围大的数据类型,表示范围大转换为表示范围小的数据类型才需要强制类型转换
2.7 什么是数组?
同一数据类型的一组数据按照顺序排列的复合数据类型—数组。
1.同一数据类型 【进入数组的数据的类型必须相同】
2.按照顺序排列
3.复合数据类型
2.8 认识Arrays类【数组的帮助类】?
Arrays 类的定义:
Arrays类位于java.util 包中,主要包含了操纵数组的各种方法
Arrays 类的常用方法:
下面介绍一些常用的Arrays方法
sort()方法:对数组进行升序排序
Arrays.sort(数组名);
toString()方法:将一个数组array转换成一个字符串
Arrays.toString(数组名);
fill()方法:把数组array所有元素都赋值为指定数据值
Arrays.fill(数组名,value值);
copyOf()方法:把数组array复制成一个长度为length的新数组,返回类型与复制的数组一致
Arrays.copyOf(数组名,长度);
binarySearch()方法:查询元素值在数组中的下标(要求数组中元素已经按升序排列)
Arrays.binarySearch(数组名,所查元素)
equals()方法:比较两个数组是否相等
Arrays.equals(数组名1,数组名2)
2.9 基本数据类型与复合(引用)数据类型的区别?
内存分配不同
- 基本数据类型的存储原理:所有的简单数据类型不存在“引用”的概念,基本数据类型都是直接存储在内存中的栈上的,数据本身的值就是存储在内存的栈区,在栈区开辟空间,堆区不会开辟空间,Java语言里面八种数据类型是这种存储模型。
- 引用类型的存储原理:引用类型继承于Object类(也是引用类型)都是按照Java里面存储对象的内存模型来进行数据存储的,使用Java堆和栈来进行这种类型的数据存储,简单地讲,“引用”(存储对象在内存堆上的地址)是存储在有序的栈上的,而对象本身的值存储在堆上的;
不论是基本数据类型还是引用类型,他们都会先在栈中分配一块内存,对于基本类型来说,这块区域包含的是基本类型的内容;而对于引用类型来说,真实的数据分配在堆区,而栈区只是一个数据地址的引用值。
2.10 String 属于基础的数据类型吗?
String 不属于基础类型,基础类型有 8 种:byte、boolean、char、short、int、float、long、double,而 String 属于对象。
3.1 常见的运算符和表达式
1.赋值运算符 【=】
2.算术运算符 【+ - * / %{求余数} ++ – 】
3.关系运算符【比较运算符】【> < >= <= == !=】运算结果是一个布尔值
4.逻辑运算符【|| && !】
3.2 for循环和while循环的区别
- 知道执行次数的时候一般用for,条件循环时一般用while。for循环可以设置次数,while循环条件满足没有次数限制。
- while 语句类似for,只是运行语句内程序后不再有其他运算,而是直接判断是否满足条件,若满足,则再次运行语句内程序,判断是否满足条件。直到不满足条件时,退出while 语句。
- do while ,与while 的区别是多了一个do ,效果就是运行到do while 时,不先判断是否满足条件,而是先运行一遍do while内的语句,再判断,剩下的就和while 相同了。
3.3 break,continue,return的区别
作用不同、结束不同、紧跟不同。
一、作用不同
1、break:执行break操作,跳出所在的当前整个循环,到外层代码继续执行。
2、continue:执行continue操作,跳出本次循环,从下一个迭代继续运行循环,内层循环执行完毕,外层代码继续运行。
3、return:执行return操作,直接返回函数,所有该函数体内的代码(包括循环体)都不会再执行。
二、结束不同
1、break:break不仅可以结束其所在的循环,还可结束其外层循环,但一次只能结束一种循环。
2、continue:continue结束的是本次循环,将接着开始下一次循环。
3、return:return同时结束其所在的循环和其外层循环。
三、紧跟不同
1、break:需要在break后紧跟一个标签,这个标签用于标识哪个外层循环。
2、continue:在continue后不需要加参数。
3、return:在return后需要紧跟一个返回值,用于提供给对应方法所需的返回值。
4.1 成员变量与局部变量的区别?
成员变量【全局变量】的特征:
- 类中除过方法以外的地方。
- 可以没有初始值,系统会自动赋予这个全局变量一个默认的初始值。
- 需要访问限制修饰符
- 可以在本类中的任何一个方法中被使用,且不受访问限制修饰符的影响。
局部变量的特征:
- 类中的方法里面和方法的参数。
- 局部变量一定要有初始值。
- 不能有访问限制修饰符
- 只能在定义该局部变量的方法中使用,超出本方法就错误
成员变量的隐藏:
- 类中的某一个成员变量的名称与某一个方法中的局部变量的名称相同,那么类中的成员变量的数据值被局部变量覆盖隐藏。可以通过this.成员变量名称,强制调用,被隐藏的成员变量值。
- 在子类中,自己定义的成员变量与继承自父类中的某一个成员变量名称相同。可以通过super.成员变量名称,强制调用,被隐藏的成员变量值。
static关键字修饰变量【成员变量】
成员变量【全局变量】— 类中除过方法以外的地方。
根据是否有static关键字修饰,将成员变量划分为2类:
- 有static关键字修饰的成员变量-----静态成员变量【类变量】;
- 没有static关键字修饰的成员变量—实例成员变量【实例变量】;
4.2【类变量】与【实例变量】的区别?
- 语法定义上:类变量有static,实例变量没有static
- 调用方式上:类变量可以使用对象调用,也可以使用类名调用, 实例变量只能通过对象调用
- 内存配置上:类变量是在程序运行之前分配内存空间,实例变量是在程序运行时分配内存空间
4.3 类中方法的重载
如果有两个方法的方法名相同,但参数不一致,那么可以说一个方法是另一个方法的重载。
具体说明如下:
- 方法名相同
- 方法的参数类型,参数个不一样
- 方法的返回类型可以不相同
- 方法的修饰符可以不相同
- main 方法也可以被重载
4.4 同一个类中方法与变量的调用关系?方法与方法的调用关系?
同一个类中方法与变量的调用关系
1.在同一个类中只能方法调用变量,不能变量调用方法
静态方法【类方法】中你绝对不能出现this
- 静态方法【类方法】中不能调用实例变量和实例方法
- 构造方法可以调用实例变量/实例方法,默认是this.实例变量/this.实例方法,this.可以省略。
- 构造方法可以调用类变量/类方法,默认是类名.类变量/类名.类方法,类名.可以省略,也可以是this.类变量/this.类方法,this.可以省略。
- 构造方法可以调用其他的构造方法,new + 其他的构造方法;
- 实例方法可以调用实例变量/实例方法,默认是this.实例变量/this.实例方法,this.可以省略。
- 实例方法可以调用类变量/类方法,默认是类名.类变量/类名.类方法,类名.可以省略,也可以是this.类变量/this.类方法,this.可以省略。
- 实例方法可以调用构造方法,new + 其他的构造方法;
- 类方法可以调用类变量/类方法,默认是类名.类变量/类名.类方法,类名.可以省略。
- 类方法可以调用构造方法,new + 其他的构造方法
4.5 对象的内存分配原理?
对象是通过类创建的,而类是一种复合数据类型,那么对象的内存分配与复合数据类型的内存分配是一致。因此对象的内存分配会在内存的堆区和栈区都有分配。
当我们使用new 构造方法创建一个对象的时候,每new一次都是在创建一个新的对象,都会在内存的堆区开辟一块空间存储,会与先前new好的对象不是同一个对象。
4.6 Java中子类的继承性?
1.子类的继承性是指子类可以从父类中继承那些变量和方法
2.子类的继承性与访问限制修饰符有关。
3.子类与父类在同一个包中,子类可以继承父类中除过private修饰的变量和方法。
4.在不同的包中,子类可以继承父类中protected和public修饰符修饰的变量和方法,private和缺省的修饰的变量和方法是不能被继承。
5.子类中的变量和方法,一部分是从父类继承的,另外一部分是子类自己定义的。
5.1 java中的访问限制修饰符?
访问限制修饰符就是用来限定java元素【类,变量,方法,接口…】,在哪些情况下可以访问,哪些情况不能访问。【保护隐私】
访问限制修饰符分别有:
public【公共的】 private【私有的】 protected【受保护的】 缺省的【友好的】
2. public【公共的】任何元素都可以访问 [类,变量,方法,接口]
3. private【私有的】创建者自己可以访问,其他的元素不能访问 [变量,方法]
4. protected【受保护的】与创建者有关系【继承】的可以访问,没有关系的其他元素不能访问[变量,方法]
5. 缺省的【友好的】 什么都不写 同一个包中可以访问,不同包就不能访问[类,变量,方法,接口].
类上面可以使用public【公共的】和缺省的 访问修饰符。
6. 被public修饰的类,可以在任何地方被访问。
7. 被缺省的修饰符修饰的类,只能被同一个包中其他类访问,跨出包就不能访问。
5.2 上转型对象的含义和特征?
子类对象赋值给父类变量—上转型对象
上转型对象不能操作子类新增的成员变量;不能使用子类新增的方法。上转型对象可以操作子类继承或者隐藏的成员变量,也可以使用子类继承的或者重写的方法。上转型对象操作子类继承或重写的方法,其作用等价于子类对象去调用这些方法。因此,如果子类重写了父类的某个方法,则当对象的上转型对象调用这个方法时一定是调用了这个重写的方法
5.3 方法重写
方法重写—在子类中自己定义的一个方法,与从父类中继承的方法一模一样,这时子类重写了父类的方法。可以通过super.方法名称,强制调用继承自父类的方法。
5.4 抽象类的特点
- 抽象类不能new,可以通过上转型对象构造出抽象类的对象。
- 当一个普通的java类继承一个抽象类以后,要重写抽象类中的抽象方法,否则将这个普通的java类该成抽象类
- 抽象类可以继承抽象类。
- 抽象类中可以有抽象方法,也可以一个抽象方法都没有。
- 抽象类对象调用抽象方法,实际上实在调用被子类重写以后的方法。
5.5 接口和抽象类有什么区别?
- 实现:抽象类的子类使用 extends 来继承;接口必须使用 implements 来实现接口。
- 构造函数:抽象类可以有构造函数;接口不能有。
- 实现数量:类可以实现很多个接口;但只能继承一个抽象类【java只支持单继承】。
- 访问修饰符:接口中的方法默认使用 public修饰;抽象类中的抽象方法可以使用Public和Protected修饰,如果抽象方法修饰符为Private,则报错:The abstract method 方法名 in type Test can only set a visibility modifier, one of public or protected。
5.6 接口回调对象的含义和特征?
接口回调对象:将实现该接口的子类对象赋值给该接口变量。
接口回调对象的访问特征:
- 接口回调对象和实现该接口的子类对象还有接口名称,可以调用接口中的类变量
- 接口回调对象和实现该接口的子类对象,都不能调用接口的类方法,只能接口名称去调用接口中的类方法
- 接口回调对象和实现该接口的子类对象,可以调用接口中的抽象方法,只不过调用的是被子类重写以后的抽象方法
- 接口回调对象是不能调用子类自己定义的变量和方法,子类对象可以调用子类自己定义的变量和方法。
5.7 final 在 Java 中有什么作用?
final 修饰的类叫最终类,该类不能被继承。
final 修饰的方法不能被重写。
final 修饰的变量叫常量,常量必须初始化,初始化之后值就不能被修改。
5.8 抽象类必须要有抽象方法吗?
不需要,抽象类不一定非要有抽象方法;但是包含一个抽象方法的类一定是抽象类。
示例代码:
abstract class Cat {
public static void sayHi() {
System. out. println("hi~");
}
}
上面代码,抽象类并没有抽象方法但完全可以正常运行。
5.9 普通类和抽象类有哪些区别?
普通类不能包含抽象方法,抽象类可以包含抽象方法。
抽象类是不能被实例化的,就是不能用new调出构造方法创建对象,普通类可以直接实例化。
如果一个类继承于抽象类,则该子类必须实现父类的抽象方法。如果子类没有实现父类的抽象方法,则必须将子类也定义为abstract类。
5.10 抽象类能使用 final 修饰吗?
不能,定义抽象类就是让其他类继承的,如果定义为 final 该类就不能被继承,这样彼此就会产生矛盾,所以 final 不能修饰抽象类
6.1 什么是内部类?内部类有几种?每一中内部类如何表示有那些些特征?
将一个类定义在另一个类里面,形成了包含关系。
内部类–被包含的类
外部类–包含内部类的类。
内部类一共有四种:成员内部类、静态内部类、方法内部类、匿名内部类
成员内部类:
格式:
public class 外部类{
public class 成员内部类{
}
}
在这里我们可以认为成员内部类就相当于外部类中的一个成员变量/实例方法。
A.成员内部类中不能定义静态变量和静态方法。
B.外部类的静态方法是不能访问成员内部类的。
C.其他的类中如果想访问成员内部类中的变量和方法,就得先创建外部类对象。
1️⃣成员内部类中的变量和方法的调用关系。
- 成员内部类的构造方法中可以访问成员内部类实例变量/成员内部类的实例方法,默认this.,可以省略this.
- 成员内部类的构造方法中可以访问成员内部类中其他的构造方法,通过new访问
- 成员内部类的实例方法中中可以访问成员内部类实例变量/成员内部类的实例方法,默认this.,可以省略this.
- 成员内部类的实例方法中中可以访问成员内部类构造方法,通过new访问
2️⃣成员内部类中的方法访问外部类中的变量和方法
- 成员内部类的构造方法中可以访问外部类的实例变量/外部类的实例方法,默认外部类的类名.this,可以省略外部类的类名.this。
- 成员内部类的构造方法中可以访问外部类的类变量/类方法,默认类名访问,也可以外部类的类名.this,可以省略类名/外部类的类名.this。
- 成员内部类的构造方法中可以访问外部类的构造方法,通过new访问。
- 成员内部类的实例方法中可以访问外部类的实例变量/外部类的实例方法,默认外部类的类名.this,可以省略外部类的类名.this。
- 成员内部类的实例方法中可以访问外部类的类变量/类方法,默认类名访问,也可以外部类的类名.this,可以省略类名/外部类的类名.this。
- 成员内部类的实例方法中可以访问外部类的构造方法,通过new访问。
3️⃣外部类中的方法访问成员内部类中的变量和方法
- 外部类的构造方法/实例方法中可以访问成员内部类的构造方法【new】,实例变量/实例方法【对象调用】
- 外部类的类方法中不能访问成员内部类。
- 其他类中访问成员内部类中的变量和方法
- 其他中可以访问成员内部类,先创建外部类对象,然后在创建内部类对象
静态内部类:
静态内部类是 static 修饰的内部类,这种内部类的特点是:
- 静态内部类不能直接访问外部类的非静态成员,但可以通过 new 外部类().成员 的方式访问
- 如果外部类的静态成员与内部类的成员名称相同,可通过“类名.静态成员”访问外部类的静态成员;如果外部类的静态成员与内部类的成员名称不相同,则可通过“成员名”直接调用外部类的静态成员
- 创建静态内部类的对象时,不需要外部类的对象,可以直接创建 内部类 对象名= new 内部类();
方法内部类—在这里我们可以认为方法内部类就相当于方法中的一个局部变量:
将java类定义在某一个方法中。
- 定义方法内部类的时候没有访问修饰符
- 方法内部类中不能出现类变量和类方法
- 方法内部类中的构造方法/实例方法,可以访问本方法中的局部变量,jdk8.0之前需要使用final修饰局部变量,包括参数
- 方法内部类中的构造方法/实例方法,可以访问外部类的实例变量/实例方法,默认外部类类名.this. , 可以省略外部类类名.this.
- 方法内部类中的构造方法/实例方法,可以访问外部类的类变量/类方法,默认外部类类名,也可以外部类类名.this. ,可以省略外部类类名/外部类类名.this.
- 定义该方法内部类的方法中可以访问这个方法内部类中的变量和方法,对象访问
- 外部类中的方法中是不能访问方法内部类的。【方法内部类当于方法中的一个局部变量】
匿名内部类—类/抽象类/接口的子类:
没有名字的内部类
1.继承式的匿名内部类
2.接口式的匿名内部类
优点:可以有效的减少类的创建
缺点:不利于程序的阅读和理解
6.2 异常类的体系结构?Error和Exception的区别?
1.任何人所写的程序都有可能出现异常,就像人会生病一样,程序出现异常是一种正常现象。
2.程序运行的时候可能出现的一些不正常的现象就是异常【Exception】。【可纠正,可避免】【感冒发烧】
3.程序运行的时候可能出现的一些不可回避的问题就是错误【Error】。【不可纠正】【癌症晚期】
4.java中的异常【Exception】和错误【Error】都是Throwable的子类。
public class Exception extends Throwable{}
public class Error extends Throwable{}
Throwable是java中异常处理类的顶级类。
6.3 运行时异常与非运行时异常?
Exception是程序本身可以处理的异常,这种异常分为两大类运行是异常和非运行时异常。程序中尽可能去处理这些异常。
运行时异常:都是RuntimeException类及其子类异常:
- IndexOutOfBoundsException:索引越界异常
ArithmeticException:数学运算异常
NullpointerException:空指针异常
ArrayOutOfBoundsException:数组索引越界异常
ClassNotFoundException:类文件未找到异常
ClassCastException:类型转换异常
非运行时异常:是RuntimeException以外的异常,类型上都属于Exception类及其子类。从程序语法角度讲是必须处理的异常,如果不处理,程序就不能编译通过。如:
- IOException:文件读写异常
FileNotFoundException:文件未找到异常
EXFEception:文件已结束异常
MalformedURLException:URL格式错误异常
SocketException:Socket异常
SQLException:SQL数据库异常
6.4 throw 和 throws 的区别?
throw:是真实抛出一个异常。
throws:是声明可能会抛出一个异常。
6.5 final、finally、finalize 有什么区别?
final:是修饰符,如果修饰类,此类不能被继承;如果修饰方法和变量,则表示此方法和此变量不能在被改变,只能使用。
finally:是 try{} catch{} finally{} 最后一部分,表示不论发生任何情况都会执行,finally 部分可以省略,但如果 finally 部分存在,则一定会执行 finally 里面的代码。
finalize:是一个方法,属于java.lang.object类,finalize()方法是GC(垃圾回收)运行机制的一部分,finalize()方法是在GC清理它所从属的对象时被调用的。
6.6 try-catch-finally 中哪个部分可以省略?
try-catch-finally 其中 catch 和 finally 都可以被省略,但是不能同时省略,也就是说有 try 的时候,必须后面跟一个 catch 或者 finally。
6.7 try-catch-finally 中,如果 catch 中 return 了,finally 还会执行吗?
finally 一定会执行,即使是 catch 中 return 了,catch 中的 return 会等 finally 中的代码执行完之后,才会执行。
6.8 java程序中几种常见的异常以及出现此异常的原因
- java.lang.NullpointerException(空指针异常)
原因:这个异常经常遇到,异常的原因是程序中有空指针,即程序中调用了未经初始化的对象或者是不存在的对象。
经常出现在创建对象,调用数组这些代码中,比如对象未经初始化,或者图片创建时的路径错误等等。对数组代码中出现空指针,是把数组的初始化和数组元素的初始化搞混淆了。数组的初始化是对数组分配空间,而数组元素的初始化,是给数组中的元素赋初始值 - java.lang.ClassNotFoundException(指定的类不存在)
原因:当试图将一个String类型数据转换为指定的数字类型,但该字符串不满足数值型数据的要求时,就抛出这个异常。例如将String类型的数据"123456"转换为数值型数据时,是可以转换的的。但是如果String类型的数据中包含了非数字型的字符,如123*56,此时转换为数值型时就会出现异常。系统就会捕捉到这个异常,并进行处理 - java.lang.ClassNotFoundExceptio(指定的类不存在)
原因:是因为类的名称和路径不正确,通常都是程序试图通过字符串来加载某个类的时候可能会引发异常。例如:调用Class.forName()、或者调用ClassLoad的finaSystemClass()、或者是LoadClass()时出现异常 - java.lang.IndexOutOfBoundsException(数组下标越界异常)
原因:查看程序中调用的数组或者字符串的下标值是不是超出了数组的范围,一般来说,显示调用数组不太容易出这样的错,但隐式调用就有可能出错了,还有一种情况,是程序中定义的数组的长度是通过某些特定方法决定的,不是事先声明的,这个时候可以先查看一下数组的length,以免出现这个异常 - java.lang.IllegalArgumentException(方法的参数错误)
例如g.setColor(int red,int green,int blue)这个方法中的三个值,如果有超过255的会出现这个异常,如果程序中存在这个异常,就要去检查一下方法调用中的参数传递或参数值是不是有错 - java.lang.IllegalAccessException(没有访问权限)
当程序要调用一个类,但当前的方法即没有对该类的访问权限便会出现这个异常。如果程序中用了Package的情况下有可能出现这个异常 - java.lang.ArithmeticException(数学运算异常)
当数学运算中出现了除以零这样的运算就会出这样的异常。 - java.lang.ClassCastException(数据类型转换异常)
当试图将对某个对象强制执行向下转换,但该对象又不可转换或又不可转换为其子类的实例时将出现该异常 - java.lang.FileNotFoundException(文件未找到异常)
当程序打开一个不存在的文件来进行读写时将会引发该异常。该异常由FileInputStream,FileOutputStream,RandomAccessFile的构造器声明抛出,即使被操作的文件存在,但是由于某些原因不可访问,比如打开一个
只有只读权限的文件并向其中写入数据,以上构造方法依然会引发异常 - java.lang.ArrayStoreException(数组存储异常)
当试图将类型为不兼容类型的对象存入一个Object[]数组时将引发异常 - java.lang.NoSuchMethodException(方法不存在异常)
当程序试图通过反射来创建对象,访问(修改或读取)某个方法,但是该方法不存在就会引发异常。 - java.lang.EOFException(文件已结束异常)
当程序在输入的过程中遇到文件或流的结尾时,引发异常。因此该异常用于检查是否达到文件或流的结尾 - java.lang.InstantiationException(实例化异常)
当试图通过Class的newInstance()方法创建某个类的实例,但程序无法通过该构造器来创建该对象时引发。
Class对象表示一个抽象类,接口,数组类,基本类型 。该Class表示的类没有对应的构造器。 - java.lang.InterruptedException(被中止异常)
当某个线程处于长时间的等待、休眠或其他暂停状态,而此时其他的线程通过Thread的interrupt方法终止该线程时抛出该异常。 - java.lang.CloneNotSupportedException (不支持克隆异常)
当没有实现Cloneable接口或者不支持克隆方法时,调用其clone()方法则抛出该异常 - java.lang.OutOfMemoryException (内存不足错误)
当可用内存不足以让Java虚拟机分配给一个对象时抛出该错误 - java.lang.NoClassDefFoundException (未找到类定义错误)
当Java虚拟机或者类装载器试图实例化某个类,而找不到该类的定义时抛出该错误
7.1 String 属于基础的数据类型吗?
String 不属于基础类型,基础类型有 8 种:byte、boolean、char、short、int、float、long、double,而 String 属于对象。
7.2 Java 中操作字符串都有哪些类?它们之间有什么区别?
操作字符串的类有:String、StringBuffer、StringBuilder。
三者区别:
StringBuffer和StringBuilder都继承自抽象类AbstractStringBuilder。
String 声明的是不可变的对象,每次操作都会生成新的 String 对象,然后将指针指向新的 String 对象,而 StringBuffer、StringBuilder 存储数据的字符数组没有被final修饰,说明值可以改变,抽象类AbstractStringBuilder内部都提供了一个自动扩容机制,当发现长度不够的时候(初始默认长度是16),会自动进行扩容工作,扩展为原数组长度的2倍加2,创建一个新的数组,并将数组的数据复制到新数组,所以对于拼接字符串效率要比String要高。
线程安全性:StringBuffer由于很多方法都被 synchronized 修饰了所以线程安全,但是当多线程访问时,加锁和释放锁的过程很平凡,所以效率相比StringBuilder要低。StringBuilder相反执行效率高,但是线程不安全。所以单线程环境下推荐使用 StringBuilder,多线程环境下推荐使用 StringBuffer。
执行速度:StringBuilder > StringBuffer > String。
7.3 String str="i"与 String str=new String(“i”)一样吗?
不一样,因为内存的分配方式不一样。String str=“i"的方式,Java 虚拟机会将其分配到常量池中,如果常量池中有"i”,就返回"i"的地址,如果没有就创建"i",然后返回"i"的地址;而 String str=new String(“i”) 则会被分到堆内存中新开辟一块空间。
7.4 基本数据类型和包装类型的区别
1、包装类是对象,拥有方法和字段,对象的调用都是通过引用对象的地址;基本类型不是
2、包装类型是引用的传递;基本类型是值的传递
3、声明方式不同:
基本数据类型不需要new关键字;
包装类型需要new在堆内存中进行new来分配内存空间
4、存储位置不同:
基本数据类型直接将值保存在值栈中;
包装类型是把对象放在堆中,然后通过对象的引用来调用他们
5、初始值不同:
int的初始值为 0 、 boolean的初始值为false
包装类型的初始值为null
6、使用方式不同:
基本数据类型直接赋值使用就好;
包装类型是在集合如 coolectionMap时使用
7.5 String 类的常用方法都有那些?
indexOf():返回指定字符的索引。
charAt():返回指定索引处的字符。
replace():字符串替换。
trim():去除字符串两端空白。
split():分割字符串,返回一个分割后的字符串数组。
getBytes():返回字符串的 byte 类型数组。
length():返回字符串长度。
toLowerCase():将字符串转成小写字母。
toUpperCase():将字符串转成大写字符。
substring():截取字符串。
equals():字符串比较。
7.6 ==和equals的区别
== 对于基本类型来说是值比较,对于引用类型来说是比较的是引用;而 equals 默认情况下是引用比较,只是很多类重写了 equals 方法,比如 String、Integer 等把它变成了值比较,所以一般情况下 equals 比较的是值是否相等。
7.7 Math类有哪些常用方法?
java.lang.Math
Math 类包含用于执行基本数学运算的方法,如初等指数、对数、平方根和三角函数。
成员变量
static double E 自然常数
static double PI 圆周率
静态方法
random() 得到0.0-1.0之间的随机数
round(float a)返回最接近参数的 int。
7.8 正则表达式?
正则表达式,又称规则表达式。正则表达式通常被用来检索、替换那些符合某个模式(规则)的文本。正则表达式是对字符串操作的一种逻辑公式,就是用事先定义好的一些特定字符、及这些特定字符的组合,组成一个“规则字符串”,这个“规则字符串”用来表达对字符串的一种过滤逻辑。通常都是用来验证输入的字符串数据是否复合正则表达式定义的规范,常被用来做验证操作。
8.1 Conllection与Map
1、Collection接口是Jdk提供的处理单列数据的顶级接口。
2、Collection接口的子接口List接口处理有顺序的单列数据。
List接口可以有重复的数据元素,按照顺序区分。
ArrayList类
LinkedList类
3、Collection接口的子接口Set接口处理没有顺序的单列数据。
Set接口不能有重复的数据元素,【重复的元素被视为同一个】
HashSet类
LinkedHashSet类
Map接口是处理键值对数据的顶级集合接口
8.2 Java 容器都有哪些?
Java 容器分为 Collection 和 Map 两大类,其下又有很多子类,如下所示:
8.3 List、Set、Map 之间的区别是什么?
List、Set、Map 的区别主要体现在两个方面:元素是否有序、是否允许元素重复。
三者之间的区别,如下表:
8.4 ArrayList 和 LinkedList 的区别是什么?
数据结构实现:ArrayList 是动态数组的数据结构实现,而 LinkedList 是双向链表的数据结构实现。
随机访问效率:ArrayList 比 LinkedList 在随机访问的时候效率要高,因为 LinkedList 是线性的数据存储方式,所以需要移动指针从前往后依次查找。
增加和删除效率:在非首尾的增加和删除操作,LinkedList 要比 ArrayList 效率要高,因为 ArrayList 增删操作要影响数组内的其他数据的下标。
综合来说,在需要频繁读取集合中的元素时,更推荐使用 ArrayList,而在插入和删除操作较多时,更推荐使用 LinkedList。
8.5 如何实现数组和 List 之间的转换?
数组转 List:使用 Arrays. asList(array) 进行转换。
List 转数组:使用 List 自带的 toArray() 方法。
代码示例:
// list to array
List list = new ArrayList();
list. add(“☞精◈彩◈猿◈笔◈记☜”);
list. add(“的博客”);
list. toArray();
// array to list
String[] array = new String[]{“☞精◈彩◈猿◈笔◈记☜”,“的博客”};
Arrays. asList(array);
8.6 ArrayList 和 Vector 的区别是什么?
线程安全:Vector 使用了 Synchronized 来实现线程同步,是线程安全的,而 ArrayList 是非线程安全的。
性能:ArrayList 在性能方面要优于 Vector。
扩容:ArrayList 和 Vector 都会根据实际的需要动态的调整容量,只不过在 Vector 扩容每次会增加 1 倍,而 ArrayList 只会增加 50%。
8.7 Array 和 ArrayList 有何区别?
Array 可以存储基本数据类型和对象,ArrayList 只能存储对象。
Array 是指定固定大小的,而 ArrayList 大小是自动扩展的。
Array 内置方法没有 ArrayList 多,比如 addAll、removeAll、iteration 等方法只有 ArrayList 有。
8.8 HashMap 和 Hashtable 有什么区别?
HashMap是继承自AbstractMap类,而HashTable是继承自Dictionary类。不过它们都实现了同时实现了map、Cloneable(可复制)、Serializable(可序列化)这三个接口。
Hashtable比HashMap多提供了elments() 和contains() 两个方法。
HashMap的key-value支持key-value,null-null,key-null,null-value四种。而Hashtable只支持key-value一种(即key和value都不为null这种形式)。既然HashMap支持带有null的形式,那么在HashMap中不能由get()方法来判断HashMap中是否存在某个键, 而应该用containsKey()方法来判断,因为使用get的时候,当返回null时,你无法判断到底是不存在这个key,还是这个key就是null,还是key存在但value是null。
线程安全性不同:HashMap的方法都没有使用synchronized关键字修饰,都是非线程安全的,而Hashtable的方法几乎都是被synchronized关键字修饰的。但是,当我们需要HashMap是线程安全的时,怎么办呢?我们可以通过Collections.synchronizedMap(hashMap)来进行处理,亦或者我们使用线程安全的ConcurrentHashMap。ConcurrentHashMap虽然也是线程安全的,但是它的效率比Hashtable要高好多倍。因为ConcurrentHashMap使用了分段锁,并不对整个数据进行锁定。
初始容量大小和每次扩充容量大小的不同:Hashtable默认的初始大小为11,之后每次扩充,容量变为原来的2n+1。HashMap默认的初始化大小为16。之后每次扩充,容量变为原来的2倍。
计算hash值的方法不同:为了得到元素的位置,首先需要根据元素的 KEY计算出一个hash值,然后再用这个hash值来计算得到最终的位置。Hashtable直接使用对象的hashCode。hashCode是JDK根据对象的地址或者字符串或者数字算出来的int类型的数值。然后再使用除留余数发来获得最终的位置。
8.9 如何决定使用 HashMap 还是 TreeMap?
对于在 Map 中插入、删除、定位一个元素这类操作,HashMap 是最好的选择,因为相对而言 HashMap 的插入会更快,但如果你要对一个 key 集合进行有序的遍历,那 TreeMap 是更好的选择。
8.10 说一下 HashMap 的实现原理?
HashMap 基于 Hash 算法实现的,我们通过 put(key,value)存储,get(key)来获取。当传入 key 时,HashMap 会根据 key. hashCode() 计算出 hash 值,根据 hash 值将 value 保存在 bucket 里。当计算出的 hash 值相同时,我们称之为 hash 冲突,HashMap 的做法是用链表和红黑树存储相同 hash 值的 value。当 hash 冲突的个数比较少时,使用链表否则使用红黑树。
8.11 说一下 HashSet 的实现原理?
HashSet 是基于 HashMap 实现的,HashSet 底层使用 HashMap 来保存所有元素,因此 HashSet 的实现比较简单,相关 HashSet 的操作,基本上都是直接调用底层 HashMap 的相关方法来完成,HashSet 不允许重复的值。
8.12 Set,HashSet,TreeSet和LinkedHashSet的区别
Set接口
Set不允许包含相同的元素,如果试图把两个相同元素加入同一个集合中,add方法返回false。
Set判断两个对象相同不是使用==运算符,而是根据equals方法。也就是说,只要两个对象用equals方法比较返回true,Set就不 会接受这两个对象。
HashSet
HashSet有以下特点
1.不能保证元素的排列顺序,顺序有可能发生变化
2.不是同步的
3.集合元素可以是null,但只能放入一个null
当向HashSet结合中存入一个元素时,HashSet会调用该对象的hashCode()方法来得到该对象的hashCode值,然后根据 hashCode值来决定该对象在HashSet中存储位置。
简单的说,HashSet集合判断两个元素相等的标准是两个对象通过equals方法比较相等,并且两个对象的hashCode()方法返回值相 等
注意,如果要把一个对象放入HashSet中,重写该对象对应类的equals方法,也应该重写其hashCode()方法。其规则是如果两个对 象通过equals方法比较返回true时,其hashCode也应该相同。另外,对象中用作equals比较标准的属性,都应该用来计算 hashCode的值。
LinkedHashSet
LinkedHashSet集合同样是根据元素的hashCode值来决定元素的存储位置,但是它同时使用链表维护元素的次序。这样使得元素看起 来像是以插入顺序保存的,也就是说,当遍历该集合时候,LinkedHashSet将会以元素的添加顺序访问集合的元素。
LinkedHashSet在迭代访问Set中的全部元素时,性能比HashSet好,但是插入时性能稍微逊色于HashSet。
TreeSet
TreeSet是SortedSet接口的唯一实现类,TreeSet可以确保集合元素处于排序状态。TreeSet支持两种排序方式,自然排序 和定制排序,其中自然排序为默认的排序方式。向TreeSet中加入的应该是同一个类的对象。
TreeSet判断两个对象不相等的方式是两个对象通过equals方法返回false,或者通过CompareTo方法比较没有返回0
9.1 Files的常用方法都有哪些?
Files. exists():检测文件路径是否存在。
Files. createFile():创建文件。
Files. createDirectory():创建文件夹。
Files. delete():删除一个文件或目录。
Files. copy():复制文件。
Files. move():移动文件。
Files. size():查看文件个数。
Files. read():读取文件。
Files. write():写入文件。
···
9.2 Java 中 IO 流分为几种?
按功能来分:输入流(input)、输出流(output)。
按类型来分:字节流和字符流。
- 字节流和字符流的区别是:字节流按 8 位传输以字节为单位输入输出数据,由于所有的数据都可以转换成字节,因此字节流可以处理任何类型的数据【文本,图片,视频,音频…】;
- 字符流按 16 位传输以字符为单位输入输出数据。只能处理文本型数据【word文档,记事本文件】,不能处理图片,视频,音频这些类型的文件。
10.1 并行和并发有什么区别?
并行:多个处理器或多核处理器同时处理多个任务。
并发:多个任务在同一个 CPU 核上,按细分的时间片轮流(交替)执行,从逻辑上来看那些任务是同时执行。
如下图:【并发 = 两个队列和一台咖啡机】 【并行 = 两个队列和两台咖啡机】
10.2 线程和进程的区别?
一个程序下至少有一个进程,一个进程下至少有一个线程,一个进程下也可以有多个线程来增加程序的执行速度。
10.3 守护线程是什么?
守护线程是运行在后台的一种特殊进程。它独立于控制终端并且周期性地执行某种任务或等待处理某些发生的事件。在 Java 中垃圾回收线程就是特殊的守护线程。[共死]
10.4 多线程有几种实现方式?
有4种,分别是:
继承Thread类
实现Runnable接口
实现Callable接口通过FutureTask包装器来创建Thread线程
通过线程池创建线程,使用线程池接口ExecutorService结合Callable、Future实现有返回结果的多线程。
前面两种【无返回值】原因:通过重写run方法,run方法的返回值是void,所以没有办法返回结果。
后面两种【有返回值】原因:通过Callable接口,就要实现call方法,这个方法的返回值是Object,所以返回的结果可以放在Object对象中。
10.5 说一下 Runnable和 Callable有什么区别?
Runnable没有返回值,Callable可以拿到有返回值,Callable可以看作是 Runnable的补充。
10.6 线程有哪些状态?
线程的6种状态:
初始(NEW):新创建了一个线程对象,但还没有调用start()方法。
运行(RUNNABLE):Java线程中将就绪(ready)和运行中(running)两种状态笼统的称为“运行”。线程对象创建后,其他线程(比如main线程)调用了该对象的start()方法。该状态的线程位于可运行线程池中,等待被线程调度选中,获取CPU的使用权,此时处于就绪状态(ready)。就绪状态的线程在获得CPU时间片后变为运行中状态(running)。
阻塞(BLOCKED):表示线程阻塞于锁。
等待(WAITING):进入该状态的线程需要等待其他线程做出一些特定动作(通知或中断)。
超时等待(TIMED_WAITING):该状态不同于WAITING,它可以在指定的时间后自行返回。
终止(TERMINATED):表示该线程已经执行完毕。
10.7 sleep() 和 wait() 有什么区别?
类的不同:sleep() 来自 Thread,wait() 来自 Object。
释放锁:sleep() 不释放锁;wait() 释放锁。
用法不同:sleep() 时间到会自动恢复;wait() 可以使用 notify()/notifyAll()直接唤醒。
10.8 notify()和 notifyAll()有什么区别?
notifyAll()会唤醒所有的线程,notify()之后唤醒一个线程。notifyAll() 调用后,会将全部线程由等待池移到锁池,然后参与锁的竞争,竞争成功则继续执行,如果不成功则留在锁池等待锁被释放后再次参与竞争。而 notify()只会唤醒一个线程,具体唤醒哪一个线程由虚拟机控制。
10.9 线程的 run() 和 start() 有什么区别?
start() 方法用于启动线程,run() 方法用于执行线程的运行时代码。run() 可以重复调用,而 start() 只能调用一次。
10.10 创建线程池有哪几种方式?
线程池创建有七种方式,最核心的是最后一种:
newSingleThreadExecutor():它的特点在于工作线程数目被限制为 1,操作一个无界的工作队列,所以它保证了所有任务的都是被顺序执行,最多会有一个任务处于活动状态,并且不允许使用者改动线程池实例,因此可以避免其改变线程数目;
newCachedThreadPool():它是一种用来处理大量短时间工作任务的线程池,具有几个鲜明特点:它会试图缓存线程并重用,当无缓存线程可用时,就会创建新的工作线程;如果线程闲置的时间超过 60 秒,则被终止并移出缓存;长时间闲置时,这种线程池,不会消耗什么资源。其内部使用 SynchronousQueue 作为工作队列;
newFixedThreadPool(int nThreads):重用指定数目(nThreads)的线程,其背后使用的是无界的工作队列,任何时候最多有 nThreads 个工作线程是活动的。这意味着,如果任务数量超过了活动队列数目,将在工作队列中等待空闲线程出现;如果有工作线程退出,将会有新的工作线程被创建,以补足指定的数目 nThreads;
newSingleThreadScheduledExecutor():创建单线程池,返回 ScheduledExecutorService,可以进行定时或周期性的工作调度;
newScheduledThreadPool(int corePoolSize):和newSingleThreadScheduledExecutor()类似,创建的是个 ScheduledExecutorService,可以进行定时或周期性的工作调度,区别在于单一工作线程还是多个工作线程;
newWorkStealingPool(int parallelism):这是一个经常被人忽略的线程池,Java 8 才加入这个创建方法,其内部会构建ForkJoinPool,利用Work-Stealing算法,并行地处理任务,不保证处理顺序;
ThreadPoolExecutor():是最原始的线程池创建,上面1-3创建方式都是对ThreadPoolExecutor的封装。
10.11 线程池都有哪些状态?
RUNNING:这是最正常的状态,接受新的任务,处理等待队列中的任务。
SHUTDOWN:不接受新的任务提交,但是会继续处理等待队列中的任务。
STOP:不接受新的任务提交,不再处理等待队列中的任务,中断正在执行任务的线程。
TIDYING:所有的任务都销毁了,workCount 为 0,线程池的状态在转换为 TIDYING 状态时,会执行钩子方法 terminated()。
TERMINATED:terminated()方法结束后,线程池的状态就会变成这个。
10.12 线程池中 submit() 和 execute() 方法有什么区别?
execute():只能执行 Runnable 类型的任务。
submit():可以执行 Runnable 和 Callable 类型的任务。
Callable 类型的任务可以获取执行的返回值,而 Runnable 执行无返回值。
10.13 在 Java 程序中怎么保证多线程的运行安全?
方法一:使用安全类,比如 Java. util. concurrent 下的类。
方法二:使用自动锁 synchronized。
方法三:使用手动锁 Lock。
手动锁 Java 示例代码如下:
Lock lock = new ReentrantLock();
lock. lock();
try {
System. out. println(“获得锁”);
} catch (Exception e) {
// TODO: handle exception
} finally {
System. out. println(“释放锁”);
lock. unlock();
}
10.14 多线程中 synchronized 锁升级的原理是什么?
synchronized 锁升级原理:在锁对象的对象头里面有一个 threadid 字段,在第一次访问的时候 threadid 为空,jvm 让其持有偏向锁,并将 threadid 设置为其线程 id,再次进入的时候会先判断 threadid 是否与其线程 id 一致,如果一致则可以直接使用此对象,如果不一致,则升级偏向锁为轻量级锁,通过自旋循环一定次数来获取锁,执行一定次数之后,如果还没有正常获取到要使用的对象,此时就会把锁从轻量级升级为重量级锁,此过程就构成了 synchronized 锁的升级。
锁的升级的目的:锁升级是为了减低了锁带来的性能消耗。在 Java 6 之后优化 synchronized 的实现方式,使用了偏向锁升级为轻量级锁再升级到重量级锁的方式,从而减低了锁带来的性能消耗。
10.15 什么是死锁?
当线程 A 持有独占锁a,并尝试去获取独占锁 b 的同时,线程 B 持有独占锁 b,并尝试获取独占锁 a 的情况下,就会发生 AB 两个线程由于互相持有对方需要的锁,而发生的阻塞现象,我们称为死锁。
10.16 怎么防止死锁?
尽量使用 tryLock(long timeout, TimeUnit unit)的方法(ReentrantLock、ReentrantReadWriteLock),设置超时时间,超时可以退出防止死锁。
尽量使用 Java. util. concurrent 并发类代替自己手写锁。
尽量降低锁的使用粒度,尽量不要几个功能用同一把锁。
尽量减少同步的代码块。
10.17 ThreadLocal 是什么?有哪些使用场景?
ThreadLocal 为每个使用该变量的线程提供独立的变量副本,所以每一个线程都可以独立地改变自己的副本,而不会影响其它线程所对应的副本。
ThreadLocal 的经典使用场景是数据库连接和 session 管理等。
10.18 说一下 synchronized 底层实现原理?
synchronized 是由一对 monitorenter/monitorexit 指令实现的,monitor 对象是同步的基本实现单元。在 Java 6 之前,monitor 的实现完全是依靠操作系统内部的互斥锁,因为需要进行用户态到内核态的切换,所以同步操作是一个无差别的重量级操作,性能也很低。但在 Java 6 的时候,Java 虚拟机 对此进行了大刀阔斧地改进,提供了三种不同的 monitor 实现,也就是常说的三种不同的锁:偏向锁(Biased Locking)、轻量级锁和重量级锁,大大改进了其性能。
10.19 synchronized 和 volatile 的区别是什么?
volatile 是变量修饰符;synchronized 是修饰类、方法、代码段。
volatile 仅能实现变量的修改可见性,不能保证原子性;而 synchronized 则可以保证变量的修改可见性和原子性。
volatile 不会造成线程的阻塞;synchronized 可能会造成线程的阻塞。
10.20 synchronized 和 Lock 有什么区别?
synchronized 可以给类、方法、代码块加锁;而 lock 只能给代码块加锁。
synchronized 不需要手动获取锁和释放锁,使用简单,发生异常会自动释放锁,不会造成死锁;而 lock 需要自己加锁和释放锁,如果使用不当没有 unLock()去释放锁就会造成死锁。
通过 Lock 可以知道有没有成功获取锁,而 synchronized 却无法办到。
10.21 synchronized 和 ReentrantLock 区别是什么?
synchronized 早期的实现比较低效,对比 ReentrantLock,大多数场景性能都相差较大,但是在 Java 6 中对 synchronized 进行了非常多的改进。
主要区别如下:
ReentrantLock 使用起来比较灵活,但是必须有释放锁的配合动作;
ReentrantLock 必须手动获取与释放锁,而 synchronized 不需要手动释放和开启锁;
ReentrantLock 只适用于代码块锁,而 synchronized 可用于修饰方法、代码块等。
ReentrantLock 标记的变量不会被编译器优化;synchronized 标记的变量可以被编译器优化。
11.1 http 响应码 301 和 302 代表的是什么?有什么区别?
301:永久重定向;302:暂时重定向。
它们的区别是,301 对搜索引擎优化(SEO)更加有利;302 有被提示为网络拦截的风险。
404:访问路径错误
500:服务器端程序错误
200:OK
11.2 forward 和 redirect 的区别?
forward 是转发 和 redirect 是重定向:
地址栏 url 显示:foward url 不会发生改变,redirect url 会发生改变;
数据共享:forward 可以共享 request 里的数据,redirect 不能共享;
效率:forward 比 redirect 效率高。
11.3 简述 tcp 和 udp的区别?
TCP:传输控制协议。
TCP协议在通信的时候,要求通信的双方先建立起连接(面向有连接的协议)。在建立连接的过程中需要经过三次握手才能完成连接的建立。.
UDP:用户数据报协议。它是面向无连接的协议。发送一方,不用关心接受一方是否在线,能不能接受到数据,接受的数据正确与否。就直接发送数据。如果对方在就可以接受数据,如果对方不在,这时数据就自动的被丢弃。
UDP优点:消耗小,效率较高。
UDP缺点:协议不安全,不可靠,不能传输大数据。
区别:
TCP 和 UDP 是 OSI 模型中的运输层中的协议。tcp 提供可靠的通信传输,而 udp 则常被用于让广播和细节控制交给应用的通信传输。
两者的区别大致如下:
tcp 面向连接,udp 面向非连接即发送数据前不需要建立链接;
tcp 提供可靠的服务(数据传输),udp 无法保证;
tcp 面向字节流,udp 面向报文;
tcp 数据传输慢,udp 数据传输快;
11.4 tcp 为什么要三次握手,两次不行吗?为什么?
第一次握手:客户端向服务器发出连接请求,等待服务器确认
第二次握手:服务器向客户端发送响应,通知客户端收到连接请求
第三次握手:客户端再次向服务器端确认请求
如果采用两次握手,那么只要服务器发出确认数据包就会建立连接,但由于客户端此时并未响应服务器端的请求,那此时服务器端就会一直在等待客户端,这样服务器端就白白浪费了一定的资源。若采用三次握手,服务器端没有收到来自客户端的再此确认,则就会知道客户端并没有要求建立请求,就不会浪费服务器的资源。
11.7 OSI(开放式系统互联) 的七层模型都有哪些?
物理层:利用传输介质为数据链路层提供物理连接,实现比特流的透明传输。
数据链路层:负责建立和管理节点间的链路。
网络层:通过路由选择算法,为报文或分组通过通信子网选择最适当的路径。
传输层:向用户提供可靠的端到端的差错和流量控制,保证报文的正确传输。
会话层:向两个实体的表示层提供建立和使用连接的方法。
表示层:处理用户信息的表示问题,如编码、数据格式转换和加密解密等。
应用层:直接向用户提供服务,完成用户希望在网络上完成的各种工作。
11.6 get 和 post 请求有哪些区别?
1、url可见性:
get,参数url可见;
post,url参数不可见
2、数据传输上:
get,通过拼接url进行传递参数;
post,通过body体传输参数
3、缓存性:
get请求是可以缓存的
post请求不可以缓存
4、后退页面的反应
get请求页面后退时,不产生影响
post请求页面后退时,会重新提交请求
5、传输数据的大小
get一般传输数据大小不超过2k-4k(根据浏览器不同,限制不一样,但相差不大)
post请求传输数据的大小根据php.ini 配置文件设定,也可以无限大。
6、安全性
这个也是最不好分析的,原则上post肯定要比get安全,毕竟传输参数时url不可见,但也挡不住部分人闲的没事在那抓包玩。安全性个人觉得是没多大区别的,防君子不防小人就是这个道理。对传递的参数进行加密,其实都一样。
12.1 Jdbc访问数据库的流程?
13.1 说一下你熟悉的设计模式?
单例模式:保证被创建一次,节省系统开销。
懒汉式:是在得到本类对象的静态方法中创建的本类对象
饿汉式:是在定义本类对象的变量时就创建好了本类对象
从程序的运行速度角度分析:饿汉式的单例模式要比懒汉式的单例模式更快一些。
从程序的内存使用角度分析:懒汉式的单例模式要比饿汉式的单例模式更节省内存一些。
以后我们在构造自己的程序是如果需要某一个java类的对象在整个程序中只有一个对象的话,那么我们首先要想到的就是单例模式。
工厂模式(简单工厂、抽象工厂):解耦代码。简单工厂又叫静态工厂,由一个工厂对象决定创建哪一个产品对象。
代理模式:为其他对象提供一种代理以控制对这个对象的访问。在某些情况下,一个对象不适合或者不能直接引用另一个对象,而代理对象可以在客户端和目标对象之间起到中介的作用。
观察者模式:定义了对象之间的一对多的依赖,这样一来,当一个对象改变时,它的所有的依赖者都会收到通知并自动更新。
外观模式:提供一个统一的接口,用来访问子系统中的一群接口,外观定义了一个高层的接口,让子系统更容易使用。
模版方法模式:定义了一个算法的骨架,而将一些步骤延迟到子类中,模版方法使得子类可以在不改变算法结构的情况下,重新定义算法的步骤。
状态模式:允许对象在内部状态改变时改变它的行为,对象看起来好像修改了它的类。
13.2 简单工厂和抽象工厂有什么区别?
简单工厂:用来生产同一等级结构中的任意产品,对于增加新的产品,无能为力。
工厂方法:用来生产同一等级结构中的固定产品,支持增加任意产品。
抽象工厂:用来生产不同产品族的全部产品,对于增加新的产品,无能为力;支持增加产品族。
14.1 什么是反射?
反射是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性;这种动态获取的信息以及动态调用对象的方法的功能称为 Java 语言的反射机制。
14.2 什么是 Java 序列化?什么情况下需要序列化?
序列化和反序列化的概念:
序列化:把Java对象转换为字节序列的过程。
反序列化:把字节序列恢复为Java对象的过程。
对象的序列化主要有两种用途:
把对象的字节序列永久地保存到硬盘上,通常存放在一个文件中;
(持久化对象)在网络上传送对象的字节序列。(网络传输对象)
14.3 动态代理是什么?有哪些应用?
动态代理是运行时动态生成代理类。
动态代理的应用有 spring aop、hibernate 数据查询、测试框架的后端 mock、rpc,Java注解对象获取等。
14.4 怎么实现动态代理?
JDK 原生动态代理和 cglib 动态代理。JDK 原生动态代理是基于接口实现的,而 cglib 是基于继承当前类的子类实现的。
···
15.1 什么是XML
HTML–超文本标记语言—制作网页—提供一组静态的标记元素,无法扩展。
XML–可扩展标记语言–是一种简单的数据存储语言–没有固定的标记元素,在使用的时候可以根据自己的需要创造一个。
16.1 什么是Servlet?
运行在服务器上用来处理用户的请求,做出响应的java程序就是Servlet。
16.2 Servlet的生命周期?
Servlet的生命周期是从开始创建servlet对象一直到处理客户端请求以后,的整个过程就是Servlet的生命周期
servlet在运行的时候是由Servlet容器【服务器】来管理和维护Servlet的运行。不是程序开发者自己去实例化Servlet对象,然后调用方法执行,处理用户请求的。
16.3 session 和 cookie 有什么区别
session:是一种将会话状态保存在服务器端的技术。
Cookie :是在 HTTP 协议下, Web 服务器保存在用户浏览器(客户端)上的小文本文件,它可以包含有关用户的信息。无论何时用户链接到服务器,Web 站点都可以访问 Cookie 信息 。
存储位置不同:
安全性不同:cookie 安全性一般,在浏览器存储,可以被伪造和修改。
容量和个数限制:cookie 有容量限制,每个站点下的 cookie 也有个数限制。
存储的多样性:session 可以存储在 Redis 中、数据库中、应用程序中;而 cookie 只能存储在浏览器中。
16.4 JSP是什么?
JSP–Java Server Pages[java服务器页面]【包含有java程序的运行在服务器上的页面{HTML}】
实际上JSP就是在HTML文件中嵌套java程序所形成的一中页面【JSP】
16.5 JSP 和 servlet 有什么区别?
JSP 是 servlet 技术的扩展,本质上就是 servlet 的简易方式。servlet 和 JSP 最主要的不同点在于,servlet 的应用逻辑是在 Java 文件中,并且完全从表示层中的 html 里分离开来,而 JSP 的情况是 Java 和 html 可以组合成一个扩展名为 JSP 的文件。JSP 侧重于视图,servlet 主要用于控制逻辑。
16.6 JSP 有哪些内置对象?作用分别是什么?
JSP 有 9 大内置对象:
request:封装客户端的请求,其中包含来自 get 或 post 请求的参数;
response:封装服务器对客户端的响应;
pageContext:通过该对象可以获取其他对象;
session:封装用户会话的对象;
application:封装服务器运行环境的对象;
out:输出服务器响应的输出流对象;
config:Web 应用的配置对象;
page:JSP 页面本身(相当于 Java 程序中的 this);
exception:封装页面抛出异常的对象。
16.7 说一下 JSP 的 4 种作用域?
page:代表与一个页面相关的对象和属性。
request:代表与客户端发出的一个请求相关的对象和属性。一个请求可能跨越多个页面,涉及多个 Web 组件;需要在页面显示的临时数据可以置于此作用域。
session:代表与某个用户与服务器建立的一次会话相关的对象和属性。跟某个用户相关的数据应该放在用户自己的 session 中。
application:代表与整个 Web 应用程序相关的对象和属性,它实质上是跨越整个 Web 应用程序,包括多个页面、请求和会话的一个全局作用域。
16.8 说一下 session 的工作原理?
session 的工作原理是客户端登录完成之后,服务器会创建对应的 session,session 创建完之后,会把 session 的 id 发送给客户端,客户端再存储到浏览器中。这样客户端每次访问服务器时,都会带着 sessionid,服务器拿到 sessionid 之后,在内存找到与之对应的 session 这样就可以正常工作了。
16.9 如果客户端禁止 cookie 能实现 session 还能用吗?
可以用,session 只是依赖 cookie 存储 sessionid,如果 cookie 被禁用了,可以使用 url 中添加 sessionid 的方式保证 session 能正常使用。
16.10 spring mvc 和 struts 的区别是什么?
拦截级别:struts2 是类级别的拦截;spring mvc 是方法级别的拦截。
数据独立性:spring mvc 的方法之间基本上独立的,独享 request 和 response 数据,请求数据通过参数获取,处理结果通过 ModelMap 交回给框架,方法之间不共享变量;而 struts2 虽然方法之间也是独立的,但其所有 action 变量是共享的,这不会影响程序运行,却给我们编码和读程序时带来了一定的麻烦。
拦截机制:struts2 有以自己的 interceptor 机制,spring mvc 用的是独立的 aop 方式,这样导致struts2 的配置文件量比 spring mvc 大。
对 ajax 的支持:spring mvc 集成了ajax,所有 ajax 使用很方便,只需要一个注解 @ResponseBody 就可以实现了;而 struts2 一般需要安装插件或者自己写代码才行。
16.11 如何避免 SQL 注入?
使用预处理 PreparedStatement。
使用正则表达式过滤掉字符中的特殊字符。
17.1 什么是MyBatis?
MyBatis 是一款优秀的持久层[数据访问层]框架,对原始的JDBC技术的封装,可以帮助我们快速的链接和访问数据库。
MyBatis是一款优秀的基于ORM的持久层[数据访问层]框架
17.2 为什么要使用MyBatis?
它支持定制化 SQL、存储过程以及高级映射。MyBatis 避免了几乎所有的 JDBC 代码和手动设置参数以及获取结果集。
17.3 什么是ORM?
ORM[对象关系映射]—我们在访问数据库的时候所编写的都是Java程序,Java程序只认识Java对象,而我们所访问的数据库大多数都是关系型数据库,那么这时Java程序要想访问关系型数据库,那么就需要将Java对象转换成关系型数据,才能被数据库认识。这时我们可以认为一个Java类就是关系型数据库中的一张数据表,Java类中的成员变量是数据库表中的一个列,Java类创建的Java对象就是数据库表中的一行记录。
这时将Java对象对应成为数据库表记录的过程就是对象关系映射【ORM】.
ORM的优点:当我们使用Java程序控制Java对象的时候,数据库中的数据表记录会随之变化。
17.4 MyBatis 中 #{}和 ${}的区别是什么?
#{}是预编译处理,${}是字符替换。在使用 #{}时,MyBatis 会将 SQL 中的 #{}替换成“?”,配合 PreparedStatement 的 set 方法赋值,这样可以有效的防止 SQL 注入,保证程序的运行安全。
17.5 MyBatis的工作原理
mybatis应用程序通过SqlSessionFactoryBuilder从mybatis-config.xml配置文件(也可以用Java文件配置的方式,需要添加@Configuration)来构建SqlSessionFactory(SqlSessionFactory是线程安全的);
然后,SqlSessionFactory的实例直接开启一个SqlSession,再通过SqlSession实例获得Mapper对象并运行Mapper映射的SQL语句,完成对数据库的crud(增删改查)和事务提交,之后关闭SqlSession。
17.6 MyBatis 有几种分页方式?
分页方式:逻辑分页和物理分页。
逻辑分页:使用 MyBatis 自带的 RowBounds 进行分页,它是一次性查询很多数据,然后在数据中再进行检索。
物理分页:自己手写 SQL 分页或使用分页插件 PageHelper,去数据库查询指定条数的分页数据的形式。
17.7 RowBounds 是一次性查询全部结果吗?为什么?
RowBounds 表面是在“所有”数据中检索数据,其实并非是一次性查询出所有数据,因为 MyBatis 是对 jdbc 的封装,在 jdbc 驱动中有一个 Fetch Size 的配置,它规定了每次最多从数据库查询多少条数据,假如你要查询更多数据,它会在你执行 next()的时候,去查询更多的数据。就好比你去自动取款机取 10000 元,但取款机每次最多能取 2500 元,所以你要取 4 次才能把钱取完。只是对于 jdbc 来说,当你调用 next()的时候会自动帮你完成查询工作。这样做的好处可以有效的防止内存溢出。
17.8 MyBatis 逻辑分页和物理分页的区别是什么?
逻辑分页是一次性查询很多数据,然后再在结果中检索分页的数据。这样做弊端是需要消耗大量的内存、有内存溢出的风险、对数据库压力较大。
物理分页是从数据库查询指定条数的数据,弥补了一次性全部查出的所有数据的种种缺点,比如需要大量的内存,对数据库查询压力较大等问题。
17.9 MyBatis 是否支持延迟加载?延迟加载的原理是什么?
MyBatis 支持延迟加载,设置 lazyLoadingEnabled=true 即可。
延迟加载的原理的是调用的时候触发加载,而不是在初始化的时候就加载信息。比如调用 a. getB(). getName(),这个时候发现 a. getB() 的值为 null,此时会单独触发事先保存好的关联 B 对象的 SQL,先查询出来 B,然后再调用 a. setB(b),而这时候再调用 a. getB(). getName() 就有值了,这就是延迟加载的基本原理。
17.10 说一下 MyBatis 的一级缓存和二级缓存?
一级缓存:基于 PerpetualCache 的 HashMap 本地缓存,它的声明周期是和 SQLSession 一致的,有多个 SQLSession 或者分布式的环境中数据库操作,可能会出现脏数据。当 Session flush 或 close 之后,该 Session 中的所有 Cache 就将清空,默认一级缓存是开启的。
二级缓存:也是基于 PerpetualCache 的 HashMap 本地缓存,不同在于其存储作用域为 Mapper 级别的,如果多个SQLSession之间需要共享缓存,则需要使用到二级缓存,并且二级缓存可自定义存储源,如 Ehcache。默认不打开二级缓存,要开启二级缓存,使用二级缓存属性类需要实现 Serializable 序列化接口(可用来保存对象的状态)。Sql映射文件< cache/>
开启二级缓存数据查询流程:二级缓存 -> 一级缓存 -> 数据库。
缓存更新机制:当某一个作用域(一级缓存 Session/二级缓存 Mapper)进行了C/U/D 操作后,默认该作用域下所有 select 中的缓存将被 clear。
17.11 MyBatis 和 hibernate 的区别有哪些?
灵活性:MyBatis 更加灵活,自己可以写 SQL 语句,使用起来比较方便。
可移植性:MyBatis 有很多自己写的 SQL,因为每个数据库的 SQL 可以不相同,所以可移植性比较差。
学习和使用门槛:MyBatis 入门比较简单,使用门槛也更低。
二级缓存:hibernate 拥有更好的二级缓存,它的二级缓存可以自行更换为第三方的二级缓存。
17.12 MyBatis 有哪些执行器(Executor)?
MyBatis 有三种基本的Executor执行器:
SimpleExecutor:每执行一次 update 或 select 就开启一个 Statement 对象,用完立刻关闭 Statement 对象;
ReuseExecutor:执行 update 或 select,以 SQL 作为 key 查找 Statement 对象,存在就使用,不存在就创建,用完后不关闭 Statement 对象,而是放置于 Map 内供下一次使用。简言之,就是重复使用 Statement 对象;
BatchExecutor:执行 update(没有 select,jdbc 批处理不支持 select),将所有 SQL 都添加到批处理中(addBatch()),等待统一执行(executeBatch()),它缓存了多个 Statement 对象,每个 Statement 对象都是 addBatch()完毕后,等待逐一执行 executeBatch()批处理,与 jdbc 批处理相同。
17.13 MyBatis 分页插件的实现原理是什么?
Mybatis是如何进行分页的?分页插件的原理是什么?
1.在xml映射文件中编写SQL 语句的时候利用limit关键字分页
select * from student limit #{currIndex} , #{pageSize}
2.使用拦截器分页【利用PageHelper分页插件】— 物理分页
分页插件的原理是利用拦截器去拦截指定的查询操作,然后在拦截到的查询操作中添加相关的分页逻辑,完成分页。
怎么做的:
1.创建拦截器,拦截mybatis接口中指定的查询方法
2.在mybatis的核心配置文件中,利用标签,配置自己的拦截器
3.RowBounds分页–逻辑分页----内存溢出错误
Mybatis使用RowBounds对象进行分页,它是针对ResultSet结果集执行的内存分页,而非物理分页,可以在sql内直接书写带有物理分页的参数来完成物理分页功能,也可以使用分页插件来完成物理分页。
17.14 MyBatis 如何编写一个自定义插件?
自定义插件实现原理:
MyBatis 自定义插件针对 MyBatis 四大对象(Executor、StatementHandler、ParameterHandler、ResultSetHandler)进行拦截:
Executor:拦截内部执行器,它负责调用 StatementHandler 操作数据库,并把结果集通过 ResultSetHandler 进行自动映射,另外它还处理了二级缓存的操作;
StatementHandler:拦截 SQL 语法构建的处理,它是 MyBatis 直接和数据库执行 SQL 脚本的对象,另外它也实现了 MyBatis 的一级缓存;
ParameterHandler:拦截参数的处理;
ResultSetHandler:拦截结果集的处理。
17.15 MyBatis中的核心对象
SqlSessionFactory如何创建?有什么作用?常用方法?
SqlSessionFactory它是mybatis的核心对象,通过这个对象可以获取到与数据库的连接【SqlSession】。同时这个对象中保存着读取到的核心配置文件【mybatis-config.xml】中的信息【1.数据源 2.SQL映射文件】。
SQLSessionFactory使用SQLSessionFactoryBuilder对象获得的,SQLSessionFactoryBuilder可以通过预先定制的configuration或者xml配置文件的实例构建出SQLSessionFactory,SQLSessionFactory是线程安全的,一旦被创建,应该在应用执行期间都存在.在应用运行期间不要重复创建多次。
SqlSession如何创建?有什么作用?常用方法?
SqlSessionFactory是创建SqlSession的工厂。可以通过SqlSession openSession()创建SqlSession对象。SqlSession对象它表示的是与数据库之间的一个连接(会话)。
通过SqlSession对象可以对数据库进行CRUD操作。
但是SqlSession对象在使用的时候必须指明到底需要执行的是Mapper文件中的哪个SQL。
SqlSession对象提供的常用方法:
1.insert(statement, parameter):添加数据的方法
参数1【String】:需要执行的sql映射文件中的sql语句【数据访问接口+抽象方法名称】
参数2【Object】:输入参数。
2.update(statement, parameter):修改数据的方法
参数1【String】:需要执行的sql映射文件中的sql语句【数据访问接口+抽象方法名称】
参数2【Object】:输入参数。
3.selectOne(statement, parameter):查询一个数据的方法
参数1【String】:需要执行的sql映射文件中的sql语句【数据访问接口+抽象方法名称】
参数2【Object】:输入参数。
4.session.selectList(statement):查询所有数据的方法
参数1【String】:需要执行的sql映射文件中的sql语句【数据访问接口+抽象方法名称】
5.delete(statement, parameter):删除数据的方法
参数1【String】:需要执行的sql映射文件中的sql语句【数据访问接口+抽象方法名称】
参数2【Object】:输入参数。
6.getMapper(class):得到数据访问接口对象
参数1【Class】:被获取的数据访问接口的反射对象
7.commit():提交执行
8.close():关闭sqlsession
17.16 11.什么是动态SQL?为什么使用动态SQL?有哪些动态SQL?如何使用?
动态sql就是(在进行sql操作的时候)动态的根据属性值(所匹配的条件)来拼接数据库执行的sql语句,也就是多次查询或变更操作,根据传入的属性值不同,动态拼接出不同的可执行sql。包含判断为空、循环等;
1.< if >:
if是为了判断传入的值是否符合某种规则,比如是否不为空;
2.< where >:
where标签可以用来做动态拼接查询条件,当和if标签配合的时候,不用显示的声明类似where 1=1这种无用的条件;
3.< choose >< when >< otherwise >:
这是一组组合标签,他们的作用类似于 Java 中的 switch、case、default。只有一个条件生效,也就是只执行满足的条件 when,没有满足的条件就执行 otherwise,表示默认条件;
4.< foreach >:
foreach标签可以把传入的集合对象进行遍历,然后把每一项的内容作为参数传到sql语句中,里面涉及到 item(具体的每一个对象), index(序号), open(开始符), close(结束符), separator(分隔符);
5.< include >:
include可以把大量重复的代码整理起来,当使用的时候直接include即可,减少重复代码的编写;
6.< set >:
适用于更新中,当匹配某个条件后,才会对该字段进行更新操作
7.< trim >:
是一个格式化标签,主要有4个参数:
prefix(前缀);
prefixOverrides(去掉第一个标记);
suffix(后缀);
suffixOverrides(去掉最后一个标记);
17.17 mybatis的高级查询是一对一查询操作有几种方式
嵌套resultMap:
嵌套select:
代码详情
17.18mybatis的高级查询是一对多查询操作有几种方式
嵌套resultMap:
嵌套select:
代码详情
17.19 通常一个xml映射文件,都会写一个Dao接口与之对应,请问,这个Dao接口工作,原理是什么?dao接口接口里方法和参数,不同时,方法能重载吗?
Dao 接口即 Mapper 接口。接口的全限名,就是映射文件中的 namespace 的值;接口的方法名,就是映射文件中 Mapper 的 Statement 的 id 值;接口方法内的参数,就是传递给 sql 的参数。Mapper 接口是没有实现类的,当调用接口方法时,接口全限名+方法名拼接字符串作为 key 值,可唯一定位一个 MapperStatement。在 Mybatis 中,每一个标签,都会被解析为一个MapperStatement 对象。
Mapper 接口里的方法,是不能重载的,因为是使用 全限名+方法名 的保存和寻找策略。Mapper 接口的工作原理是 JDK 动态代理,Mybatis 运行时会使用 JDK动态代理为 Mapper 接口生成代理对象 proxy,代理对象会拦截接口方法,转而执行 MapperStatement 所代表的 sql,然后将 sql 执行结果返回。
18.1 什么是Spring?
Spring是一个开源的分层的javaSE/javaEE一站式的轻量级的容器框架,主要解决业务逻辑层【Service】与web层和数据访问层之间的松耦合问题。
(1)开源的
(2)javaSE/javaEE一站式
(3)容器框架
(4)轻量级
(5)解决业务逻辑层【Service】与web层和数据访问层之间的松耦合
18.2 Spring的结构组成
spring core:框架的最基础部分,提供 ioc 和依赖注入特性。
spring context:构建于 core 封装包基础上的 context 封装包,提供了一种框架式的对象访问方法。
spring dao:Data Access Object 提供了JDBC的抽象层。
spring aop:提供了面向切面的编程实现,让你可以自定义拦截器、切点等。
spring Web:提供了针对 Web 开发的集成特性,例如文件上传,利用 servlet listeners 进行 ioc 容器初始化和针对 Web 的 ApplicationContext。
spring Web mvc:spring 中的 mvc 封装包提供了 Web 应用的 Model-View-Controller(MVC)的实现。
从下往上test,core容器,aop【面向切面编程】,web,data access
18.3 Spring的优点
Spring的出现解决了JavaEE实际问题:
1.方便解耦,简化开发:Spring是一个超级工厂(超级容器),可以将对象的创建和依赖关系交给Spring工厂去管理
2.AOP编程:Spring提供面向切面编程,可以方便的对程序进行运行监控、权限验证等操作
3.声明事务:只需要通过配置就可以完成对事务的管理,不需要手动编程
4.方便测试:Spring支持junit4,可以通过Spring注解方式测试程序
5.方便集成各种框架:Spring支持各种开源框架的集成。例如(struts、Hibernate、MyBaties等)
6.降低JavaEE API的使用难度: Spring对JavaEE开发中非常难用的API进行封装,使这些开发API应用难度降低。
18.4 Spring的核心技术
1.IoC(Inverse of Control 反转控制):将java对象创建和维护权利交由Spring工厂进行管理和维护。
2.DI(依赖注入):将某一个java类中的依赖对象快速的添加到另一个java类中。
3.AOP(Aspect Oriented Programming 面向切面编程),基于动态代理的功能增强方式[给自己的程序中添加一些系统需求的处理【日志管理,数据的安全性检查…】]。
4.事务管理的相关操作。
5.Spring整合/管理其他各层的框架【Spring集成web层SpringMVC/Spring整合数据访问层MyBatis】{SSM}
18.4 Bean实例化4种方式
- 无参数构造方法(开发最常用)
编写Spring的配置文件:【applicationContext.xml/自己起名】{src/main/resources} - 静态工厂方法实例化bean
静态工厂方法:在一个类中书写静态的方法,这个方法返回某个Bean的对象(在方法中创建Bean的对象)。
创建一个静态工厂方法类,提供一个静态方法,让这个静态方法返回一个实体类的对象 - 实例工厂方法实例化bean
创建一个工厂类,提供实例方法,这个实例方法返回java实体类的对象 - FactoryBean接口方式实例化bean
FactoryBean是Spring提供的接口,专门用于对bean进行初始化操作的。
如果bean需要使用这种方式进行初始化,那么需要定义类实现这个FactoryBean接口,在实现类中复写getObject的方法。
18.5 什么是BeanFactory ? BeanFactory 实现举例。
BeanFactory接口表示一个Spring工厂对象【Spring容器对象】,包含了实例化好的java类对象。【管理】
BeanFactory接口有一个常用的子接口ApplicationContext接口,我们通常使用ApplicationContext接口充当Spring工厂对象【Spring容器对象】。
- ClassPathXmlApplicationContext类 – new ClassPathXmlApplicationContext()可以创建出BeanFactory接口对象/ApplicationContext对象
表示:通过查找类路径加载一个Xml文件创建Spring工厂对象 - FileSystemXmlApplicationContext类 —new FileSystemXmlApplicationContext可以创建出BeanFactory接口对象/ApplicationContext对象
表示:通过在系统文件类路径中加载一个Xml文件创建Spring工厂对象
18.6 Spring支持的几种bean的作用域
spring 支持 5 种作用域,如下:
singleton:spring ioc 容器中只存在一个 bean 实例,bean 以单例模式存在,是系统默认值;
prototype:每次从容器调用 bean 时都会创建一个新的示例,既每次 getBean()相当于执行 new Bean()操作;
request:每次 http 请求都会创建一个 bean;
session:同一个 http session 共享一个 bean 实例;
global-session:用于 portlet 容器,因为每个 portlet 有单独的 session,globalsession 提供一个全局性的 http session。
注意:使用 prototype 作用域需要慎重的思考,因为频繁创建和销毁 bean 会带来很大的性能开销。
18.7 bean的生命周期
Spring工厂对象【Spring容器对象】负责创建对象,初始化对象,销毁对象。
也就是说任何一个交给Spring的Bean,它的生命周期统一由Spring容器维护。
18.8 什么是Spring的依赖注入?有哪些不同类型的DI(依赖注入)方式?
依赖注入–在调用者类中将被调用者类的对象,添加到调用者类中这个过程就是依赖注入。在这个过程中被调用者类的对象就是调用者类的依赖对象。
1.构造方法注入
2.Set方法注入
3.注解
18.9 @autowired和@resource的区别
相同点:
@Resource的作用相当于@Autowired,均可标注在字段或属性的setter方法上。
不同点:
(1)提供方:@Autowired是由org.springframework.beans.factory.annotation.Autowired提供,换句话说就是由Spring提供;@Resource是由javax.annotation.Resource提供,即J2EE提供,需要JDK1.6及以上。
(2)注入方式:@Autowired只按照byType 注入;@Resource默认按byName自动注入,也提供按照byType 注入;
(3)属性:@Autowired按类型装配依赖对象,默认情况下它要求依赖对象必须存在,如果允许null值,可以设置它required属性为false。如果我们想使用按名称装配,可以结合@Qualifier注解一起使用。
@Resource有两个中重要的属性:name和type。name属性指定byName,如果没有指定name属性,当注解标注在字段上,即默认取字段的名称作为bean名称寻找依赖对象,当注解标注在属性的setter方法上,即默认取属性名作为bean名称寻找依赖对象。需要注意的是,@Resource如果没有指定name属性,并且按照默认的名称仍然找不到依赖对象时, @Resource注解会回退到按类型装配。但一旦指定了name属性,就只能按名称装配了。
18.10 什么是AOP?
AOP (Aspect Oriented Programing) 称为:面向切面编程,它是一种编程思想。
AOP采取横向抽取机制,取代了传统纵向继承体系重复性代码的编写方式(性能监视、事务管理、安全检查、缓存,日志记录等)。
AOP 思想: 基于代理思想,对原来目标对象,创建代理对象,在不修改原对象代码情况下,通过代理对象,调用增强功能的代码【系统需求方法】,从而对原有业务方法进行增强。
AOP的底层是动态代理机制【CGLIB动态代理】。
基于两种动态代理机制: JDK动态代理和CGLIB动态代理。
JDK动态代理:基于接口的代理,会生成目标对象的接口的子对象【实现接口的类】
CGLIB动态代理:基于类的代理,会生成目标对象的子对象。【无论是继承父类还是实现接口所产生的类】
18.11 解释一下什么是 ioc?
ioc:Inversionof Control(中文:控制反转)是 spring 的核心,对于 spring 框架来说,就是由 spring 来负责控制对象的生命周期和对象间的关系。
简单来说,控制指的是当前对象对内部成员的控制权;控制反转指的是,这种控制权不由当前对象管理了,由其他(类,第三方容器)来管理。
18.12 什么事务?
对数据库的一系列操作中,保证同时成功或者同时失败。不能出现成部分成功,失败部分的情况。而这一些列操作称为数据库的事务。
18.13 数据库的事务有4大特征【ACID】
数据库的事务有4大特征:
原子性:指事务是一个不可分割的工作单位,事务的操作要么都发生,要么都不发生.
一致性:事务前后数据的完整性必须保持一致。
隔离性:指多个用户并发访问数据库时,一个用户的事务不能被其他用户的事务干扰,多个并发之间的数据要相互隔离。
持久性:指一个事务一旦被提交,它对数据库中数据的改变就是永久性的,接下来即使数据库发生故障也不应该对其又任何影响。简称ACID。其中隔离性最重要。
18.13 事务的隔离性
使用Java操作的时候设置隔离级别由高到低分别为:
Serializable:可避免脏读、不可重复读、虚读情况的发生。
Repeatable read:可避免脏读、不可重复读情况发生。(可重复读)
Read committed:可避免脏读情况的发生。(读已提交)
Read uncommitted:最低级别,以上情况均为无法保证。(读未提交)
18.14 Spring的声明式事务管理方式
基于xml方式的事物管理操作:
基于注解方式的事物管理操作:
1.在需要管理事务的方法或者类上面 添加@Transactional 注解
2.配置注解驱动事务管理(事务管理注解生效的作用)(需要配置对特定持久层框架使用的事务管理器)
18.15 @Controller/ @RequestMapping/ @Autowired/ @Resources/ @RequestBody/ @RespontBody/@Component
- @Controller:表示在tomcat启动的时候,把这个类作为一个控制器加载到Spring的Bean工厂
- @RequestMapping:会将 HTTP 请求映射到 MVC 和 REST 控制器的处理方法上
- @Autowired:其实在启动spring Ioc时,容器自动装载了一个AutowiredAnnotationBeanPostProcessor后置处理器,当容器扫描到@Autowied、@Resource或@Inject时,就会在IoC容器自动查找需要的bean,并装配给该对象的属性
- @Resources:注解被用来激活一个命名资源(namedresource)的依赖注入
- @requestBody:可以将请求体中的JSON字符串绑定到相应的bean上,当然,也可以将其分别绑定到对应的字符串上。
- @responseBody:注解的作用是将controller的方法返回的对象通过适当的转换器转换为指定的格式之后,写入到response对象的body区,通常用来返回JSON数据或者是XML
- @Component注解:
该注解使用在类上面,表示这个类是一个component
当使用基于注解的配置和类路径扫描时,这种类就是自动检测的候选类
其他类级别的注释也可以视为标识component
通常是一种特殊的组件,比如@Repository和AspectJ的@Aspect注解
19.1 什么是SpringMVC?
Spring MVC属于SpringFrameWork的后续产品,已经融合在Spring Web Flow里面。Spring 框架提供了构建 Web 应用程序的全功能 MVC 模块。使用 Spring 可插入的 MVC 架构,从而在使用Spring进行WEB开发时,可以选择使用Spring的SpringMVC框架或集成其他WEB MVC开发框架,如Struts(现在一般不用),Struts2(一般老项目使用)等。
SpringMVC是web层的mvc开发框架,属于Spring框架的WEB模块中的一个部分。
19.2 SpringMVC的执行流程
1.启动服务器的时候配置在web.xml文件中的中央控制器【DispatcherServlet】被初始化完成,并且加载配置的springMVC的配置文件。
2.客户端浏览器发送http请求。
3.http请求被中央控制器【DispatcherServlet】拦截,转交给url解析器解析。
4.Url解析器解析http请求,得到具体的请求路径。
5.Url解析器将解析得到的具体的请求路径返回给中央控制器【DispatcherServlet】。
6.中央控制器【DispatcherServlet】将得到的具体的请求路径转交给控制器适配器。
7.控制器适配器根据具体的请求路径查找与之对应的请求处理类。
8.请求处理类就执行具体的请求处理,得到ModelAndView对象【1.数据。2.跳转地址】,将ModelAndView对象交给控制器适配器,控制器适配器将ModelAndView对象返回给中央控制器【DispatcherServlet】。
9.中央控制器【DispatcherServlet】将ModelAndView对象转交给视图解析器去解析。
10.视图解析器解析ModelAndView对象,得到一个具体的数据显示路径,将这个具体的数据显示路径返回给中央控制器【DispatcherServlet】。
11.中央控制器【DispatcherServlet】得到具体的数据显示路径之后,将路径所代表的资源转换执行成一个html数据。
将转换执行后的html数据返回给客户端浏览器。
20.1 什么是SpringBoot?
pringBoot是Spring团队在2014年,伴随Spring4.0版本推出的一个新的框架。就是帮助我们快速的创建出基于Spring的应用程序。spring boot 是为 spring 服务的,是用来简化新 spring 应用的初始搭建以及开发过程的。
20.2 SpringBoot的优点
2.1快速创建独立运行的Spring项目以及与主流框架集成
2.2使用嵌入式的Servlet容器,应用无需打成WAR包
2.3 starters自动依赖与版本控制
2.4大量的自动配置,简化开发,也可修改默认值
2.5无需配置XML,无代码生成,开箱即用
2.6准生产环境的运行时应用监控
2.7 与云计算的天然集成
20.3 spring boot 核心配置文件是什么?
spring boot 核心的两个配置文件:
bootstrap (. yml 或者 . properties):boostrap 由父 ApplicationContext 加载的,比 applicaton 优先加载,且 boostrap 里面的属性不能被覆盖;
application (. yml 或者 . properties):用于 spring boot 项目的自动化配置。
20.4 spring boot 配置文件有哪几种类型?它们有什么区别?
配置文件有 . properties 格式和 . yml 格式,它们主要的区别是书法风格不同。
properties 配置如下:
spring. RabbitMQ. port=5672
yml 配置如下:
spring:
RabbitMQ:
port: 5672
yml 格式不支持 @PropertySource 注解导入。