一、怎樣判斷對象是否可以轉換?可以使用instanceof運算符判斷一個對象是否可以轉換為指定的類型,參看實例: TestInstanceof.java
public class TestInstanceof { public static void main(String[] args) { //聲明hello時使用Object類,則hello的編譯類型是Object,Object是所有類的父類 //但hello變量的實際類型是String Object hello = "Hello"; //String是Object類的子類,所以返回true。 System.out.println("字符串是否是Object類的實例:" + (hello instanceof Object)); //返回true。 System.out.println("字符串是否是String類的實例:" + (hello instanceof String)); //返回false。 System.out.println("字符串是否是Math類的實例:" + (hello instanceof Math)); //String實現了Comparable接口,所以返回true。 System.out.println("字符串是否是Comparable接口的實例:" + (hello instanceof Comparable)); String a = "Hello"; //String類既不是Math類,也不是Math類的父類,所以下面代碼編譯無法通過 //System.out.println("字符串是否是Math類的實例:" + (a instanceof Math)); } }
二、下列語句哪一個將引起編譯錯誤?為什麼?哪一個會引起運行時錯誤?為什麼?
m=d;
d=m;
d=(Dog)m;
d=c;
c=(Cat)m;
先進行自我判斷,得出結論後,運行TestCast.java實例代碼,看看你的判斷是否正確
class Mammal{} class Dog extends Mammal {} class Cat extends Mammal{} public class TestCast { public static void main(String args[]) { Mammal m; Dog d=new Dog(); Cat c=new Cat(); m=d; //d=m; d=(Dog)m; //d=c; //c=(Cat)m; } }
d=m;
d=c;
c=(Cat)m;
這三句話有錯。
三、請看以下“變態”的類(參看示例ParentChildTest.java),運行以下測試代碼,並回答問題:1.程序運行結果是什麼?2.你如何解釋會得到這樣的輸出?3.計算機是不會出錯的,之所以得到這樣的運行結果也是有原因的,那麼從這些運行結果中,你能總結出Java的哪些語法特性?
public class ParentChildTest { public static void main(String[] args) { Parent parent=new Parent(); parent.printValue(); Child child=new Child(); child.printValue(); parent=child; parent.printValue(); parent.myValue++; parent.printValue(); ((Child)parent).myValue++; parent.printValue(); } } class Parent{ public int myValue=100; public void printValue() { System.out.println("Parent.printValue(),myValue="+myValue); } } class Child extends Parent{ public int myValue=200; public void printValue() { System.out.println("Child.printValue(),myValue="+myValue); } }
1、結果:
2、Java語法特性:
(1)當子類與父類擁有一樣的方法,並且讓一個父類變量引用一個子類對象時,到底調用哪個方法,由對象自己的“真實”類型所決定,這就是說:對象是子類型的,它就調用子類型的方法,是父類型的,它就調用父類型的方法。
這個特性實際上就是面向對象“多態”特性的具體表現。
(2)如果子類與父類有相同的字段,則子類中的字段會代替或隱藏父類的字段,子類方法中訪問的是子類中的字段(而不是父類中的字段)。如果子類方法確實想訪問父類中被隱藏的同名字段,可以用super關鍵字來訪問它。如果子類被當作父類使用,則通過子類訪問的字段是父類的!
四、請使用javap查看編譯器為TestPolymorphism.java生成的字節碼指令,然後通過互聯網搜索資料,嘗試從底層開始理解Java編譯器是如何為多態代碼生成字節碼指令,在程序運行過程中,多態特性又是如何實現的。
class Parent1 { public int value=100; public void Introduce() { System.out.println("I'm father"); } } class Son extends Parent1 { public int value=101; public void Introduce() { System.out.println("I'm son"); } } class Daughter extends Parent1 { public int value=102; public void Introduce() { System.out.println("I'm daughter"); } } public class TestPolymorphism { public static void main(String args[]) { Parent1 p=new Parent1(); p.Introduce();//子類的方法 System.out.println(p.value);//父類的變量對象 p=new Son(); p.Introduce(); System.out.println(p.value); p=new Daughter(); p.Introduce(); System.out.println(p.value); } }
結果:
五、在實例中理解多態的含義與用途
1、三種動物對應三個類,每個類定義一個eat()方法,表示吃飼養員給它們的食物,再設計一個Feeder類代表飼養員,其name字段保存飼養員名字,三個方法分別代表喂養三種不同的動物,其參數分別引用三種動物對象。
package Zoo1; public class Zoo { public static void main(String args[]) { Feeder f = new Feeder("小李"); // 飼養員小李喂養一只獅子 f.feedLion(new Lion()); // 飼養員小李喂養十只猴子 for (int i = 0; i < 10; i++) { f.feedMonkey(new Monkey()); } // 飼養員小李喂養5只鴿子 for (int i = 0; i < 5; i++) { f.feedPigeon(new Pigeon()); } } } class Feeder { public String name; public Feeder(String name) { this.name = name; } public void feedLion(Lion l) { l.eat(); } public void feedPigeon(Pigeon p) { p.eat(); } public void feedMonkey(Monkey m) { m.eat(); } } class Lion { public void eat() { System.out.println("我不吃肉誰敢吃肉!"); } } class Monkey { public void eat() { System.out.println("我什麼都吃,尤其喜歡香蕉。"); } } class Pigeon { public void eat() { System.out.println("我要減肥,所以每天只吃一點大米。"); } }
2、第一次程序重構:引入繼承,簡化Feeder類
package Zoo2; public class Zoo { public static void main(String args[]) { Feeder f = new Feeder("小李"); //飼養員小李喂養一只獅子 f.feedAnimal(new Lion()); //飼養員小李喂養十只猴子 for (int i = 0; i < 10; i++) { f.feedAnimal(new Monkey()); } //飼養員小李喂養5只鴿子 for (int i = 0; i < 5; i++) { f.feedAnimal(new Pigeon()); } } } class Feeder { public String name; Feeder(String name) { this.name = name; } public void feedAnimal(Animal an) { an.eat(); } } abstract class Animal { public abstract void eat(); } class Lion extends Animal { public void eat() { System.out.println("我不吃肉誰敢吃肉!"); } } class Monkey extends Animal { public void eat() { System.out.println("我什麼都吃,尤其喜歡香蕉。"); } } class Pigeon extends Animal { public void eat() { System.out.println("我要減肥,所以每天只吃一點大米。"); } }
3、第二次程序重構,修改feedAnimals方法,讓它接收一個Animal數組……
package Zoo3; public class Zoo { public static void main(String args[]) { Feeder f = new Feeder("小李"); Animal[] ans = new Animal[16]; //飼養員小李喂養一只獅子 ans[0] = new Lion(); //飼養員小李喂養十只猴子 for (int i = 0; i < 10; i++) { ans[1 + i] = new Monkey(); } //飼養員小李喂養5只鴿子 for (int i = 0; i < 5; i++) { ans[11 + i] = new Pigeon(); } f.feedAnimals(ans); } } class Feeder { public String name; Feeder(String name) { this.name = name; } public void feedAnimals(Animal[] ans) { for (Animal an : ans) { an.eat(); } } } abstract class Animal { public abstract void eat(); } class Lion extends Animal { public void eat() { System.out.println("我不吃肉誰敢吃肉!"); } } class Monkey extends Animal { public void eat() { System.out.println("我什麼都吃,尤其喜歡香蕉。"); } } class Pigeon extends Animal { public void eat() { System.out.println("我要減肥,所以每天只吃一點大米。"); } }
4、第三次重構,修改feedAnimals方法,讓其接收一個元素數目可變的對象容器。
package Zoo4; import java.util.Vector; public class Zoo { public static void main(String args[]) { Feeder f = new Feeder("小李"); Vector<Animal> ans = new Vector<Animal>(); //飼養員小李喂養一只獅子 ans.add(new Lion()); //飼養員小李喂養十只猴子 for (int i = 0; i < 10; i++) { ans.add(new Monkey()); } //飼養員小李喂養5只鴿子 for (int i = 0; i < 5; i++) { ans.add(new Pigeon()); } f.feedAnimals(ans); } } class Feeder { public String name; Feeder(String name) { this.name = name; } public void feedAnimals(Vector<Animal> ans) { for (Animal an : ans) { an.eat(); } } } abstract class Animal { public abstract void eat(); } class Lion extends Animal { public void eat() { System.out.println("我不吃肉誰敢吃肉!"); } } class Monkey extends Animal { public void eat() { System.out.println("我什麼都吃,尤其喜歡香蕉。"); } } class Pigeon extends Animal { public void eat() { System.out.println("我要減肥,所以每天只吃一點大米。"); } }
5、從這個示例中可以看到,通過在編程中應用多態,可以使我們的代碼具有更強的適用性。當需求變化時,多態特性可以幫助我們將需要改動的地方減少到最低限度。
多態編程有兩種主要形式:
(1)繼承多態:示例程序使用的方法
(2)接口多態:使用接口代替抽象基類。
使用多態最大的好處是:
當你要修改程序並擴充系統時,你需要修改的地方較少,對其它部分代碼的影響較小!千萬不要小看這兩個“較”字!程序規模越大,其優勢就越突出。
六、用多態的方法模擬ATM操作流程。
//王榮榮 2016/11/18 import java.util.Scanner; class PersonalAccount{ private String passWord="123456";//密碼 private String number;//銀行卡號 private int money=0; public int getMoney(){ return money; }//余額 public void setPw(String s){ passWord=s; }//設置密碼 public void addMoney(int x){ money+=x; }//加錢 public void minusMoney(int x){ money-=x; }//減錢 public boolean whetherPwTrue(String s){//密碼是否正確 if(s.equals(passWord)) return true; else return false; } } abstract class PATM{ abstract boolean withdraw(int x);//取款 abstract void save(int x);//存款 abstract boolean transfer(String s,int x);//轉賬 abstract boolean ifPass(String s);//判斷輸入的密碼是否正確 abstract int getRest();//查詢余額 abstract void setPassword(String s);//設置密碼 } class ATM extends PATM{ private String numbers[]={"123451","123452", "123453","123454","123455"};//數據庫中已有的賬戶卡號 private PersonalAccount account=new PersonalAccount(); public boolean withdraw(int x) { if(x>account.getMoney()) return false; else{ account.minusMoney(x); return true; } } public void save(int x) { account.addMoney(x); } public boolean transfer(String s, int x) { //轉賬 //先判斷轉到賬戶號是否存在 //再判斷余額是否足夠 boolean flag=false; for(int i=0;i<numbers.length;i++) if(s.equals(numbers[i])) flag=true; if(x>account.getMoney()) flag=false; if(x<=account.getMoney()&&flag) account.minusMoney(x);; return flag; } public boolean ifPass(String s) { return account.whetherPwTrue(s); } public int getRest() { return account.getMoney(); } public void setPassword(String s) { account.setPw(s); } } public class Atm1 { public static void main(String[] args) { Scanner in=new Scanner(System.in); ATM atm=new ATM(); int choose=0,num=0; String pw=""; next:while(true){ System.out.println("是否進入賬戶(0否1是):"); int kk=in.nextInt(); if(kk==0) break; else if(kk!=1){ System.out.println("輸入錯誤!"); continue; } System.out.println("輸入賬戶密碼:"); pw=in.next(); if(atm.ifPass(pw)){ while(true){ showFace(); choose=in.nextInt(); switch(choose){ case 1: System.out.println("輸入存款金額:"); num=in.nextInt(); atm.save(num); System.out.println("存款成功!"); System.out.println("當前余額:"+atm.getRest()+"元"); break; case 2: System.out.println("請選擇:"); int a[]={100,500,1000,1500,2000,5000}; for(int i=0;i<a.length;i++) System.out.println((i+1)+"."+a[i]+"元"); System.out.println("7.其他"); int ch=in.nextInt(); if(ch>=1&&ch<=6){ if(atm.withdraw(a[ch-1])) System.out.println("取款成功!"); else System.out.println("余額不足!"); } else if(ch==7){ System.out.println("請輸入取款金額:"); num=in.nextInt(); if(atm.withdraw(num)) System.out.println("取款成功!"); else System.out.println("余額不足!"); } else System.out.println("輸入有誤!"); System.out.println("當前余額:"+atm.getRest()+"元"); break; case 3: System.out.println("賬戶號:"); String s=in.next(); System.out.println("轉賬金額:"); int i=in.nextInt(); if(atm.transfer(s, i)) System.out.println("轉賬成功!"); else System.out.println("轉賬失敗!"); System.out.println("當前余額:"+atm.getRest()+"元"); break; case 4: System.out.println("輸入六位數密碼:"); String p=in.next(); atm.setPassword(p); break; case 5: System.out.println("當前余額:"+atm.getRest()+"元"); break; default: continue next; } } } else System.out.println("密碼錯誤!"); } } //顯示菜單方法 public static void showFace(){ System.out.println("1.存款"); System.out.println("2.取款"); System.out.println("3.轉賬匯款"); System.out.println("4.修改密碼"); System.out.println("5.查詢余額"); System.out.println("6.退卡"); System.out.println("請選擇:"); } }
結果: