# Core JAVA Note # Ch5 繼承 1. 繼承父類語法 建構子 & 註解方式 若要調用父類別的參數可用super(…param) 若要調用父類別的方法可用super.method() ```java= public class Employee(...){ //atttrbite //constructor public void getSalary(){ return this.salry; } } public class Manager extends Employee{ private int bouns; //attribute super(attribue); public void getSalary(){ int salary = super.getSalary(); return baseSalary + bonus; } } ``` 2. 在一個方法的多型中,若父類為private,子類也必須為private,若宣告為final則不能再被繼承 3. 利用instanceof來確認是否可以進行型態轉換 4. 抽象使用時機:當「多個類別(Class)」之間有共同的方法(function)或屬性(attribute)時,可以將這些共用的地方寫成「抽象類別(Abstract Class)」,讓其他的「子類別(Class)」去繼承。 5. 在abstract class中盡量不要有具體方法。若需要則放在subclass or superclass。 ## 5.抽象類別宣告方式 ```java= //一個關於Person基本資訊 public abstract class Person { private String name ; private String address; public abstract String getDescription(); public Person(String name, String address) { name = name; address = address; } public String getName() { return name; } } ``` 在抽象類別中不實做,而是在擴展子類別中完成實作: ```java= public class Student extends Person{ private String major; public Student (String name , String major){ super(name); this.major = major; } public String getDescription() { return String.format("this major in ", major); } } ``` ## 6.修飾子 **Private**:僅限類別內部 使用,無論是子類別、任何外部類別,都不準直接存取。 **Protected**:限同一package成員直接存取,其它package的成員,必須透過繼承的方式,才可以在子類別中存取該成員。 **Public**:可以被所有成員 存取,為最廣之存取範圍。 ## 7.相等測試 在類型測試時,盡量不要用 ```instanceof```,看下例: ```java= if(!(otherObject insanceof Employee)) return false; ``` 這樣就允許otherObject屬於一個子類別。但是這樣會有一個問題:我們還是拿Employee和Mnager舉例子,我們調用```Employee.equals(Manager)``` 和```Manager.equals(Employee)``` 的結果會不一樣,這違反了Java語言規範要求equals()方法的對稱性。 * 對稱性 - 對於任何引用x和y,當且僅當y.equals(x) 返回true, x.equals(y) 也應該返回true * 如果子類可以有自己的相等性概念,則對稱性需求將強制使用getClass檢測。 * 如果父類決定相等性概念,那麼就可以使用instanceof字符來檢測,這樣可以在不同子類的對象之間進行相等性比較 ## 8.ArrayList ### ArrayList是Collection的子介面List的實作類別 * **建立 ArrayList** ```java= ArrayList<Employee> staff = new ArrayList<Employee>(); var staff = new ArrayList<>(); ``` * **加入元素 add(object o)** ```java= staff.add(new Employee("tom", ..., ...)); ``` * **陣列大小 size()** ```java= staff.size(); ``` * **取得資料 get(int index)** ```java= Employee e = staff.get(i); ``` * **設置資料 set(int index, object o)** ```java= staff.set(1, harry); ``` 以下的Code可以使ArrayList達到靈活且容易取得內部資料: ```java= var list = new ArrayList<>(X); while(...){ x = ...; list.add(x); //利用toArray()複製a到list中 var a = new X[list.size()]; list.toArray(a); } ``` Note: * 不必指定ArrayList大小 * 使用```size()```而不是用length() * 使用```a.get(i)```而不是a[i]來取得元素 ## 9.Wrapper and autoboxing Java中有兩個型態系統,**基本型態**與**類別型態** ,使用基本型態目的在於效率,然而更多時候,會使用類別建立實例,因為物件本身可以攜帶更多資訊,如果要讓基本型態像物件一樣操作,可以使用Long、Integer、Double、Float、Boolean、Byte等類別來包裹(Wrap)基本型態。 ```java= //J2SE 5.0後可以自動裝箱 //也可以自動拆箱(Auto unboxing),也就是自動取出包裹器中的基本形態資訊。例如: Integer wrapper = 10; // 自動裝箱 int foo = wrapper; // 自動拆箱 ``` ## 9.進階enum ```java= enum Size { SMALL("S"), MEDIUM("M"), LARGE("L"), EXTRA_LARGE("XL"); private String abbreviation; private Size(String abbreviation) { this.abbreviation = abbreviation; } public String getAbbreviation() { return abbreviation; } } ``` --- # Ch6 Interface lambda ## 1.Interface * 定義屬性成員皆為常數 (即預設 public static final),因此必須給定初始值 * 定義方法時,只能為抽象方法 (即預設 public abstract,定義功能的名稱,實作部分留給相關類別 override ```java= public interface Moveable{ public abstract void move(double x, double y ) } ``` #### Interface vs Abstract : 一個Abstract class只能繼承一次,Interface class可以拓展很多次: ```java= public interface Power extends Moveable{ double milesPerGallon(); } ``` Java8 開始多了 default 關鍵字,可替介面加上預設實作: ```java= public interface Compareable<T>{ default int compareTo(T other){ return 0; } } ``` 剛剛定義了移動的介面,接下來實作出Car class ```java= class CarMove implements Moveable{ double speed; public CarMove(s){ this.speed = s; } public void move(double x, double y ){ x++; y++; } } ``` ## 2.Interface defult衝突 ```java= interface Person{ default String getName(){ return ;}; } interface Name{ default String getName(){ return ;}; } //此時若有一個class同時實作上述 interface將會產生衝突 class Student implements Person, Named{ public String getName(){return ....} } ``` 因此,可以將Code改成: ```java= class Student implements Person, Named{ public String getName(){ return Person.super.getName(); } } ``` ## 2.Object clone ```java= var o = new employee("john"); emplyee copy = o.clone(); copy.raisesalary(10); ``` ## 3.Lambda **將匿名函數複製給變量的簡寫方式的函數稱為 lambda 表達式。** **Lambda表達式本身就是一個介面的實現。(將interface new 出來後,實現class)** ```java= //一般寫法 Runnable runnbale = new Runnable() { public void run() { System.out.println("run me!"); } }; //lambda寫法 Runnable runnbale = () -> System.out.println("run me!"); //利用lambda來寫function interface //一般寫法 public static void main(String[] args) { ActionListener listener = new TimePrinter(); Timer t = new Timer(10000, listener); } class TimePrinter implements ActionListener { public void actionPerformed(ActionEvent event) { System.out.println("At the tone, the time is " + new Date()); Toolkit.getDefaultToolkit().beep(); } } //lambda 寫法 Timer t = new Timer(1000, event -> System.out.println("The time is " + new Date())); t.start(); ``` lamda還有方法引用,可以將println直接傳遞到建構子中 ```java= var timer = new Timer(1000,System.out::println) ``` note: * Java lambda 類似於 Js arrow function,例: ```javascript= var x = () => { console.log("run me") } ``` * lambda引述外部變數會有問題 ```java= public static void reapeatMsg(string text, int delay){ ActionListener listener = event -> { //這樣會有併發問題 system.out.println(text) } } ``` ## 4.內部類 使用時機:GUI開發 & 事件處理的監聽器 * 成員內部類 ```java= class Car { private int year; // A member inner class named Tire public class Tire { private double radius; public Tire(double radius) { this.radius = radius; } public double getRadius() { return radius; } } // Member inner class declaration ends here ``` ## 5.Comparator interface 1.compare(Object obj1, Object obj2) ```java= humans.sort( (Human h1, Human h2) -> h1.getName().compareTo(h2.getName())); ``` # Ch7 異常控制 **異常控制基本精神** * 退回到安全狀態,並讓使用者可以執行其他命令 * 保存上次的結果,並能退出 **需要考慮到的情境** * 使用者的輸入錯誤 * 設備錯誤 * 物理限制 * 程式碼錯誤 ## 異常分類 所有的異常類別都是由Throwable中的實例 ![](https://i.imgur.com/9fQD6M0.png) 1. 聲明檢查異常 ```java= public image loadImage(String s) throws IOException{ ... } ``` 2. 拋出異常 ```java= String readData(Scanner in) throws EOFException{ while(...){ ... throw new EOFException(); } } ``` 3. 自建異常 ```java= public class MyException extends Exception { private int detail; MyException(int a) { detail = a; } public String toString(int detail) { return "MyException = " + detail; } } class ExceptionDemo { static void computer(int a ) throws MyException{ System.out.println("call compute:" + a); if(a > 10){ throw new MyException(a); }else { System.out.println("all ok"); } } public static void main(String[] args) { try { computer(1); computer(20); } catch (MyException e) { System.out.println("error: " + e); } } } ``` ![](https://i.imgur.com/byA6hmu.png) 4. try-catch-finally ```java= var in = new FileInputStream(...); try{ //1 }catch{ //2 }finally{ in.close(); } ``` 5. try-with-resource ```java= public static void main(String[] args) throws Exception { try (MyAutoCloseable myAutoClosable = new MyAutoCloseable()) { myAutoClosable.doIt(); } } public class MyAutoCloseable implements AutoCloseable { @Override public void close() throws Exception { System.out.println("close"); } public void doIt() { System.out.println("MyAutoClosable doing it!"); } } ``` ## assertion(斷言) * 基本用於開發測試環境 ```java= //啟用assertion java -ea:MyClass ``` ## Logger 1. 基本日誌 ```java= Logger.getGlobal().info("File -> open menu item selected") ``` 2. 級別 ``` Logger的級別: SEVERE 嚴重 WARNING 警告 INFO 資訊 CONFIG 配置 FINE 良好 FINER 較好 FINEST 最好 ``` logger預設的級別是INFO,比INFO更低的日誌將不顯示。 Logger的預設級別定義是在安裝目錄的lib下面的logging.properties。 java.util.logging.ConsoleHandler.level = INFO ```java= selfie = person.shootASelfie(); try { selfie.show(); } catch (NullPointerException e) {} ``` A: ```java= selfie = person.shootASelfie(); try { selfie.show(); } catch (NullPointerException e) { throw new NullPointerException("it's null pointer");; } ``` # Ch8 泛型 ## 泛型基本概念 在Java增加泛型機制之前就已經有一個ArrayList類,這個ArrayList類的泛型概念是使用繼承來實現的。 ```java= public class ArrayList { private Object[] elementData; public Object get(int i) {....} public void add(Object o) {....} } ``` 這個類存在兩個問題: 當獲取一個值的時候必須進行強制類型轉換 沒有錯誤檢查,可以向陣列中添加任何類的物件 ## 泛型基本寫法 ```java= //Object<ClassName> arrayListName; ArrayList<Employee> x = new ArrayList<Employee>(); ``` ```java= List<IHat> hats = new ArrayList<>(); hats.add(new Ushanka()); // that one has ear flaps hats.add(new Fedora()); hats.add(new Sombrero()); for (IHat hat : hats) { if (hat.hasEarFlaps()) { hats.remove(hat); } } ``` ```java= public class IHat { private int price; private String size; private String color; public IHat() { } public int getPrice() { return price; } public String getSize() { return size; } public String getColor() { return color; } } ``` ## 定義一個簡單的泛型 ```java= public class Pair<T>{ private T first; private T second; public Pair(){ first == null ;second == null}; public Pair(T first , T second){ this.first = first , this.second = second; } //getter } ``` note:<T>:為類型變數,<E>:表示變數,<K,V>為鍵和值 可以用具體的類型來實例化: ```java= Pair<String> x; ``` ## 帶有型別參數的方法 接著,我們可以定義一個帶有型別參數的方法 而泛型方法可以在一般的class中定義,也可以在泛型中定義 ```java= class ArrayAlg{ public static <T> T getMiddle(T ...a){ return a[a.length/2]; } } ``` 當未來我們要調用此方法時,可以像這樣寫: ```java= String middle = Array.<String>getMiddle(...) ``` ## 型別變數的限定 有時候我們對型別變數會有些約束,如下程式碼會有些問題存在: ```java= class ArrayAlg{ public static <T> T min(T[] a) { if( a == null ) return null; T small = a[0]; for(int i = 1 ; i<a.length() ; a++){ if(small.compareTo(a[i])) { small = a[i]; } return small; } } ``` 在上面的程式碼中,無法確定T是否有compareTo的方法 所以我們可以改寫為: ```java= pubic static <T extends comparable> T min<T[] a>... ``` ## 型別擦除 Java在編譯期間,所有的泛型資訊都會被擦掉,下列程式碼證明Java型別的型別擦除: ```java= public class Test { public static void main(String[] args) { ArrayList<String> list1 = new ArrayList<String>(); list1.add("abc"); ArrayList<Integer> list2 = new ArrayList<Integer>(); list2.add(123); System.out.println(list1.getClass() == list2.getClass()); } } ``` 上述說明泛型型別String和Integer都被擦除掉了,只剩下原始型別。 ## 泛型限制 1. 泛型型別變數不能是基本型別 ```java= //error ArrayList<double> x = new ArrayList<double>(); ``` 2. 編譯時的instanceof ArrayList<String> arrayList = new ArrayList<String>(); 因為型別擦除之後,ArrayList<String>只剩下原始型別,泛型資訊String不存在了。 那麼,編譯時進行型別查詢的時候使用下面的方法是錯誤的 ```java= if( arrayList instanceof ArrayList<String>) ``` 3. 無法創建型別參數的實例 ```java= public static <E> void append(List<E> list) { E elem = new E(); // compile-time error list.add(elem); } ``` 但是可以這樣做: ```java= public static <E> void append(List<E> list, Class<E> cls) throws Exception { E elem = cls.newInstance(); // OK list.add(elem); } ``` 最後這樣調用他: ```java= List<String> ls = new ArrayList<>(); append(ls, String.class); ``` 4. 不能創建參數化的陣列 ```java= var Table = new Pair<String>[10]; ``` 5. 不能聲明型別是型別參數的靜態字段: ```java= public class MobileDevice<T> { private static T os; // ... } ``` 因為下列程式碼會造成混淆: ```java= MobileDevice<Smartphone> phone = new MobileDevice<>(); MobileDevice<Pager> pager = new MobileDevice<>(); MobileDevice<TabletPC> pc = new MobileDevice<>(); ``` 6. 泛型不能直接或間接地擴展Throwable ```java= // Extends Throwable indirectly class MathException<T> extends Exception { /* ... */ } // compile-time error // Extends Throwable directly class QueueFullException<T> extends Throwable { /* ... */ // compile-time error ``` 但是,可以在throws 子句中使用類型參數: ```java= class Parser<T extends Exception> { public void parse(File file) throws T { // OK // ... } } ``` ## 泛型的繼承規則 若Employee與Manerger一個為class另一個為subclass,那Pair<Manerger>是Pair<Employee>的子類嗎? 答案是不是 ```java= Manerger[] top = ...; Pair<Employee> result = ArrayAlg.minmax(top);//error ``` ## 型態通配字元(Wildcard) 假設使用 GenericFoo 類別來如下宣告名稱: ```java= GenericFoo<Integer> foo1 = null; GenericFoo<Boolean> foo2 = null; ``` 那麼名稱 foo1 就只能參考 GenericFoo<Integer> 類型的實例,而名稱 foo2 只能參考 GenericFoo<Boolean> 類型的實例,也就是說下面的方式是可行的: ```java= foo1 = new GenericFoo<Integer>(); foo2 = new GenericFoo<Boolean>(); ``` 但是有這麼一個需求,foo 可以如下接受所指定的實例,讓foo可以接受兩個實例 ```java= foo = new GenericFoo<ArrayList>(); foo = new GenericFoo<LinkedList>(); ``` 那可以改寫成 ```java= GenericFoo<? extends List> foo = null; foo = new GenericFoo<ArrayList>(); ..... foo = new GenericFoo<LinkedList>(); .... ``` 上述<? extends List> 表示型態未知,只知會是實作 List 介面的類別,屬於向上限制 除了可以向上限制,也可以向下限制,只要使用 "super" 關鍵字,例如: ```java= GenericFoo<? super StringBuilder> foo = null; ``` foo 就只接受 StringBuilder 及其上層的父類型態,也就是只能接受 GenericFoo<StringBuilder> 與 GenericFoo<Object> 的實例。 # Ch9 Collection ![](https://i.imgur.com/hPWDobq.png) ![](https://i.imgur.com/tQvLAJW.png) ## LinkedList ```java= public class LinkedListTest { public static void main(String[] args) { List<String> a = new LinkedList<>(); a.add("Amy"); a.add("Carl"); a.add("Erica"); List<String> b = new LinkedList<>(); b.add("Bob"); b.add("Doug"); b.add("Frances"); b.add("Gloria"); // merge the words from b into a ListIterator<String> aIter = a.listIterator(); Iterator<String> bIter = b.iterator(); while (bIter.hasNext()) { if (aIter.hasNext()) aIter.next(); aIter.add(bIter.next()); } System.out.println(a); // remove every second word from b bIter = b.iterator(); while (bIter.hasNext()) { bIter.next(); // skip one element if (bIter.hasNext()) { bIter.next(); // skip next element bIter.remove(); // remove that element } } System.out.println(b); // bulk operation: remove all words in b from a a.removeAll(b); System.out.println(a); } } ``` ## Set ```java= public class SetTest { public static void main(String[] args) { Set<String> words = new HashSet<>(); // HashSet implements Set long totalTime = 0; try (Scanner in = new Scanner(System.in)) { while (in.hasNext()) { String word = in.next(); long callTime = System.currentTimeMillis(); words.add(word); callTime = System.currentTimeMillis() - callTime; totalTime += callTime; } } Iterator<String> iter = words.iterator(); for (int i = 1; i <= 20 && iter.hasNext(); i++) System.out.println(iter.next()); System.out.println(". . ."); System.out.println(words.size() + " distinct words. " + totalTime + " milliseconds."); } } ``` ## TreeSet ```java= public class TreeSetTest { public static void main(String[] args) { SortedSet<Item> parts = new TreeSet<>(); parts.add(new Item("Toaster", 1234)); parts.add(new Item("Widget", 4562)); parts.add(new Item("Modem", 9912)); System.out.println(parts); NavigableSet<Item> sortByDescription = new TreeSet<>( Comparator.comparing(Item::getDescription)); sortByDescription.addAll(parts); System.out.println(sortByDescription); } } ``` ## Priority queue ```java= public class PQTest { public static void main(String[] args) { PriorityQueue<LocalDate> pq = new PriorityQueue<>(); pq.add(LocalDate.of(1906, 12, 9)); // G. Hopper pq.add(LocalDate.of(1815, 12, 10)); // A. Lovelace pq.add(LocalDate.of(1903, 12, 3)); // J. von Neumann pq.add(LocalDate.of(1910, 6, 22)); // K. Zuse System.out.println("Iterating over elements..."); for (LocalDate date : pq) System.out.println(date); System.out.println("Removing elements..."); while (!pq.isEmpty()) System.out.println(pq.remove()); } } ``` Result: ![](https://i.imgur.com/TNZe7l8.png) ## Map ```java= public class MapTest { public static void main(String[] args) { Map<String, EmployeeForMap> staff = new HashMap<>(); staff.put("144-25-5464", new EmployeeForMap("Amy Lee")); staff.put("567-24-2546", new EmployeeForMap("Harry Hacker")); staff.put("157-62-7935", new EmployeeForMap("Gary Cooper")); staff.put("456-62-5527", new EmployeeForMap("Francesca Cruz")); // print all entries System.out.println(staff); // remove an entry staff.remove("567-24-2546"); // replace an entry staff.put("456-62-5527", new EmployeeForMap("Francesca Miller")); // look up a value System.out.println(staff.get("157-62-7935")); // iterate through all entries staff.forEach((k, v) -> System.out.println("key=" + k + ", value=" + v)); } } public class EmployeeForMap { private String name; private double salary; public EmployeeForMap(String name) { this.name = name; salary = 0; } public String toString() { return "[name=" + name + ", salary=" + salary + "]"; } } ``` ### IdentityHashMap ```java= public class AddingElementsToIdentityHashMap { public static void main(String[] args) { // Creating an empty IdentityHashMap Map<Integer, String> identity_hash = new IdentityHashMap<Integer, String>(); // Mapping string values to int keys // using put() method identity_hash.put(10, "Geeks"); identity_hash.put(15, "4"); identity_hash.put(20, "Geeks"); identity_hash.put(25, "Welcomes"); identity_hash.put(30, "You"); // Displaying the IdentityHashMap System.out.println("Initial Mappings are: " + identity_hash); // Inserting existing key along with new value // previous value gets returned and stored in // returned_value String returned_value = (String)identity_hash.put(20, "All"); // Verifying the returned value System.out.println("Returned value is: " + returned_value); // Displaying the new map System.out.println("New map is: " + identity_hash); // Creating a new Identityhash map and copying Map<Integer, String> new_Identityhash_map = new IdentityHashMap<Integer, String>(); new_Identityhash_map.putAll(identity_hash); // Displaying the final IdentityHashMap System.out.println("The new map: " + new_Identityhash_map); } } ``` ![](https://i.imgur.com/CL8fP2n.png) **HashMap 與 IdentityHashMap主要差異:** ![](https://i.imgur.com/0ET2g04.png) ## 排序 ```java= public class ShuffleTest { public static void main(String[] args) { List<Integer> numbers = new ArrayList<>(); for (int i = 1; i <= 49; i++) numbers.add(i); Collections.shuffle(numbers); List<Integer> winningCombination = numbers.subList(0, 6); Collections.sort(winningCombination); System.out.println(winningCombination); } } ```
{"metaMigratedAt":"2023-06-16T08:43:27.714Z","metaMigratedFrom":"Content","title":"Core JAVA Note","breaks":true,"contributors":"[{\"id\":\"5ab386fa-9b07-4b0c-a740-d1ef5cf00a9a\",\"add\":21217,\"del\":1134}]"}
    217 views