博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
原来你是这样的JAVA[03]-继承、多态、抽象类
阅读量:6906 次
发布时间:2019-06-27

本文共 5044 字,大约阅读时间需要 16 分钟。

一、继承

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类的实例,看看调用顺序。

@Testpublic 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)");     }}

添加单元测试:

@Testpublic 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)
 
完整源码参见:     /_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看看。

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

运行结果:

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

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

完整例子: /09_abstract

转载地址:http://eildl.baihongyu.com/

你可能感兴趣的文章
利用bentley view将Revit模型输出为3D PDF文档
查看>>
Log4j配置详解
查看>>
nodejs 笔记
查看>>
优化网站设计(十):最小化JAVASCRIPT和CSS
查看>>
hdu 2516(斐波那契博弈)
查看>>
Ext.Net动态构建树-TreePanel使用详解
查看>>
nullnullhow to read directory name using std c in the linux
查看>>
开源请求程序员的黄金时代
查看>>
合同设备SQL树形数据的一种解决方法
查看>>
jquary 选择器大全
查看>>
iOS开发复选框类库SSCheckBoxView
查看>>
动态链接库、静态库、import库区别
查看>>
android的消息处理机制(图+源码分析)——Looper,Handler,Message
查看>>
My Apple Developer Library Catalog
查看>>
[置顶] 王志成30岁前自传-我曾创造过的“第一”
查看>>
Java中Runnable和Thread的区别
查看>>
Java中数组Arrays.binarySearch,快速查找数组内元素位置
查看>>
Fastjson是一个Java语言编写的高性能功能完善的JSON库。
查看>>
大数据应用之Windows平台Hbase客户端Eclipse开发环境搭建
查看>>
项目呈现器 classFactory来创建
查看>>