A股上市公司传智教育(股票代码 003032)旗下技术交流社区北京昌平校区

 找回密码
 加入黑马

QQ登录

只需一步,快速开始

© 湛添友 中级黑马   /  2014-4-18 08:48  /  1289 人查看  /  8 人回复  /   0 人收藏 转载请遵从CC协议 禁止商业使用本文

谁能具体的概括一下抽象类的作用!

8 个回复

倒序浏览
首先,我们来看一下抽象类的概念,java编程思想中说“万物皆对象”,我们知道所有的对象都是通过类来描绘的,但是反过来却不是这样。并不是所有的类都是用来描绘对象的,如果一个类中没有包含足够的信息来描绘一个具体的对象,这样的类就是抽象类。抽象类是表征我们对问题领域进行分析、设计中得出的抽象概念,是对一系列看上去不同,但是本质上相同的具体概念的抽象。好比,我们都知道三角形是一个形状,世界上有三角形这样具体的东西,但是确没有形状这样具体的东西,我们要描述这个形状的概念就要用到抽象类。因此在java中抽象类是不允许被实例化的。
在面向对象领域,抽象类主要用来进行类型隐藏。那什么是类型隐藏呢?我们可以构造出一个固定的一组行为的抽象描述,但是这组行为却能够有任意个可能的具体实现方式。这个抽象描述就是抽象类,而这一组任意个可能的具体实现则表现为所有可能的派生类。好比,动物是一个抽象类,人、猴子、老虎就是具体实现的派生类,我们就可以用动物类型来隐藏人、猴子和老虎的类型。
再来看一下接口,接口是什么呢?Java中的接口是一系列方法的声明,是一些方法特征的集合,一个接口只有方法的特征没有方法的实现,因此这些方法可以在不同的地方被不同的类实现,而这些实现可以具有不同的行为(功能)。接口是一种特殊形式的抽象类。

抽象类和接口有很大的区别,首先,抽象类在Java语言中表示的是一种继承关系,一个类只能使用一次继承关系。但是,一个类却可以实现多个接口。也许,这是Java语言的设计者在考虑Java对于多重继承的支持方面的一种折中考虑吧。
其次,在抽象类的定义中,我们可以赋予方法的默认行为。但是在接口的定义中,方法却不能拥有默认行为,为了绕过这个限制,必须使用委托,但是这会 增加一些复杂性,有时会造成很大的麻烦。
已经提到过,抽象类在Java语言中体现了一种继承关系,要想使得继承关系合理,父类和派生类之间必须存在”is a”关系,即父类和派生类在概念本质上应该是相同的。对于接口来说则不然,并不要求接口的实现者和接口定义在概念本质上是一致的,仅仅是实现了接口定义的契约而已。接口表示的是”like a”关系。

使用抽象类来定义允许多个实现的类型,比使用接口有一个明显的优势:抽象类的演化比接口的演化要容易的多。在后续的发行版中,如果希望在抽象类中增加一个方法,只增加一个默认的合理的实现即可,抽象类的所有实现都自动提供了这个新的方法。对于接口,这是行不通的。虽然可以在骨架实现类中增加一方法的实现来解决部分问题,但这不能解决不从骨架实现类继承的接口实现的问题。由此,设计公有的接口要非常谨慎,一旦一个接口被公开且被广泛实现,对它进行修改将是不可能的。

所以,使用接口还是抽象类,取决于我们对问题的概念的本质理解和设计的意图。

评分

参与人数 1技术分 +1 收起 理由
zzkang0206 + 1

查看全部评分

回复 使用道具 举报
我也是新手~~
抽象类就是将一些东西的共性都提取出来,当你再遇到有这种共性的子类时就可以直接调用抽象类中定义的共性功能。
假如很多人要买水果吃,吃的动作只有一个,但是有的人要用现金买,有的人用信用卡,有的人赊帐。要为每个人定义一个类,就要定义多个相同的吃的方法。如果定义一个抽象类,在里面实现吃的方法,再做一个买的抽象方法。那每个人的类都从这个抽象类派生下来,只要实现买的方法即可,吃的方法就可以直接用父类的方法了。如果要改吃的方法就不用改多个,只要改这个抽象类里的就行了。

