JAVA学习笔记 09 - 抽象类、接口、内部类

本文是Java基础课程的第九课。也是Java面向对象编程中非常重要的部分,主要介绍Java中的抽象类、接口及内部类等内容

一、抽象类

1、抽象类是什么

在使用面向对象思想描绘现实世界的过程中,有时会遇到这样的情况:设想中的一个类没有足够信息描绘一个具体对象的行为。比如有一个类用来描绘所有的动物,该类中有一个方法用来描绘动物发出叫声的行为,当动物类作为基类,派生出狗类及猫类时,狗类和猫类中可以分别具体描绘狗和猫是怎样发出叫声的,而单就动物类而言,由于动物的范围很笼统,便没有办法描绘动物具体怎样发出叫声。

在Java中,可以创建这样的类,该类中可以没有足够信息描绘一个具体对象的行为,这样的类便是抽象类

2、声明和使用抽象类

2.1、声明抽象类

在Java中,声明抽象类的方法非常简单,只需使用abstract关键字即可。
声明抽象类的语法如下:

[权限修饰符] abstract class 类名 {
	// 类体
}

下面是一个示例:
Animal类的源码:

package com.codeke.java.test;

/**
 * 动物类
 */
public abstract class Animal {
	// 属性
	String type;    // 类型
	String breed;   // 品种
	String name;    // 名称

	/**
	 * 构造函数
	 */
	public Animal() {
		super();
	}
	
	/**
	 * 构造函数
	 * @param type  类型
	 * @param breed 品种
	 * @param name  名称
	 */
	public Animal(String type, String breed, String name) {
		this.type = type;
		this.breed = breed;
		this.name = name;
	}
}

Test类的源码:

package com.codeke.java.test;

/**
 * 测试类
 */
public class Test {
	public static void main(String[] args) {
		// Animal animal = new Animal() ;  // 这句代码报错,抽象类不能被直接实例化
	}
}

说明:

  • 当一个类是抽象类时,它便不能被用来实例化对象。本例中,Animal类是一个抽象类,使用语句new Animal()试图实例化Animal类的对象时会报错。
  • 抽象类除了不能被用来实例化对象之外,类的其它功能依然存在,成员变量、成员方法和构造方法的访问方式和普通类一样。

2.2、声明抽象方法

在抽象类的基础上,需要使用抽象方法描述缺少行为信息抽象方法就是只有方法头方法声明),缺少方法体的方法,声明抽象方法仍然使用abstract关键字
声明抽象方法的语法如下:

[权限修饰符] abstract 返回值类型 方法名称([参数列表]);

下面是一个示例:
修改后Animal类的源码:

package com.codeke.java.test;

/**
 * 动物类
 */
public abstract class Animal {
	// 属性
	String type;    // 类型
	String breed;   // 品种
	String name;    // 名称

	/**
	 * 构造函数
	 * @param type  类型
	 * @param breed 品种
	 * @param name  名称
	 */
	public Animal(String type, String breed, String name) {
		this.type = type;
		this.breed = breed;
		this.name = name;
	}

	/**
	 * 构造函数
	 */
	public Animal() {
		super();
	}

	/**
	 * 抽象方法,发出声音
	 */
	public abstract void makeSound();
}

说明:

  • 本例中,Animal类中的makeSound()方法是一个抽象方法,它没有方法体
  • 抽象类可以包含普通的方法,也可以不包含普通方法
  • 抽象类可以包含抽象方法,也可以不包含抽象方法
  • 如果一个包含抽象方法,那么这个类必须是抽象类
  • 构造方法类成员方法(用 static修饰的方法)不能声明抽象方法

2.3、继承抽象类

由于抽象类不能被用来实例化对象,所以抽象类必须作为基类被派生类继承后,才能被使用。正因如此,开发人员通常需要在设计阶段慎重考虑哪些类要设计为抽象类。

下面下面是一个示例:
Animal类的源码同上例,不再赘述。
Dog类的源码:

package com.codeke.java.test;

/**
 * 狗类
 */
public class Dog extends Animal {
	/**
	 * 派生类构造函数
	 * @param breed 品种
	 * @param name  名称
	 */
	public Dog(String breed, String name) {
		super("狗", breed, name);
	}

	/**
	 * 重写基类的makeSound()方法
	 */
	@Override
	public void makeSound() {
		System.out.printf("%s发出叫声,汪汪汪。\n", name);
	}
}

Cat类的源码:

package com.codeke.java.test;

/**
 * 猫类
 */
