解析JavaSe的抽象类和接口

目录

  • 1. 抽象类和抽象方法
  • 2. 相关面试题
    • 1、抽象类必须要有抽象方法吗?
    • 2、普通类和抽象类有哪些区别?
    • 3、抽象类能使用 final 修饰吗?
  • 3. 接口
    • 3.1 接口中的常量
    • 3.2 接口中的方法
      • 3.2.1 接口中的普通方法
      • 3.2.2 接口中的静态方法
      • 3.2.3 接口中的默认方法
    • 3.3 接口中的接口和枚举类
      • 3.4 接口和抽象类
      • 总结

        1. 抽象类和抽象方法 抽象方法和抽象类必须使用abstract修饰符来定义,有抽象方法的类只能被定义成抽象类,抽象类里可以没有抽象方法。抽象方法和抽象类的规则如下:
        (1) 抽象类和抽象方法必须使用abstract修饰符来修饰,抽象方法不能有方法体。
        (2) 抽象类不能被实例化,无法使用new关键字来调用抽象类的构造器创建抽象类的实例。即使抽象类里不包含抽象方法,这个抽象类也不能创建实例。
        (3) 抽象类可以包含Field、方法、构造器、初始化块、内部类、枚举类6种成分。抽象类的构造器不能用于创建实例,主要是用于被其子类调用。
        (4) 含有抽象方法的类只能被定义成抽象类。
        (5) abstract不能用于修饰Field,不能用于修饰局部变量,即没有抽象变量、没有抽象Field等说法;abstract也不能用于修饰构造器,没有抽象构造器,抽象类里定义的构造器只能是普通构造器。
        定义抽象方法只需在普通方法上增加abstract修饰符,并把普通方法的方法体(也就是方法后花括号括起来的部分)全部去掉,并在方法后增加分号即可。
        public abstract class Person {// 初始化块{System.out.println("执行Person类的初始化块"); }private int age; // 该构造器并不是为了创建对象,而是为了子类调用public Person(){}public Person(int age){this.age = age; }// 抽象方法,没有方法体public abstract void show(); public void test(){System.out.println("非抽象方法"); }}

        抽象类不能用于创建实例,只能当作父类被其他子类继承。
        public class Student extends Person {public Student(int age){super(age); }@Overridepublic void show() {System.out.println("重写抽象类中的抽象方法"); }}

        注意:
        (1) 当使用abstract修饰类时,表明这个类只能被继承;当使用abstract修饰方法时,表明这个方法必须由子类提供实现(即重写)。而final修饰的类不能被继承,final修饰的方法不能被重写。因此final和abstract永远不能同时使用。
        (2) 当使用static修饰一个方法时,表明这个方法属于该类本身,即通过类就可调用该方法,但如果该方法被定义成抽象方法,则将导致通过该类来调用该方法时出现错误(调用了一个没有方法体的方法肯定会引起错误)。因此static和abstract不能同时修饰某个方法,即没有所谓的类抽象方法。
        (3) 抽象类不能创建实例,只能当成父类来被继承。从语义的角度来看,抽象类是从多个具体类中抽象出来的父类,它具有更高层次的抽象。

        2. 相关面试题
        1、抽象类必须要有抽象方法吗?
        抽象类不一定非要有抽象方法,抽象类中可以含有抽象方法和非抽象方法,可以只含有抽象方法,也可以只含有非抽象方法
        public abstract class Person {public void test(){System.out.println("非抽象方法"); }}


        2、普通类和抽象类有哪些区别?
        (1) 普通类不能包含抽象方法,抽象类可以包含抽象方法。
        (2) 抽象类不能直接实例化,只能当作父类被其他子类继承,普通类可以直接实例化。
        public abstract class Person {// 抽象方法public abstract void show(); // 非抽象方法public void test(){System.out.println("非抽象方法"); }}

        外部类的形式继承抽象类Person
        public class Student extends Person {@Overridepublic void show() {System.out.println("重写抽象类中的抽象方法"); }}

        内部类的形式继承抽象类Person
        public class Teacher {public static void main(String[] args) {Person person = new Person() {@Overridepublic void show() {System.out.println("重写抽象类的抽象方法"); }}; person.show(); }}


        3、抽象类能使用 final 修饰吗?
        当使用abstract修饰类时,表明这个类只能被继承;当使用abstract修饰方法时,表明这个方法必须由子类提供实现(即重写)。而final修饰的类不能被继承,final修饰的方法不能被重写。因此final和abstract永远不能同时使用。

        3. 接口 接口只是对一类事物的属性和行为更高层次的抽象。对修改关闭,对扩展(不同的实现implements)开放,接口是对开闭原则的一种体现。
        接口体:
        interface 接口名{常量抽象方法静态方法默认方法}interface 接口名{常量抽象方法静态方法默认方法}


        3.1 接口中的常量
        接口中的所有成员变量都默认是由public static final修饰的,且由于接口里没有构造器和初始化块,因此需要在定义Field时就指定初始值;
        【解析JavaSe的抽象类和接口】接口中的Field都是常量,经常用来被定义常量的集合:
        public interface FieldInterface {/*** 一年的天数*/int DAY = 365; /*** 一年的星期数*/int WEEK = 52; /*** 一年的月数*/int MONTH = 12; }

        public class Main {public static void main(String[] args) {/*** 接口中定义的Field都是public static final修饰的常量,因此需要使用接口名来访问*/System.out.println(FieldInterface.DAY); }}

        一个类实现某个接口时,该类将会获得接口中定义的Field :
        public class FieldImpl implements FieldInterface {// 将会继承FieldInterface中定义的所有Field}

        public class Main {public static void main(String[] args) {System.out.println(FieldInterface.DAY); // 使用实现类调用接口中的常量System.out.println(FieldImpl.DAY); }}


        3.2 接口中的方法
        接口中的三种方法:
        (1) 接口中的普通方法,默认都是public abstract修饰的抽象方法,没有方法体;
        (2) 接口中的静态方法,静态方法必须要有实现,且这个静态方法只能用public修饰或不写;
        (3) 接口中的默认方法,默认方法必须要有实现,用default修饰且不可省略,用来供子类继承或重写,二选一,但只能在实现类中使用或者实现类对象中使用;
        分别展开举例说明:

        3.2.1 接口中的普通方法 接口中的普通方法,默认都是public abstract修饰的抽象方法,没有方法体;
        • 接口的实现类如果是普通类,那么必须重写接口中的所有抽象方法
        • 接口的实现类如果是抽象类,那么可以不用重写接口中的抽象方法
        public interface BaseMethod {/*** 接口中的普通方法* 以下方法默认都是public abstract修饰的抽象方法,没有方法体*/public abstract void show1(); abstract void show2(); public void show3(); void show4(); }

        ① 接口的实现类如果是普通类,那么必须重写接口中的所有抽象方法:
        public class BaseMethodImpl implements BaseMethod {/*** 当一个类实现BaseMethod接口后,需要实现BaseMethod接口中的所有抽象方法*/@Overridepublic void show1() { }@Overridepublic void show2() { }@Overridepublic void show3() { }@Overridepublic void show4() { }}

        ② 接口的实现类如果是抽象类,那么可以不用重写接口中的抽象方法:
        public abstract class BaseMethodImpl2 implements BaseMethod {/*** 抽象类会继承接口中定义的所有抽象方法和field* 这个类仍然是抽象类,可以不用实现接口中所有的抽象方法*/@Overridepublic void show1() { }}


        3.2.2 接口中的静态方法
        • 调用形式:接口名.静态方法名
        • 接口中定义的静态方法,不能被子接口继承
        • 接口中定义的静态方法,不能被实现该接口的类继承
        public interface StaticMethod {/*** 接口中的静态方法* 接口中是可以定义静态方法的,静态方法必须要有实现。且这个静态方法只能用public修饰或不写。*/public static void test1(){System.out.println("接口中定义静态方法"); }}

        public class Main {public static void main(String[] args) {/*** 接口中的静态方法,只能通过接口名来调用,就像类的静态方法一样*/StaticMethod.test1(); }}

        ① 接口中定义的静态方法不能被子接口继承:
        public interface StaticMethod1 extends StaticMethod {}

        public class Main {public static void main(String[] args) {/*** 编译报错,说明接口中定义的静态方法不能被子接口继承*/StaticMethod1.test1(); }}

        ② 接口中定义的静态方法不能被实现类继承:
        public class StaticMethodImpl implements StaticMethod {}

        public class Main {public static void main(String[] args) {/*** 编译报错,说明接口中定义的静态方法不能被实现类继承*/StaticMethodImpl.test1(); }}


        3.2.3 接口中的默认方法
        • 接口中的默认方法,不能通过接口名调用,需要通过接口实现类的实例进行访问,即对象名.默认方法名()
        • 接口中的默认方法,可以被实现类继承,也可以在实现类中重写
        • 接口中的默认方法,可以被子接口继承,也可以在子接口中重写
        public interface DefaultMethod {/*** 接口中的默认方法* 用default修饰,不可省略,供子类继承或重写,二选一,但只能在实现类中使用或者实现类对象中使用*/public default void test2(){System.out.println("接口中定义默认方法"); }}

        ① 接口中的默认方法,可以被实现类继承,也可以在实现类中重写
        public class DefaultMethodImpl implements DefaultMethod {// 继承接口中的方法}

        public class DefaultMethodImpl implements DefaultMethod {// 重写接口中的方法@Overridepublic void test2() {System.out.println("实现类重写接口中的方法"); }}

        public class DefaultMethodImpl implements DefaultMethod {// 重写接口中的方法@Overridepublic void test2() {System.out.println("实现类重写接口中的方法"); }}

        ② 接口中的默认方法,可以被子接口继承,也可以在子接口中重写
        public interface DefaultMethod1 extends DefaultMethod {// 继承父接口中的方法}

        public interface DefaultMethod1 extends DefaultMethod {// 重写父接口中的方法@Overridedefault void test2() {System.out.println("子接口中重写父接口中的方法"); }}


        3.3 接口中的接口和枚举类
        public interface Base {/*** 在接口中定义接口*/interface CommonConstant{/*** 一年的天数*/int DAY = 365; /*** 一年的星期数*/int WEEK = 52; /*** 一年的月数*/int MONTH = 12; /*** 在接口中定义静态方法*/static void show() {System.out.println("在接口中定义接口"); }}/*** 在接口中定义枚举类*/@AllArgsConstructorenum WhiteStatusEnum {/*** 未加白*/NO_WHITE("未加白", "未加白"),/*** 部分加白*/PART_WHITE("部分加白", "部分加白"),/*** 全部加白*/ALL_WHITE("全部加白", "全部加白"); @Getterprivate final String label; @Getterprivate final String value; }}


        3.4 接口和抽象类
        共同点:
        (1) 接口和抽象类都不能被实例化,它们都位于继承树的顶端,用于被其他类实现和继承;
        (2) 接口和抽象类都可以包含抽象方法,实现接口或继承抽象类的普通子类都必须实现这些抽象方法;
        (3) 接口和抽象类中都可以包括抽象方法和非抽象方法;
        不同点:
        (1) 接口里只能定义静态常量Field,不能定义普通Field;抽象类里则既可以定义普通Field,也可以定义静态常量Field。
        (2) 接口里不包含构造器;抽象类里可以包含构造器,抽象类里的构造器并不是用于创建对象,而是让其子类调用这些构造器来完成属于抽象类的初始化操作。
        (3) 接口里不能包含初始化块;但抽象类则完全可以包含初始化块。
        (4) 一个类最多只能有一个直接父类,包括抽象类;但一个类可以直接实现多个接口,通过实现多个接口可以弥补Java单继承的不足。
        public class MethodImpl implements FieldInterface, MethodInterface {}


        总结 本篇文章就到这里了,希望能够给你带来帮助,也希望您能够多多关注脚本之家的更多内容!

          推荐阅读