评分

参与人数 1技术分 +1 收起 理由
zzkang0206 + 1

查看全部评分

回复 使用道具 举报
本帖最后由 赵小豪 于 2014-4-18 09:24 编辑


抽象类提供了一个继承的出发点,而具体的类不同,具体类可以实例化,应当给出一个有商业逻辑实现的对象模板。由于抽象类不可以被实例化,因此设计一个抽象类一定是用来被继承的,反过来也是对的:具体类不是用来继承的!

A:具体类不是用来继承的

在类图里,非叶子节点一定不会是具体类,一定是接口或者抽象类。如果在一个原始的设计里,有两个具体类之间有继承关系,那么应该怎么进行代码重构呢?如假设有两个具体的类A和B,B是A的子类,那么最简单的修改方案应当是建立一个抽象类(或者接口)C,然后让类A和类B成为C的子类

B:抽象类应当拥有尽可能多的共同代码

把重复的代码从子类里面移动到超类里面,可以提高代码的复用率,由于代码在共同的超类而不是几个子类中出现,在代码发生改变时,只需要改变一个地方。一个对象从超类继承而来的代码,在不使用时不会造成对资源的浪费

C:抽象类应当拥有尽可能少的数据

与代码的移动方向相反的是,数据的移动是从抽象类到个体类,也即从继承的等级结构的高端向等级的低端移动,一个对象的数据不论是否使用都会占用资源,因此数据应当尽量放到具体的类或者等级的低端。


(2)基于抽象类的模式和原则

A:针对抽象编程,不要对具体编程,这就是依赖倒转原则。换言之,就是要针对抽象类编程,不要针对子类编程,这一原则点出了抽象类对代码复用的一个重要作用.

B:正确使用继承

Java中继承分为两种:一种是类对接口的实现,称作接口继承,另一种是类对类的继承,称为实现继承,第二种继承是很容易被滥用的一种复用工具,只要可能,尽量使用合成而不是继承来达到复用的目的。


(3)什么时候才应当使用继承复用

A:子类扩展超类的责任

子类应当扩展超类的责任,而不是置换掉(Override)或撤消掉(Nullify)超类的责任,如果一个子类需要将继承自超类的责任取消或置换后才能使用的话,很有可能这个子类根本就不是那个超类的子类。打个比方,如果将狗设计成猫的子类,猫有上树的能力,狗没有,为了使继承成立,只好把猫上树的能力取消掉,这个继承关系显然是错误的。我们应当设计一个动物抽象类让猫和狗去继承.一般而言,如果子类需要置换太多超类的行为,那么一定是因为子类的行为与超类的有太大的区别,这个时候,很有可能子类并不能取代超类出现在任何需要超类的地方,也就是说它们不满足里氏代换原则.

B:不要从工具类继承

这个只讲一个例子:这是一个真实的华尔街金融网站的系统设计,设计师将内容划分为Aticile,Alert,Survey,Contact,MarketSpin,Link等几种,所有的这些内容都分别由一个javabean负责,而所有的这些javabean都是一个ContentDataBean类的子类。同时,这个系统还有一个操纵数据库的工具类DBManager...如果到此为止一切还算好,但是负责这个设计的设计师将ContentDataBean设计成DBManager类的子类,看上去这个好处很明显,所有的子类一下子就得到了所有DBManager的数据库功能...这就是将继承关系当成权宜之计,而没有做分类学上的考虑。所有的ContentDataBean的各个内容子类都是同一类型的东西,而这些内容类和DBManager的区别就像猫和狗的区别,这就是一种滥用继承关系的例子.

纠正:这种滥用的情况不能使用引进一个抽象类的办法进行代码重构,而是应当采用将继承关系改为委派的办法纠正,也就是说,将DBManager到ContentDataBean的继承关系改成从ContentDataBean到DBManager的委派关系.