public class Cat extends Animal {
	/**
	 * 派生类构造函数
	 * @param breed 品种
	 * @param name  名称
	 */
	public Cat(String breed, String name) {
		super("猫", breed, name);
	}

	/**
	 * 重写父类的makeSound()方法
	 */
	@Override
	public void makeSound() {
		System.out.printf("%s发出叫声,喵喵喵。\n", name);
	}
}

测试类PetShop类的源码:

package com.codeke.java.test;

/**
 * 宠物店(测试类)
 */
public class PetShop {
	/**
	 * 用来测试的main方法
	 */
	public static void main(String[] args) {
		// 实例化Cat类和Dog类的对象,并将它们赋值给基类Animal类的变量
		// Cat类和Dog类各自完整的实现了Animal类中的抽象方法
		Animal animal1 = new Cat("波斯猫", "大花");
		Animal animal2 = new Dog("牧羊犬", "大黑");
		
		// 使用Animal类的变量调用Animal类中被派生类重写过的方法
		animal1.makeSound();
		animal2.makeSound();
	}
}

说明:

  • 本例中,Cat类和Dog类分别完整的实现方法实现给出每个抽象方法的方法体)了Animal类中的抽象方法,因此,Cat类和Dog类可以被用来实例化对象。
  • 抽象类的派生类只有实现基类所有抽象方法才能被用来实例化派生类对象。
  • 如果有任何一个抽象方法未在派生类中被实现,该派生类必须是抽象类

3、抽象类和抽象方法总结

Java中抽象类的要点总结如下:

  • 抽象类不能被实例化(编译无法通过)。只有抽象类的非抽象派生类可以被用来实例化对象
  • 抽象类中不一定包含抽象方法,但是包含抽象方法的类必定是抽象类
  • 抽象类中的抽象方法只是声明不包含方法体(就是不给出方法的具体实现)。
  • 构造方法类成员方法(用 static修饰的方法)不能声明抽象方法
  • 抽象类的派生类必须给出抽象类中的抽象方法具体实现除非派生类是抽象类
  • 抽象类和抽象方法进一步诠释巩固了Java面向对象编程核心特征中的多态性,使开发人员可以在设计、编码过程中更好的运用多态性。

二、接口(interface)

1、Java中的接口(interface)是什么

在前面的章节中,已经介绍过API应用程序编程接口)的概念,API即是在编程过程中应用之间进行信息交换媒介(或者理解为方式、渠道、手段等等)。另外也提到,当声明一个方法时,方法头方法声明)对于开发人员来说即是一个API。更进一步说, 前文中提到的抽象方法对开发人员来说,即是API

在Java中,接口interface)是和class并列的概念。类用来描述对象的属性和行为;而接口interface)用来描述一组抽象行为,或者说一组API。具体来说,Java中的接口interface)即是一组抽象方法集合,它被用来声明一组抽象方法,向外界提供一组统一的、规范的、可供使用API

在Java中,一个接口interface一经声明,也就成为了一种引用数据类型。这意味着,开发人员可以声明接口类型变量,但是,与抽象类类似,开发人员无法示例化一个接口类型对象。另外,接口interface)中的抽象方法需要具体重写提供具体的方法实现,这一过程被称为 接口实现,这样的被称为该接口的 实现类 。实现了同一个接口的多个实现类同时具有了相同的行为,每个实现类又可以根据自身需求给出这些行为的具体实现,当使用接口类型的变量引用实现类的对象时,接口中方法便表现多态性

接口interface声明抽象方法,不给出方法体,由实现类实现所声明的抽象方法。这提供了一种方法声明方法实现分离机制。在设计层面,这种机制可以避免开发人员被一些具体的程序细节一叶障目,从而让开发人员从更加宏观的角度对应用做更好的审视;在代码层面,接口可以降低程序的耦合度,使程序更容易维护扩展

2、声明和使用接口(interface)

2.1、声明接口(interface)

在Java中,声明接口interface)需要使用interface关键字。
声明接口interface)的语法如下:

[权限修饰符] interface 接口名 {
	// 常量成员列表
	// 抽象方法成员列表
}

