面試題1:自增變量
如下代碼的運行結果:
/**
* ClassName: Test1
* Date: 2020/2/25 22:29
* author: Oh_MyBug
* version: V1.0
*/
public class Test1 {
public static void main(String[] args) {
int i = 1;
i = i ++;
int j = i ++;
int k = i + ++i * i++;
System.out.println("i = " + i);
System.out.println("j = " + j);
System.out.println("k = " + k);
}
}
// 輸出:
i = 4
j = 1
k = 11
總結:
- 賦值=,最後計算
- =右邊的從左到右加載值依次壓入操作數棧
- 實際先算哪個,看運算符優先級
- 自增、自減操作都是直接修改變量的值,不經過操作數棧
- 最後的賦值之前,臨時結果也是存儲在操作數棧中
面試題2:單例設計模式
編程題:寫一個singleton示例
什麼是Singleton?
- Singleton:在Java中指單例設計模式,它是軟件開發中最常用的設計模式之一。
- 單:一個
- 例:實例
- 單例設計模式,即某個類在整個系統中只能有一個實例對象可被獲取和使用的代碼模式。
- 例如:代表JVM運行環境的Runtime類
要點
- 某個類只能有一個實例
- 構造器私有化
- 它必須自行創建這個實例
- 含有一個該類的靜態變量來保存這個唯一的實例
- 它必須自行向整個系統提供這個實例
- 對外提供獲取該實例對象的方式:
- 直接暴露
- 用靜態變量的get方法獲取
- 對外提供獲取該實例對象的方式:
幾種常見形式
- 餓漢式:直接創建對象,不存在線程安全問題
- 直接實例化餓漢式(簡潔直觀)
- 枚舉式(最簡潔)
- 靜態代碼塊餓漢式(適合複雜實例化)
/**
* ClassName: Singleton1
* Date: 2020/2/25 23:30
* author: Oh_MyBug
* version: V1.0
* 餓漢式:
* 在類初始化的時候直接創建實例對象,不管你是否需要這個對象
*
* (1)構造器私有化
* (2)自行創建,並且用靜態變量保存
* (3)向外提供這個實例
* (4)強調這是一個單例,我們可以用final修飾
*/
public class Singleton1 {
public static final Singleton1 INSTANCE = new Singleton1();
private Singleton1(){
}
}
/**
* ClassName: TestSingleton1
* Date: 2020/2/25 23:36
* author: Oh_MyBug
* version: V1.0
*/
public class TestSingleton1 {
public static void main(String[] args) {
Singleton1 s = Singleton1.INSTANCE;
System.out.println(s);
}
}
// 輸出:
Singleton1@10f87f48
/**
* ClassName: Singleton2
* Date: 2020/2/25 23:35
* author: Oh_MyBug
* version: V1.0
* 枚舉類型,表示該類型的對象是有限的幾個
* 我們可以限定爲一個,就成了單例
*/
public enum Singleton2 {
INSTANCE
}
/**
* ClassName: TestSingleton2
* Date: 2020/2/25 23:37
* author: Oh_MyBug
* version: V1.0
*/
public class TestSingleton2 {
public static void main(String[] args) {
Singleton2 s = Singleton2.INSTANCE;
System.out.println(s);
}
}
//輸出:
INSTANCE
import java.io.IOException;
import java.util.Properties;
/**
* ClassName: Singleton3
* Date: 2020/2/25 23:39
* author: Oh_MyBug
* version: V1.0
*/
public class Singleton3 {
public static final Singleton3 INSTANCE;
private String info;
static {
try {
Properties pro = new Properties();
pro.load(Singleton3.class.getClassLoader().getResourceAsStream("single.properties"));
INSTANCE = new Singleton3(pro.getProperty("info"));
} catch (IOException e) {
throw new RuntimeException(e);
}
}
private Singleton3(String info){
this.info = info;
}
public String getInfo() {
return info;
}
public void setInfo(String info) {
this.info = info;
}
@Override
public String toString() {
return "Singleton3{" +
"info='" + info + '\'' +
'}';
}
}
/**
* ClassName: TestSingle3
* Date: 2020/2/25 23:48
* author: Oh_MyBug
* version: V1.0
*/
public class TestSingleton3 {
public static void main(String[] args) {
Singleton3 s = Singleton3.INSTANCE;
System.out.println(s);
}
}
// 輸出:
Singleton3{info='Oh_MyBug'}
- 懶漢式:延遲創建對象
- 線程不安全(適用於單線程)
- 線程安全(適用於多線程)
- 靜態內部類形式(適用於多線程)
/**
* ClassName: SIngleton4
* Date: 2020/2/25 23:54
* author: Oh_MyBug
* version: V1.0
* 懶漢式:
* 延遲創建這個實例對象
* (1)構造器私有化
* (2)用一個靜態變量保存這個唯一的實例
* (3)提供一個靜態方法,獲取這個實例對象
*/
public class Singleton4 {
static Singleton4 instance;
private Singleton4(){
}
public static Singleton4 getInstance(){
if (instance == null){
instance = new Singleton4();
}
return instance;
}
}
/**
* ClassName: TestSingleton4
* Date: 2020/2/25 23:57
* author: Oh_MyBug
* version: V1.0
*/
public class TestSingleton4 {
public static void main(String[] args) {
Singleton4 s1 = Singleton4.getInstance();
Singleton4 s2 = Singleton4.getInstance();
System.out.println(s1 == s2);
System.out.println(s1);
System.out.println(s2);
}
}
// 輸出:
true
Singleton4@5b480cf9
Singleton4@5b480cf9
可能存在線程安全問題!
/**
* ClassName: Singleton4
* Date: 2020/2/25 23:54
* author: Oh_MyBug
* version: V1.0
* 懶漢式:
* 延遲創建這個實例對象
* (1)構造器私有化
* (2)用一個靜態變量保存這個唯一的實例
* (3)提供一個靜態方法,獲取這個實例對象
*/
public class Singleton4 {
static Singleton4 instance;
private Singleton4(){
}
public static Singleton4 getInstance(){
if (instance == null){
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
instance = new Singleton4();
}
return instance;
}
}
import java.util.concurrent.*;
/**
* ClassName: TestSingleton4
* Date: 2020/2/25 23:57
* author: Oh_MyBug
* version: V1.0
*/
public class TestSingleton4 {
public static void main(String[] args) throws ExecutionException, InterruptedException {
// Singleton4 s1 = Singleton4.getInstance();
// Singleton4 s2 = Singleton4.getInstance();
//
// System.out.println(s1 == s2);
// System.out.println(s1);
// System.out.println(s2);
Callable<Singleton4> c = new Callable<Singleton4>() {
@Override
public Singleton4 call() throws Exception {
return Singleton4.getInstance();
}
};
ExecutorService es = Executors.newFixedThreadPool(2);
Future<Singleton4> f1 = es.submit(c);
Future<Singleton4> f2 = es.submit(c);
Singleton4 s1 = f1.get();
Singleton4 s2 = f2.get();
System.out.println(s1 == s2);
System.out.println(s1);
System.out.println(s2);
es.shutdown();
}
}
// 輸出:
false
Singleton4@1ddc4ec2
Singleton4@133314b
/**
* ClassName: Singleton4
* Date: 2020/2/25 23:54
* author: Oh_MyBug
* version: V1.0
* 懶漢式:
* 延遲創建這個實例對象
* (1)構造器私有化
* (2)用一個靜態變量保存這個唯一的實例
* (3)提供一個靜態方法,獲取這個實例對象
*/
public class Singleton5 {
static Singleton5 instance;
private Singleton5(){
}
public static Singleton5 getInstance(){
if (instance == null) {
synchronized (Singleton5.class) {
if (instance == null) {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
instance = new Singleton5();
}
}
}
return instance;
}
}
import java.util.concurrent.*;
/**
* ClassName: TestSingleton4
* Date: 2020/2/25 23:57
* author: Oh_MyBug
* version: V1.0
*/
public class TestSingleton5 {
public static void main(String[] args) throws ExecutionException, InterruptedException {
Callable<Singleton5> c = new Callable<Singleton5>() {
@Override
public Singleton5 call() throws Exception {
return Singleton5.getInstance();
}
};
ExecutorService es = Executors.newFixedThreadPool(2);
Future<Singleton5> f1 = es.submit(c);
Future<Singleton5> f2 = es.submit(c);
Singleton5 s1 = f1.get();
Singleton5 s2 = f2.get();
System.out.println(s1 == s2);
System.out.println(s1);
System.out.println(s2);
es.shutdown();
}
}
// 輸出:
true
Singleton5@1ddc4ec2
Singleton5@1ddc4ec2
/**
* ClassName: Singleton6
* Date: 2020/2/26 0:08
* author: Oh_MyBug
* version: V1.0
* 在內部類被加載和初始化時,才創建INSTANCE實例對象
* 靜態內部類不會自動隨着外部類的加載和初始化而初始化,它是要單獨去加載和初始化
* 因爲是在內部類加載和初始化時創建的,因此是線程安全的
*/
public class Singleton6 {
private Singleton6(){
}
private static class Inner{
private static final Singleton6 INSTANCE = new Singleton6();
}
public static Singleton6 getInstance(){
return Inner.INSTANCE;
}
}