文章目录
一、java基础
1. java类初始化顺序
- clinit 方法由静态类变量显示赋值代码和静态代码块组成
- 类变量显示赋值代码和静态代码块代码<mark>从上到下执行</mark>
- clinit 方法只调用一次
父类静态属性(成员变量)>父类静态代码块>子类静态属性>子类静态代码块
2. java实例初始化属性
- init () 方法可能重载有多个,有几个构造器就有几个 init() 方法
- init() 方法由非静态实例变量显示赋值代码和非静态代码块,对应构造器代码组成
- 非静态实例变量显示赋值代码和非静态代码块从上到下顺序执行,而对应构造器的代码最后执行
- 每次创建实例对象,调用对应构造器,执行的就是对应的 ini方法
- init 方法的首行是super()和super(实参列表) ,即对应父类的 init 方法
父类非静态属性>父类非静态代码块>父类构造器>子类非静态属性>子类非静态代码块>子类构造器
整个步骤
父类静态属性(成员变量)>父类静态代码块>子类静态属性>子类静态代码块>父类非静态属性>父类非静态代码块>父类构造器>子类非静态属性>子类非静态代码块>子类构造器
3. 重载和重写
① 哪些方法不可以被重写
- final方法
- 静态方法
- private等子类中不可见方法
②对象的多态性
- 子类如果重写了父类的方法,通过子类对象调用的一定是子类重写过的代码
- 非静态方法默认的调用对象是this
- this对象在构造器或者说方法中就是正在创建的对象
示例代码:
Father.java
package com.atguigu.classLoader;
/** * 父类初始化<clinit> * 1、j = method() * 2、 父类的静态代码块 * * 父类实例化方法: * 1、super()(最前) * 2、i = test() (9) * 3、子类的非静态代码块 (3) * 4、子类的无参构造(最后)(2) * * * 非静态方法前面其实有一个默认的对象this * this在构造器或<init> 他表示的是正在创建的对象,因为咱们这里是正在创建Son对象,所以 * test()执行的就是子类重写的代码(面向对象多态) * * 这里i=test() 执行的就是子类重写的test()方法 * @author gcq * @Create 2020-09-25 */
public class Father {
private int i = test();
private static int j = method();
static{
System.out.println("(1)");
}
Father() {
System.out.println("(2)");
}
{
System.out.println("(3)");
}
public int test(){
System.out.println("(4)");
return 1;
}
public static int method() {
System.out.println("(5)");
return 1;
}
}
Son.java
package com.atguigu.classLoader;
/** * 子类的初始化<clinit> * 1、j = method() * 2、子类的静态代码块 * * 先初始化父类 (5)(1) * 初始化子类 (10) (6) * * 子类实例化方法: * 1、super()(最前 * 2、i = test() (9) * 3、子类的非静态代码块 (8) * 4、子类的无参构造(最后)(7) * @author gcq * @Create 2020-09-25 */
public class Son extends Father {
private int i = test();
private static int j = method();
static {
System.out.println("(6)");
}
Son() {
super();
System.out.println("(7)");
}
{
System.out.println("(8)");
}
public int test(){
System.out.println("(9)");
return 1;
}
public static int method() {
System.out.println("(10)");
return 1;
}
public static void main(String[] args) {
Son son = new Son();
System.out.println();
Son son1 = new Son();
}
}
执行结果
(5)(1)(10)(6)(9)(3)(2)(9)(8)(7)
(9)(3)(2)(9)(8)(7)
4. 方法参数传递机制
package com.atguigu.methodParam;
import java.util.Arrays;
/** * @author gcq * @Create 2020-09-28 */
public class Exam4 {
public static void main(String[] args) {
int i = 1;
String str = "hello";
Integer num = 200;
int[] arr = {
1,2,3,4,5};
MyData my = new MyData();
//arr和my变了
change(i,str,num,arr,my);
System.out.println("i= " + i);
System.out.println("str= " + str);
System.out.println("num= " + num);
System.out.println("arr= " + Arrays.toString(arr));
System.out.println("my.a= " + my.a);
}
public static void change(int j, String s, Integer n, int[] a, MyData m) {
j += 1;
s += "world";
n += 1;
a[0] += 1;
m.a += 1;
}
}
class MyData {
int a = 10;
}
结果
i= 1
str= hello
num= 200
arr= [2, 2, 3, 4, 5]
my.a= 11
考点?
方法的参数传递机制
String、包装类等对象的不可变性
方法的参数传递机制
1、形参是基本数据类型
- 传递数据值
2、实参是引用数据类型 - 传递地址值
特殊的类型:String、包装类等对象的不可变性
5. 成员变量与局部变量
局部变量:栈
实例变量:堆
类变量:方法区
堆(Heap) ,此内存区域的唯一目的就是存放对象实例,几乎所有的对象实例都在这里分配内存。这一点在Java虚拟机规范中的描述是:所有的对象实例以及数组都要在堆上分配。
通常所说的栈(Stack) ,是指虚拟机栈。虚拟机栈用于存储局部变量表等。局部变量
表存放了编译期可知长度的各种基本数据类型(boolean、byte、 char、short、 int、 float、long、double) 、对象引用(reference 类型,它不等同于对象本身,是对象在堆内存的首地址)。方法执行完, 自动释放。
方法区(Method Area)用于存储已被虛拟机加载的类信息、常量、静态变量、即时编译器编译后的代码等数据。
二、SSM面试题
1. spring
1. 事物的传播行为
事务的传播行为
当事务方法被另一个事务方法调用时,必须指定事务应该如何传播,列如方法可能继续在现有事务中运行,也可能开启一个新事务,并在自己的事务中运行,事务传播的行为有传播属性指定,Spring定义了7中类传播行为
传播属性 | 描述 |
---|---|
REQUIRED | 如果有事务在运行,当前的方法就在这个事务内运行,否则就启动一个新的事务,并在自己的事务内运行 |
REQUIRED_NEW | 当前方法必须启动事务,并在它自己的事务内运行,如果有事务正在运行,应该将他挂起 |
SUPPORTS | 如果有事务在运行,REQUIRED_NEW当前的方法就在这个事务内运行,否则他可以不运行在事务中 |
NOT_SUPPORTS | 当前的方法不应该运行在事务中,如果有运行的事务,将他挂起 |
MANDATORY | 当前的方法必须运行在事务内部,如果没有正在运行的事务,就抛出异常 |
NEVER | 当前方法不应该运行在事务中,如果有运行的事务,就抛出异常 |
NESTED | 如果有事务在运行,当前的方法就应该在这个事物的嵌套事务内运行,否则,就启动一个新的事务,并在它自己的事务内运行 |
事务传播属性可以在@Transactional注解的propagation属性中定义
2. 事物的隔离级别
2.1 数据库事务并发问题
假设现在有两个事务:Transaction01和Transaction02并发执行。
1) 脏读
①Transaction01将某条记录的AGE值从20修改为30。
②Transaction02读取了Transaction01更新后的值:30。
③Transaction01回滚,AGE值恢复到了20。
④Transaction02读取到的30就是一个无效的值。
2) 不可重复读
①Transaction01读取了AGE值为20。
②Transaction02将AGE值修改为30。
③Transaction01再次读取AGE值为30,和第一次读取不一致。
3) 幻读
①Transaction01读取了STUDENT表中的一部分数据。
②Transaction02向STUDENT表中插入了新的行。
③Transaction01读取了STUDENT表时,多出了一些行。
2.2 隔离级别
数据库系统必须具有隔离并发运行各个事务的能力,使它们不会相互影响,避免各种并发问题。一个事务与其他事务隔离的程度称为隔离级别。SQL标准中规定了多种事务隔离级别,不同隔离级别对应不同的干扰程度,隔离级别越高,数据一致性就越好,但并发性越弱。
- 读未提交:READ UNCOMMITTED
允许Transaction01读取Transaction02未提交的修改。
- 读已提交:READ COMMITTED
要求Transaction01只能读取Transaction02已提交的修改。
- 可重复读:REPEATABLE READ
确保Transaction01可以多次从一个字段中读取到相同的值,即Transaction01执行期间禁止其它事务对这个字段进行更新。
- 串行化:SERIALIZABLE
确保Transaction01可以多次从一个表中读取到相同的行,在Transaction01执行期间,禁止其它事务对这个表进行添加、更新、删除操作。可以避免任何并发问题,但性能十分低下。
- 各个隔离级别解决并发问题的能力见下表
SpringMvc
整体流程
SpringMVC框架是一个基于请求驱动的Web框架,并且使用了‘前端控制器’模型来进行设计,再根据‘请求映射规则’分发给相应的页面控制器进行处理。
具体步骤:
1、 首先用户发送请求到前端控制器,前端控制器根据请求信息(如 URL)来决定选择哪一个页面控制器进行处理并把请求委托给它,即以前的控制器的控制逻辑部分;图中的 1、2 步骤;
2、 页面控制器接收到请求后,进行功能处理,首先需要收集和绑定请求参数到一个对象,这个对象在 Spring Web MVC 中叫命令对象,并进行验证,然后将命令对象委托给业务对象进行处理;处理完毕后返回一个 ModelAndView(模型数据和逻辑视图名);图中的 3、4、5 步骤;
3、 前端控制器收回控制权,然后根据返回的逻辑视图名,选择相应的视图进行渲染,并把模型数据传入以便视图渲染;图中的步骤 6、7;
4、 前端控制器再次收回控制权,将响应返回给用户,图中的步骤 8;至此整个结束。
具体步骤:
第一步:发起请求到前端控制器(DispatcherServlet)
第二步:前端控制器请求HandlerMapping查找 Handler (可以根据xml配置、注解进行查找)
第三步:处理器映射器HandlerMapping向前端控制器返回Handler,HandlerMapping会把请求映射为HandlerExecutionChain对象(包含一个Handler处理器(页面控制器)对象,多个HandlerInterceptor拦截器对象),通过这种策略模式,很容易添加新的映射策略
第四步:前端控制器调用处理器适配器去执行Handler
第五步:处理器适配器HandlerAdapter将会根据适配的结果去执行Handler
第六步:Handler执行完成给适配器返回ModelAndView
第七步:处理器适配器向前端控制器返回ModelAndView (ModelAndView是springmvc框架的一个底层对象,包括 Model和view)
第八步:前端控制器请求视图解析器去进行视图解析 (根据逻辑视图名解析成真正的视图(jsp)),通过这种策略很容易更换其他视图技术,只需要更改视图解析器即可
第九步:视图解析器向前端控制器返回View
第十步:前端控制器进行视图渲染 (视图渲染将模型数据(在ModelAndView对象中)填充到request域)
第十一步:前端控制器向用户响应结果
总结核心开发步骤
1、 DispatcherServlet 在 web.xml 中的部署描述,从而拦截请求到 Spring Web MVC
2、 HandlerMapping 的配置,从而将请求映射到处理器
3、 HandlerAdapter 的配置,从而支持多种类型的处理器
注:处理器映射求和适配器使用纾解的话包含在了注解驱动中,不需要在单独配置
4、 ViewResolver 的配置,从而将逻辑视图名解析为具体视图技术
5、 处理器(页面控制器)的配置,从而进行功能处理
View是一个接口,实现类支持不同的View类型(jsp、freemarker、pdf…)
Mybatis
实体类中的属性名和表中的字段不一样,怎么办
解决方案:
1、写 SQL 语句的时候 写别名
2、在MyBatis的全局配置文件中开启驼峰命名规则
<!-- 开启驼峰命名规则,可以将数据库中下划线映射为驼峰命名 列如 last_name 可以映射为 lastName -->
<setting name="mapUnderscoreToCameLCase" value="true" />