说明:

  • 接口(interface)也声明在以.java结尾的文件中,编译后也保存在以.class结尾的文件中。
  • 接口(interface)的访问权限是public默认权限,与类的访问权限类似。
  • 接口(interface)中最主要的部分便是抽象方法成员列表,在接口(interface)中声明抽象方法的语法如下:
    返回值类型 方法名称([参数列表]);
    
    接口(interface)中的方法通常且默认公开抽象的,即接口(interface)中的方法通常会被隐式的指定为 public abstract(如果要显式声明,通常也只能是 public abstract)。
  • 接口(interface)中还可以声明常量,接口(interface)中声明常量的语法如下:
    数据类型 常量名称 = 字面量值;
    
    接口(interface)中的常量必须且默认被指定为 public static final(如果要显式声明,也只能是 public static final)。
  • 注意,接口(interface)中没有构造方法
  • 还需注意,接口(interface)并不继承java.lang.Object,但是接口(interface)隐式声明了一组与java.lang.Object公开(由public修饰)的方法相一致的方法。

下面是一个示例:
Flyable接口的源码:

package com.codeke.java.test;

/**
 * 飞行接口
 */
public interface Flyable {
    void fly(); // 飞行方法
}

Swimmable接口的源码:

package com.codeke.java.test;

/**
 * 游泳接口
 */
public interface Swimmable {
    void swim(); // 游泳方法
}

说明:

  • 本例中,声明了两个接口,为Flyable接口和Swimmable接口,表示可以飞行的和可以游泳的,Flyable接口中有方法fly()表示飞行的行为,Swimmable接口中有方法swim()表示游泳的行为。接口(interface)的名称一般使用名词或者描述某种能力形容词,如Appendable(可追加的)、Iterable(可迭代的)、Comparable(可比较的)。

2.2、实现接口(interface)

接口(interface)描述、规范了一组抽象的行为,需要具体的实现类来实现。声明实现类需要使用implements关键字,其语法为:

[修饰符] class 实现类名 implements 接口名1[, 接口名2, ...] {
	// 重写的接口中的方法
	// 其他类成员
}

说明:

  • Java中的类可以同时实现多个接口
  • 实现类应该重写其实现的所有接口中·的所有抽象方法,如果有抽象方法没有被重写,则该实现类应该抽象的。

下面是一个示例:
Flyable接口和Swimmable接口的源码同上例;
Duck类的源码:

package com.codeke.java.test;

/**
 * 鸭子类
 */
public class Duck implements Flyable, Swimmable{

    // 属性
    String type;    // 类型
    String breed;   // 品种
    String name;    // 名称

    // 重写的飞行的方法
    @Override
    public void fly() {
        System.out.printf("%s在天上飞!\n", this.name);
    }

    // 重写的游泳的方法
    @Override
    public void swim() {
        System.out.printf("%s在水里游!\n", this.name);
    }

    // 构造方法
    public Duck(String type, String breed, String name) {
        this.type = type;
        this.breed = breed;
        this.name = name;
    }
}

测试类PetShop类的源码:

package com.codeke.java.test;

/**
 * 宠物店(测试类)
 */
public class PetShop {
    public static void main(String[] args) {
        // 实例化实现类(鸭子类)的对象
        Duck duck = new Duck("鸭子", "野鸭", "大鸭");
        // 声明了一个接口(Flyable)类型的变量,引用了鸭子对象
        Flyable flyable = duck;
        // 声明了一个接口(Swimmable)类型的变量,也引用了鸭子对象
        Swimmable swimmable = duck;
        // 使用接口(Flyable)类型的变量调用fly()方法,实际执行的是实现类中重写过的方法
        flyable.fly();
        // 使用接口(Swimmable)类型的变量调用swim()方法,实际执行的是实现类中重写过的方法
        swimmable.swim();
    }
}

说明:

  • 本例中,Duck类同时实现了Flyable接口和Swimmable接口,并提供了fly()方法和swim()方法的实现。
  • 在本例的测试类main方法中,使用接口类型声明了变量,并引用了实现类的对象,在使用接口类型的变量调用方法时,实际执行的是实现类中的提供的方法实现,这体现多态性

在Java中,一个类可以作为派生类继承一个基类同时,也可以作为实现类实现一个或多个接口interface),其语法为:

[修饰符] class 类名 extends 基类名 implements 接口名1[, 接口名2, ...] {
	// 重写的基类中的和接口中的方法
	// 其他类成员
}

下面是另一个示例:
Flyable接口和Swimmable接口的源码同上例;
Animal类的源码:

package com.codeke.java.test;

/**
 * 动物类
 */
public abstract class Animal {
	// 属性
	String type;    // 类型
	String breed;   // 品种
	String name;    // 名称

	/**
	 * 构造函数
	 * @param type  类型
	 * @param breed 品种
	 * @param name  名称
	 */
	public Animal(String type, String breed, String name) {
		this.type = type;
		this.breed = breed;
		this.name = name;
	}

	/**
	 * 构造函数
	 */
	public Animal() {
		super();
	}

	/**
	 * 抽象方法,发出声音
	 */
	public abstract void makeSound();
}

Duck类的源码:

package com.codeke.java.test;

/**
 * 鸭子类
 */
public class Duck extends Animal implements Flyable, Swimmable{

    // 属性
    String type;    // 类型
    String breed;   // 品种
    String name;    // 名称

    // 重写发出声音的方法
    @Override
    public void makeSound() {
        System.out.printf("%s发出叫声,嘎嘎嘎。\n", this.name);
    }

    // 重写的飞行的方法
    @Override
    public void fly() {
        System.out.printf("%s在天上飞!\n", this.name);
    }

    // 重写的游泳的方法
    @Override
    public void swim() {
        System.out.printf("%s在水里游!\n", this.name);
    }

    // 构造方法
    public Duck(String type, String breed, String name) {
        this.type = type;
        this.breed = breed;
        this.name = name;
    }
}

测试类PetShop类的源码:

package com.codeke.java.test;

/**
 * 宠物店(测试类)
 */
public class PetShop {
    public static void main(String[] args) {
        // 实例化实现类(鸭子类)的对象
        Duck duck = new Duck("鸭子", "野鸭", "大鸭");
        // 声明了一个接口(Flyable)类型的变量,引用了鸭子对象
        Flyable flyable = duck;
        // 声明了一个接口(Swimmable)类型的变量,也引用了鸭子对象
        Swimmable swimmable = duck;
        // 声明了一个Animal类型的变量,也引用了鸭子对象
        Animal animal = duck;
        // 使用接口(Flyable)类型的变量调用fly()方法,实际执行的是实现类中重写过的方法
        flyable.fly();
        // 使用接口(Swimmable)类型的变量调用swim()方法,实际执行的是实现类中重写过的方法
        swimmable.swim();
        // 使用Animal类型的变量调用makeSound()方法,实际执行的是派生类中重写过的方法
        animal.makeSound();
    }
}

说明:

  • 本例中,Duck类继承了Animal类,提供了makeSound()方法的实现,Duck又同时实现了Flyable接口和Swimmable接口,并提供了fly()方法和swim()方法的实现。
  • 通过本例的测试类main方法,可以看到Java中类的继承机制接口的实现机制,都体现多态性
  • 派生类基类之间的关系可以用 is a 来形容,与此对应的,实现类接口(interface)之间的关系通常可以用 like a 来形容。

2.3、接口(interface)的继承

在Java中,接口interface之间可以存在继承关系,接口之间的继承也使用extends关键字来体现,语法如下:

[修饰符] interface 派生接口名 extends 基接口名1 [, 基接口名2, ...] {
	// 常量成员列表
	// 抽象方法成员列表
}

前面的章节中提到,Java中的类不支持多继承。与此不同的,Java中的接口interface支持多继承,以下的代码是合法的:

interface A { }
interface B { }
interface C extends A, B { }

2.4、接口(interface)中的默认方法

在JDK1.8以前,开发人员在使用接口(interface)时有一点非常不方便,即当需要修改接口时,需要修改全部该接口的实现类。从JDK1.8开始,为了解决这一问题,接口(interface)中新增了默认方法。接口(interface)中的默认方法,即接口中已经存在默认实现方法,实现类可以选择不去实现该方法。

在接口(interface)中声明默认方法需要使用default关键字,语法如下:

default 返回值类型 方法名称([参数列表]) {
	// 方法体
}

说明:

  • 接口(interface)中的默认方法必须是公开的,即接口(interface)中的默认方法会被隐式的指定为 public(如果要显式声明,也只能是 public)。

下面是一个示例:
TestInterface接口的源码:

package com.codeke.java.test;

public interface TestInterface {
    default void print(){
        System.out.println("TestInterface中的print()方法执行了");
    }
}

TestClass类的源码:

package com.codeke.java.test;

public class TestClass implements TestInterface { }

测试类Test类的源码:

package com.codeke.java.test;

public class Test {
    public static void main(String[] args) {
        TestClass testClass = new TestClass();
        testClass.print();
    }
}

执行输出结果:

TestInterface中的print()方法执行了

