文章目录

  • 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. 类初始化

规则:

  1. 一个类要创建实例必须先初始化该类;
  2. main方法所在的类总是要先加载和初始化;
  3. 子类要初始化必须先初始化父类;
  4. 一个类的初始化就是执行 <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. 实例初始化

规则:

  1. 实例初始化就是执行 <init> 方法;
  2. <init> 方法首行是 super(),即对应父类的 <init> 方法;(最先执行)
  3. <init> 方法可能重载多个,几个构造器就有几个该方法;
  4. <init> 方法由 非静类变量显示赋值代码非静态代码块对应构造器代码组成;三部分执行顺序:非静类变量显示赋值代码 、非静态代码块按先后顺序执行,对应构造器代码最后执行;
  5. 每次实例化,调用对应构造器,就是执行 <init> 方法,子类构造器中一定会调用父类构造器;

注意:

  1. 哪些方法不能被重写?
    final方法、静态方法、private等子类中不可见方法
  2. 子类如果重写了父类的方法,则调用的一定是子类重写后的方法;
  3. 非静态方法默认的调用对象是 this;
  4. 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();
    }
}

结果:

java 初始化实体赋值 java初始化和实例化_java 初始化实体赋值


分析:

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)第二个实例初始化,即执行两次上面的步骤。

方法的参数传递机制

实参给形参赋值:

  1. 是基本数据类型,传递数值;(byte、boolean、short、char、int、float、long、double)
  2. 是引用数据类型:传递地址值,特殊引用类型不可变性(String、Integer)
  • 代码:
  • java 初始化实体赋值 java初始化和实例化_System_02


  • 结果:
  • java 初始化实体赋值 java初始化和实例化_父类_03


  • 分析:
    执行change方法方法前
  • java 初始化实体赋值 java初始化和实例化_System_04

  • 执行change方法后:只有数组和MyData类的成员变量改变了
  • java 初始化实体赋值 java初始化和实例化_父类_05


递归与迭代

问题:有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);
    }
}

结果:

java 初始化实体赋值 java初始化和实例化_System_06


分析:

java 初始化实体赋值 java初始化和实例化_父类_07


java 初始化实体赋值 java初始化和实例化_System_08


java 初始化实体赋值 java初始化和实例化_System_09


java 初始化实体赋值 java初始化和实例化_子类_10


java 初始化实体赋值 java初始化和实例化_System_11

  • 注意:
    局部变量与实例变量重名时:在实例变量前加 “this”;
    局部变量与类变量重名时:在类变量前加 “类名.”
Spring

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 支持的事务传播属性和事务隔离级别

事务传播属性

事务传播行为:一个方法运行在了一个开启了事务的方法中,当前方法使用原来的事务还是开启新的事务

  1. 事务的默认属性:propagation=Propagation.REQUIRED
@Transactional

情景:买书的方法在同一个事务中,共有100元,book1价值70元,book2价值50元,依次购买,买完book1后发现钱不够支持买book2了,此时事务回滚,两次购买均失败。

  1. 将事务挂起,开启新事物 Propagation.REQUIRES_NEW
@Transactional(propagation=Propagation.REQUIRES_NEW)

情景:买书的方法在同一个事务中,共有100元,book1价值70元,book2价值50元,依次购买,买完book1后发现钱不够支持买book2了,但是开启了新的事务,成功购买book1。

事务隔离级别

  1. 数据库事务并发问题:
    有两个事务 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 执行期间 ,禁止其他事务对这个表进行修改,删除,增加操作;都可以解决。
  • 注意:
  1. 不是隔离级别越高越好,级别越高数据一致性更好,但并发性越弱;
  2. MySQL四种隔离级别都支持,默认为:可重复读(REPEATABLE READ)
Spring MVC

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的工作流程

java 初始化实体赋值 java初始化和实例化_父类_12