1、求以下這些例子的輸出結(jié)果(考察點(diǎn):自增變量):
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);
}
1.1分析:
1顾患、int i = 1, 得i = 1
2琳拭、i = i++ ,目前i = 1,將其壓入操作數(shù)棧描验,在“=”號(hào)返回之前,修改i的值為2坑鱼,然后“=”將棧中的1賦給i膘流,因此目前i = 1
3絮缅、同理上一步,j = 1呼股,i = 2
4耕魄、目前i的值為2,將其壓入操作數(shù)棧彭谁,然后遇到了++i吸奴,將3壓入操作數(shù)棧,又遇到i++缠局,也將3壓入操作數(shù)棧则奥,本地變量i變?yōu)?。
所以目前操作數(shù)棧:3 3 2狭园。局部變量i = 4读处,j = 1
最后使用運(yùn)算符計(jì)算值:k = 2 + 3 * 3 = 11
最終結(jié)果:
i = 4
j = 1
k = 11
1.2小結(jié):
1、賦值操作唱矛,最后才計(jì)算值罚舱。
2、等號(hào)右邊的绎谦,從左到右加載值并依次壓入操作數(shù)棧管闷。
3、實(shí)際算哪個(gè)要看運(yùn)算符的優(yōu)先級(jí)窃肠。
4包个、自增、自減操作都是直接改變變量的值铭拧,不經(jīng)過(guò)操作數(shù)棧赃蛛。
5、沒(méi)賦值之前搀菩,臨時(shí)結(jié)果存儲(chǔ)在操作數(shù)棧中呕臂。
2、單例模式(考點(diǎn):多種實(shí)現(xiàn)方式肪跋,多線(xiàn)程環(huán)境)
- 一個(gè)類(lèi)只有一個(gè)實(shí)例
- 構(gòu)造器私有化
- 必須是他自己創(chuàng)建實(shí)例
- 必須有一個(gè)靜態(tài)變量保存這個(gè)類(lèi)的唯一實(shí)例
- 必須向系統(tǒng)提供這個(gè)實(shí)例
- 提供一個(gè)方法給外部獲取實(shí)例
實(shí)現(xiàn)的方式
1.1餓漢式
特點(diǎn):直接創(chuàng)建對(duì)象歧蒋,不存在線(xiàn)程問(wèn)題
- 直接餓漢
- 枚舉類(lèi)
- 靜態(tài)代碼塊實(shí)現(xiàn)餓漢式
/**
* 直接餓漢:
* 直接創(chuàng)建對(duì)象,不存在線(xiàn)程問(wèn)題
*
*/
public class Singleton01 {
//使用public州既,而且是final
public final static Singleton01 INSTANCE = new Singleton01();
//私有構(gòu)造
private Singleton01(){
}
}
/**
* 枚舉餓漢式
* 枚舉類(lèi)就是限定若干個(gè)實(shí)例
* 我們只限定一個(gè)實(shí)例就是單例模式
*/
public enum Singleton02 {
INSTANCE;
}
/**
* 靜態(tài)代碼塊的餓漢式
* 在靜態(tài)代碼可以編寫(xiě)一些設(shè)置屬性的方法谜洽,更靈活
*/
public class Singleton03 {
//使用public,而且是final
public final static Singleton03 INSTANCE ;
private String info ;
static {
Properties properties = new Properties();
try {
//讀取配置文件(提前在類(lèi)路徑下吴叶,寫(xiě)一個(gè)文件singleton/kv.properties)
properties.load(Singleton03.class.getClassLoader().getResourceAsStream("singleton/kv.properties"));
//讀取值
String info1 = properties.getProperty("info");
INSTANCE = new Singleton03(info1);
} catch (IOException e) {
throw new RuntimeException();
}
}
private Singleton03(){
}
private Singleton03(String info){
this.info = info;
}
1.2懶漢式
特點(diǎn): 延遲創(chuàng)建對(duì)象
- 普通懶漢式阐虚,有線(xiàn)程安全問(wèn)題
- 基于普通懶漢式,增加雙重校驗(yàn)鎖避免線(xiàn)程安全問(wèn)題
- 用靜態(tài)內(nèi)部類(lèi)實(shí)現(xiàn)蚌卤,也能適應(yīng)多線(xiàn)程環(huán)境
/**
* 普通懶漢式:
* 延遲加載实束,但是有線(xiàn)程安全問(wèn)題
*/
public class Singleton04 {
private static Singleton04 instance ;
private Singleton04(){
}
/**
* 調(diào)用獲取方法時(shí)才加載實(shí)例
* @return
*/
public static Singleton04 getInstance() {
if (null == instance){
try {
//設(shè)置一些阻礙奥秆,更容易暴露多線(xiàn)程中的問(wèn)題
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
instance = new Singleton04();
}
return instance;
}
}
public class TestSingleton04 {
public static void main(String[] args) {
/**
* 多線(xiàn)程環(huán)境
*/
Callable<Singleton04> singleton04Callable = () -> Singleton04.getInstance();
ExecutorService executorService = Executors.newFixedThreadPool(2);
Future<Singleton04> submit = executorService.submit(singleton04Callable);
Future<Singleton04> submit2 = executorService.submit(singleton04Callable);
try {
System.out.println(submit.get() == submit2.get());
System.out.println(submit.get());
System.out.println(submit2.get());
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}finally {
executorService.shutdown();
}
}
}
/**
* 雙重鎖校驗(yàn)的懶漢式:
* 延遲加載,且線(xiàn)程安全
*/
public class Singleton05 {
private static Singleton05 instance ;
private Singleton05(){
}
/**
* 調(diào)用獲取方法時(shí)才加載實(shí)例
* @return
*/
public static Singleton05 getInstance() {
//雙重鎖校驗(yàn)咸灿,提高了性能和安全
if (null == instance){
synchronized (Singleton05.class){
if (null == instance){
try {
//設(shè)置一些阻礙构订,更容易暴露多線(xiàn)程中的問(wèn)題
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
instance = new Singleton05();
}
}
}
return instance;
}
}
/**
* 靜態(tài)內(nèi)部類(lèi)實(shí)現(xiàn)的懶漢式:
* 延遲加載,且線(xiàn)程安全
*/
public class Singleton06 {
private Singleton06(){
}
/**
* 靜態(tài)內(nèi)部類(lèi)只有在調(diào)用時(shí)才會(huì)加載
*/
private static class Inner{
private static Singleton06 instance = new Singleton06();
}
/**
* 調(diào)用獲取方法時(shí)才加載實(shí)例
* @return
*/
public static Singleton06 getInstance() {
return Inner.instance;
}
}
3避矢、類(lèi)的初始化和實(shí)例的初始化(考點(diǎn):類(lèi)是怎么初始化的悼瘾?實(shí)例是怎么初始化的?多態(tài)性审胸?)
Q:求出輸出結(jié)果
public class Father {
private int i = test();
private static int j = method();
static {
System.out.println("(1)");
}
Father(){
System.out.println("(2)");
}
{
System.out.println("(3)");
}
public int test(){
System.out.println("(4)");
return 1;
}
public static int method(){
System.out.println("(5)");
return 1;
}
}
public class Son extends Father{
private int i = test();
private static int j = method();
static {
System.out.println("(6)");
}
Son(){
System.out.println("(7)");
}
{
System.out.println("(8)");
}
public int test(){
System.out.println("(9)");
return 1;
}
public static int method(){
System.out.println("(10)");
return 1;
}
public static void main(String[] args) {
Son son = new Son();
System.out.println();
Son son1 = new Son();
}
//解題步驟:
//第一步:類(lèi)的初始化:
//從main方法存在的類(lèi)開(kāi)始加載亥宿,也就是Son類(lèi),但是加載前要先加載他的父類(lèi)father的<clinit>()方法
//一個(gè)類(lèi)的初始化就是執(zhí)行< clinit >()方法歹嘹,且只會(huì)執(zhí)行一次
//< clinit >()方法由靜態(tài)類(lèi)變量顯式賦值代碼和靜態(tài)代碼塊組成箩绍,從上到下按順序執(zhí)行
//所以先輸出(5)(1)
//然后回到子類(lèi)的初始化,輸出(10)(6)
//第二步:實(shí)例的初始化
//執(zhí)行實(shí)例初始化是執(zhí)行<init>()方法尺上,<init>()方法可能重載有多個(gè)材蛛,有幾個(gè)構(gòu)造器就有幾個(gè)< init >()方法
// < init >()方法由非靜態(tài)實(shí)例變量顯式賦值代碼和非靜態(tài)代碼塊、對(duì)應(yīng)構(gòu)造器代碼組成
// 非靜態(tài)實(shí)例變量顯式賦值代碼和非靜態(tài)代碼塊從上到下順序執(zhí)行怎抛,而對(duì)應(yīng)構(gòu)造器的代碼最后執(zhí)行
// 每次創(chuàng)建實(shí)例對(duì)象卑吭,調(diào)用對(duì)應(yīng)構(gòu)造器,執(zhí)行的就是對(duì)應(yīng)的< init >()方法
// < init >()方法的首行是super()或super(實(shí)參列表)马绝,即對(duì)應(yīng)父類(lèi)的< init >()方法
// 所以執(zhí)行new Son()時(shí)豆赏,先執(zhí)行父類(lèi)的非靜態(tài)實(shí)例變量顯式賦值和非靜態(tài)代碼塊
//執(zhí)行父類(lèi) private int i = test();時(shí),由于該方法已被子類(lèi)重寫(xiě)富稻,this的指向?yàn)樽宇?lèi)掷邦,
//因此執(zhí)行的是子類(lèi)的method方法,輸出(9)
//然后執(zhí)行到父類(lèi)的非靜態(tài)代碼塊椭赋,輸出(3)
//最后才會(huì)執(zhí)行父類(lèi)的無(wú)參構(gòu)造函數(shù)抚岗,輸出(2)
//回到子類(lèi),遇到子類(lèi)的 private int i = test();時(shí)哪怔,輸出(9)
//執(zhí)行子類(lèi)的非靜態(tài)代碼塊宣蔚,輸出(8)
//最后才執(zhí)行子類(lèi)的無(wú)參構(gòu)造函數(shù),輸出(7)
/**最終結(jié)果:
(5)
(1)
(10)
(6)
(9)
(3)
(2)
(9)
(8)
(7)
(9)
(3)
(2)
(9)
(8)
(7)
*/
}
解題關(guān)鍵:
類(lèi)初始化的過(guò)程
- 一個(gè)類(lèi)要?jiǎng)?chuàng)建實(shí)例需要先加載并初始化該類(lèi)
- main方法所在的類(lèi)需要先加載和初始化
- 一個(gè)子類(lèi)的初始化需要先初始化父類(lèi)
- 一個(gè)類(lèi)的初始化就是執(zhí)行< clinit >()方法认境,且只會(huì)執(zhí)行一次
- < clinit >()方法由靜態(tài)類(lèi)變量顯式賦值代碼和靜態(tài)代碼塊組成
- 類(lèi)變量顯式賦值代碼和靜態(tài)代碼塊從上到下按順序執(zhí)行
- < clinit >()方法只執(zhí)行一次
實(shí)例初始化的過(guò)程
實(shí)例初始化就是執(zhí)行< init >()方法
- < init >()方法可能重載有多個(gè)胚委,有幾個(gè)構(gòu)造器就有幾個(gè)< init >()方法
- < init >()方法由非靜態(tài)實(shí)例變量顯式賦值代碼和非靜態(tài)代碼塊、對(duì)應(yīng)構(gòu)造器代碼組成
- 非靜態(tài)實(shí)例變量顯式賦值代碼和非靜態(tài)代碼塊從上到下順序執(zhí)行叉信,而對(duì)應(yīng)構(gòu)造器的代碼最后執(zhí)行
- 每次創(chuàng)建實(shí)例對(duì)象亩冬,調(diào)用對(duì)應(yīng)構(gòu)造器,執(zhí)行的就是對(duì)應(yīng)的< init >()方法
- < init >()方法的首行是super()或super(實(shí)參列表)硼身,即對(duì)應(yīng)父類(lèi)的< init >()方法
4鉴未、方法的參數(shù)傳遞機(jī)制
Q:以下代碼的輸出結(jié)果是枢冤?
/**
* 參數(shù)的傳遞機(jī)制
*/
public class TestParameter {
public static void main(String[] args) {
int i = 1;
String str = "hello";
Integer num = 200;
int[] arr = {1,2,3,4,5};
MyData my = new MyData();
change(i,str,num,arr,my);
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 = " + my.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;
}
}
class MyData{
int a = 10;
}
結(jié)果:
i = 1
str = hello
num = 200
arr = [2, 2, 3, 4, 5]
my.a = 11
分析:
- 1、形參是基本數(shù)據(jù)類(lèi)型
- 傳遞數(shù)據(jù)值
- 2铜秆、實(shí)參是引用數(shù)據(jù)類(lèi)型
- 傳遞地址值
- 特色的類(lèi)型:String、包裝類(lèi)等對(duì)象不可變性
5讶迁、遞歸
時(shí)間復(fù)雜度连茧?
空間復(fù)雜度?
Q:求N步的臺(tái)階巍糯,有多少種走法啸驯?
實(shí)現(xiàn)方式:
1、遞歸
//遞歸實(shí)現(xiàn) 01
public int f01(int n){
if (n < 1){
return 0;
}
if (n == 1 || n == 2){
return n;
}
return f01(n-1) + f01(n-2);
}
2祟峦、迭代
/**
* 迭代實(shí)現(xiàn) 02
* @param n
* @return
*/
public long f02(int n){
if (n < 1){
return 0;
}
if (n == 1 || n == 2){
return n;
}
//初始化:走第一級(jí)臺(tái)階有一種走法罚斗,走第二級(jí)臺(tái)階有兩種走法
int first = 1, second = 2;
int third = 0;
//把每次計(jì)算的結(jié)果保存在變量中,避免重復(fù)計(jì)算
for (int i = 3; i <= n; i++) {
third = first + second;
first = second;
second = third;
}
return third;
}