说明:

  • 本例中,实现类TestClass并没有重写其实现的TestInterface接口中的默认方法print(),在Test类的main方法中实例化TestClass类的对象,并调用print()方法,执行的是TestInterface接口中的默认方法print()的方法体。

下面是另一个示例:
TestInterface接口的源码同上例;
TestSupClass类的源码:

package com.codeke.java.test;

public abstract class TestSupClass implements TestInterface{
    @Override
    public void print(){
        System.out.println("TestSupClass中的print()方法执行了");
    }
}

TestClass类的源码:

package com.codeke.java.test;

public class TestClass extends TestSupClass { }

测试类Test类的源码同上例;

执行输出结果:

TestSupClass中的print()方法执行了

说明:

  • 默认方法遵循“类优先”原则 ,即若一个接口(interface)中定义了一个默认方法,而实现类(或实现类所继承的基类)中又定义了一个具有相同名称和参数列表的方法时,位于继承关系下游类中方法优先被调用

再来看另一个示例:
TestInterfaceA接口的源码:

package com.codeke.java.test;

public interface TestInterfaceA {
    default void print(){
        System.out.println("TestInterfaceA中的print()方法执行了");
    }
}

TestInterfaceB接口的源码:

package com.codeke.java.test;

public interface TestInterfaceB {
    default void print(){
        System.out.println("TestInterfaceB中的print()方法执行了");
    }
}

TestClass类的源码:

package com.codeke.java.test;

public class TestClass implements TestInterfaceA, TestInterfaceB {
    @Override
    public void print() {
        TestInterfaceA.super.print();
        // TestInterfaceB.super.print();
    }
}

测试类Test类的源码同上例;

执行输出结果:

TestInterfaceA中的print()方法执行了

说明:

  • 本例中,TestInterfaceA接口和TestInterfaceB接口中都有默认方法print()TestClass类同时实现TestInterfaceA接口和TestInterfaceB接口,此时,需要在TestClass类中显式的覆盖print()方法来解决冲突。如果一个类实现多个接口,并且这些接口提供了一个具有相同名称参数列表方法(不管方法是否是默认方法),那么必须覆盖该方法解决冲突
  • 本例中,在实现类TestClass重写的print()方法中,语句TestInterfaceA.super.print()可以调用接口TestInterfaceA中的默认方法print()

2.5、接口(interface)中的静态方法

在JDK1.8以前,接口(interface)中不允许出现静态成员方法;而从JDK1.8开始,为了更灵活起见,接口interface)中可以声明静态成员方法
下面是一个示例:
TestInterface接口的源码:

package com.codeke.java.test;

public interface TestInterface {
    // 接口中的静态方法
    static void print(){
        System.out.println("TestInterface接口中的print()方法执行了");
    }
}

测试类Test类的源码:

package com.codeke.java.test;

public class Test {
    public static void main(String[] args) {
        TestInterface.print();
    }
}

执行输出结果:

TestInterface接口中的print()方法执行了

说明:

  • 接口(interface)静态成员方法只能使用该接口名直接调用

3、接口(interface)和抽象类的异同

接口(interface)和抽象类的相同点

接口(interface)、抽象类
相同点都是引用类型
不能实例化
都可以包含抽象方法

接口(interface)和抽象类的不同点

接口(interface)抽象类
实现可以实现多个接口(interface)派生只能继承一个抽象基
接口(interface)可以继承多个其他接口(interface)只能继承一个抽象基
实现类接口(interface)的关系是 like a派生类抽象基类的关系是is a
成员包括常量抽象方法
默认方法静态方法
内部类
成员包括实例成员实例变量实例方法)、
静态成员静态变量静态方法)、
抽象方法内部类
实现类实现抽象方法必须指定public权限派生类重写抽象方法不能缩小访问权限
接口(interface)没有构造方法抽象类有构造方法
不继承java.lang.Object继承java.lang.Object

三、内部类

1、内部类是什么

在Java 中,可以将一个类定义另一个类里面或者一个方法里面,这样的类称为内部类。广泛意义上的内部类一般来说包括:成员内部类局部内部类匿名内部类

2、常见的内部类

2.1、成员内部类

成员内部类是最普通的内部类,它的定义位于另一个类内部和成员变量成员方法同级。这里提到的另一个类也被称为外部类成员内部类看起来就像是外部类的一个成员

成员内部类也可以按照是否使用static修饰而分为实例成员内部类静态成员内部类

下面是一个示例:
TestOutterClass类的源码:

package com.codeke.java.test;
// 外部类TestOutterClass
public class TestOutterClass {

