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:線程安全

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;
	}
}

在這裏插入圖片描述

小結

如果是餓漢式,枚舉形式最簡單
如果是懶漢式,靜態內部類形式最簡單

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章