Java 抽象类 接口 继承 实现

引言

接口和抽象类的概念不一样。接口是对动作的抽象,抽象类是对根源的抽象。
抽象类表示的是,这个对象是什么。接口表示的是,这个对象能做什么。比如,男人,女人,这两个类(如果是类的话……),他们的抽象类是人。说明,他们都是人。
人可以吃东西,狗也可以吃东西,你可以把“吃东西”定义成一个接口,然后让这些类去实现它(类实现多个接口,实现多个动作).
所以,在高级语言上,一个类只能继承一个类(抽象类,java类的单继承,接口可以多继承)。(正如人不可能同时是生物和非生物),但是可以实现多个接口(吃饭接口、走路接口)。
第一点. 接口是抽象类的变体,接口中所有的方法都是抽象的。而抽象类是声明方法的存在而不去实现它的类。
第二点. 接口可以多继承,抽象类不行
第三点. 接口定义方法,不能实现,而抽象类可以实现部分方法。
第四点. 接口中基本数据类型为static 而抽类象不是的。
当你关注一个事物的本质的时候,用抽象类;当你关注一个操作的时候,用接口。

PS(一个类只能继承一个类),类的单继承:

public class MyClassOne {
    int  len =  1 ;
}
public class MyClassTwo {
    int  len =  2 ;
}
//下面编译不过,去掉,MyClassTwo 编译过
public class MyClass extends MyClassOne, MyClassTwo{   
    public static void main(String args[]){
        MyClass my = new MyClass();
        System.out.println(my.len);

    }
}

抽象类

有时候,我们可能想要构造一个很抽象的父类对象,它可能仅仅代表一个分类或抽象概念,它的实例没有任何意义,因此不希望它能被实例化。例如:有一个父类 水果(Fruit),它有几个子类苹果(Apple)、“橘子(Orange)、香蕉(Banana)等。水果在这里仅仅只是作为一个分类, 显然水果的实例没有什么意义(就好像一个人如果告诉你他买了一些水果但是却不告诉你是苹果还是橘子,你很难想象他到底买的是什么。)。而水果类又要能被子 类化,这就要求我们使用抽象类(abstract)来解决这个问题。
在java中,通过在class关键字前增加abstract修饰符,就可以将一个类定义成抽象类。抽象类不能被实例化。例如:
定义抽象类水果(Fruit)

    public abstract class Fruit { 
                  …… 
    } 

如果我们试图用以下语句来获得一个实例,将无法编译成功。
Fruit fruit = new Fruit(); // 不能实例化
而我们仍然可以构造水果类的子类,如:

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 {       //只能定义为抽象类abstract
                  …… 
                  public abstract void draw(); 
                  …… 
           }

抽象方法还有一个特点是,它强迫子类要么仍然保持抽象性(即不具体实现该方法并仍然定义为抽象类),要么具体表现出这个方法的行为(实现具体的动作或者通过抛出UnsupportedOperationException异常来表明不支持该行为)。这样也可以强化多态性。
这里写图片描述

匿名内部类实例化

abstract class B {
    private String str;

    public B(String a) {
        System.out.println("父类已经实例化");
        this.str=a;
        System.out.println(str);
    }

    public abstract void play();
}

public class A {

    public static void main(String[] args) {
        B aa = new B("test") {
            @Override
            public void play() {
                System.out.print("B play method");
            }
        };

        aa.play();
    }

}

输出
父类已经实例化
test
B play method

抽象类的确不能实例化。
这种格式(new TestAbs(){要重写的方法})叫匿名内部类,实际上是实例化一个它的子类。其实就相当于下面这样,只是匿名不匿名的区别。

class Test extends B{
    @Override
            public void play() {
                System.out.print("B play method");
            }
}
B aa = new Test();
aa.play("test");

接口

java语言使用关键字interface定义一个接口。接口也是抽象对象,它甚至比抽象类更抽象。接口中的方法都是抽象方法 (接口中一般只包含一组public抽象方法,且必须是公有抽象方法,但方法定义中public abstract可省略,也可以包含public 静态final数据)。
一个接口可以继承其他接口(可多个);一个类通过关键字implements声明要实现一个接口,并具体实现接口的方法。
例如:有一个接口InterfaceA,

public   interface  InterfaceA {    
         void  methodA();    
}  

类ClassA实现接口InterfaceA。

public   class  ClassA  implements InterfaceA {    
          public   void  methodA() {    
               System.out.println( "methodA of ClassA implements InterfaceA" );    
         }    
}

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

public abstract class ClassBS implements InterfaceA{ }
// 子类ClassBSub实现接口InterfaceA,但是没有具体实现方法methodA(),

public   class  ClassBSub implements InterfaceA{    
         public   void  methodA() {    
             System.out.println( "methodA of ClassBSub the subclass of ClassB" );    
        }    
}

接口继承

public interface Interface1 {
    int  len =  1 ;
    void  output();
}

public interface Interface2 {
    int  len =  2 ;
    void  output();
}

public interface Interface3 extends Interface1, Interface2 {
    int  len =  3 ;
    @Override
    void  output();
}

public class InterfaceSub implements Interface1, Interface2 {
    public void output() {
        System.out.println("output in class interfaceTest.InterfaceSub.");
    }

