zoukankan      html  css  js  c++  java
  • 多态动手动脑

    多态动手动脑

    一、怎样判断对象是否可以转换?可以使用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("请选择:");
        }
        }

    结果:

  • 相关阅读:
    SqlServer 数据库同步的两种方式 (发布、订阅),主从数据库之间的同步
    Haproxy+Heartbeat 高可用集群方案操作记录
    HAProxy+Keepalived高可用负载均衡
    Centos 6/7 忘记root密码处理方法
    Centos 7配置nginx反向代理负载均衡集群
    各种官网系统镜像文件
    Tomcat通过Redis实现session共享的完整部署记录
    ELK平台搭建及日志监控
    快速搭建ELK日志分析系统
    idea各种快捷键
  • 原文地址:https://www.cnblogs.com/kailugaji/p/6081624.html
Copyright © 2011-2022 走看看