JAVASE面试总结篇

单利设计模式

1)构造器私有化
2)用一个静态私有变量保存这个唯一的实例
3)提供一个静态方法、获取这个实例对象
最基本的单例:线程不安全。

public class Singleton1 {
    private static Singleton1 instance;
    private Singleton1(){}
    public static Singleton1 getInstance(){
        if(instance==null) {
            instance=new Singleton1();
        }
        return instance;
    }
}

线程安全,书写复杂的单例模式

public class Singleton2 {

    private volatile static Singleton uniqueInstance;

    private Singleton() {
    }

    public static Singleton getUniqueInstance() {
       //先判断对象是否已经实例过,没有实例化过才进入加锁代码
        if (uniqueInstance == null) {
            //类对象加锁
            synchronized (Singleton.class) {
                if (uniqueInstance == null) {
                    uniqueInstance = new Singleton();
                }
            }
        }
        return uniqueInstance;
    }
}

测试

@Test
    void getSingleton() throws ExecutionException, InterruptedException {

//        Singleton1 singleton1=Singleton1.getInstance();
//        Singleton1 singleton2=Singleton1.getInstance();
//        Singleton1 singleton3=Singleton1.getInstance();
//        System.out.println("单线程~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~");
//        System.out.println(singleton1==singleton2);
//        System.out.println("单线程"+singleton1+"singleton1");
//        System.out.println("单线程"+singleton2+"singleton2");
//        System.out.println("单线程"+singleton3+"singleton3");

        Callable<Singleton1> callable=new Callable<Singleton1>() {
            @Override
            public Singleton1 call() throws Exception {
                return Singleton1.getInstance();
            }
        };
        ExecutorService executorService=Executors.newFixedThreadPool(2);
        Future<Singleton1> f1= executorService.submit(callable);
        Future<Singleton1> f2= executorService.submit(callable);
        Future<Singleton1> f3= executorService.submit(callable);

        Singleton1 s1=f1.get();
        Singleton1 s2=f2.get();
        Singleton1 s3=f3.get();

        System.out.println("多线程~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~");
        System.out.println(s1==s2);
        System.out.println("多线程"+s1+"singleton1");
        System.out.println("多线程"+s2+"singleton2");
        System.out.println("多线程"+s3+"singleton3");
    }

线程安全,内部类方法

/**
 1. 在内部类被加载和初始化时、才能创建INSTANCE实例对象
 2. 静态内部类不会自动随着外部类大家在和初始化而初始化,它是要单独去加载和初始化的
 3. 另外是在内部类加载和初始化时创建的。是线程安全的
 */
public class Singleton3 {

    private Singleton3(){

    }

    private static class Inner{
        private static final Singleton3 INSTANCE=new Singleton3();
    }

    public static Singleton3 getInstance() {
        return Inner.INSTANCE;
    }
}

类初始化过程

当初始化子类时,调用的过程:
先初始化父类》初始化子类》子类的实现1super(),2具体的方法,3子类的非静态代码块4子类的无参构造

1、类初始化过程

  1. 一个类要创建实例需要先加载并初始化该类

main方法所在的类需要先加载和初始化

  1. 一个子类要初始化需要先初始化父类
  2. 一个类初始化就是执行< Clinit >()方法

< Clinit >()方法由静态类变量显示赋值代码和静态代码块组成
类变量显示赋值代码和静态代码块代码从上下顺序执行
< Clinit >()只执行一次
2、实例初始化过程
1)实例初始化就是执行< init >()方法

  • < init >()方法可能重载有多个、有几个构造器就有几个< init >()方法
  • < init >()方法由非静态实例变量显示赋值代码和非静态代码块、对应构造器代码组成
  • 非静态实例变量显示赋值代码和非静态代码块代码从上到虾顺序执行、而对应构造器的代码最后执

  • 每次创建实例对象、调用对应构造器、执行的就是对应的< init >()方法
  • < init >()方法的首行是super()或者super(实参列表),即对应父类的< init >()方法

3、方法重写
1)哪些方法不可以被重写

  • final方法
  • 静态方法
  • private等子类中不可见的方法

2)对象的多态性

  • 子类如果重写了父类的方法、通过子类对象调用的一定是子类重写过的代码
  • 非静态方法默认的调用对象是this
  • this对象在构造器或者说< init >方法中就是正在创建对对象

JAVA的传参机制

1)形参是基本数据类型:传递数据值

Java语言提供了八种基本类型。六种数字类型(四个整数型,两个浮点型),一种字符类型,还有一种布尔型。

byte:

byte 数据类型是8位、有符号的,以二进制补码表示的整数; 最小值是 -128(-2^7); 最大值是 127(2^7-1); 默认值是
0; byte 类型用在大型数组中节约空间,主要代替整数,因为 byte 变量占用的空间只有 int 类型的四分之一; 例子:byte a
= 100,byte b = -50。 short:

short 数据类型是 16 位、有符号的以二进制补码表示的整数 最小值是 -32768(-2^15); 最大值是 32767(2^15 -
1); Short 数据类型也可以像 byte 那样节省空间。一个short变量是int型变量所占空间的二分之一; 默认值是 0;
例子:short s = 1000,short r = -20000。 int:

int 数据类型是32位、有符号的以二进制补码表示的整数; 最小值是 -2,147,483,648(-2^31); 最大值是
2,147,483,647(2^31 - 1); 一般地整型变量默认为 int 类型; 默认值是 0 ; 例子:int a =
100000, int b = -200000。 long:

long 数据类型是 64 位、有符号的以二进制补码表示的整数; 最小值是
-9,223,372,036,854,775,808(-2^63); 最大值是 9,223,372,036,854,775,807(2^63 -1); 这种类型主要使用在需要比较大整数的系统上; 默认值是 0L; 例子: long a = 100000L,Long b = -200000L。 "L"理论上不分大小写,但是若写成"l"容易与数字"1"混淆,不容易分辩。所以最好大写。 float:

float 数据类型是单精度、32位、符合IEEE 754标准的浮点数; float 在储存大型浮点数组的时候可节省内存空间; 默认值是
0.0f; 浮点数不能用来表示精确的值,如货币; 例子:float f1 = 234.5f。 double:

double 数据类型是双精度、64 位、符合IEEE 754标准的浮点数; 浮点数的默认类型为double类型;
double类型同样不能表示精确的值,如货币; 默认值是 0.0d; 例子:double d1 = 123.4。 boolean:

boolean数据类型表示一位的信息; 只有两个取值:true 和 false; 这种类型只作为一种标志来记录 true/false 情况;
默认值是 false; 例子:boolean one = true。 char:

char类型是一个单一的 16 位 Unicode 字符; 最小值是 \u0000(即为0); 最大值是 \uffff(即为65,535);
char 数据类型可以储存任何字符; 例子:char letter = ‘A’;。

在这里插入图片描述
2)实参是引用数据类型:传递地址值
特殊类型:String、包装类等对象不可变性。(修改后变成新对象)

递归和迭代

递归:方法调用自身
优点:大问题转化为小问题、可以减少代码量、同时代码精简、可读性好
确定:递归调用浪费了空间、而且递归太深容易造成堆栈溢出。
迭代:利用变量的原值推出新值为迭代
优点:代码运行效率好、因为时间只因为循环次数而增加、而且没有额外的空间开销
缺点:代码不如递归简洁、可读性好

两个方法函数

public class RecursionAndIteration {

    /**
     * 递归法
     *
     * @param
     * @return
     * @throws IllegalAccessException
     */
    public static Integer RecursionFunction(Integer i) throws IllegalAccessException {
        if (i < 1) {
            throw new IllegalAccessException(i + "不能小于1");
        }
        if (i == 1 || i == 2) {
            return i;
        }
        return RecursionFunction(i - 1) + RecursionFunction(i - 2);
    }

    /**
     * 迭代法
     *
     * @param
     * @return
     * @throws IllegalAccessException
     */
    public static Integer IterationFunction(Integer i) throws IllegalAccessException {
        if (i < 1) {
            throw new IllegalAccessException(i + "不能小于1");
        }
        if (i == 1 || i == 2) {
            return i;
        }
        int one = 2;//初始化为走到第二阶台阶的走法
        int two = 1;//初始化为走到第一阶台阶的走法
        int sum = 0;
        for (int k = 3; k <= i; k++) {
            sum = one + two;
            two = one;
            one = sum;
        }
        return sum;
    }
}

测试类

 @Test
    public void testfunc() throws IllegalAccessException {
        System.out.println("迭代法开始-----------------------------------");
        Long start = System.currentTimeMillis();
        System.out.println(RecursionAndIteration.IterationFunction(40));
        Long end = System.currentTimeMillis();
        System.out.println("迭代法结束-----------------------------------");
        System.out.println(end - start);

        System.out.println("递归法开始-----------------------------------");
        Long start1 = System.currentTimeMillis();
        System.out.println(RecursionAndIteration.RecursionFunction(40));
        Long end1 = System.currentTimeMillis();
        System.out.println("递归法结束-----------------------------------");
        System.out.println(end1 - start1);
    }

在这里插入图片描述

成员变量 和 局部变量

1、就近原则
2、变量的分类:成员变量、局部变量
1)声明的位置
局部变量:方法体中、形参中、代码块中
成员变量:类中方法外

  • 类变量:有static修饰
  • 实例变量:没有static修饰

2)修饰符
局部变量:final
成员变量:public、protected、private、final、static、volatile、transient(不参与序列化过程)
3)存储的位置
局部变量:栈
成员变量:

  • 实例变量:堆
  • 类变量:方法区

4)作用域
局部变量:从声明处开始、到所属的}结束
实例变量:在当前类中“this.”,在其他类中“对象名.”访问
类变量:在当前类中“类名.”,在其他类“类名.”或者“对象名.”访问
5)生命周期
局部变量:每一个线程、每一次调用执行都是新的生命周期
实例变量:随着对象的创建而初始化、随着对象的回收而消亡、每一个对象的实例变量是独立的
类变量:随着类的初始化而初始化、随着类的卸载而消亡、该类的所有对象的类变量是共享的
在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值