java不用抽象类实现多态_原来你是这样的JAVA[03]-继承、多态、抽象类

一、继承

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

1.子类构造器

java会自动在子类的构造器中插入对父类构造器的调用,也就是说在子类可以访问父类之前已经完成了父类的初始化。

如果想调用带参数的父类构造器,应该使用super关键字。

/***@author陈敬

* @date 18/1/17*/

public classProduct {privateString name;publicProduct(String name) {this.name =name;

System.out.println("[Product constructor]");

}

}public class Bread extendsProduct {private intprice;public Bread(String name, intprice) {super(name);//调用父类构造器this.price =price;

System.out.println("[Bread constructor]");

}

}

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

@Testpublic voidtestConstructor(){

Bread bread=new Bread("毛毛虫面包",10);

}

打印结果:

[Product constructor]

[Bread constructor]

2.调用父类方法

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

public classProduct {privateString name;publicString getName() {returnname;

}publicProduct(String name) {this.name =name;

}

}public class Bread extendsProduct {publicBread(String name) {super(name);

}public voiddisplay(){

System.out.println(getName());

}

}

然后写个单元测试:

@Testpublic voidtestPrivate(){

Bread bread=new Bread("毛毛虫面包");

bread.display();//毛毛虫面包

}

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

3.关于重载

如果父类中存在重载方法,子类又进行了重载,会覆盖父类中的方法吗?实际上,父类和子类中的方法都可以正常重载,不会被覆盖。

首先在父类Product中添加方法getDescription():

public classProduct {

……publicString getDescription() {return "[Product]name="+name;

}

}

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

public class Bread extendsProduct {

……publicString getDescription(String storeName) {return "[Bread]storename="+storeName;

}

}

增加一个单元测试:

public classExtendClassTests {

@Testpublic voidtestOverload(){

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 classProduct {privateString name;publicProduct(String name) {this.name =name;

}public voiddisplay() {

System.out.println("[Product]getDescription()");

}

}public class Bread extendsProduct {private intprice;public Bread(String name, intprice) {super(name);this.price =price;

}

@Overridepublic voiddisplay() {

System.out.println("[Bread]getDescription()");

}public voiddisplay(String storeName) {

System.out.println("[Bread]getDescription(String storeName)");

}

}

添加单元测试:

@Testpublic voiddynamicBind(){

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 classBaseJob {public voidrun(){

System.out.println("==START "+getDescription()+"==");

String lastJobId=getLastJobId();

execute(lastJobId);

writeLog();

System.out.println("==END "+getDescription()+"==");

}protected abstractString getDescription();protected abstract voidexecute(String jobId);private voidwriteLog() {

System.out.println("write log to DB");

}privateString getLastJobId() {return "job1221";

}

}

public class ArticleJob extendsBaseJob {

@OverrideprotectedString getDescription() {return "抓取文章任务";

}

@Overrideprotected voidexecute(String jobId) {

System.out.println("抓取站点新闻文章 jobid="+jobId);

}public static voidmain(String[] args) {

BaseJob articleJob=newArticleJob();

articleJob.run();

}

}

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

@Testpublic voidarticleJob(){

BaseJob articleJob=newArticleJob();

articleJob.run();

}

运行结果:

==START 抓取文章任务==抓取站点新闻文章 jobid=job1221

write log to DB==END 抓取文章任务==

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

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值