文章目录
- Java基础
- Java类、实例的初始化
- 1. 类初始化
- 2. 实例初始化
- 方法的参数传递机制
- 递归与迭代
- 1. 递归
- 2. 迭代循环
- 成员变量和局部变量
- 1. 区别
- 2. 代码
- Spring
- Spring Bean的作用域
- Spring 支持的事务传播属性和事务隔离级别
- 事务传播属性
- 事务隔离级别
- Spring MVC
- Spring MVC的post请求如何解决中文乱码
- Spring MVC的get请求如何解决中文乱码
- 简述Spring MVC的工作流程
Java基础
Java类、实例的初始化
1. 类初始化
规则:
- 一个类要创建实例必须先初始化该类;
- main方法所在的类总是要先加载和初始化;
- 子类要初始化必须先初始化父类;
- 一个类的初始化就是执行
<clinit>
方法,该方法由 静类变量显示赋值代码 和 静态代码块 组成,这两部分的执行顺序是:谁在前面谁先执行;该方法只执行一次;
代码演示:
- 父类
public class Father {
// 父类静态变量赋值
private static int j = method();
static {
System.out.println("父类静态代码块");
}
public static int method(){
System.out.println("父类静态常量显示赋值代码");
return 1;
}
}
- 子类
public class Son extends Father{
// 子类静态变量赋值
private static int j = method();
static {
System.out.println("子类静态代码块");
}
public static int method(){
System.out.println("子类静态变量显示赋值代码");
return 1;
}
// main方法
public static void main(String[] args) {
}
}
- 结果:执行main方法
2. 实例初始化
规则:
- 实例初始化就是执行
<init>
方法; <init>
方法首行是 super(),即对应父类的<init>
方法;(最先执行)<init>
方法可能重载多个,几个构造器就有几个该方法;<init>
方法由 非静类变量显示赋值代码 、非静态代码块、对应构造器代码组成;三部分执行顺序:非静类变量显示赋值代码 、非静态代码块按先后顺序执行,对应构造器代码最后执行;- 每次实例化,调用对应构造器,就是执行
<init>
方法,子类构造器中一定会调用父类构造器;
注意:
- 哪些方法不能被重写?
final方法、静态方法、private等子类中不可见方法 - 子类如果重写了父类的方法,则调用的一定是子类重写后的方法;
- 非静态方法默认的调用对象是 this;
- this 对象在
<init>
方法中就是正在创建的对象
- 父类
public class Father {
private int i = test();
private static int j = method();
static {
System.out.println("父类静态代码块");
}
Father(){
System.out.println("父类空参构造器");
}
{
System.out.println("父类非静态代码块");
}
public int test(){
System.out.println("父类的test方法");
return 1;
}
public static int method(){
System.out.println("父类静态常量显示赋值代码");
return 1;
}
}
- 子类
public class Son extends Father{
private int i = test();
private static int j = method();
static {
System.out.println("子类静态代码块");
}
Son(){
super(); // super() 写不写都存在
System.out.println("子类空参构造器");
}
{
System.out.println("子类非静态代码块");
}
public int test(){
System.out.println("子类重写父类的test方法");
return 1;
}
public static int method(){
System.out.println("子类静态变量显示赋值代码");
return 1;
}
public static void main(String[] args) {
System.out.println("===第一个实例化===");
Son s1 = new Son();
System.out.println("===第二个实例化===");
Son s2 = new Son();
}
}
结果:
分析:
main方法在子类;
1. 先执行类初始化的代码;<clinit>方法
2. 执行 <init> 方法:
1)子类中的super();
2)super()即Son的父类Father;
3)执行父类中的非静类变量显示赋值代码:i = test(); 结果应该是:"父类的test方法",
但由于子类重写了父类的test方法所以结果是:"子类重写父类的test方法";
4)执行父类的非静态代码块;
5)执行父类的构造器;
6)super()执行完,接着执行子类中的非静类变量显示赋值代码:int i = test();非静态代码块;
7)最后执行子类的构造器;
8)第二个实例初始化,即执行两次上面的步骤。
方法的参数传递机制
实参给形参赋值:
- 是基本数据类型,传递数值;(byte、boolean、short、char、int、float、long、double)
- 是引用数据类型:传递地址值,特殊引用类型不可变性(String、Integer)
- 代码:
- 结果:
- 分析:
执行change方法方法前 - 执行change方法后:只有数组和MyData类的成员变量改变了
递归与迭代
问题:有n阶台阶,一次只能上1阶或者2阶,一共有多少种上法?
1. 递归
思路:设台阶数为n
n=1 跨一步 f(1)=1
n=2 跨一步,再跨一步
直接跨两步 f(2)=2
n=3 先到达f(1),然后从f(1)直接跨两步
先到达f(2),然后从f(2)跨一步 f(3)=f(1)+f(2)
n=4 先到达f(2),然后从f(2)直接跨两步
先到达f(3),然后从f(3)跨一步 f(4)=f(2)+f(3)
n=x 先到达f(x-2),然后从f(x-2)直接跨两步
先到达f(x-1),然后从f(x-1)跨一步 f(x)=f(x-1)+f(x-2)
代码实现:
public class RecursionDemo {
public static void main(String[] args) {
long start = System.currentTimeMillis();
int steps = steps(40);
long end = System.currentTimeMillis();
System.out.println("共有" + steps + "种方法");
System.out.println("耗时" + (end-start) + "毫秒"); // 耗时358毫秒
}
public static int steps(int n) {
if (n < 1) {
throw new IllegalArgumentException(n + "不能小于一");
}
if (n==1 || n==2) {
return n;
}
return steps(n-1) + steps(n-2);
}
}
优点:将大问题拆分成小问题,简化代码,阅读性好;
缺点:递归调用浪费空间,调用太多容易造成堆栈溢出;
2. 迭代循环
思路:设台阶数为n,设置两个变量,一个(one)用来存放最后只跨一步这种情况前面的所有方法数,另一个(two)用来存放最后直接跨两步前面的所有方法数;
n=1 跨一步 f(1)=1
n=2 跨一步,再跨一步
直接跨两步 f(2)=2
n=3 先到达f(1),然后从f(1)直接跨两步 f(3)=two+one
先到达f(2),然后从f(2)跨一步 f(3)=f(1)+f(2)
n=4 先到达f(2),然后从f(2)直接跨两步 f(3)=two+one
先到达f(3),然后从f(3)跨一步 f(4)=f(2)+f(3)
n=x 先到达f(x-2),然后从f(x-2)直接跨两步 f(3)=two+one
先到达f(x-1),然后从f(x-1)跨一步 f(x)=f(x-2)+f(x-1)
代码:
public class RecursionDemo {
public static void main(String[] args) {
long start = System.currentTimeMillis();
int steps = steps(40);
long end = System.currentTimeMillis();
System.out.println("共有" + steps + "种方法");
System.out.println("耗时" + (end - start) + "毫秒"); //耗时0毫秒
}
public static int steps(int n) {
if (n < 1) {
throw new IllegalArgumentException(n + "不能小于一");
}
if (n == 1 || n == 2) {
return n;
}
int one = 2; // 初始化走到第二阶台的走法
int two = 1; // 初始化走到第一阶台的走法
int sum = 0; // 初始化走法总数
for (int i = 3; i <= n; i++) {
sum = one + two; // 最后跨2步和最后跨1步的走法总和
two = one;
one = sum;
}
return sum;
}
}
优点:运行效率高,时间只随着循环次数增加而增加,没有多余的空间浪费;
缺点:代码冗杂,阅读性不好。
成员变量和局部变量
1. 区别
- 声明位置
成员变量:类中方法外,包括:类变量:有static修饰;实例变量:没有static修饰;
局部变量:方法体中,代码块中{},形参。 - 修饰符
成员变量:public、protected、private、final、static、volatile、transient
局部变量:final - 存储位置
成员变量:类变量:方法区;实例变量:堆;
局部变量:栈 - 作用域
局部变量:从声明处开始,到 } 结束 ;
类变量:当前类中,“类名.” 访问(类名有时候也可以省略),其他类中 “类名.” 或 “对象名.” 访问;
实例变量:当前类中,“this.” 访问(this有时候也可以省略),其他类中 “对象名.” 访问 - 生命周期
局部变量:每一个线程,每一次调用都是新的生命周期;
类变量:随着类的初始化而加载,随着类的消亡而消亡,该类的所有类变量都是共享的;
实例变量:随着对象的创建而加载,随着对象的回收而消亡,每一个对象的实例变量是独立的
2. 代码
public class VariableTest {
static int s; // 类变量: s
int i; // 实例变量: i
int j; // 实例变量: j
{
int i = 1; // 局部变量:i
i++;
j++;
s++;
}
public void test (int j) { // 局部变量:j (形参)
i++;
j++;
s++;
}
public static void main(String[] args) { // 局部变量:args (形参)
VariableTest v1 = new VariableTest(); // 局部变量:v1
VariableTest v2 = new VariableTest(); // 局部变量:v2
v1.test(10);
v1.test(20);
v2.test(30);
System.out.println("i=" + v1.i + "," + "j=" + v1.j + "," + "s=" + v1.s);
System.out.println("i=" + v2.i + "," + "j=" + v2.j + "," + "s=" + v2.s);
}
}
结果:
分析:
- 注意:
局部变量与实例变量重名时:在实例变量前加 “this”;
局部变量与类变量重名时:在类变量前加 “类名.”
Spring Bean的作用域
在 <bean>
元素 的 scope
属性里设置bean的作用域,来决定这个bean是单实例还是多实例,默认Spring为每个在 IOC容器里声明的 bean 创建唯一的一个实例,后面使用 getBean() 调用和 bean 引用就会返回唯一的实例,该作用域称为singleton,也是Spring 所有 bean 默认的作用域。
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="hello" class="com.chen.pojo.Hello" scope="">
<property name="name" value="Spring"/>
</bean>
</beans>
1. singleton(默认作用域) 当IOC容器一创建,就会创建 bean 的实例,而且是单例,每次得到的是同一个;
2. prototype 当IOC容器创建时,不会创建 bean 的实例,每次调用 getBean()方法时,就会创建一个该 bean 的实例;
下面的两个是在 web 环境下:
3. request 每次请求会实例化 bean
4. session 每次会话共享一个 bean
Spring 支持的事务传播属性和事务隔离级别
事务传播属性
事务传播行为:一个方法运行在了一个开启了事务的方法中,当前方法使用原来的事务还是开启新的事务
- 事务的默认属性:
propagation=Propagation.REQUIRED
@Transactional
情景:买书的方法在同一个事务中,共有100元,book1价值70元,book2价值50元,依次购买,买完book1后发现钱不够支持买book2了,此时事务回滚,两次购买均失败。
- 将事务挂起,开启新事物
Propagation.REQUIRES_NEW
@Transactional(propagation=Propagation.REQUIRES_NEW)
情景:买书的方法在同一个事务中,共有100元,book1价值70元,book2价值50元,依次购买,买完book1后发现钱不够支持买book2了,但是开启了新的事务,成功购买book1。
事务隔离级别
- 数据库事务并发问题:
有两个事务 Transactional1、Transactional2
- 脏读:其他事务读取到了另一个事务更新但没有提交成功的数据;
如:在 Transactional1 中将 age 的值从20修改为30,Transactional2 读取到了 Transactional1 修改的值 30 ,此时 Transactional1 回滚,Transactional2 读取的30就是一个无效的值; - 不可重读读性
如:Transactional1中的age为20,Transactional2将age改为了30并提交,Transactional1再读取age就是30而不是20; - 幻读
如:Transactional1读取某个表中的部分数据,Transactional2向该表插入新的行,Transactional1再去读取时发现多了新的行。 - 隔离级别
isolation=Isolation.
1. 读未提交:READ UNCOMMITTED:允许Transactional1 读取Transactional2修改未提交的数据;不能解决脏读、不可重复读、幻读。
2. 读已提交:READ COMMITTED:要求Transactional1 只能读取Transactional2 提交的数据;可以解决脏读,不解决不可重复读、幻读。
3. 可重复读:REPEATABLE READ:Transactional1 执行期间,禁止其他事务对当前操作的字段进行修改;可以解决脏读、不可重复读、不解决幻读。
4. 序列化:SERIALIZABLE:Transactional1 执行期间 ,禁止其他事务对这个表进行修改,删除,增加操作;都可以解决。
- 注意:
- 不是隔离级别越高越好,级别越高数据一致性更好,但并发性越弱;
- MySQL四种隔离级别都支持,默认为:可重复读(REPEATABLE READ)
Spring MVC的post请求如何解决中文乱码
Spring MVC提供了一个过滤器:CharacterEncodingFilter
在 web.xml中配置即可:
<!-- 乱码处理 过滤器 /* :包括.jsp-->
<filter>
<filter-name>CharacterEncodingFilter</filter-name>
<filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
<init-param>
<param-name>encoding</param-name>
<param-value>utf-8</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>CharacterEncodingFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
Spring MVC的get请求如何解决中文乱码
在服务器的 server.xml 配置文件中:添加URIEncoding=“UTF-8”
<Connector URIEncoding="UTF-8" port="8080" protocol="HTTP/1.1" connectionTimeout="20000" redirectPort="8443" />
简述Spring MVC的工作流程