java高频面试题目记录一

程序题–自增变量

在这里插入图片描述
源自B站视频:传送门
这里注意容易出错的地方是上图右边步骤中的2,5 自增是在局部变量表中自增。而赋值操作是将操作数栈里的数赋值给局部变量表对应的变量。
在这里插入图片描述

编程题–写一个单例设计模式

在这里插入图片描述
在这里插入图片描述

饿汉式的三种创建方式

1:直接实例化

/*
 *饿汉式
 *在类初始化的时候,直接创建实例对象,不管你是否需要这个对象,都会创建
 * 
 * (1)构造器私有化
 * (2)自行创建,并保存在静态变量中
 * (3)对外提供获取该实例对象的方式--public
 * (4)强调单例,用final修饰(final修饰的一般为常量,因此instance改为大写)
 */
public class Singleton1 {
	public static final Singleton1 INSTANCE = new Singleton1();//饿汉式直接创建实例对象
	private Singleton1() {
		
	}

}

2:枚举式

/*
 * 枚举类型代表该类型对象是有限的几个
 * 我们可以限定为只有一个,就成为单例了
 * 更简洁了
 * 
 */
public enum Singleton2 {
	INSTANCE
}

3:静态代码块

public class Singleton3 {
	public static final Singleton3 INSTANCE ;
	private String info;
	//在静态代码块中实例化,也是在类加载和初始化过程中,静态常量便创建出来
	static {
		try {
			//从配置文件去读取info值,配置文件放在src下,用类加载器去加载
			//静态代码块适用于比较复杂的,需要读一堆初始化数据的
			Properties  properties = new Properties();
			properties.load(Singleton3.class.getClassLoader().getResourceAsStream("single.properties"));
			//用当前类得类加载器去加载配置文件
			INSTANCE = new Singleton3(properties.getProperty("info"));
		} catch (IOException e) {
			throw new RuntimeException(e);
		}
	}
	
	
}

single.properties文件放上我们想要的数据

#key=value
info=abc

上述三种方式的测试
在这里插入图片描述

懒汉式的三种创建方式

1:线程不安全

package singleton;
/*
 * (1)构造器私有化
 * (2)不自行创建,只定义一个静态变量
 * (3)提供一个静态方法,获取实例对象
 */

public class Singleton4 {
    private static  Singleton4 instance;
    //这里就不能public,因为我们没有给他创建对象,那么直接这样调用,可能是个空对象
	private Singleton4() {	
	}
	public static Singleton4 getInstance(){
		if(instance==null) {
			//测试当两个线程,先后进入到这里休眠,那么就会创建两个实例,所以这个例子存在线程安全问题
			try {
				Thread.sleep(100);
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			instance = new Singleton4();
		}
		return instance;
	}
	
}

测试代码:

public class TestSingleton4 {
	public static void main(String[] args) throws InterruptedException, ExecutionException {
		Callable<Singleton4> c = new Callable<Singleton4>() {

			@Override
			public Singleton4 call() throws Exception {
				// TODO Auto-generated method stub
				return Singleton4.getInstance();
			}
		};
		/*
		 * 启动线程服务
		 * 创建线程池
		 * 提交线程服务
		 */
		ExecutorService eService =Executors.newFixedThreadPool(2);
		Future<Singleton4> future1 = eService.submit(c);
		Future<Singleton4> future2 = eService.submit(c);
		
		Singleton4 s1 = future1.get();
		Singleton4 s2 = future2.get();
		System.out.println(s1 == s2);
		eService.shutdown();
	}

}

因此线程不安全,返回的是false,

2:线程安全

扫描二维码关注公众号,回复: 9395967 查看本文章
package singleton;
/*
 * (1)构造器私有化
 * (2)不自行创建,只定义一个静态变量
 * (3)提供一个静态方法,获取实例对象
 */

public class Singleton5 {
    private static  Singleton5 instance;
    //这里就不能public,因为我们没有给他创建对象,那么直接这样调用,可能是个空对象
	private Singleton5() {
	}
	public static Singleton5 getInstance(){
		//添加一个同步锁,保证线程安全
		//为了保证线程安全得同时,提供效率,把对instance==null得判断放在锁得外面
		if(instance==null) {
			synchronized (Singleton5.class) {
				if(instance==null) {
					//测试当两个线程,先后进入到这里,休眠,那么就会创建两个实例,所以这个例子存在线程安全问题
					try {
						Thread.sleep(100);
					} catch (InterruptedException e) {
						// TODO Auto-generated catch block
						e.printStackTrace();
					}
					instance = new Singleton5();
				}
				
				
			}
			
		}
		return instance;
		
	}
		
}

同样的测试线程安全,返回的是true,
3:静态内部类

package singleton;
/*
 * 在内部类加载和初始化时,才创建instance实例对象
 * 静态内部类不会随着外部类得加载和初始化而初始化,它是要单独去加载和初始化得
 *因为是在内部类加载和初始化时创建得,因此是线程安全的
 */

public class Singleton6 {
	private Singleton6() {
	}
	private static class Inner {
		private static Singleton6 instance = new Singleton6();
	}
	public static Singleton6 getInstance() {
		return Inner.instance;
	}
}

在这里插入图片描述

小结

如果是饿汉式,枚举形式最简单
如果是懒汉式,静态内部类形式最简单

发布了18 篇原创文章 · 获赞 1 · 访问量 2304

猜你喜欢

转载自blog.csdn.net/Better_WZQ/article/details/104436103