• 原来你是这样的JAVA[03]-继承、多态、抽象类


    一、继承


    Java中的继承使用关键字extends ,跟C#的语法略有差别。

    1.子类构造器


    java会自动在子类的构造器中插入对父类构造器的调用,也就是说在子类可以访问父类之前已经完成了父类的初始化。
    如果想调用带参数的父类构造器,应该使用super关键字。

    /**
      * @author 陈敬
      * @date 18/1/17
      */
    public class Product {
         private String name;
    
        public Product(String name) {
             this.name = name;
             System.out.println("[Product constructor]");
         }
    }
    
    public class Bread extends Product {
         private int price;
    
        public Bread(String name, int price) {
             super(name);//调用父类构造器
             this.price = price;
             System.out.println("[Bread constructor]");
         }
    }

    我们创建一个Bread类的实例,看看调用顺序。

    @Test
    public void testConstructor(){
         Bread bread=new Bread("毛毛虫面包",10);
    }

    打印结果:
    [Product constructor]
    [Bread constructor]

    2.调用父类方法


    子类是不能直接访问到父类的私有域的,如果想访问只能借助父类公开的get访问器。子类调用父类中的方法也需要使用super关键字。

    public class Product {
        private String name;
    
        public String getName() {
            return name;
        }
    
        public Product(String name) {
            this.name = name;
        }
    }
    public class Bread extends Product {
        public Bread(String name) {
            super(name);
        }
    
        public void display(){
            System.out.println(getName());
        }
    }

    然后写个单元测试:

       @Test
        public void testPrivate(){
            Bread bread=new Bread("毛毛虫面包");
            bread.display();//毛毛虫面包
        }

    需要说明一点,super并不是一个对象的引用,不能将super赋值给变量,它只是一个特殊的关键字,告诉编辑器要调用父类中的方法。

    3.关于重载


    如果父类中存在重载方法,子类又进行了重载,会覆盖父类中的方法吗?实际上,父类和子类中的方法都可以正常重载,不会被覆盖。
    首先在父类Product中添加方法getDescription():

    public class Product {
         ……
    
        public String getDescription() {
             return "[Product]name="+name;
         }
    }

    然后在子类中重载该方法:

    public class Bread extends Product {
         ……
    
        public String getDescription(String storeName) {
            return "[Bread]storename="+storeName;
         }
    }

    增加一个单元测试:

    public class ExtendClassTests {
         @Test
         public void testOverload(){
             Bread bread=new Bread("豆沙面包",9);
             System.out.println(bread.getDescription());
             System.out.println(bread.getDescription("味多美"));
         }
    }

    输出:
    [Product]name=豆沙面包
    [Bread]storename=味多美

    4.继承准则


    继承准则:尽量少用继承。一般用继承表达行为间的差异,用组合表示状态上的变化。

    二、多态

    1.变量多态


    在Java中对象变量是多态的,一个Product变量可以引用Product对象,也可以引用一个Product子类的对象。

    @Test
    
    public void testParent(){
    Product product=new Bread("毛毛虫面包",10);
    product.display();

    //强制类型转换
    if(product instanceof Bread){
    Bread brand=(Bread)product;
    brand.display("味多美");
    }
    }

    由于Bread实例向上转型为Product类型,所以不能再调用Bread.getDescription(String storeName)方法。
    如果需要将父类强制转换为子类时,要先通过instanceof检测对象类型,我们最好尽量避免使用强制类型转换。

    2.动态绑定


    所谓动态绑定,就是在运行时根据对象的类型决定要调用的方法。在java中,动态绑定是默认行为,不需要添加额外的关键字实现多态。

    再写个demo来看一下,在父类和子类中重载了display方法。

    public class Product {
         private String name;
    
        public Product(String name) {
             this.name = name;
         }
    
        public void display() {
             System.out.println("[Product]getDescription()");
         }
    }
    
    public class Bread extends Product {
         private int price;
    
        public Bread(String name, int price) {
             super(name);
             this.price = price;
         }
    
        @Override
         public void display() {
             System.out.println("[Bread]getDescription()");
         }
         public void display(String storeName) {
             System.out.println("[Bread]getDescription(String storeName)");
         }
    }

    添加单元测试:

    @Test
    public void dynamicBind(){
         Product product=new Product("product");
         product.display();  //[Product]getDescription()
    
        Bread bread=new Bread("毛毛虫",9);
         bread.display();  //[Bread]getDescription()
         bread.display("maimai");  //[Bread]getDescription(String storeName)
    
        Product product1=bread;
         product1.display();  //[Bread]getDescription()
    }

    虚拟机为每个类创建一个方法表,列出所有方法的签名和实际调用的方法。这样一来,当动态调用方法的时候,只需要查找方法表就能快速的找到真正调用的方法了。
    Product:
         display()->Product.display()
    Bread:
         display()->Bread.display()
         display(String name)->Bread.display(String name)
     
    完整源码参见:https://github.com/cathychen00/cathyjava     /_08_extend

    三、抽象类

    定义抽象方法用用abstract关键字,它仅有声明而没有方法体。
    包含抽象方法的类叫做抽象类,如果一个类包含一个或多个抽象方法,那么必须被定义为抽象类。
    如果一个类从抽象类继承,那么必须为抽象类中的所有抽象方法提供实现,否则该类也必须被定义为抽象类。
    看一个场景:我们有一些定时任务,要进行的工作流程类似,只有具体一部分细节内容不同。我们可以定义一个抽象基类BaseJob,再不同的部分封装为抽象方法,具体的实现在子类中进行。

    public abstract class BaseJob {
         public void run(){
             System.out.println("==START "+getDescription()+"==");
             String lastJobId=getLastJobId();
             execute(lastJobId);
             writeLog();
             System.out.println("==END "+getDescription()+"==");
         }
    
        protected abstract String getDescription();
    
        protected abstract void execute(String jobId);
    
        private void writeLog() {
             System.out.println("write log to DB");
         }
    
        private String getLastJobId() {
             return "job1221";
         }
    }
    public class ArticleJob extends BaseJob {
         @Override
         protected String getDescription() {
             return "抓取文章任务";
         }
    
        @Override
         protected void execute(String jobId) {
             System.out.println("抓取站点新闻文章 jobid="+jobId);
         }
    
        public static void main(String[] args) {
             BaseJob articleJob=new ArticleJob();
             articleJob.run();
         }
    }

    创建单元测试,调用ArticleJob看看。

    @Test
    public void articleJob(){
         BaseJob articleJob=new ArticleJob();
         articleJob.run();
    }

    运行结果:

    ==START 抓取文章任务==
    抓取站点新闻文章 jobid=job1221
    write log to DB
    ==END 抓取文章任务==

    当再次添加符合该流程的定时任务时,只需要新建一个类,实现BaseJob就可以了。

    完整例子:https://github.com/cathychen00/cathyjava /09_abstract

  • 相关阅读:
    .NET 3.5新特性(转)
    (转)常用正则表达式
    IEC 61850(转)
    好几年了,我又回来了。
    EPR和SAP的一些名词解释(转载)
    为blogs添加风采,添加奥运金牌榜及赛程
    VS2010崩溃重启解决方法.
    C#制作Windows service服务系列二:演示一个定期执行的windows服务及调试(windows service)(转载)
    C#中操作XML (修改完整版) (转)
    C#制作Windows service服务系列一:制作一个可安装、可启动、可停止、可卸载的Windows service
  • 原文地址:https://www.cnblogs.com/janes/p/8309741.html
Copyright © 2020-2023  润新知