本文目录
一、本文目标
二、抽象类
2.1 抽象类概念
2.2 抽象方法
2.3 抽象类
2.4 抽象方法和抽象类的使用
2.5 注意事项
三、接口
3.1 接口的概念
3.2 接口的定义
3.2.1 含有抽象方法
3.2.2 含有默认方法
3.2.3 含有静态方法
3.2.4 含有私有方法和私有静态方法
3.3 基本的实现
3.3.1 实现的概述
3.3.2 抽象方法的使用
3.3.3 默认方法的使用
3.3.4 静态方法的使用
3.3.5 私有方法的使用
3.4 接口的多实现
3.4.1 抽象方法
3.4.2 默认方法
3.4.3 静态方法
3.4.4 优先级的问题
第一:描述抽象方法的概念、写出抽象类的格式和抽象方法的格式、能够说出父类抽象方法的存在意义;
第二:写出定义接口的格式并实现接口的格式,掌握接口中成员的特点;
Java语法规定,包含抽象方法的类就是抽象类。
父类中的方法,被它的子类们重写,子类各自的实现都不尽相同。那么父类的方法声明和方法主体,只有声明还有意义,而方法主体则没有存在的意义了。我们把没有方法主体的方法称为抽象方法,而包含抽象方法的类就是抽象类。
所以我们定义:
抽象方法 : 没有方法体的方法。
抽象类:包含抽象方法的类。
使用 abstract 关键字修饰方法,该方法就成了抽象方法,抽象方法只包含一个方法名,而没有方法体。
定义的格式:
修饰符 abstract 返回值类型 方法名 ( 参数列表 ) ;
代码举例:
public abstract void run () ;
如果一个类包含抽象方法,那么该类必须是抽象类。
定义的格式:
abstract class 类名字 {}
代码举例:
public abstract class Animal {public abstract void run () ;}
继承抽象类的子类必须重写父类所有的抽象方法。否则,该子类也必须声明为抽象类。最终,必须有子类实现该父类的抽象方法。
抽象类不对创建对象,所以如果从最初的父类到所有的子类都没有重写父类的抽象方法,那么所有的类都不能创建对象,这样就失去了意义。
代码示例:
public abstract class AbstractClassAnimal {
public static void main(String[] args) {
// 创建子类的对象
Cat cat = new Cat();
// 调用 run() 方法
cat.run();
}
}
/**
* 这是一个抽象类(包含有一个抽象方法的类),抽象类动物
*/
abstract class Animal {
/**
* 这是一个抽象方法(只有方法声明,没有方法体),抽象方法跑
*/
public abstract void run();
}
class Cat extends Animal {
@Override
public void run() {
System.out.println("小猫在轻轻地走~~~");
}
}
此时的方法重写,是子类对父类抽象方法的完成实现,我们将这种方法重写的操作,也叫做实现方法。
关于抽象类的使用,以下为语法上要注意的细节,虽然条目较多,但若理解了抽象的本质,则不需要记忆就能写出代码。
- 1、抽象类不能创建对象,如果创建,编译无法通过而报错。只能创建其非抽象子类的对象。
理解方法:假设创建了抽象类的对象,调用抽象的方法,而抽象方法没有具体的方法体,所以这样做没有意义。
- 2、抽象类中,不一定包含抽象方法,但是有抽象方法的类必定是抽象类。
理解方法:未包含抽象方法的抽象类,目的就是不想让调用者创建该类对象,通常用于某些特殊的类结构设计。
- 3、抽象类中,可以有构造方法,是供子类创建对象时,初始化父类成员使用的。
理解方法:子类的构造方法中,有默认的super(),可以访问父类构造方法。
- 4、抽象类的子类,必须重写抽象父类中所有的抽象方法,否则,编译无法通过而报错。除非该子类也是抽象类。
理解方法:假设不重写所有抽象方法,则类中可能包含抽象方法。那么创建对象后,调用抽象的方法,这样做也没有意义。
接口,是Java语言中一种引用类型,是方法的集合,如果说类的内部封装了成员变量、构造方法和成员方法,那么接口的内部主要就是封装了方法,它包含抽象方法(JDK 7及以前),默认方法和静态方法(JDK 8),私有方法 (JDK 9)。
接口的定义,它与定义类方式相似,但是使用 interface 关键字。它也会被编译成 .class 文件,但一定要明确它并不是类,而是另外一种引用数据类型。
引用数据类型:数组,类,接口。
接口的使用,它不能创建对象,但是可以被实现( implements ,类似于被继承)。一个实现接口的类(可以看做是接口的子类),需要实现接口中所有的抽象方法,创建该类对象,就可以调用方法了,否则它必须是一个抽象类。
public interface 接口名称 {// 抽象方法// 默认方法// 静态方法// 私有方法}
抽象方法:使用 abstract 关键字修饰,可以省略,没有方法体。该方法供子类实现使用。
代码示例:
/**
* 这是一个含有抽象方法的接口
*/
public interface InterfaceNameAbstractMethod {
/**
* 这是一个抽象方法
*/
public abstract void method();
}
默认方法:使用 default 修饰,不可省略,供子类调用或者子类重写。
代码示例:
/**
* 这是一个含有默认方法的接口
*/
public interface InterfaceNameDefaultMethod {
/**
* 这是一个默认方法
*/
public default void method() {
System.out.println("这里就是一个默认方法体!");
}
}
静态方法:使用 static 修饰,供接口直接调用。
/**
* 这是一个含有静态方法的接口
*/
public interface InterfaceNameStaticMethod {
/**
* 这里是一个静态方法
*/
public static void method() {
System.out.println("这里是一个静态方法体!");
}
}
私有方法:使用 private 修饰,供接口中的默认方法或者静态方法调用。
示例代码:
/**
* 这是一个含有私有方法和私有静态方法的接口,JDK9以及以上版本才支持
*/
public interface InterfaceNamePrivateMethod {
/**
* 这里一个私有方法,JDK9以及以上版本才支持
*/
private void method() {
System.out.println("这里一个私有方法!");
}
/**
* 这里一个私有静态方法,JDK9以及以上版本才支持
*/
private static void method() {
System.out.println("这里一个私有静态方法!");
}
}
类与接口的关系为实现关系,即类实现接口,该类可以称为接口的实现类,也可以称为接口的子类。实现的动作类似继承,格式相仿,只是关键字不同,实现使用 implements 关键字。
非抽象子类实现接口:
实现格式:
class 类名 implements 接口名 {// 重写接口中抽象方法【必须】// 重写接口中默认方法【可选】}
接口里的抽象方法必须全部实现,代码如下:
定义接口:
/**
* 定义一个动物的接口
*/
public interface AnimalInterface {
// 定义动物吃的抽象方法
public abstract void eat();
// 定义动物睡的抽象方法
public abstract void sleep();
}
定义接口的实现类:
/**
* 定义动物接口的实现类
*/
public class AnimalInterfaceImpl implements AnimalInterface {
@Override
public void eat() {
System.out.println("动物吃东西!");
}
@Override
public void sleep() {
System.out.println("动物睡觉!");
}
}
定义测试方法:
public class AnimalInterfaceDemo {
public static void main(String[] args) {
// 创建子类对象
AnimalInterfaceImpl animalInterface = new AnimalInterfaceImpl();
// 调用实现后的方法
animalInterface.eat();
animalInterface.sleep();
}
}
可以继承,可以重写,二选一,但是只能通过实现类的对象来调用。
/**
* 定义接口
*/
public interface LiveAble {
public default void fly() {
System.out.println("在天上飞!");
}
}
/**
* 定义实现类
*/
class AnimalDemo1 implements LiveAble {
// 继承,什么都不用写,直接调用
}
/**
* 定义测试类
*/
class AnimalDemo1Test {
public static void main(String[] args) {
// 创建子类的对象
AnimalDemo1 animalDemo1 = new AnimalDemo1();
// 调用默认方法
animalDemo1.fly();
}
}
/**
* 定义接口
*/
public interface LiveAble1 {
/**
* 定义默认方法
*/
public default void fly() {
System.out.println("在天上飞!");
}
}
/**
* 定义实现类
*/
class AnimalDemo2 implements LiveAble1 {
@Override
public void fly() {
System.out.println("在天空自由自在的飞翔!");
}
}
class AnimalDemo2Test {
public static void main(String[] args) {
// 创建子类对象
AnimalDemo2 animalDemo2 = new AnimalDemo2();
// 调用重写后的方法
animalDemo2.fly();
}
}
静态与.class 文件相关,只能使用接口名调用,不可以通过实现类的类名或者实现类的对象调用,
代码如下:
/**
* 定义接口
*/
public interface LiveAble2 {
/**
* 定义静态方法
*/
public static void run() {
System.out.println("兴高采烈的跑起来......");
}
}
/**
* 定义实现类
*/
class AnimalDemo3 implements LiveAble2 {
// 无法重写静态方法
}
/**
* 定义测试类
*/
class AnimalDemo3Test {
public static void main(String[] args) {
// 无法继承方法,也无法调用
// AnimalDemo3.run();
LiveAble2.run();
}
}
如果一个接口中有多个默认方法,并且方法中有重复的内容,那么可以抽取出来,封装到私有方法中,供默认方法去调用。从设计的角度讲,私有的方法是对默认方法和静态方法的辅助。
代码示例:
/**
* 定义接口
*/
public interface LiveAble3 {
default void run() {
run1();
run2();
}
private void run1() {
System.out.println("run1 跑起来......");
}
private void run2() {
System.out.println("run2 跑起来......");
}
}
咱们之前都学过,在继承体系中,一个类只能继承一个父类。而对于接口而言,一个类是可以实现多个接口的,这叫做接口的多实现。并且,一个类能继承一个父类,同时实现多个接口。
实现格式:
class 类名 [ extends 父类名 ] implements 接口名 1 , 接口名 2 , 接口名 3 ... {// 重写接口中抽象方法【必须】// 重写接口中默认方法【不重名时可选】}
[ ]: 表示可选操作。
接口中,有多个抽象方法时,实现类必须重写所有抽象方法。如果抽象方法有重名的,只需要重写一次。代码如下:
public interface InterfaceA {
public abstract void printA();
public abstract void print();
}
interface InterfaceB {
public abstract void printB();
public abstract void print();
}
class C implements InterfaceA, InterfaceB {
@Override
public void printA() {
System.out.println("printA");
}
@Override
public void printB() {
System.out.println("printB");
}
@Override
public void print() {
System.out.println("print");
}
}
接口中,有多个默认方法时,实现类都可继承使用。如果默认方法有重名的,必须重写一次。代码如下:
/**
* 定义接口D
*/
public interface InterfaceD {
public default void methodD() {
}
public default void printMethod() {
}
}
/**
* 定义接口E
*/
interface InterfaceE {
public default void methodE() {
}
public default void printMethod() {
}
}
/**
* 定义实现类
*/
class F implements InterfaceD, InterfaceE {
@Override
public void printMethod() {
System.out.println("这里是一个打印的方法!");
}
}
接口中,存在同名的静态方法并不会冲突,原因是只能通过各自接口名访问静态方法。
当一个类,既继承一个父类,又实现若干个接口时,父类中的成员方法与接口中的默认方法重名,子类就近选择执行父类的成员方法。代码如下:
/**
* 定义一个接口G
*/
public interface InterfaceG {
public default void methodG() {
System.out.println("接口G的中方法G!");
}
}
/**
* 定义一个父类
*/
class ClassG {
public void methodG() {
System.out.println("类G中的方法G!");
}
}
/**
* 定义一个子类并继承父类实现接口G
*/
class ClassH extends ClassG implements InterfaceG {
// 未重写 methodG 方法
}
/**
* 定义测试类
*/
class DemoTest {
public static void main(String[] args) {
// 创建子类对象
ClassH classH = new ClassH();
// 调用接口的方法
classH.methodG();
}
}
运行结果如下:
完结!