Java面向对象----抽象类和接口

Java面向对象:抽象类和接口

在总结完Java程序面向对象的三大特征(封装、继承、多态)之后,我慢慢理解了Java语言这种面向对象程序设计的优越性,它既能保持自身独立性又可以不断进化和发展。
如果说继承是实现Java多态性的基础,那抽象类和接口更是为多态提供了非常好的支持。
因为抽象类和接口之间很难区分,所以把他们放在一起总结进行区分。

一、抽象类

从形式上来说,用abstract修饰的类就是抽象类。抽象类是不完整的,只能做基类,且不能够被实例化(不能new)。

通俗来讲,抽象类它本身不做任何事情,它是去要求别人来实现它的规范的。它定义了一组抽象的方法,至于这组抽象方法的具体表现形式由派生类(子类)来实现。抽象类的实现要用到继承,不然抽象类就没有意义。

使用抽象类必须注意以下几点:

1.抽象类只是一个引用而已,不能被实例化,实例化的工作要交给它的子类;

2.抽象方法必须由子类来进行重写;

3.在一个类中,只要有一个方法被定义为抽象方法(被abstract修饰了),那么这个
类就必须被定义为抽象类(类名也要被abstract修饰),若子类没有重写父类全部的
抽象方法,则必须为抽象类。 

4.抽象类中可以包含具体方法,也可以不包含;

5.子类中的抽象方法不能与父类的抽象方法同名;

6.不能用abstract修饰变量、代码块、构造器; 

7.不能用abstract修饰私有方法、静态方法、final的方法、final的类
public abstract class ChouX {
	// 抽象类中可以包含具体方法,也可以不包含;
    public abstract void method1();

    public void method2() {

    }
}

代码:

public abstract class Animal {
    public abstract void shout();
}

//猫子类
public class Cat extends Animal {
	@Override
    public void shout() {
        System.out.println("喵~~");
    }
}

//Dog子类
public class Dog extends Animal {
	@Override
    public void shout() {
        System.out.println("汪汪汪。。。");
    }
}
//测试类
public class Test {
    public static void main(String[] args) {
        Animal a1 = new Dog();
        Animal a2 = new Cat();
        a1.shout();
        a2.shout();
    }
}

在这里插入图片描述
二、接口

对于面向对象编程来说,抽象是它的一大特征(可以说是第四大特征)。在java中,可以通过两种形式来体现OOP的抽象:抽象类和接口。

接口(interface),在软件工程中,接口泛指供别人调用的方法或者函数。

接口的本质是契约,标准,规范,就像我们的法律一样。制定好后大家都 要遵守。

接口(interface)是抽象方法和常量值定义的集合。

接口的特点:
    1) 用interface来定义。 
    2)接口中的所有成员变量都默认是由public static final修饰的。 
    3)接口中的所有抽象方法都默认是由public abstract修饰的。 
    4)接口中没有构造器。 
    5)接口采用多继承机制。
//例子
public interface Doorpublic void open();
	// 默认是 public abstract
	public abstract void close();

定义Java类的语法格式:先写extends,后写implements

public class SubClass extends SuperClass implements InterfaceA,InterfaceB{ 
}

一个类可以实现多个接口,接口也可以继承其它接口(多重继承)。

注意:
   1)实现接口的类中必须实现接口中所有方法。否则,仍为抽象类。 
   2)接口的主要用途就是被实现类实现。(面向接口编程) 
   3)与继承关系类似,接口与实现类之间存在多态性 
   4)接口和类是并列关系,或者可以理解为一种特殊的类。从本质上讲, 接口是
      一种特殊的抽象类,这种抽象类中只包含常量和方法的定义 (JDK7.0及之前),
      而没有变量和方法的实现。

Java 8中关于接口的改进
Java 8中,你可以为接口添加静态方法和默认方法。从技术角度来说,这是完全合法的,只是它看起来违反了接口作为一个抽象定义的理念。

静态方法:使用 static 关键字修饰。
         可以通过接口直接调用静态方法,并执行其方法体。

默认方法:默认方法使用 default 关键字修饰。可以通过实现类对象来调用。 
         我们在已有的接口中提供新方法的同时,还保持了与旧版本代码的兼容性。 
public interface AA { 
    double PI = 3.14; 
    public default void method() { 
        System.out.println("北京"); 
    } 
    default String method1() { 
        return "上海"; 
    } 
    public static void method2() { 
        System.out.println(“hello lambda!"); 
    } 
}

接口冲突

若一个接口中定义了一个默认方法,而另外一个接口中也定义了一个同名同 参数的方法(不管此方法是否是默认方法),在实现类同时实现了这两个接 口时,会出现:接口冲突。

为解决这种多继承关系,Java8提供了下面三条规则:

1) 类中的方法优先级最高,类或父类中声明的方法的优先级高于任何声明为默认方法
   的优先级。
2) 如果第一条无法判断,那么子接口的优先级更高:方法签名相同时,优先选择拥有
   最具体实现的默认方法的接口, 即如果B继承了A,那么B就比A更加具体。
3) 如果还是无法判断,继承了多个接口的类必须通过显式覆盖和调用期望的方法, 
   显式地选择使用哪一个默认方法的实现。

情况一:

public interface A {
    default void hello() {
        System.out.println("hello from A");
    }
}
public interface B extends A {
    default void hello() {
        System.out.println("hello from B");
    }
}
public class C implements A, B {
    public static void main(String[] args) {
        new C().hello();
    }
}

结果:

 规则(1)不满足。
 因为B继承了A,所以B比A更具体,所以应该选择B的hello()方法。
 所以,程序会打印输出"hello from B"。

情况二:

public class D implements A {
    public void hello() {
        System.out.println("hello from D");
    }
}

// 测试类
public class C extends D implements A, B {
    public static void main(String[] args) {
        new C().hello();
    }
}

结果:

 C继承了D,D覆盖了A的默认方法。
 依据规则(1),父类中声明的方法具有更高的优先级。
 所以程序会打印输出"hello from D"。

情况三:

public interface A {
    default void hello() {
        System.out.println("hello from A");
    }
}

// 假设现在B不继承A:
public interface B {
    default void hello() {
        System.out.println("hello from B");
    }
}

// 测试类
public class C implements A, B {
    public static void main(String[] args) {
        new C().hello();
    }
}

结果:

 此时,由于编译器无法识别A还是B的实现更加具体。
 所以会抛出编译错误:”C inherits unrelated defaults for hello() from types A and B“。

像这种场景要解决冲突,可以在C中覆盖hello()方法并在方法内显示的选择调用A还是B的方法。

调用方式如下:
public class C extends D implements A, B {
    public void hello() {
        // 显式地选择调用接口A中的方法
        A.super.hello();
        // 同理,要调用接口B中的方法,可以这样:B.super.hello()
    }

    public static void main(String[] args) {
        // 输出 hello from A
        new C().hello();
    }
}

三、抽象类和接口的区别

1.语法层面的区别

首先,抽象类可以提供成员方法实现的细节(抽象类就比普通类多了抽象方法),
      接口中只能存在public abstract 方法;

其次,抽象类中的成员变量可以是各种类型的,
      接口中的成员变量只能是public static final类型的;

再者,接口中不能含有静态代码块和静态方法,而抽象类可以;

最后,一个类只能继承一个抽象类,而可以实现(继承)多个接口。

2.设计层面上的区别

首先,抽象类是对一种事物的抽象,即对类的抽象;
      接口是对行为的抽象。

再者,抽象类作为很多子类的父类,它是一种模板式的设计。
      接口是一种行为规范。

最后,在一个抽象类中,如果你想更改一个方法,可以直接在抽象类中实现,子类可以不进行更改。
     如果发生在接口上,那么所有实现这个接口的类都需要更改。

在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值