抽象类定义
在面向对象的概念中,所有的对象都是通过类来描述的,但反过来,并不是所有的类都是用来描述对象的。如果一个类没有足够的信息来描述一个特定的对象,那么这个类就是抽象的。简单地说,使用关键字 abstract 装饰类称为抽象类。
抽象类使用示例代码如下:
abstract class AbstractAnimal { public AbstractAnimal() { System.out.println("Init AbstractAnimal."); } static String name = "AbstractAnimal"; public abstract void eat(); public void run() { System.out.println("AbstractAnimal Run."); }}class Animal extends AbstractAnimal { public static void main(String[] args) { AbstractAnimal animal = new Animal(); animal.run(); System.out.println(animal.name); animal.eat(); } // 抽象父类的方法必须重写 @Override public void eat() { System.out.println("Animal Eat."); }}
上述代码执行结果:
Init AbstractAnimal.AbstractAnimal Run.AbstractAnimalAnimal Eat.
抽象方法使用 abstract 修改关键字的方法称为抽象方法,抽象方法只声明没有方法体。代码如下:
public abstract void m();
抽象特征- 抽象类不能初始化
- 抽象可以有结构方法
- 如果抽象子类是普通子类,则必须重写抽象子类中的所有抽象方法
- 抽象方法可以是抽象方法或普通方法
- 如果一个类包含抽象方法,这个类必须是抽象类
- 子类的抽象方法不能与父类的抽象方法同名
- 不能做抽象的方法 private、static、final 等待关键字修改
- 抽象类可以包含普通成员变量,可以任意指定访问类型,也可以使用静态变量(static)
接口(interface)这是抽象类的延伸。它允许一个类实现多个接口,弥补抽象类无法继承的缺陷。接口是对类的描述和使用 interface 声明关键字。
接口使用示例代码如下:
interface IAnimal { void run();}class AnimalImpl implements IAnimal { public static void main(String[] args) { IAnimal animal = new AnimalImpl(); animal.run(); } @Override public void run() { System.out.println("AnimalImpl Run."); }}
Java 8 中间接口的变化1)增加了界面 default 方法和 static 例代码可以通过方法体现,如下:
interface IAnimal { static void printSex() { System.out.println("Male Dog"); } default void printAge() { System.out.println("18"); }}class AnimalImpl implements IAnimal { public static void main(String[] args) { IAnimal.printSex(); IAnimal animal = new AnimalImpl(); animal.printAge(); }}
注意:static 该方法属于接口方法,可直接使用;default 属于实例方法,必须先创建实例。
2)接口中的静态变量将继承示例代码,如下:
interface IAnimal { static String animalName = "Animal Name"; static void printSex() { System.out.println("Male Dog"); }}class AnimalImpl implements IAnimal { public static void main(String[] args) { System.out.println(animalName); IAnimal.printSex(); }}
注:静态变量将继承,静态方法不会继承。
3)新增函数接口
函数式接口(Function Interface)使用特殊接口是一种特殊接口 @FunctionInterface
可以使用注释声明来定义这个接口 Lambda 直接调用表达式。示例代码如下:
@FunctionalInterfaceinterface IAnimal { static String animalName = "Animal Name"; static void printSex() { System.out.println("Male Dog"); } default void printAge() { System.out.println("18"); } void sayHi(String name);}class FunctionInterfaceTest { public static void main(String[] args) { IAnimal animal = name -> System.out.println(name); animal.sayHi("WangWang"); }}
注意:使用 @FunctionInterface
对于声明的函数接口,必须只有一种抽象方法,但可以包括其他非抽象方法。
答:方法体可以包含在抽象类中。抽象类的组成也可以是包含方法体的普通方法,但这并不是使用抽象类的最佳方法。
标题分析:方法体抽象示例代码如下:
abstract class AbstractAnimal { public void run() { System.out.println("AbstractAnimal Run."); }}class Animal extends AbstractAnimal { public static void main(String[] args) { AbstractAnimal animal = new Animal(); animal.run(); }}
上述代码执行的结果如下: AbstractAnimal Run.
答:抽象类不能实例化,因为抽象类和界面的设计是用来规定子类行为的特征,即让其他类继承,这是多态思想的设计体现,因此强制规定抽象类不能实例化。
3.可以采用抽象方法 private 修改?为什么?答:抽象方法不能使用 private 修改,因为抽象方法是继承和重写子类,如果设置 private 子类不能重写这种抽象方法,这违背了抽象方法的设计理念,因此不能被重写 private 修饰。
4.添加以下哪个选项不会导致编译器报错?abstract class AbstractAnimal { static String animalName = "AbstractAnimal"; // 添加代码处}
A:protected abstract void eat();B: void eat();C:abstract void eat(){};D:animalName += "Cat";
答:A
主题分析:选项 B 一般方法必须有方法体;选项 C 抽象方法不能有方法体;选项 D 变量赋值操作必须在方法内。
5.以下关于抽象类和抽象方法的说法是正确的?A:抽象中的所有方法都必须是抽象B: 抽象类必须包含抽象方法C:抽象类不能包含普通方法D:抽象中的所有方法都可以是普通方法(包括方法体)
答:D
题目分析:抽象类中可以没有方法或全部普通方法,如下代码所示:
abstract class AbstractAnimal { public void run() { System.out.println("AbstractAnimal Run."); }}class Animal extends AbstractAnimal { public static void main(String[] args) { AbstractAnimal animal = new Animal(); animal.run(); }}
程序执行的结果如下:AbstractAnimal Run.
6.接口和普通类有什么关系?答:在 Java 在语言设计中,接口不是类,而是对类的一组需求描述,必须按照接口描述的统一格式来定义。
7.接口能有方法体吗?答:JDK 8 接口之前不能有方法体,JDK 8 之后新增了 static 方法和 default 方法,可以包含方法体。
8.执行以下代码会输出什么结果?interface IAnimal { static String animalName = "Animal Name";}class AnimalImpl implements IAnimal { static String animalName = new String("Animal Name"); public static void main(String[] args) { System.out.println(IAnimal.animalName == animalName); }}
答:执行结果为 false。
主题分析:子类使用 new String… 变量重新创建 animalName,又因为使用 == 比较内存地址,所以结果是 false。
9.抽象类和接口有什么区别?答:抽象与接口的区别主要分为以下几个部分。
- 默认方法
- 抽象可以通过默认方法实现
- JDK 8 以前的界面不能实现默认的方法,JDK 8 之后,接口可以实现默认方法
- 继承方式
- 子类使用 extends 继承抽象类的关键词
- 子类使用 implements 实现接口的关键字类
- 构造器
- 抽象类可以有结构器
- 接口不能有结构器
- 方法访问修饰符
- 可采用抽象方法 public / protected / default 等修饰符
- 接口默认是 public 访问修饰符,不得使用其他修饰符
- 多继承
- 子类只能继承一个抽象类
- 一个子类可以实现多个接口
A:抽象方法可以是静态的(static)的B:抽象法可以同时进行本地方法(native)C:可采用抽象方法 synchronized 修饰D:以上都不是
答:D
主题分析:抽象方法需要被子重写,静态方法不能重写,因此抽象方法不能静态(static)修改;本地方法是由本地代码实现的,而抽象方法没有实现,所以抽象方法不能同时是本地方法;synchronized 与实现细节有关,而抽象方法不涉及实现细节,所以抽象的方法是不可能的 synchronized 修饰。
总结在面向对象的编程中,抽象和接口是多态的具体实现 Java 在编程思想中起着重要的作用,也是初级面试岗位必须问的问题之一。然而,由于界面是 JDK 8 变化很大,所以面试官在网上发现的绝大多数关于界面和抽象差异的答案都是不准确的,这需要面试官特别注意。