Java 抽象类、普通类、接口的区别

转载自2篇文章:

原文链接:https://blog.csdn.net/csdn_aiyang/article/details/71171886

原文链接:https://blog.csdn.net/qq_36769100/article/details/87345275

 

概念


抽象类和具体类是相对的概念。“抽象”是一种存在思想逻辑中的概念,而“具体”是一种可见可触摸的现实对象。简单说,比如“人”比“男人”抽象一点,“动物”又比“人”更抽象一点,而“生物”又比“动物”更抽象。  

抽象的概念是由具体概念依其“共性”而产生的,把具体概念的诸多个性排出,集中描述其共性,就会产生一个抽象性的概念。抽象思维,是人类思维达到高级阶段产生的一种能力,例如,当小孩子思维尚未成熟时,他们只能掌握具体概念,他们在学习代词“你、我、他”时往往遇到困难,因为代词具有较高的抽象性。

总之,抽象概念的外延大,内涵小;具体概念的外延小,内涵大。

一、抽象类与普通类


(1)普通类可以去实例化调用;抽象类不能被实例化,因为它是存在于一种概念而不非具体。

(2)普通类和抽象类都可以被继承,但是抽象类被继承后子类必须重写继承的方法,除非自类也是抽象类。

(3)实例演示:

public class Pet {
 
public void play(){                //这是宠物类,普通父类,方法里是空的
}
}
--------------------------
public class Cat extends Pet {    //这是子类,是一个猫类,重写了父类方法
public void play(){
  System.out.println("1、猫爬树");
}
}
------------------------
public class Dog extends Pet {    //这是子类,是一个狗类,重写了父类方法
  public void play(){
  System.out.println("2、狗啃骨头");
 }
}
-------------------------
public class Test {
public static void main(String[] args) {  //这是测试类,分别调用了子类的不同方法
 
Pet p1=new Cat();                               //多典型的多态表现啊,相当的给力
Pet p2=new Dog();
 
p1.play();
p2.play();
}
}
-----------------------
输出结果:
1、猫爬树
2、狗啃骨头
-----------------------

问:

把父类改成抽象类,方法改成抽象方法,那么public void play();  子类不变,依然重写父类方法,那这个跟普通父类没区别啊?难道说就一个抽象方法没方法体就完事了??那我普通方法有方法体,我空着不写内容不就得了,不跟抽象方法一个样吗??别跟我说抽象类还不能实例化,哥也不需要去new它!普通类都能搞定的,还弄个抽象类有什么意义?我前面都说了普通类的方法我可以空着不写,达到跟抽象类方法没方法体一样的效果。既然两种方式都能达到同一个输出效果,弄一种方式不就得了,那为什么还要创造出一个抽象类出来?难道是比普通类看着舒服?用着爽?还是更加便捷?还是为了强制让别人用的时候必须强制化实现抽象方法省的你忘了什么的?

答:

就是为了强制不能实例化,以及强制子类必须实现方法这不是你忘不忘的问题,你说你不去new它就行了,这话没错
那你想另一个问题,为什么要有访问控制呢?为什么要有private和public之分呢?我可以全部public,不该访问的,我不访问就行了啊?小程序里,看不出什么区别,反而private成员要写一堆set和get函数,多麻烦,我自己写小程序的时候也会偷懒全部public,但是项目大了,代码多了,这种严谨的结构就很重要了。且不说会有很多人合作一起写一个程序,哪怕还是你一个人写,也保不住有忘记的时候,那时候编译器不报错,茫茫码海上哪找错误去面向对象说到底就是方便你思考,易扩展、易维护管理,硬要说没必要,整个面向对象都没必要了,C语言有什么干不了的呀,运行效率还高。

 

二、抽象类与接口
 

1、概念

接口是对动作的抽象,抽象类是对本质的抽象。

抽象类表示的是,这个对象是什么。接口表示的是,这个对象能做什么。比如,男人和女人,他们的抽象类是人类,而猫和狗的抽象类是宠物类。人类可以吃东西,宠物类也可以吃东西,但是两者不能混为一谈,因为有本质的区别。这个“吃东西”是一个动作,你可以把“吃东西”定义成一个接口,然后让两个类去实现它的方法。

