Java面试题总结(1)

自增运算

public static void main(String[] args) {
        int i = 1;
        i = i++;//i先赋值,再加一,最后结果还是1
        int j = i++;//j=1,然后i+1---》j=1,i=2
        int k = i + ++i * i++;//(i=2)+(++i=3)*(i=3++)--->k=11,i=4
        System.out.println("i="+i);//i=4
        System.out.println("j="+j);//1
        System.out.printf("k="+k);//k=11
    }

编写一个Singleton实例

单例设计模式,既某个类在整个系统中只能由一个实例对象可以被获取和使用的代码模式。
比如:代表JVM运行环境的Runtime类
要点:
1. 某个类只能有一个实例—>构造器私有化
2. 他必须自行创建这个实例—>含有一个该类的静态变量来保存这个唯一的实例
3. 必须向整个系统提供这个实例—>对外提供获取这个实例的方法(直接暴露,或者提供get方法)

创建方式:饿汉式和懒汉式

方法1: 饿汉式1

/**
 * 饿汉式:在类初始化的时候直接创建实例对象---不管需不需要都会创建
 * (1)构造器私有化
 * (2)自行创建,并且用静态变量保存
 *  (3)向外提供实例
 * (4)强调这是单例--final
 */
public class Singletone1 {//这就是最简单的单例
    public static final Singletone1 INSTANCE = new Singletone1();
    private  Singletone1(){}
}

**方法二:**饿汉式—枚举类型(最简单)

/**
 * 枚举类型:表示该类型的对象就有限的几个
 * 我们限定成一个,就成了单例
 */
public enum  Singleton2 {
    INSSTANCE
}

方法三: 饿汉式–构造器用于初始化时用

public class Singleton3 {
    public static final Singleton3 INSTANCE;
    private String info;
    static {
        try {
            Properties properties = new Properties();
            properties.load(Singleton3.class.getClassLoader().getResourceAsStream("single.properties"));//加载类路径下配置文件single.properties
            INSTANCE = new Singleton3(properties.getProperty("info"));
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }
    private Singleton3(String info){
        this.info = info;
    }//构造器需要初始化的时候用这种单例模式
}

方法四: 懒汉式—有线程安全问题

/**
 * 构造器私有化
 * 用静态变量保存这个唯一的实例
 * 提供一个静态方法获取这个实例对象
 */
public class LazyMan1 {
    private static LazyMan1 instance;
    private LazyMan1(){}
    public static LazyMan1 getInstance() throws InterruptedException {
        if (instance == null){
            Thread.sleep(100);
            instance = new LazyMan1();
        }
        return instance;
    }
}

方法五: 懒汉式----没有线程安全问题

public class LazyMan2 {
    private static LazyMan2 instance;
    private LazyMan2(){}
    public static LazyMan2 getInstance(){
        if (instance == null) {//这一步为了提升效率
            synchronized (LazyMan2.class) {
                if (instance == null){
                    try {
                        Thread.sleep(100);
                    }catch (InterruptedException e){
                        e.printStackTrace();
                    }
                    instance = new LazyMan2();
                }
            }
        }
        return instance;
    }
}

方法六: 懒汉式—内部类形式

/**
 * 在内部类被加载和初始化的时候,才创建这个instance实例对象
 * 内部类不会随着外部类的加载和初始化而初始化,他是单独需要加载初始化的
 * 因为是在内部类初始化,所有它是安全的
 */
public class LazyMan3 {
    private LazyMan3(){}

    private static class InnerClass{
        private static final LazyMan3 INSTANCE = new LazyMan3();
    }
    public static LazyMan3 getInstance(){
        return InnerClass.INSTANCE;
    }
}

类初始化考点

类初始化过程:

  1. 一个类要创建实例需要先加载并初始化该类
    -)main方法所在的类需要先加载并初始化
  2. 一个子类初始化需要先初始化父类
  3. 一个类初始化就是执行()发方法
    -)clinit方法由静态类变量显示赋值代码静态代码块组成
    -)类变量显示赋值代码和静态代码块组成顺序执行
    -)clint方法只执行一次

实例初始化过程:
实例初始化就是执行()方法
1)init方法可能重载有多个,有几个构造器就有几个init方法
2)init方法由非静态实例变量显示赋值代码非静态代码块、对应构造器代码组成
3)非静态实例变量显示赋值代码非静态代码块代码顺序执行,而对应构造器的代码最后执行
4)每次创建实例对象,调用对应构造器,执行的就是对应的init方法
5)init方法的首行是super(),基对应父类的init方法

方法的重写Override:

  1. 不能被重写的方法—final方法、静态方法、private等子类中不可见方法
  2. 对象的多态性:
    1. 子类如果重写了父类的方法,通过子类对象调用的一定是子类重写过的代码
    2. 非静态方法默认的调用对象是this
    3. this对象在构造器或者说init方法中就是正在创建的对象

代码:Father和Son的故事

package Fa;

/**
 * 父类的初始化inti
 *  1. j=method()
 *  2. 父类的静态代码块
 *
 *  父类的实例化方法:
 *  *  1.super()--最前面
 *  *  2.非静态变量i=test();
 *  *  3.父类的非静态代码块
 *  *  4.父类的无参构造--最后
 *
 *  非静态方法前面其实有一个默认的对象this
 *  this再构造器(或init) 表示的是正在创建的对象,因为这里是在创建son对象,
 *  所以test执行的是子类重写的代码(面向多态)
 *
 *  这里i=test()执行的是子类重写的test()方法
 */
public class Father {
    private int i = test();
    private static int j = method();

    static{
        System.out.print("1--");
    }
    Father(){
        System.out.print("2--");
    }
    {
        System.out.print("3--");
    }

