第三章
- Java是一種強類型語言。https://blog.csdn.net/qq_36192099/article/details/79464196
- 在Java中,整型的范圍與機器無關。
int 4字節
short 2字節
long 8字節
byte 1字節 - 子串:Substring
拼接:String.join
String類對象是不可變字符,可通過substring+”” 改變字符串變量
不能用==來比較字符串,應該用equals。一個常量和一個變量比較,推薦把常量寫在前面 - 任何一個Java對象都可以轉換成字符串
- 輸入輸出
首先要構造一個Scanner對象。
Scanner類有各種方法,nextLine()讀取一行,next()讀取一個單詞,nextInt()讀取一個整數,nextDouble()讀取一個浮點數。 - Java提供了一種帶標簽的break語句。只能跳出語句塊,而不能跳入語句塊。
- 大數值BigInteger類
- for each循環:
for(int element:a) System.out.println(element);
底層使用的是迭代器,所以在遍歷的過程中,不能對集合中的元素進行增刪。目標只能是Collection或者是數組。
-
Arrays.copyOf可以拷貝數組,如果直接b=a,拷貝的是數組地址值,改變b會改變a
第四章、對象和類
- 類之間最常見的關系有
依賴(uses-a):一個類的方法操縱另一個類的對象。盡可能的將相互依賴的類減至最小。
聚合(has-a):以為着類A的對象包含類B的對象
繼承(is-a): - 構造器(構造方法)用來構造並初始化對象。通過new關鍵字構造一個新對象。構造器與其他方法有一個重要的不同,構造器總是伴隨new操作符的執行被調用,而不能對一個已經存在的對象調用構造器來打到重新設置實例域的目的。構造器沒有返回值
- 一個對象變量並沒有實際包含一個對象,而僅僅引用一個對象,如:
Date deadline = new Date();
有兩個部分。New Date()構造了一個Date類型的對象,它的值是新創建的對象的引用。這個引用儲存在deadline中。
- 靜態域、靜態方法(用static修飾)伴隨着類一直存在。靜態方法通過類名調用。調用靜態方法不需要創建實例(這也是main是靜態方法的原因)。https://www.cnblogs.com/LZL-student/p/5861365.html,靜態方法只能訪問靜態域。
- 在下面兩種情況下使用靜態方法:
一個方法不需要訪問對象狀態,其所需參數都是通過顯示參數提供(如:Math.pow)
一個方法只需要訪問類的靜態域 - Java中方法參數的總結(Java中都是值傳遞,而不是引用傳遞):
一個方法不能修改一個基本數據類型的參數(數值型或布爾型)
一個方法可以改變一個對象參數的狀態
一個方法不能讓對象參數引用一個新的對象(Java中值傳遞的體現) - 當且僅當類沒有提供任何構造器時,系統才會提供一個默認的構造器。
- 類設計技巧:P144
第五章、繼承
- this的兩個主要用途:一是引用隱式參數,二是調用該類其他的構造器;
super的兩個主要用途:一是調用超類的方法,二是調用超類的構造器。
調用構造器時,兩者很相似,調用構造器的語句只能作為另一個構造器的第一條語句出現。 - Java不支持多繼承。Java中多繼承可通過接口實現。
- 多態、向上轉型和向下轉型:https://www.cnblogs.com/betterluo/p/10959239.html
- 父子類構造方法:子類構造方法必須調用父類構造方法。不寫則有一個默認super()自動調用父類無參構造方法,如果父類沒有無參構造方法,會報錯,這時需在子類重載父類已有的有參數的構造方法即可。而且super重載必須是子類構造方法的第一句。
- 子類重寫方法的返回值范圍必須【小於等於】父類方法的返回值。例如父類返回值是void,子類是int,報錯;父類返回值是Object,子類是String,不報錯。
子類方法的權限必須【大於等於】父類方法的權限修飾符 - 關於靜態綁定和動態綁定:https://www.cnblogs.com/betterluo/p/10927746.html
- final:一個方法被聲明為final,子類不能覆蓋重寫這個方法。一個域被聲明為final,構造對象之后不能改變值。一個類聲明為final,只是其中的方法自動成為final,不包括類中的域。
- 內聯:如果一個方法沒有被覆蓋並且很短,編譯器就能夠對它進行優化處理,這個過程稱為內聯。(挖個坑,以后學到JVM時來填)
- 抽象方法必須在抽象類中
- 抽象類除了抽象方法,還可以包含具體數據和具體方法。例如Person類可以保存姓名和一個返回姓名的具體方法
public abstract class Person { private String name; public Person(String name) { this.name = name; } public abstract String getDescription(); public String getNmame(); { return name; } }
盡量將通用的域和方法(不管是否是抽象的)放在超類(不管是否是抽象類)中。
- 類即使不含抽象方法,也可以將類聲明為抽象類。
抽象類不能被實例化,如果將一個類聲明為abstract,就不能創建這個類的對象
注意:可以定義一個抽象類的對象變量,但是它只能引用非抽象子類的對象。例如Person p = new Student("Vince Vu", "Economics"); //p是一個抽象類Person的變量,Person引用了一個非抽象子類Student的實例
可以理解為多態/向上轉型
-
只有基本類型不是對象,例如:數值、字符、布爾類型的值。
- Object中的equals方法,如果是基本類型比較的是值,如果是對象比較的是地址值。String重寫了equals方法,比較的是兩字符串的內容是否相等。https://www.cnblogs.com/dolphin0520/p/3592500.html。數組可以使用靜態的Arrays.equals檢測相應的數組元素是否相等。重寫equals來比較兩個對象的建議:P169。IDEA直接可以自動生成重寫的equals和toString方法。。。
重寫equals,記得參數列表為(Object other)。(重寫:在繼承中,方法的名稱一樣,參數列表也一樣;重載:方法名稱一樣,參數列表不一樣)
getClass()是使用反射技術來判斷對象所屬的類。 - 不同的兩個對象可能會有相同的散列碼,所以重寫equals就必須重寫hashCode方法。P170。https://www.cnblogs.com/dolphin0520/p/3681042.html
- toString是一種很好的調試工具。數組可通過Arrays.toString。建議每一個類都添加toString方法
- ArrayList:https://www.cnblogs.com/betterluo/p/10965464.html
- 自動裝箱和拆箱:
有一個很有用的特性,便於添加int的元素到ArrayList<Integer>:
list.add(3);
將自動變換成
list.add(Integer.valueOf(3));
這種變化稱為自動裝箱(autoboxing)(基本類型的數據->包裝類)
相反地,當一個Integer對象賦給一個int值時,將會自動的拆箱(包裝類->基本類型的數據),包裝類無法直接參與運算
int n = list.get(i);
自動變成
int n = list.get(i).intValue();
在算數表達式中也能夠自動的裝箱和拆箱
Integer n = 3; n++;
編譯器將自動地插入一條對象拆箱的指令,然后進行自增計算,最后再將結果裝箱。
比較兩個包裝器對象時要調用equals,如果用==可能會出錯。 - 包裝器中包含了一些基本方法,如一個整數字符串轉換成數值
int x = Integer.parseInt(s);
這里與Integer對象沒有任何關系,parseInt是一個靜態方法,Interger類只是放置這個方法的地方。
Integer.toString()可以把一個整數轉換成字符串 - Integer對象是不可變的:包含在包裝器中的內容不會改變。所以
public static void triple(Integer x) // won't work { ... }
不會改變參數值。
org.omg.CORBA包中定義持有者(holder)類型,可以訪問儲存在其中的值,進而改變參數值。 - 參數數量可變的方法
1.一個方法只能有一個可變參數;2.如果方法的參數有多個,那么可變參數要寫在參數的末尾public static int max(int... values){ int lagest=0; for (int i = 0; i < values.length ; i++) { if(values[i]>lagest) lagest=values[i]; } return lagest; } //可變參數的特殊(終極)寫法 public static void method(Object...obj){ }
- 枚舉類型實際上是一個類,例如
public enum Size {SMALL, MEDIUM, LARGE, EXTRA_LARGE };
這個聲明定義的類型是一個類,它剛好有4個實例。
比較兩個枚舉類型的值,永遠不要用equals,用==。
枚舉類型中可以添加一些構造器、方法和域。 - 反射(之后再回來看)
- Class類:Object中的getClass()方法可以返回一個Class類型的實例。
- 繼承的設計技巧:P208
第六章、接口、lambda表達式與內部類
- 接口中的所有方法自動地屬於public,聲明時可省略。但是在實現接口時,必須把方法生命為public
- 接口中的變量其實是常量,接口不允許有實例域(常量)
- 實現Arrays中的sort方法:https://blog.csdn.net/qq_37856300/article/details/84940888
- 接口中的方法自動被設置為public,接口中的域自動設為public static final。java語言規范建議不要書寫這些多余的關鍵字。
- 引用接口,而不是只用抽象類的原因是一個類只能繼承一個類,但是可以實現多個接口
- 接口的默認方法與靜態方法:https://www.cnblogs.com/dustcode/p/10007969.html
接口的默認方法可以通過接口實現類對象,直接調用
接口的默認方法可以被接口實現類覆蓋重寫
默認方法的主要優勢是拓展接口的方法,而不破壞現有代碼。 - 解決默認方法沖突:
①超類優先:如果繼承了一個類,實現了一個接口,那么超類優先
②接口沖突:如果實現了兩個接口有想通的方法,必須通過覆蓋來解決沖突 - lambda
- 內部類包括成員內部類、局部內部類和匿名內部類
- 如何使用成員內部類:
間接方式:
在外部類的方法中,使用內部類,在外部類方法中創建內部類對象,通過內部類對象調用內部類方法,main只是調用外部類的方法。通過外部類的對象,調用外部類的方法,里面間接再使用內部類
public class Outer { public class Inner{ public void show(){ System.out.println("內部類的方法"); } } public void method(){ System.out.println("外部類的方法"); Inner inner = new Inner(); //創建內部類對象 inner.show(); //通過內部類對象調用內部類方法 } }
//通過調用外部類對象,調用外部類的方法 public class Main { public static void main(String[] args) { Outer outer = new Outer(); outer.method(); } }
直接方式://類名稱 對象名 = new 類名稱(); //【外部類名稱.內部類名稱 對象名 = new 外部類名稱().new 內部類名稱();】 public class Main { public static void main(String[] args) { Outer.Inner inner = new Outer().new Inner(); inner.show(); } }
-
內部類既可以訪問自身的數據域,也可以訪問創建它的外圍類對象的數據域。(內用外,隨意訪問;外用內,需要先建立內部類對象,通過內部類對象訪問)
沒重名可直接調用外部類數據域,如果重名,通過【外部類名稱.this.外部類成員變量名】來調用。public class Outer { private int num = 100; public class Inner{ final int num = 200; public void show(){ int num = 300; System.out.println(num);//300 System.out.println(this.num);//200 System.out.println(Outer.this.num);//100 } } }
- 局部內部類定義:如果一個類是定義在一個方法內部的,那么這就是一個局部內部類。“局部”:只有當前所屬的方法才能使用它,除了這個方法外面就不能用了。
訪問局部內部類,是通過調用外部類包含該內部類的方法
public class Outer { public void methodOuter(){ class Inner { int num = 10; public void methodInner() { System.out.println(num); } } Inner inner = new Inner(); inner.methodInner(); } public static void main(String[] args) { Outer obj = new Outer(); obj.methodOuter(); } }
- 類的權限修飾符:
public > protected > (default) >private
定義一個類的時候,權限修飾符:
①外部類:public / (default)
②成員內部類:public / protected / (default) / private
③局部內部類:什么都不能寫 - 局部內部類想訪問所在方法的局部變量,這個局部變量必須是【有效final的】,即final或者沒有更改過的
class Outer { public void methodOuter(){ final int num = 5; // num = 9; 錯誤 class Inner { public void methodInner() { System.out.println(num); } } } }
- 匿名內部類:如果接口的實現類,(或者是父類的子類)只需要使用唯一的一次,那么這種情況下就可以省略該類的定義,二改為使用【匿名內部類】。
/* 匿名內部類格式 接口名稱 對象名 = new 接口名稱(){ //覆蓋重寫所有抽象方法 }; //注意要有分號 */ public static void main(String[] args){ //匿名內部類 MyInterface obj = new MyInterface(){ //new代表創建對象的動作 //接口名稱是匿名內部類需要實現的接口 @Override //大括號中的內容才是匿名內部類的內容 public void method(){ } }; obj.method(); } /* 注意: 1.匿名內部類,在【創建對象】的時候,只能使用唯一一次。如果希望多次創建對象,而且類的內容一樣的話,那么就必須使用單獨定義的實現類了。 2.匿名對象,在【調用方法】的時候,只能調用唯一一次。如果希望同一個對象,調用多次方法,那么必須給對象起一個名字。 3.匿名內部類是省略了【實現類/子類名稱】,但是匿名對象是省略了【對象名稱】。匿名內部類和匿名對象不是一碼事!!
匿名內部類作用:不用專門寫一個類來實現接口,直接使用匿名內部類調用接口。
如果想重復使用,就不要用任何匿名的東西。不管是匿名內部類還是匿名對象。//如果有兩個對象,要寫兩遍 //使用匿名內部類 MyInterface objA = new MyInterface(){ @Override public void method(){ System.out.println("匿名內部類實現了方法!"); } }; objA.method(); MyInterface objB = new MyInterface(){ @Override public void method(){ System.out.println("匿名內部類實現了方法!"); } }; objB.method();
匿名對象://使用了匿名內部類,而且省略了對象名稱,也是匿名對象 new MyInterface(){ @Override public void method1(){ System.out.println("匿名對象匿名內部類實現了方法1"); } @Override public void method2(){ System.out.println("匿名對象匿名內部類實現了方法2"); } }.method1(); //匿名對象只能調用一次方法 //如果還想調用method2還要創建一個新的匿名對象 new MyInterface(){ @Override public void method1(){ System.out.println("匿名對象匿名內部類實現了方法1"); } @Override public void method2(){ System.out.println("匿名對象匿名內部類實現了方法2"); } }.method2(); //如果想重復使用,就不要用任何匿名的東西
- 內部類是一種編譯器現象,與虛擬機無關