所以,在高级语言上,一个类只能继承一个类或抽象类,正如人不可能同时是动物类又是植物类,但是可以实现多个接口,例如,吃饭接口、呼吸接口等。

 

2、使用情况

a.抽象类 和 接口 都是用来抽象具体对象的,但是接口的抽象级别最高;

b.抽象类可以有具体的方法和属性,  接口只能有抽象方法和不可变常量(final)

c.抽象类主要用来抽象类别,接口主要用来抽象功能;

d.抽象类中不包含任何实现,派生类必须覆盖它们。接口中所有方法都必须是未实现的;

e.抽象类实现接口时,接口的方法在抽象类中可以被实现也可以不被实现,而普通实现接口必须实现所有接口方法。

 

3、使用方向

当你关注一个事物的本质的时候,用抽象类;
当你关注一个操作的时候,用接口。
 

三、小结
 

抽象类的功能要远超过接口,但是,定义抽象类的代价高。因为高级语言来说(从实际设计上来说也是)每个类只能继承一个类。在这个类中,你必须继承或编写出其所有子类的所有共性。虽然接口在功能上会弱化许多,但是它只是针对一个动作的描述。而且你可以在一个类中同时实现多个接口。在设计阶段会降低难度的。
————————————————
详述java中的抽象类,与普通类,接口的区别

摘要:

如果是一个新手程序员的话,那么对抽象类可以说是只知道其存在,但不知道其真正的作用,所以在工程中很少用抽象类来实现代码。

但是抽象类在某些时候的功能很强大,可以保证子类中百分百实现父类中的方法——普通类的弊端、消除子类的冗余代码——接口的弊端(敲黑板,这些是重点)

那么今天我来简单叙述一下抽象类的优势,并且拿来有普通类和接口比较一下

1.何为抽象类


抽象类的声明与普通类相比,就多了一个abstract关键词。
抽象类中的方法同接口中的方法一样,没有body体。
抽象类中可以有抽象方法,也可以没有抽象方法,但是有抽象方法存在的类必须是抽象类。
如果一个普通类作为父类,那么他的子类会重写父类中的方法;但是如果一个抽象类中的抽象方法被子类实现,那么该子类是实现父类中的抽象方法


2.基础知识支持:多态


概念:父类或者是接口的引用,可以指向子类或者是实现类的对象。

那么该对象既可以调用子类/实现类中的方法,也可以调用父类中的方法

3.普通类举例


1.声明一个普通父类,该父类中有一个其所有子类同化的方法,和一个所有子类可以个性化的方法

package com.util;
 
public class Parent {
 
    /**
     * @Description 所以子类同化的方法,子类中无须重写
     * @author lvyingliang
     * @date 2019年2月15日
     * @return_type void
     */
    public void parentHabits(){
        System.out.println("I can sleep.");
    }
    
    /**
     * @Description 当子类实现该父类时,生成的子类中不会自动添加需要重写的方法,需要人为对照父类中的方法名来实现,麻烦且不安全(方法名易照搬错误)
     * @author lvxiaobu
     * @date 2019年2月15日
     * @return_type void
     */
    public void sonHabit(){
        System.out.println("There will be overrided by son.");
    }
}


2.声明一个该父类的子类,对个性化方法sonHabit进行重写

package com.util;
 
public class Son extends Parent {
 
    
    
    /**
     * @Description 子类中的方法不会与父类关联,所以在子类中重写方法时,需要再次打开父类代码,参照并格外注意重写方法名的一致性
     * @author lvxiaobu
     * @date 2019年2月15日
     * @return_type void
     */
    public void sonHatbit(){
        System.out.println(" I am a fish , and I just can  swim in the sea .");
    }
}

 

3.输出结果:

package com.util;
 
public class Test {
 
    public static void main(String[] args) {
 
        //普通父类
        Parent p = new Son();
        p.parentHabits();
        p.sonHabit();
        
        //接口
//        InterfaceParent p = new InterfaceSon();
//        p.parentHabits();
//        p.sonHabit();
        
        //抽象父类
//        AbstractParent son = new AbstractSon();
//        son.parentHabits();
//        son.sonHabit();
    }
}
//执行结果
I can sleep.
 I am a fish , and I just can  swim in the sea .


