java面向对象—抽象类、接口与多继承

有时候,我们可能想要构造一个很抽象的父类对象,它可能仅仅代表一个分类或抽象概念,它的实例没有任何意义,因此不希望它能被实例化。例如:有一个父类“ 水果(Fruit)”,它有几个子类“苹果(Apple)”、“橘子(Orange)”、“香蕉(Banana)”等。水果在这里仅仅只是作为一个分类,显然水果的实例没有什么意义(就好像一个人如果告诉你他买了一些水果但是却不告诉你是苹果还是橘子,你很难想象他到底买的是什么。)。而水果类又要能被子类化,这就要求我们使用抽象类(abstract class)来解决这个问题。
在java中,通过在class关键字前增加abstract修饰符,就可以将一个类定义成抽象类。抽象类不能被实例化。例如:
          定义抽象类水果(Fruit)
          public abstract class Fruit {
                  ……
          }
           如果我们试图用以下语句来获得一个实例,将无法编译成功。
           Fruit fruit = new Fruit();
而我们仍然可以构造水果类的子类,如:
          子类“苹果(Apple)”
           public class Apple extends Fruit {
                   ……
           }
          子类“橘子(Orange)”
           public class Orange extends Fruit {
                   ……
           }
这样就达到我们的目的了。
抽象类除了能象普通类一样可以拥有一般的属性和方法,也可以拥有抽象方法(abstract method)。例如:
           抽象类“形状(Shape)”拥有抽象方法draw()。
           public abstract class Shape {
                  ……
                  public abstract void draw();
                  ……
           }
抽象方法与抽象的行为相对应,通常是这个行为对父对象没有意义,而子对象有具体动作。例如方法draw()对于类Shape没有意义,而类Shape的子类矩形(Rectangle)的方法draw()可以有实际的动作(根据矩形的四个顶点画出矩形的四个边),子类圆(Circle)的方法draw()也可以有实际的动作(根据圆心和半径画出圆周)。
抽象类可以有抽象方法也可以没有抽象方法;但是如果一个类有抽象方法,那这个类只能定义为抽象类。
           如果按照以下代码类“形状(Shape)”仍然拥有抽象方法draw(),但没有定义为抽象类,将会编译失败。
           public class Shape {
                  ……
                  public abstract void draw();
                  ……
           }
抽象方法还有一个特点是,它强迫子类要么仍然保持抽象性(即不具体实现该方法并仍然定义为抽象类),要么具体表现出这个方法的行为(实现具体的动作或者通过抛出UnsupportedOperationException异常来表明不支持该行为)。这样也可以强化多态性。
上面简要分析了抽象类,下面谈谈接口(interface)。java语言使用关键字interface定义一个接口。接口也是抽象对象,它甚至比抽象类更抽象。接口中的方法都是抽象方法。
一个接口可以继承其他接口;一个类通过关键字implements声明要实现一个接口,并具体实现接口的方法。
           例如:有一个接口InterfaceA,

Java代码

  1. public interface InterfaceA {   
  2.         void methodA();   
  3. }  

 

           类ClassA实现接口InterfaceA。

Java代码

  1. public class ClassA implements InterfaceA {   
  2.          public void methodA() {   
  3.                System.out.println("methodA of ClassA implements InterfaceA");   
  4.          }   
  5. }  

 

如果是抽象类实现一个接口,那么抽象类中可以不具体实现接口的方法(保持其抽象性),而由其子类去实现。
           抽象类ClassB实现接口InterfaceA,但是没有具体实现方法methodA(),

Java代码

  1. public abstract class ClassB  {           }  

 

           子类ClassBSub实现接口InterfaceA,但是没有具体实现方法methodA(),

Java代码

  1. public class ClassBSub {   
  2.         public void methodA() {   
  3.               System.out.println("methodA of ClassBSub the subclass of ClassB");   
  4.         }   
  5. }  

 

接口和抽象类显著的共同点是接口和抽象类都可以有抽象方法。
接口和抽象类的不同点有:
           (1)抽象类可以有实例变量,而接口不能拥有实例变量,接口中的变量都是静态(static)的常量(final)。
           (2)抽象类可以有非抽象方法,而接口只能有抽象方法。
java中,类与类之间是不能多继承的。java之所以禁止类与类之间的多继承是因为多继承有很大的缺点。
多继承虽然能使子类同时拥有多个父类的特征,但是其缺点也是很显著的,主要有两方面:
(1)如果在一个子类继承的多个父类中拥有相同名字的实例变量,子类在引用该变量时将产生歧义,无法判断应该使用哪个父类的变量。例如:
           类ClassA:

Java代码

  1. public class ClassA {   
  2.        protected int varSame = 0;   
  3. }  

 

           类ClassB:

Java代码

  1. public class ClassB {   
  2.         protected int varSame = 1;   
  3. }  

 

           子类ClassC:(假设允许类与类之间多继承)

Java代码

  1. public class ClassC extends ClassA, ClassB {   
  2.         public void printOut() {   
  3.                 System.out.println(super.varSame);   
  4.         }   
  5.         public static void main(String[] args) {   
  6.                 ClassC classC = new ClassC();   
  7.                 classC.printOut();   
  8.         }   
  9. }  

 

           上面程序的运行结果会是什么呢?输出0还是1?
(2)如果在一个子类继承的多个父类中拥有相同方法,子类中有没有覆盖该方法,那么调用该方法时将产生歧义,无法判断应该调用哪个父类的方法。例如:
           类ClassA:

Java代码

  1. public class ClassA {   
  2.         public void printOut() {   
  3.                 System.out.println(0);   
  4.         }   
  5. }  

 

           类ClassB:

 

Java代码

  1. public class ClassB {   
  2.         public void printOut() {   
  3.                 System.out.println(1);   
  4.         }   
  5. }  

 

           子类ClassC:(假设允许类与类之间多继承)

Java代码

  1. public class ClassC extends ClassA, ClassB {   
  2.                    public static void main(String[] args) {   
  3.                            ClassA classA = new ClassC();   
  4.                            classA.printOut();      // -------------------------  A行   
  5.                            ClassB classB = new ClassC();   
  6.                            classB.printOut();      // -------------------------  B行   
  7.                            ClassC classC = new ClassC();   
  8.                            classC.printOut();       //-------------------------  C行   
  9.                    }   
  10.            }  

 

           上面程序的运行结果会是什么呢?A、B、C三行的输出是0还是1?
正因为有以上的致命缺点,所以java中禁止一个类继承多个父类;但是幸运的是java提供了接口,并能通过接口的功能获得多继承的许多优点而又摒弃了类与类多继承的缺点。
java允许一个接口继承多个父接口,也允许一个类实现多个接口,而这样的多继承有上面提到的缺点马?
答案是没有,这是由接口的抽象性决定的。
正如前面介绍的,在接口中不能有实例变量,只能有静态的常量,不能有具体的方法(包含方法体),只能有抽象方法,因此也就摒弃了多继承的缺点。
对于一个类实现多个接口的情况,因为接口只有抽象方法,具体方法只能由实现接口的类实现,在调用的时候始终只会调用实现类的方法(不存在歧义),因此不存在多继承的第二个缺点;而又因为接口只有静态的常量,但是由于静态变量是在编译期决定调用关系的,即使存在一定的冲突也会在编译时提示出错;而引用静态变量一般直接使用类名或接口名,从而避免产生歧义,因此也不存在多继承的第一个缺点。
对于一个接口继承多个父接口的情况也一样不存在这些缺点。
请看以下示例。
            接口A:

Java代码

  1. public interface InterfaceA {   
  2.         int len = 1;   
  3.         void output();   
  4. }  

 

            接口B:

Java代码

  1. public interface InterfaceB {   
  2.           int len = 2;   
  3.           void output();   
  4. }  

 

            接口Sub继承接口A和接口B:

Java代码

  1. public interface InterfaceSub extends InterfaceA, interfaceB {            }  

 

            类Xyz实现接口Sub:

Java代码

  1. public class Xyz implements InterfaceSub {   
  2.         public void output() {   
  3.                 System.out.println("output in class Xyz.");   
  4.         }   
  5.          public void outputLen(int type) {   
  6.                  switch(type) {   
  7.                          case InterfaceA.len:   
  8.                                  System.out.println("len of InterfaceA=."+type);   
  9.                                  break;   
  10.                          case InterfaceB.len:   
  11.                                  System.out.println("len of InterfaceB=."+type);   
  12.                                  break;   
  13.                  }   
  14.         }   
  15.        public static void main(String[] args) {   
  16.                Xyz xyz= new Xyz ();   
  17.                xyz .output();   
  18.                xyz .outputLen();   
  19.        }   

 

           以上代码不存在什么问题,但是如果试图编写以下存在冲突的代码,则会编译失败。

Java代码

  1. Xyz xyz = new Xyz();   
  2. int len = xyz.len;   
  3. System.out.println(len);  

 

由于引入了接口,java显得非常灵活,也使得java中的多态性更加富有魔力。

时间: 2024-10-22 15:05:11

java面向对象—抽象类、接口与多继承的相关文章

PHP面向对象 抽象类 接口 常量学习

  PHP抽象类的使用和定义   <?php   abstract class A {    public $name;    function fun(){     echo $this->name;    }   abstract function cc($n,$nn=3);  }  class B extends A{    function cc($m,$mm=7){    echo "aaa";    }  }  $b = new B;   ?> PHP面向

java面向对象(二)之继承

继承 介绍 继承是从已有的类中派生出新的类,新的类能吸收已有类的数据属性和行为,并能扩展新的能力.继承即常说的is-a关系.子类继承父类的特征和行为,使得子类具有父类的各种属性和方法.或子类从父类继承方法,使得子类具有父类相同的行为. 例子: 比如可以先定义一个类叫车,车有以下属性:车体大小,颜色,方向盘,轮胎,而又由车这个类派生出轿车和卡车两个类,为轿车添加一个小后备箱,而为卡车添加一个大货箱. 继承所表达的就是一种对象类之间的相交关系,它使得某类对象可以继承另外一类对象的数据成员和成员方法.

对于Java中的接口实现多继承的疑问

问题描述 目前的理解接口:Interface   的作用就是包含一些抽象方法   然后再其他类中implement接口并override这些抽象方法        感觉纯粹只为了达到统一的方法名访问而作这么个抽象方法,跟直接在类中创建这么一个方法没啥区别      如果要做到像extend那样不重写方法就能使用父类的方法,Interface还是不行啊   实现的多继承也就变成了重写多个接口中的抽象方法,没有那层继承的意义啊 解决方案 嘿嘿,看看大师们是怎么用interface的.多看看设计模式,

做一个饲养员给动物喂食物的例子体现JAVA中的面向对象思想,接口(抽象类)的用处

做一个饲养员给动物喂食物的例子体现JAVA中的面向对象思想,接口(抽象类)的用处 interface Animal{             //动物的接口    public void eat(Food food); //接口中只有抽象的方法和静态常量!这里void前面省略了abstract.同样,变量可以省略static final} class Cat implements Animal //一种动物类:猫  {      public void eat(Food food) //这里是对

java面向对象(三)之抽象类,接口

java类 java类分为普通类和抽象类,接口,上一节我大概讲了java类的一般格式,今天将抽象类和接口.同时讲一下它们是怎样存储的. 最重要的是理解为什么要有抽象和接口,这样学下来你猜不会迷茫,才能更好的去使用,所以多看看我写的关于抽象类和接口的目的. 抽象类 目的 为了对代码更好的维护和重用. 解析: 抽象类往往用来表征对问题领域进行分析.设计中得出的抽象概念,是对一系列看上去不同,但是本质上相同的具体概念的抽象. 1.因为抽象类不能实例化对象,所以必须要有子类来实现它之后才能使用.这样就可

Java基础10 接口的继承与抽象类

作者:Vamei 出处:http://www.cnblogs.com/vamei 欢迎转载,也请保留这段声明.谢谢!   在实施接口中,我们利用interface语法,将interface从类定义中独立出来,构成一个主体.interface为类提供了接口规范. 在继承中,我们为了提高程序的可复用性,引入的继承机制.当时的继承是基于类的.interface接口同样可以继承,以拓展原interface.   接口继承 接口继承(inheritance)与类继承很类似,就是以被继承的interface

Java中的面向对象封装、抽象、继承、多态特点

 面向对象主要有四大特性:封装.抽象.继承和多态.各自定义: 封装:在面向对象语言中,封装特性是由类来体现的,我们将现实生活中的一类实体定义成类,其中包括属性和行为(在Java中就是方法),就好像人类,可以具有name,sex,age等属性,同时也具有eat(),sleep()等行为,我们在行为中实现一定的功能,也可操作属性,这是面向对象的封装特性: 抽象:抽象就是将一类实体的共同特性抽象出来,封装在一个抽象类中,所以抽象在面向对象语言是由抽象类来体现的.比如鸟就是一个抽象实体,因为抽象实体并不

Java面向对象程序设计之接口应用

Java语言提供了一种接口(interface)机制.这种接口机制使Java的面向对象编程变得更加灵活.我们可以用接口来定义一个类的表现形式,但接口不能包含任何实现.在<Thinking in Java>一书中,作者对接口有这样的描述:"接口(interface)比抽象(abstract)的概念更进了一步.你可以把一个接口看成是一个纯的抽象类."我认为作者对接口的这一解释再准确不过了. 理解并用好接口机制将帮助我们更好的掌握Java这种面向对象的编程语言.下面我们来讨论一下

Java中抽象类和接口区别的个人见解

抽象类 抽象类是用来捕捉子类的通用特性的 .它不能被实例化,只能被用作子类的超类.抽象类是被用来创建继承层级里子类的模板.以JDK中的GenericServlet为例: public abstract class GenericServlet implements Servlet, ServletConfig, Serializable {     // abstract method     abstract void service(ServletRequest req, ServletRe