抽象类abstract class 。就是你把你以后需要用到的方法先写出来,就相当于一本书的目录一样。具体内容,需要到书中指定页面才可以看到。而程序,具体的实现是有它的子类来实现的。即子类继承抽象类。

接口,和抽象类差不多,不过有区别。jdk,当出现一个陌生类,你没接触过,不知道其方法和属性,和不知道如何创建其实例时,可以去看jdk


1.抽象类不可以创建实例对象。

2.抽象类中可以有普通方法,

3.抽象类的抽象方法由其子类来实现。



评分

参与人数 1技术分 +1 收起 理由
ily521125 + 1

查看全部评分

回复 使用道具 举报
用abstract修饰的类都是抽象类。
特点:
(1)抽象类是不完整的,只能用作基类。不能用final修饰。
(2)抽象类不能生成对象,即不允许存在对象实例,对抽象类使用new时编译是错误的。
(3)抽象类可以包含抽象成员(但不要求)。如果有成员方法,要使用abstract关键字,
(4)如果一个类包含抽象方法,或者没有为它的超类或它实现的接口中的抽象方法提供实现,那么这个类必须声明为抽象类。
(5)必须被子类继承。在继承抽象类时,必覆盖该类中的每一个抽象方法,而每个已实现的方法必须和抽象类中指定的方法一致,即接收相同数目和类型的参数,具有相同返回值。
抽象的目的是定义一种类别,并且定义该类别的用途和功能。

评分

参与人数 1技术分 +1 收起 理由
ily521125 + 1

查看全部评分

回复 使用道具 举报
  1. public class Test1 {
  2.         public static void main(String[] args) {
  3.                 USB phUsb=new Phone();
  4.                 USB sbUsb=new ShuBiao();
  5.                 phUsb.staywork();
  6.                 phUsb.endwork();
  7.                 sbUsb.staywork();
  8.                 sbUsb.endwork();
  9.         }
  10. }
复制代码
  1. /**
  2. * 父类  USB接口
  3. * @author ZiHao
  4. *
  5. */
  6. public abstract class USB {
  7.         //用USB接口工作的很多,我们并不知道是什么,所以需要用抽象类  比如:手机、U盘
  8.         //而具体的的东西实现USB工作不一样,所以用抽象方法  比如:U盘传数据   鼠标操作电脑
  9.         //所以不同事物实现USB,会有不同的结果
  10. abstract void staywork();//开始工作
  11. abstract void endwork();//停止工作
  12. }
复制代码
  1. /**
  2. * 子类 手机  继承 父类USB
  3. * @author ZiHao
  4. *
  5. */
  6. public class Phone extends USB {
  7. //子类继承父类,父类中的抽象方法必须实现
  8.         @Override
  9.         void staywork() {
  10.                 // TODO Auto-generated method stub
  11.                 System.out.println("手机开始进行充电");
  12.         }

  13.         @Override
  14.         void endwork() {
  15.                 // TODO Auto-generated method stub
  16.                 System.out.println("手机停止充电");
  17.         }

  18. }
复制代码
  1. /**
  2. * 子类鼠标 继承 父类USB
  3. * @author ZiHao
  4. *
  5. */
  6. public class ShuBiao extends USB {

  7.         @Override
  8.         void staywork() {
  9.                 // TODO Auto-generated method stub
  10.                 System.out.println("开始操作电脑");
  11.         }

  12.         @Override
  13.         void endwork() {
  14.                 // TODO Auto-generated method stub
  15.                 System.out.println("停止操作电脑");
  16.         }

  17. }
复制代码

结果:
手机开始进行充电
手机停止充电
开始操作电脑
停止操作电脑

回复 使用道具 举报
当多个类中出现相同功能,但是功能主题不同
这时可以进行向上抽取,这时只抽取功能定义,不抽取功能主体

抽象类的特点:
1,抽象方法一定在抽象类中
2,抽象方法和抽象类abstract关键字修饰
3,抽象类不可以用new创建对象,因为调用抽象方法没意义
4,抽象类中的抽象方法要被使用必须由子类复写其抽象方法后,建立子类对象调用
5,如果子类只覆盖了部分抽象方法,该子类还是一个抽象类