4.思考:

当子类需要重写父类中的某一个方法时,需要格外注意父类中被重写的方法名是否与子类中重写的方法名一致,这一点比较麻烦。

有没有一种可能,就像实现类实现接口那样(那样是哪样?可以看一下下面的接口例子),让程序帮我们自动关联父类中的需要重写的方法,保证子类中重写的方法百分百是父类中的方法呢?

答案当然是有。

4.接口实现举例:


1.声明一个接口,该接口中有例1中的同化方法和个性方法供子类实现

package com.util;
 
public interface InterfaceParent {
 
    /**
     * @Description 弊端:如果实现该接口的所有实现类中的parentHabits一样,那么就需要在各个实现类中出现大量重复的代码
     * @author lvxiaobu
     * @date 2019年2月15日
     * @return_type void
     */
    public void parentHabits();
    
    public void sonHabit();
}


2.声明一个实现类,实现上述中的全部方法

package com.util;
 
public class InterfaceSon implements InterfaceParent {
 
    @Override
    public void parentHabits() {
        System.out.println("I can sleep.");//如果还有其他子类,此方法需要重复实现
    }
 
    @Override
    public void sonHabit() {
        System.out.println(" I am a fish , and I just can  swim in the sea .");
    }
 
}


3.输出结果

package com.util;
 
public class Test {
 
    public static void main(String[] args) {
 
        //普通父类
//        Parent p = new Son();
//        p.parentHabits();
//        p.sonHabit();
        
        //接口
        InterfaceParent p = new InterfaceSon();
        p.parentHabits();
        p.sonHabit();
        
        //抽象父类
//        AbstractParent son = new AbstractSon();
//        son.parentHabits();
//        son.sonHabit();
    }
}


4.思考:

如果该接口不止一个 实现类,那么所有的实现类都需要将接口中的两个方法全部实现。但是因为第一个parentHabits()方法是所有子类同化的方法,所以这就会在多个子类中产生大量相同的代码。

那么有没有一种可能,将所有子类的同化代码在接口中统一实现,实现类中只实现自己的个性化方法呢?

答案当然也是有。

 

那么下面就有请我们的抽象类登场。

 

5.抽象类举例


1.创建一个父类抽象类,需要注意几点

    1.将该类下所有子类的同化方法声明为普通方法,直接实现。这样,子类就无需再重复实现该同化方法了,减少代码

    2.将子类的个性化方法声明为抽象方法。这样,当子类继承该父类时,会提示需要实现的方法,保证百分百实现父类中的该方法。

package com.util;
 
public abstract class AbstractParent {
 
    
    /**
     * @Description 该父类下所有子类的共同方法
     * @author lvxiaobu
     * @date 2019年2月15日
     * @return_type void
     */
    public void parentHabits(){
        System.out.println("I can sleep.");
    }
    
    /**
     * @Description 该父类下所有子类的个性方法供子类自己实现
     * @author lvxiaobu
     * @date 2019年2月15日
     * @return_type void
     */
    public abstract void sonHabit();
}

2.声明一个子类,继承该抽象类,并且实现自己的个性化方法sonHabit()

package com.util;
 
public class AbstractSon extends AbstractParent {
 
 
    @Override
    public void sonHabit() {
        System.out.println(" I am a fish , and I just can  swim in the sea .");
        
    }
 
}

3.测试结果

package com.util;
 
public class Test {
 
    public static void main(String[] args) {
 
        //普通父类
//        Parent p = new Son();
//        p.parentHabits();
//        p.sonHabit();
        
        //接口
//        InterfaceParent p = new InterfaceSon();
//        p.parentHabits();
//        p.sonHabit();
        
        //抽象父类
        AbstractParent son = new AbstractSon();
        son.parentHabits();
        son.sonHabit();
    }
}

总结:

系统的来说,抽象类中既可以有自己特有的方法,也可以有供子类自己实现的方法。

因为面向对象的多态特性,抽象类中的特有的方法可以供继承该类的所有子类调用,所以也就成了父类一劳,所有子类永益的方法。

 

如果有书写错误的地方,或者是有问题的地方请及时评论或者是私信我,以免误导个别萌新。
 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值