    public void outputLen(int type) {
        switch (type) {
            case Interface1.len:
                System.out.println("len of interfaceTest.Interface1=." + type);
                break;
            case Interface2.len:
                System.out.println("len of interfaceTest.Interface2=." + type);
                break;
            case Interface3.len:
                System.out.println("len of interfaceTest.Interface2=." + type);
                break;
        }
    }
    public   static   void  main(String[] args) {
        InterfaceSub interfaceSub=  new InterfaceSub();
//        interfaceTest.Interface1 a = new interfaceTest.Interface1() {
//            @Override
//            public void output() {
                interfaceTest.Interface1.len
//            }
//        };
        interfaceSub.output();
        interfaceSub.outputLen(1);
        interfaceSub.outputLen(2);
        interfaceSub.outputLen(3);
    }
}

输出

output in class interfaceTest.InterfaceSub.
len of interfaceTest.Interface1=.1
len of interfaceTest.Interface2=.2
len of interfaceTest.Interface2=.3

区别

接口和抽象类显著的共同点是接口和抽象类都可以有抽象方法。

接口和抽象类的不同点

(1)抽象类可以有实例变量,而接口不能拥有实例变量(接口是公开的,里面不能有私有的方法或变量,是用于让别人使用的,而抽象类是可以有私有方法或私有变量的),接口中的变量都是静态的常量(public static final)。 (首先接口是一种高度抽象的"模版",,而接口中的属性也就是’模版’的成员,就应当是所有实现"模版"的实现类的共有特性,所以它是public 的 ,是所有实现类共有的 .否则具体实现类不能使用该变量,则就没有了定义的意义,一个既是static又是final的字段表示只占据一段不能改变的存储空间 )
(2) 抽象类可以有非抽象方法,而接口只能有抽象方法(public abstract 默认省略)
(3)抽象的子类可以选择性实现其基类的抽象方法,而接口的子类必须实现

java允许一个接口继承(extend)多个父接口,也允许一个类实现多个接口,而这样的多继承有上面提到的缺点马? (类单继承,接口多继承)
答案是没有,这是由接口的抽象性决定的。
正如前面介绍的,在接口中不能有实例变量,只能有静态的常量,不能有具体的方法(包含方法体),只能有抽象方法,因此也就摒弃了多继承的缺点。
对于一个类实现多个接口的情况,因为接口只有抽象方法,具体方法只能由实现接口的类实现,在调用的时候始终只会调用实现类的方法(不存在歧义), 因此不存在多继承的第二个缺点;而又因为接口只有静态的常量,但是由于静态变量是在编译期决定调用关系的,即使存在一定的冲突也会在编译时提示出错;而引 用静态变量一般直接使用类名或接口名,从而避免产生歧义,因此也不存在多继承的第一个缺点。
对于一个接口继承多个父接口的情况也一样不存在这些缺点。
请看以下示例。
接口A:

public   interface  InterfaceA {    
        int  len =  1 ;    
        void  output();    
}

接口B:

public   interface  InterfaceB {    
           int  len =  2 ;    
           void  output();    
}

接口InterfaceSub继承接口A和接口B:
public interface InterfaceSub extends InterfaceA, interfaceB { }

类Xyz实现接口InterfaceSub:

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();    
       }   
 }
//或者
public class Xyz implements InterfaceA,InterfaceB {
   ...
} 

以上代码不存在什么问题,但是如果试图编写以下存在冲突的代码,则会编译失败(根本就访问不了len)。

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

疑问

Java实现接口必须重写其中全部的方法吗

抽象类可以不用,普通类必须全部重写。
比如

public interface A {//定义一个接口
   public void show();//定义一个接口方法
} 
public abstract class AExtend implements A{
  //抽象类实现接口A,但可以不实现show方法,由子类再去实现
}

Java 接口 对象 = new 实现类 与 实现类 对象= new 实现类 区别

接口 :
public interface UserService {
// 注册
public void regist();
}
实现类:
public class UserServiceImpl implements UserService {
@Override
public void regist() {
System.out.println("区别");
}
}
main(){
UserService userService = new UserServiceImpl();
userService.regist();
}
//匿名类 new接口 需要实现方法
UserService userService3 =   new UserService() {
            @Override
            public void regist() {
                // you impl

            }
       };

问题

为什么main 函数中 构造对象的时候 是:
1) UserService userService = new UserServiceImpl(); 而不是
UserServiceImpl userService = new UserServiceImpl();第二种可以的

接口的设计主要还是为了实现多态的。

你这里觉得没区别是因为你只有一个UserServiceImpl实现类。
假设我们还有类A,B,C,他们都具有共同的行为regist。
假设我们还有个方法(其他变量使用do方法)

void do(UserService us){
    //us.regist();
}

当然如果不用interface,那么你可能要定义4个方法来应对我们不同的对象了

void do(UserServiceImpl us){
    //us.regist();
}
void do(A us){
    //us.regist();
}
...

尽管他们方法体一样,要做的事一样。可是如果没有interface,我们还是要乖乖的这样做。

当然抽象类也可以这么用,但是因为一个类只能继承一个类,如果把抽象类拿来当接口用,那多态就是笑话了。

参考:
http://blog.csdn.net/lyflower/article/details/4204449
http://swearyd7.iteye.com/blog/1471798
http://blog.csdn.net/fenglibing/article/details/2745123
http://zhidao.baidu.com/link?url=lvYrFKZHw0Uj4MLM56b1YCxUbJyPqPDQRhlBVOWBmMlHqwrax9VUYiDiO6dUZnLcb0AEP5BIbI0BsY_bWuBwM_
http://www.cnblogs.com/liangqiyuan/p/5568464.html(抽象类)
https://www.cnblogs.com/nerxious/archive/2013/01/25/2876489.html(匿名类小结)
https://www.zhihu.com/question/34797840(为什么说Java中抽象类不可以实例化?)

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值