抽象类和一般类没有太大的区别。
该如何描述事物,就如何描述事物,只不过该事物中出现了一些看不懂的东西。
这些不确定的部分,也是该事物的功能,需要明确出现。但是无法定义主体

抽象类比一般类多了抽象方法
抽象类不可以实例化

特殊:抽象类中可以不定义抽象方法,这样做仅仅是不让该类建立对象

代码演示:
  1. //定义一个抽象类
  2. abstratc class Student
  3. {
  4.         //定义一个抽象方法
  5.         abstract void study();
  6. }

  7. //定义一个子类继承抽象类
  8. class BaseStudent extends Student
  9. {
  10.         //覆盖study()方法
  11.         void study()
  12.         {
  13.                 System.out.println("Base Student");
  14.         }
  15. }

  16. class AdvStudent extends Student
  17. {
  18.         //覆盖父类的方法,实现自己的方法体
  19.         void study()
  20.         {
  21.                 System.out.println("Adv Student");
  22.         }
  23. }

  24. class AbstractDemo
  25. {
  26.         public static void main(String[] args)
  27.         {
  28.                 new Student();
  29.                 //new BaseStudent().study();
  30.         }
  31. }
复制代码

评分

参与人数 1技术分 +1 收起 理由
ily521125 + 1

查看全部评分

回复 使用道具 举报
我想用比较通俗的方法告诉你:
假如有两个程序员,两个在两个程序里都要用到一种功能,比如要取一个对象名。
甲自己做了一个方法叫getname,乙也作了一个方法叫qumingzi。如果两个人要去看对方的程序,那么这个方法要读懂是不是要有一个过程?
如果在公司里,有个抽象类,离面有个抽象方法较getName,公司规定,凡遇到这样的问题就实现这个方法。那么这两个人要读对方的代码是不是就容易了??

评分

参与人数 1技术分 +1 收起 理由
枫儿 + 1 赞一个!

查看全部评分

回复 使用道具 举报
抽象类和它的特点:

当多个类中出现相同功能,但是功能主体不同。
这时可以进行向上抽取。只抽取功能定义,而不抽取功能主体。
abstract class Student
{
abstract void study();  ‘void study(){}’   没有大括号,但要有分号。
}

抽象类的特点:
1.抽象方法一定在抽象类中。
2.抽象方法和抽象类都必须被abstract关键字修饰。
3.抽象类不可以用new创建对象。因为调用抽象方法没意义。
4.抽象类中的抽象方法要被使用,必须由子类复写起所有的抽象方法后,建立子类对象调用。
如果子类只覆盖了部分抽象方法,那么该子类还是一个抽象类。

子类必须复写父类中的抽象方法,才可以使用
抽象类和一般类没有太大的不同。
该如何描述事物,就如何描述事物,只不过,该事物出现了一些看不懂的东西。
这个不确定的部分,也是该事物的功能,需要明确出现。但是无法定义主体。
通过抽象方法来表示。

抽象类比一般类多个抽象函数。就是在类中定义抽象方法。
抽象类不可以实例化。即不能建立对象。
抽象类中可以不定义抽象方法,这样做仅仅是不让该类建立对象。

与接口比较:

接口:初期理解,可以认为是一个特殊的抽象类
当抽象类中的方法都是抽象的,那么该类可以通过接口的形式来表示。
class用于定义类
interface用于定义接口
接口定义时,格式特点:
1.接口中常见定义:常量,抽象方法。
2.接口中的成员都有“固定修饰符”
常量:public static final
方法:public abstract
接口的成员都是public的
举例:
interface Inter
{
int NUM = 3;      //其实是public static final int NUM = 3;
void show();      //其实是public abstract void show();
}

接口:是不可以创建对象的,因为有抽象方法。
需要被子类实现,子类对接口中的抽象方法全都覆盖后,子类才可以实例化。
否则子类也是一个抽象类

评分

参与人数 1黑马币 +1 收起 理由
枫儿 + 1 很给力!

查看全部评分

回复 使用道具 举报
您需要登录后才可以回帖 登录 | 加入黑马