    private String str = "我是TestOutterClass类中的成员变量str";
    public void print() {
        System.out.println("TestOutterClass类中的print()方法执行了");
        System.out.println("TestOutterClass类中的print()方法打印str:" + str);
    }

    // 内部类TestInnerClass
    class TestInnerClass {
        private String str = "我是TestInnerClass类中的成员变量str";
        public void print() {
            // print(); 内部类和外部类有相同名称和参数列表的方法,默认调用内部类的方法,这里会死循环,
            // 需要通过下面的语句调用外部类的print()方法
            TestOutterClass.this.print();
            System.out.println("TestInnerClass类中的print()方法执行了");
            System.out.println("TestInnerClass类中的print()方法打印str:" + str);
        }
    }
}

测试类Test类的源码:

package com.codeke.java.test;

public class Test {
    public static void main(String[] args) {
        TestOutterClass testOutterClass = new TestOutterClass();
        TestOutterClass.TestInnerClass testInnerClass = testOutterClass.new TestInnerClass();
        testInnerClass.print();
    }
}

执行输出结果:

TestOutterClass类中的print()方法执行了
TestOutterClass类中的print()方法打印str:我是TestOutterClass类中的成员变量str
TestInnerClass类中的print()方法执行了
TestInnerClass类中的print()方法打印str:我是TestInnerClass类中的成员变量str

说明:

  • 没有被static修饰成员内部类可以无条件访问外部类所有成员属性成员方法包括private成员静态成员);而static修饰成员内部类只能访问外部类中同样static修饰成员
  • 没有被static修饰成员内部类依附外部类对象而存在的,也就是说,如果要创建该类型的成员内部类的对象,前提是必须存在一个外部类的对象。如同本例Testmain方法中那样;static修饰成员内部类不依附外部类对象,创建该类型的内部类对象使用new 外部类名.内部类名()即可。
  • 在成员内部类中,当成员内部类拥有和外部类同名的、非静态成员变量或者方法(方法需要参数列表也相同)时,默认情况访问的是内部类成员如果访问外部类同名成员,需要使用外部类名.this.成员名,如本例中的TestOutterClass.this.print()
  • 没有被static修饰成员内部类不能存在静态成员外部类中如果要访问该类型成员内部类的成员必须创建一个成员内部类对象,再通过指向这个对象的引用来访问;对于被static修饰成员内部类外部类中如果要访问该类型成员内部类的静态成员,可以不需要内部类对象,而访问非静态成员时,仍然需要内部类对象
  • 成员内部类作为外部类的成员,可以使用所有的访问权限修饰符,即publicprotected缺省private

2.2、局部内部类

局部内部类定义在一个方法或者一个语句块里面的类,它的访问仅限于方法内或者语句块内
下面是一个示例:
TestOutterClass类的源码:

package com.codeke.java.test;

public class TestOutterClass {
    public void print(){
        // 局部内部类
        class TestInnerClass {
            void print(){
                System.out.println("TestInnerClass类中的print()方法执行了");
            }
        }
        new TestInnerClass().print();
    }
}

测试类Test类的源码:

package com.codeke.java.test;

public class Test {
    public static void main(String[] args) {
        new TestOutterClass().print();
    }
}

执行输出结果:

TestInnerClass类中的print()方法执行了

说明:

  • 局部内部类就像是方法里面的一个局部变量一样,是不能用publicprotectedprivate以及static修饰符修饰的。

2.3、匿名内部类

在开发过程中,如果接口或者抽象类中需要实现的方法很少,临时使用接口或者抽象类时,重新定义一个类单独实现方法又有些麻烦,可以直接使用匿名内部类对接口或者抽象类进行实现。

下面是一个示例:
Printable接口的源码:

package com.codeke.java.test;

public interface Printable {
    void print();
}

测试类Test类的源码:

package com.codeke.java.test;

public class Test {
    public static void main(String[] args) {
        Printable printable = new Printable() {
            @Override
            public void print() {
                System.out.println("匿名内部类中的print()方法执行了");
            }
        };
        printable.print();
    }
}

执行输出结果:

匿名内部类中的print()方法执行了

说明

  • 本例中,自始至终并没有见到实现了Printable接口的类的类名,这也是该类被称为匿名内部类的原因。

需要注意,内部类丰富了开发人员继承类、实现接口的手段,并且利于数据安全和代码封装、隐藏,但内部类不利于代码复用,一定程度上增加了代码阅读难度,故在开发过程中,需要根据具体情况选择使用。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值