    public int test(){
        System.out.print("4--");
        return 1;
    }
    public static int method(){
        System.out.print("5--");
        return 1;
    }
}

package Fa;

/**
 * 先初始化父类再初始化子类
 * 子类的初始化<clinit>
 *     1.j = method();
 *     2.子类的静态代码块
 *
 *     先初始化父类:5--1--,再初始化子类:10--6--;
 *
 *子类的实例化方法:
 *  1.super()--最前面  9--3--2--
 *  2.非静态变量i=test();  9
 *  3.子类的非静态代码块    8
 *  4.子类的无参构造--最后  7
 *
 * 因为创建了两个Son对象,所以实例化方法init执行了两次
 * 又来一遍9--3--2--9--8--7
 */
public class Son extends Father {
    private int i = test();
    private static int j = method();
    static {
        System.out.print("6--");
    }
    Son(){
        //super();不写也有
        System.out.print("7--");
    }
    {
        System.out.print("8--");
    }
    public int test(){
        System.out.print("9--");
        return 1;
    }
    public static int method(){
        System.out.print("10--");
        return 1;
    }

    public static void main(String[] args) {
        Son son1 = new Son();
        System.out.println();
        Son son2 = new Son();
    }
}

方法的参数传递机制:

  1. 形参是基本数据类型----->传递数据值
  2. 实参是引用数据类型----->传递地址值,特殊的类型:String、包装类等对象不可变性
public class MethodTransfer {
    public static void main(String[] args) {
        int i = 1;
        String  str = "hello";
        Integer num = 200;
        int[] arr = {1,2,3,4,5};
        MyData myData = new MyData();

        change(i,str,num,arr,myData);

        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= "+myData.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;
    }

    static class MyData{
        int a = 10;
    }
}
输出结果:
i= 1
str= hello
num= 200
arr= [2, 2, 3, 4, 5]
my.a= 11

递归算法和迭代算法

走台阶问题:一只青蛙一次可以跳上1级台阶,也可以跳上2级。求该青蛙跳上一个n级的台阶总共有多少种跳法。

public class StepRecursion {
    //实现f(n):求n步台阶一共有多少种走法--;每次只能走一步或者两部
    public static int f(int n){//垃圾算法,时间复杂度O(C(m,m+n))----多项式时间内无法解决,谁用谁傻逼!
        if (n==0) return 0;
        else if (n==1) return 1;
        else if (n==2) return 2;

        return f(n-2)+f(n-1);
    }

    public static long loop(long n){//时间复杂度O(n),推荐
        if (n<1L){
            throw new IllegalArgumentException(n+"不能小于1");
        }
        if (n==1L||n==2L){
            return n;
        }
        long one = 2L;
        long two = 1L;
        long sum = 0L;

        for (int i = 3; i <= n; i++) {
            sum = two + one;
            two = one;
            one = sum;
        }
        return sum;
    }


    public static void main(String[] args) {
        long start = System.currentTimeMillis();
        System.out.println(loop(8L));
        System.out.println(System.currentTimeMillis()-start);
    }
}

成员变量作用域问题

public class LocalVarAndChengyuanVar {
    static int s;//类变量--成员变量----存在方法区(共享)
    int i,j;//实例变量-----成员变量----存在堆内(不共享)
    {
        int i = 1;
        i++;
        j++;
        s++;
    }
    public void test(int j){
        i++;j++;s++;
    }

    public static void main(String[] args) {
        LocalVarAndChengyuanVar obj1 = new LocalVarAndChengyuanVar();
        LocalVarAndChengyuanVar obj2 = new LocalVarAndChengyuanVar();
        obj1.test(10);//栈中存放局部对象变量
        obj1.test(20);
        obj2.test(30);
        System.out.println(obj1.i+","+obj1.j+","+obj1.s);
        System.out.println(obj2.i+","+obj2.j+","+obj2.s);
    }
}
//2,1,5
//1,1,5

在这里插入图片描述

Bean的作用域

在Spring中,可以在元素的scope属性中设置bean的作用域,以决定这个bean是单例的还是多实例的。
默认spring只为每个在IOC容器里声明的bean创建一个实例,整个IOC容器范围内共享这个实例:后续的getBean()调用和bean引用都将返回这个唯一的bean实例----也就是singleton----bean的默认作用域

类别说明
singleton在SpringIOC容器中仅存在一个bean实例
prototype每次调用getBean方法都会返回一个新的实例
request每次HTTP请求都会创建一个新的bean,该作用域仅适用于WebApplicationContext环境
session同一个HTTP Session共享一个Bean,不同的使用不一样。也是仅适用于WebApplicationContext环境

事务的传播属性

事务的属性:

  1. propagation:用来设置事务的传播行为。
    –传播行为:一个方法运行在了一个开启了事务的方法中时,当前方法是使用原来的事务还是开启一个新的事务
    Propagation.REQUIRED:默认,使用原来的事务
    Propagation。REQURIRES_NEW:将原来的事务挂起,开启一个新的事务
  2. isolation:用来设置事务的隔离级别
    –Isolation.REPEATABLE_READ:可重复读,MySQL默认的隔离级别
    –Isolation.READ_COMMITTED:读已提交,Oracle默认的隔离级别,较常使用。

数据库事务并发问题:

  1. 脏读:A:1-》2-》1 , A更改又回退;B读到了2,无效。
  2. 不可重复读:A读取值20,B修改成了30,A再次读发现数值不一样了
  3. 幻读:你第一次读取数据,再次读发现这个数据多个很多行
    在这里插入图片描述

SpringMVC解决请求乱码问题

  1. get请求乱码可以直接在server.xml文件中的标签中添加URIEncoding="UTF-8"解决
  2. post请求乱码需要在wem.xml中配置过滤器CharacterEncodingFilter,过滤器中配置参数名encoding,值UTF-8
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值