MLDN
课程咨询[孔老师]QQ 1031143579孔老师QQ课程咨询留言 课程咨询[徐老师 ]QQ 945313230
徐老师QQ课程咨询留言
课程咨询[刘老师 ]QQ 514543793
刘老师QQ课程咨询留言
java培训
北京java培训
IT电子教育门户 高端JAVA培训 -=> 资源中心 -=> JAVA SE技术专区 -=> JAVA面向对象 -=> 正文

Java抽象类和接口和继承之间关系

 发布日期:2009-4-10 9:19:00 发布者:[IT电子教育门户]   评论:[]  浏览:

有时候,我们可能想要构造一个很抽象的父类对象,它可能仅仅代表一个分类或抽象概念,它的实例没有任何意义,因此不希望它能被实例化。例如:有一个父类“ 水果(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代码
public   interface  InterfaceA {   
         void  methodA();   
}  
 
           类ClassA实现接口InterfaceA。

Java代码
public   class  ClassA implements InterfaceA {   
          public   void  methodA() {   
               System.out.println( "methodA of ClassA implements InterfaceA" );   
         }   
}  
 
如果是抽象类实现一个接口,那么抽象类中可以不具体实现接口的方法(保持其抽象性),而由其子类去实现。
           抽象类ClassB实现接口InterfaceA,但是没有具体实现方法methodA(),

Java代码
public   abstract   class  ClassB  {           }  
 
           子类ClassBSub实现接口InterfaceA,但是没有具体实现方法methodA(),

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

Java代码
public   class  ClassA {   
        protected   int  varSame =  0 ;   
}  
 
           类ClassB:

Java代码
public   class  ClassB {   
         protected   int  varSame =  1 ;   
}  
 
           子类ClassC:(假设允许类与类之间多继承)

Java代码
public   class  ClassC  extends  ClassA, ClassB {   
         public   void  printOut() {   
                System.out.println( super .varSame);   
        }   
         public   static   void  main(String[] args) {   
                ClassC classC =  new  ClassC();   
                classC.printOut();   
        }   
}   
 

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

Java代码
public   class  ClassA {   
         public   void  printOut() {   
                System.out.println( 0 );   
        }   
}   
 

           类ClassB:

 

Java代码
public   class  ClassB {   
         public   void  printOut() {   
                System.out.println( 1 );   
        }   
}  
 
           子类ClassC:(假设允许类与类之间多继承)

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

Java代码
public   interface  InterfaceA {   
         int  len =  1 ;   
         void  output();   
}  
 
            接口B:

Java代码
public   interface  InterfaceB {   
           int  len =  2 ;   
           void  output();   
}  
 
            接口Sub继承接口A和接口B:

Java代码
public   interface  InterfaceSub  extends  InterfaceA, interfaceB {            }  
 
            类Xyz实现接口Sub:

Java代码
public   class  Xyz  implements  InterfaceSub {   
         public   void  output() {   
                System.out.println( "output in class Xyz." );   
        }   
          public   void  outputLen( int  type) {   
                  switch (type) {   
                          case  InterfaceA.len:   
                                 System.out.println( "len of InterfaceA=." +type);   
                                  break ;   
                          case  InterfaceB.len:   
                                 System.out.println( "len of InterfaceB=." +type);   
                                  break ;   
                 }   
        }   
        public   static   void  main(String[] args) {   
               Xyz xyz=  new  Xyz ();   
               xyz .output();   
               xyz .outputLen();   
       }    
 

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

Java代码
Xyz xyz =  new  Xyz();   
int  len = xyz.len;   
System.out.println(len);   
 

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

java视频教程
JAVA核心_75对象序列化练习
 JAVA核心_75对象序列化..
JAVA核心_74对象序列化
 JAVA核心_74对象序列化..
JAVA核心_73字符编码
 JAVA核心_73字符编码 ..
JAVA核心_72Scanner
 JAVA核心_72Scann..
JAVA核心_71 IO练习 二
 JAVA核心_71 IO练习..
相关文章 推荐文章
详细解析Java中抽象类和接口的..[11.7]
详细解析Java中抽象类和接口的..[10.19]
JAVA接口的妙用[9.19]
接口与抽象类[9.5]
接口和抽象类的定义方式举例说明 ..[1.31]
Java抽象类和接口和继承之间关系
JAVA里面方法调用时传对象参数的陷阱..
Java字符串与文件的互转
Java的DBC接口设计
Java判断字符串是否为空的三种方法
热门文章
java中关于数组初始化的常用方法
Java抽象类和接口和继承之间关系
JAVA里面方法调用时传对象参数的陷阱..
如何用JAVA来实现“生产者―消费者”..
理解Java面向对象的程序设计思想
Java调用存储过程
操纵java数组
java术语集
检查是否是电话号码的函数
java性能优化
今日更新
Java抽象类和接口和继承之间关系
String类和StringBuffe..
JAVA里面方法调用时传对象参数的陷阱..
Java字符串与文件的互转
Java的DBC接口设计
Java判断字符串是否为空的三种方法
Java中跳出多层循环的简单方法
Java的垃圾回收总结
扩展java.lang.String功..
JAVA四种基本排序
JAVA招聘网
 评一评
正在读取…
  姓名:
  评论:
    
【注】 发表评论必需遵守以下条例: !!!
  • 尊重网上道德,遵守中华人民共和国的各项有关法律法规
  • 承担一切因您的行为而直接或间接导致的民事或刑事法律责任
  • 本站管理人员有权保留或删除其管辖留言中的任意内容
  • 本站有权在网站内转载或引用您的评论
  • 参与本评论即表明您已经阅读并接受上述条款
关于我们 | 商务合作 | 招聘信息 | 客服中心 | 服务条款 | 免责声明 | 网站导航 QQ留言
Copyright 2009 魔乐培训MLDN.CN all rights reserved 版权所有 京ICP备07008611号