内部类不仅经常出现在各种面试题中,还会在 Java 源码中频频出现,因此只有搞明白了 Java 内部类,才能搞定面试和看懂各种 Java 源码。
内部类
Java 内部类,分为以下四种:
- 成员内部类
- 静态成员内部类
- 局部内部类
- 匿名内部类
下面分别来看这些内部类的使用。
成员内部类
定义
在一个类中定义了另一个类,则将定义在类中的那个类称之为成员内部类。成员内部类也是最普通的内部类。
使用
成员内部类的使用示例如下:
class Outer {
public Outer() {
System.out.println("Outer Class.");
}
class Inner {
public void sayHi() {
System.out.println("Hi, Inner.");
}
}
}
其中 Inner 类则为成员内部类。 而成员内部类的创建和使用,请参考以下完整的示例代码:
class InnerTest {
public static void main(String[] args) {
Outer out = new Outer();
// 创建成员内部类
Outer.Inner inner = out.new Inner();
inner.sayHi();
}
}
class Outer {
public Outer() {
System.out.println("Outer Class.");
}
class Inner {
public void sayHi() {
System.out.println("Hi, Inner.");
}
}
}
成员内部类的创建
语法:
Outer.Inner inner = new Outer().new Inner();
内部类访问外部类
语法:
Outer.this.xxx
代码示例:
class Outer {
private String name = "OuterClass";
public void sayHi() {
System.out.println("Hi, Outer.");
}
class Inner {
public void sayHi() {
// 内部类访问外部类
Outer.this.sayHi();
System.out.println(Outer.this.name);
System.out.println("Hi, Inner.");
}
}
}
class InnerTest {
public static void main(String[] args) {
Outer.Inner inner = new Outer().new Inner();
inner.sayHi();
}
}
外部类访问内部类
语法:
new Inner().xxx
代码示例:
class Outer {
public void sayHi() {
System.out.println(new Inner().name);
System.out.println("Hi, Outer.");
}
private class Inner {
String name = "InnerClass";
public void sayHi() {
System.out.println("Hi, Inner.");
}
}
}
class InnerTest {
public static void main(String[] args) {
new Outer().sayHi();
}
}
小结
- 成员内部类可直接访问外部类(使用:外部类.this.xxx);
- 外部成员类要访问内部类,必须先建立成员内部类对象;
- 成员内部类可使用任意作用域修饰(public、protected、默认、private);
- 成员内部类可访问外部类任何作用域修饰的属性和方法;
- 外部类建立成员内部类对象之后,可以访问任何作用域修饰的内部类属性和方法。
静态成员内部类
定义
在一个类中定义了另一个 static 类,则将定义在类中的那个 static 类称之为静态成员内部类。
静态成员内部类也就是给内部成员类加上 static 修饰符。
使用
静态成员内部类的使用示例如下:
class OuterClass {
public OuterClass() {
System.out.println("OuterClass Init.");
}
protected static class InnerClass {
public void sayHi() {
System.out.println("Hi, InnerClass.");
}
}
}
class InnerClassTest {
public static void main(String[] args) {
OuterClass.InnerClass innerClass = new OuterClass.InnerClass();
innerClass.sayHi();
}
}
与内部成员类的创建方式 new Outer().new Inner() 不同,静态成员内部类可使用 new OuterClass.InnerClass() 的方式进行创建。
注意:不能从静态成员内部类中访问非静态外部类对象。
局部内部类
定义
一个类定义在另一个类的局部(方法或者任意作用域),这个类就称之为局部内部类。
使用
局部内部类的使用示例如下:
class OutClass {
public void sayHi() {
class InnerClass {
InnerClass(String name) {
System.out.println("InnerClass:" + name);
}
}
System.out.println(new InnerClass("Three"));
System.out.println("Hi, OutClass");
}
}
class OutTest {
public static void main(String[] args) {
new OutClass().sayHi();
}
}
局部内部类特点
- 局部内部类不能使用任何访问修饰符;
- 局部类如果在方法中,可以直接使用方法中的变量,不需要通过 OutClass.this.xxx 的方式获得。
匿名内部类
定义
没有名字的内部类就叫做匿名内部类。
使用
匿名内部类的使用示例如下:
interface AnonymityOuter {
void hi();
}
class AnonymityTest {
public static void main(String[] args) {
AnonymityOuter anonymityOuter = new AnonymityOuter() {
@Override
public void hi() {
System.out.println("Hi, AnonymityOuter.");
}
};
anonymityOuter.hi();
}
}
其中,new AnonymityOuter() 之后的 {…} 大括号包含的部分就为匿名内部类。
匿名内部类特点
- 匿名内部类必须继承一个父类或者实现一个接口
- 匿名内部类不能定义任何静态成员和方法
- 匿名内部类中的方法不能是抽象的
枚举类
枚举类是 JDK 1.5 引入的新特性,使用关键字“enum”声明。枚举功能虽小,却非常实用,大大方便了程序的开发者。
枚举类的使用
请参考以下代码:
enum ColorEnum {
RED,
BLUE,
YELLOW,
GREEN
}
class EnumTest {
public static void main(String[] args) {
ColorEnum color = ColorEnum.GREEN;
switch (color) {
case RED:
System.out.println("Red");
break;
case BLUE:
System.out.println("Blue");
break;
case YELLOW:
System.out.println("Yellow");
break;
case GREEN:
System.out.println("Green");
break;
default:
break;
}
}
}
枚举类命名规范
《阿里巴巴 Java 开发手册》对枚举类的命名规范建议,如下图:
扩展枚举类
我们可以自定义一些枚举类方法,扩展枚举类的使用,请参考以下代码:
enum ColorsEnum {
RED("红色", 1),
BLUE("蓝色", 2),
YELLOW("黄色", 3),
GREEN("绿色", 4);
ColorsEnum(String name, int index) {
this.name = name;
this.index = index;
}
private String name;
private int index;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getIndex() {
return index;
}
public void setIndex(int index) {
this.index = index;
}
}
class EnumTest {
public static void main(String[] args) {
System.out.println(ColorsEnum.RED.getName());
System.out.println(ColorsEnum.RED.getIndex());
}
}
执行以上代码返回的结果:
红色
1