今天要學的是 Abstract Classes
Animal.java
public abstract class Animal {
private String name; public Animal(String name) {
this.name = name;
} public abstract void eat();
public abstract void breathe();
public String getName() {
return name;
}
}
Dog.java
public class Dog extends Animal{
public Dog(String name) {
super(name);
} @Override
public void eat() {
System.out.println(getName() + " is eating");
} @Override
public void breathe() {
System.out.println(getName() + " was breathe in and out repeat");
}
}
Bird.java
public class Bird extends Animal {
public Bird(String name) {
super(name);
} @Override
public void eat() {
System.out.println(getName() + " is pecking.");
} @Override
public void breathe() {
System.out.println(getName() + " was breathe in and out repeat.");
}
}
MainAnimal.java
public class MainAnimal {
public static void main(String[] args) {
Dog dog = new Dog("Husky");
dog.breathe();
dog.eat(); Bird bird = new Bird("WenWen");
bird.breathe();
bird.eat();
}
}
輸出結果:
Husky was breathe in and out repeat
Husky is eating
WenWen was breathe in and out repeat.
WenWen is pecking.
Animal 就是 Abstract Classes
簡單的說就是其他 Class 的模板
跟 Interface 相似的地方為 一樣不寫實際功能
實際功能寫在子類繼承裡
如 Dog 跟 Bird
Bird.java 修改
public abstract class Bird extends Animal {
public Bird(String name) {
super(name);
}
@Override
public void eat() {
System.out.println(getName() + " is pecking.");
} @Override
public void breathe() {
System.out.println(getName() + " was breathe in and out repeat.");
}
public abstract void fly();
}
現在把 Bird 也改成 Abstract Classes
但是在 MainAnimal.java 裡就會報錯
因為跟 Interface 一樣
Abstract Classes 也不能直接實例化
就像 List 一樣不能直接 new
MainAnimal.java 修改
public class MainAnimal {
public static void main(String[] args) {
// Dog dog = new Dog("Husky");
// dog.breathe();
// dog.eat(); Parrot parrot = new Parrot("Rainbow");
parrot.breathe();
parrot.eat();
parrot.fly();
}
}
輸出結果:
Rainbow was breathe in and out repeat.
Rainbow is pecking.
Rainbow was jumping to another tree branch
Penguin.java
public class Penguin extends Bird{
public Penguin(String name) {
super(name);
} @Override
public void fly() {
System.out.println(getName() + ", I am just a penguin.");
}
}
MainAnimal.java 修改
public class MainAnimal {
public static void main(String[] args) {
// Dog dog = new Dog("Husky");
// dog.breathe();
// dog.eat();// Parrot parrot = new Parrot("Rainbow");
// parrot.breathe();
// parrot.eat();
// parrot.fly(); Penguin penguin = new Penguin("Happy feet");
penguin.breathe();
penguin.eat();
penguin.fly();
}
}
輸出結果:
Happy feet was breathe in and out repeat.
Happy feet is pecking.
Happy feet, I am just a penguin.
CanFly.java
public interface CanFly {
void fly();
}
Bird.java 修改
public abstract class Bird extends Animal implements CanFly {
public Bird(String name) {
super(name);
}
@Override
public void eat() {
System.out.println(getName() + " is pecking.");
} @Override
public void breathe() {
System.out.println(getName() + " was breathe in and out repeat.");
} @Override
public void fly() {
System.out.println(getName() + " is flapping own wings.");
}
}
Parrot.java 修改
public class Parrot extends Bird{
public Parrot(String name) {
super(name);
}
}
Penguin.java 修改
public class Penguin extends Bird{
public Penguin(String name) {
super(name);
} @Override
public void fly() {
super.fly();
System.out.println(getName() + ", I am just a penguin.");
}
}
MainAnimal.java 修改
public class MainAnimal {
public static void main(String[] args) {
// Dog dog = new Dog("Husky");
// dog.breathe();
// dog.eat(); Parrot parrot = new Parrot("Rainbow");
parrot.breathe();
parrot.eat();
parrot.fly(); Penguin penguin = new Penguin("Happy feet");
penguin.breathe();
penguin.eat();
penguin.fly();
}
}
輸出結果:
Rainbow was breathe in and out repeat.
Rainbow is pecking.
Rainbow is flying.
Happy feet was breathe in and out repeat.
Happy feet is pecking.
Happy feet is flying.
Happy feet, I am just a penguin.
小挑戰:
For this challenge, create an abstract class to define items that can be stored in a list.
The class should contain 2 references to items which will represent the next and previous
items (in the case of a linked list).
I.e., if you call your abstract class ListItem, then it would have 2 member variables of
type ListItem that will hold references to the next/right and previous/left ListItems.
The abstract class will also need to hold a value — try to be as flexible as possible
when defining the type of this value.
The class will also need methods to move to the next item and back to the previous item,
and methods to set the next and previous items.
You should also specify a compareTo() method that takes a parameter of the same type as the
class and returns 0 if the values are equal, greater than zero if the value sorts greater than
the parameter and less than zero if it sorts less than the parameter.
Create a concrete class from your abstract list item class and use this in a LinkedList
class to implement a linked list that will add items in order (so that they are sorted
alphabetically). Duplicate values are not added.
Note that you are creating your own LinkedList class here, not using the built-in Java one..
The rules for adding an item to the linked list are:
If the head of the list is null, make the head refer to the item to be added.
If the item to be added is less than the current item in the list, add the item before the
current item (i.e., make the previous item’s “next” refer to the new item, and the new item’s
“next” refer to the current item).
If the item to be added is greater than the current item, move onto the next item and compare
again (if there is no next item then that is where the new item belongs).
Care will be needed when inserting before the first item in the list (as it will not have a previous
item).
You will also need a method to remove an item from the list.
Hint: If you are creating classes with names such as List, LinkedList, Node etc, make sure that
you create your classes before referring to them. In previous videos we have often referred to
classes that we create later, but if you use names that IntelliJ recognises as Java classes (such
as LinkedList) then it will create imports for them and possibly cause you problems later.
Optional: create a class to use your concrete class to implement a Binary Search Tree:
When adding items to a Binary Search Tree, if the item to be added is less than the current item
then move to the left, if it is greater than the current item then move to the right.
The new item is added when an attempt to move in the required direction would involve following a
null reference.
Once again, duplicates are not allowed.
Hint: to avoid typing loads of “addItem” lines, split a string into an array and create your list in
a loop as in the example below.
Create a string data array to avoid typing loads of addItem instructions:
參考解答:
ListItem.java
public abstract class ListItem {
protected ListItem rightLink = null;
protected ListItem leftLink = null; protected Object value; public ListItem(Object value) {
this.value = value;
} abstract ListItem next(); abstract ListItem setNext(ListItem rightLink); abstract ListItem previous(); abstract ListItem setPrevious(ListItem rightLink); abstract int compareTo(ListItem item); public ListItem getRightLink() {
return rightLink;
} public ListItem setRightLink(ListItem rightLink) {
return this.rightLink = rightLink;
} public ListItem getLeftLink() {
return leftLink;
} public ListItem setLeftLink(ListItem leftLink) {
return this.leftLink = leftLink;
} public Object getValue() {
return value;
} public void setValue(Object value) {
this.value = value;
}
}
Node.java
public class Node extends ListItem {
public Node(Object value) {
super(value);
} @Override
ListItem next() {
return getRightLink();
} @Override
ListItem setNext(ListItem rightLink) {
return setRightLink(rightLink);
} @Override
ListItem previous() {
return getLeftLink();
} @Override
ListItem setPrevious(ListItem leftLink) {
return setLeftLink(leftLink);
} /**
* if compare result is same, return 0
* https://www.runoob.com/java/java-string-compareto.html
*/
@Override
int compareTo(ListItem item) {
if (item != null) {
return ((String) getValue()).compareTo((String) item.getValue());
}
return -1;
}
}
NodeList.java (interface)
public interface NodeList {
ListItem getRoot(); boolean addItem(ListItem item); boolean removeItem(ListItem item); void traverse(ListItem root);
}
MyLinkedList.java
public class MyLinkedList implements NodeList {
private ListItem root; public MyLinkedList(ListItem root) {
this.root = root;
} @Override
public ListItem getRoot() {
return this.root;
} @Override
public boolean addItem(ListItem newItem) {
if (this.root == null) {
// This list was empty.
this.root = newItem;
return true;
} ListItem currentItem = this.root;
while (currentItem != null) {
int comparison = currentItem.compareTo(newItem);
if (comparison < 0) {
// newItem is greater than current item in Alphabetical order
if (currentItem.next() != null) {
// move right if possible
currentItem = currentItem.next();
} else {
// there is not next, just insert new item to right
currentItem.setNext(newItem);
// and set previous pointer
// if don't set previous, current item will reset to null;
newItem.setPrevious(currentItem);
return true;
}
} else if (comparison > 0) {
// newItem is smaller than current item in Alphabetical order
// we already move to correct position, insert new item to left
if (currentItem.previous() != null) {
// Need to reset previous and next pointer to correct item
currentItem.previous().setNext(newItem);
newItem.setPrevious(currentItem.previous());
newItem.setNext(currentItem);
currentItem.setPrevious(newItem);
} else {
// current item is root and had no previous item
newItem.setNext(this.root);
this.root.setPrevious(newItem);
// reset new item to root
this.root = newItem;
}
return true; } else {
// find the same item in the list
System.out.println(newItem.getValue() + " was already in the list");
return false;
}
} System.out.println("Error, adding new item function.");
return false;
} @Override
public boolean removeItem(ListItem delItem) {
ListItem currentItem = this.root;
while (currentItem != null) {
int comparison = currentItem.compareTo(delItem);
if (comparison == 0) {
// find the match item
if (currentItem == this.root) {
// match item is root
this.root = currentItem.next();
} else {
//check here
currentItem.previous().setNext(currentItem.next());
if (currentItem.next() != null) {
currentItem.next().setPrevious(currentItem.previous());
}
}
System.out.println(delItem.getValue() + " is deleting.");
return true;
} else if (comparison < 0) {
// delete item is greater than current item in Alphabetical order
currentItem = currentItem.next();
} else {
return false;
}
}
System.out.println("Error, remove item function, no item in the list.");
return false;
} @Override
public void traverse(ListItem root) {
if (root == null) {
System.out.println("The list is empty.");
} else { while (root != null) {
System.out.println(root.getValue());
root = root.next();
} }
}
}
SearchTree.java
public class SearchTree implements NodeList { private ListItem root; public SearchTree(ListItem root) {
this.root = root;
} @Override
public ListItem getRoot() {
return this.root;
} @Override
public boolean addItem(ListItem newItem) {
if (this.root == null) {
// the tree was empty
this.root = newItem;
return true;
} ListItem currentItem = this.root;
while (currentItem != null) {
int comparison = (currentItem.compareTo(newItem));
if (comparison < 0) {
// newItem is greater than current item in Alphabetical order
if (currentItem.next() != null) {
// move to right if possible
currentItem = currentItem.next();
} else {
// there's no node to the right, so add to the right
currentItem.setNext(newItem);
return true;
}
} else if (comparison > 0) {
// newItem is smaller than current item in Alphabetical order
if (currentItem.previous() != null) {
// move to left if possible
currentItem = currentItem.previous();
} else {
// there's no node to the lett, so add to the lett
currentItem.setPrevious(newItem);
return true;
}
} else {
// comparison == 0, new item already in the tree
System.out.println(newItem.getValue() + " is already in tree.");
return false;
}
} return false;
} @Override
public boolean removeItem(ListItem item) {
// tomorrow check
if (item != null) {
System.out.println("Deleting item " + item.getValue());
}
ListItem currentItem = this.root;
ListItem parentItem = currentItem; while (currentItem != null) {
int comparison = currentItem.compareTo(item);
if (comparison < 0) {
parentItem = currentItem;
currentItem = currentItem.next();
} else if (comparison > 0) {
parentItem = currentItem;
currentItem = currentItem.previous();
} else {
performRemoval(currentItem, parentItem);
return true;
}
} return false;
} private void performRemoval(ListItem currentItem, ListItem parentItem) {
if (currentItem.next() == null) {
if (parentItem.next() == currentItem) {
parentItem.setNext(currentItem.previous());
} else if (parentItem.previous() == currentItem) {
parentItem.setPrevious(currentItem.previous());
} else {
this.root = currentItem.previous();
}
} else if (currentItem.previous() == null) {
if (parentItem.next() == currentItem) {
parentItem.setNext(currentItem.next());
} else if (parentItem.previous() == currentItem) {
parentItem.setPrevious(currentItem.next());
} else {
this.root = currentItem.next();
}
} else {
ListItem current = currentItem.next();
ListItem leftmostParent = currentItem;
while (current.previous() != null) {
leftmostParent = current;
current = current.previous();
}
currentItem.setValue(current.getValue());
if (leftmostParent == currentItem) {
currentItem.setNext(current.next());
} else {
leftmostParent.setPrevious(current.next());
}
}
} @Override
public void traverse(ListItem root) {
// recursive method
if (root != null) {
traverse(root.previous());
System.out.println(root.getValue());
traverse(root.next());
} }
}
MainMyLinkedList.java
public class MainMyLinkedList {
public static void main(String[] args) {// MyLinkedList list = new MyLinkedList(null);
// String stringData = "Darwin Brisbane Perth Melbourne Canberra Adelaide Sydney Canberra";
// String[] data = stringData.split(" ");
// for (String s : data) {
// list.addItem(new Node(s));
// }
// list.traverse(list.getRoot());
// MyLinkedList list = new MyLinkedList(null);
// String stringData = "7 5 3 9 1 2 8 0 4 6";
// String[] data = stringData.split(" ");
// for (String s : data) {
// list.addItem(new Node(s));
// }
// list.removeItem(new Node("3"));
// list.removeItem(new Node("2"));
// list.removeItem(new Node("1"));
// list.removeItem(new Node("0"));
// list.traverse(list.getRoot());
//
// list.removeItem(new Node("6"));
// list.removeItem(new Node("4"));
// list.removeItem(new Node("5"));
// list.traverse(list.getRoot());
//
// list.removeItem(new Node("7"));
// list.removeItem(new Node("8"));
// list.removeItem(new Node("9"));
// list.traverse(list.getRoot()); SearchTree list = new SearchTree(null);
String stringData = "7 5 3 9 1 2 8 0 4 6";
// String stringData = "Darwin Brisbane Perth Melbourne Canberra Adelaide Sydney Canberra";
String[] data = stringData.split(" ");
for (String s : data) {
list.addItem(new Node(s));
} list.removeItem(new Node("3"));
list.removeItem(new Node("2"));
list.removeItem(new Node("1"));
list.removeItem(new Node("0"));
list.traverse(list.getRoot()); list.removeItem(new Node("6"));
list.removeItem(new Node("4"));
list.removeItem(new Node("5"));
list.traverse(list.getRoot()); list.removeItem(new Node("7"));
list.removeItem(new Node("8"));
list.removeItem(new Node("9"));
list.traverse(list.getRoot()); }
}
這個挑戰我也是直接看解答
這次連題目都看不懂了
就算看懂了估計也寫不出來
我連抄完代碼後,要整個搞懂都花了不少時間
簡單的來說,題目是叫我們模仿寫出 Linked List
不直接使用系統預設的 Linked List
而是自創出 Linked List
關鍵在於 fields 裡
放入兩個相同的 Class
一個當作 左 或 前
一個當作 右 或 後
這樣每創一個 Class 就相當於創了三個 Class
剩下的就是寫 Method 做數據的操作
P.S protect 只是保護資料,只在同個 package 能被看見
白話的說就是
我現在把表格加入一個數據 A
A 還會產生出 左 跟 右
現在要加入第二個數據 B
由於我想按大小排序
我就把 A 的 右 設成 B
一開始是 A左(空)、A本位(A) 、A右(空)
加入 B 後,就是
A左(空)、A本位和B左(A) 、A右跟B本位(B)、B右
括弧裡面的是寫入的資料
括弧左邊則是表的位置
要對裡面的資料做操作,我就直接看表的位置在哪,然後去操作就好
加分題還涉及到 Binary Search Tree
這又是另一個觀念了
另外還使用到 遞歸
這遞歸還不是我以前看過的
一個 Method 裡面只有一行代碼的那種
在 Traverse 中,裡面就分別使用了兩次遞歸
我光開 Debug 弄懂程序走到哪了
就已經消耗許多腦力
這個題目對我這初學者來說
真的複雜跟難到爆炸
拆成 3~6 個挑戰可能會比較合理
我把代碼的邏輯都寫在註釋裡了
這裡就不重複敘述
隨著學到越多東西
越來越覺得發明這些的人
一定是天才中的天才中的天才
我這種凡人不要說發明了
能把這些觀念弄懂7成
我就已經覺得自己好棒棒了