使用内部类原因:
- 内部类方法可以访问该类定义所在的作用域中的数据,包括私有的数据。
- 内部类可以对同一个包中的其他类隐藏起来。
- 当想要定义一个回调函数且不想编写大量代码时,使用匿名内部类比较便捷。
# 使用内部类访问对象状态
package com.example.demo.test; | |
import javax.swing.*; | |
import java.awt.*; | |
import java.awt.event.ActionEvent; | |
import java.awt.event.ActionListener; | |
import java.util.Date; | |
public class InnerClassTest { | |
public static void main(String[] args) { | |
Person person = new Person(true); | |
person.run(); | |
} | |
} | |
class Person { | |
private boolean isHungry; | |
public Person(boolean isHungry) { | |
this.isHungry = isHungry; | |
} | |
public void run() { | |
Eat eat = new Eat(); | |
eat.eatSomthing(); | |
} | |
public class Eat { | |
public void eatSomthing() { | |
if (isHungry) { | |
System.out.println("Eating!"); | |
} | |
} | |
} | |
} |
运行结果:
Eating!
在内部类 Eat 中,可以访问到类外部的 isHungary 变量。
内部类对象拥有一个对外围类对象的引用,如下图:
这个引用 outer 类似于 super,但是 outer 并不是 Java 的关键字。
Eat 内部类中,没有定义构造器,编译器为其生成了一个默认的构造器,代码如下:
public Eat(Person person) { | |
outer = person; | |
} |
Person 类中 run 方法 new 一个 Eat 对象时,默认传入一个 this 引用参数,代码如下:
Eat eat = nwe Eat(this); |
# 内部类的特殊语法规则
表达式 OuterClass.this
表示外围类的引用。例如,在 Eat 内部类中:
if (Person.this.isHungry) { | |
System.out.println("Eating!"); | |
} |
表达式 outerObject.new InnerClass(construction parameters)
表示内部对象的构造器。例如,在 Person 类的 run 方法中:
Eat eat = this.new Eat(); |
当使用另一个外部对象 new 一个内部对象时,这种写法就比较有意义。
package com.example.demo.test; | |
import javax.swing.*; | |
import java.awt.*; | |
import java.awt.event.ActionEvent; | |
import java.awt.event.ActionListener; | |
import java.util.Date; | |
public class InnerClassTest { | |
public static void main(String[] args) { | |
Person person = new Person(false); | |
person.run(); | |
} | |
} | |
class Person { | |
private boolean isHungry; | |
public Person(boolean isHungry) { | |
this.isHungry = isHungry; | |
} | |
public void run() { | |
Person person = new Person(true); | |
Eat eat = person.new Eat(); | |
eat.eatSomthing(); | |
} | |
public class Eat { | |
public void eatSomthing() { | |
if (Person.this.isHungry) { | |
System.out.println("Eating!"); | |
} | |
} | |
} | |
} |
运行结果:
Eating!
创建了一个 isHungary 为 false 的 person 对象,如果创建这个对象的内部对象,程序运行不会打印出任何结果。在 run 方法中,创建的 isHungary 为 true 的 person 的内部对象,所以程序运行有输出结果。
表达式 OuterClass.InnerClass
表示在外围类中引用内部类。也可以在 Person 类外部实现 run 方法的逻辑:
public class InnerClassTest { | |
public static void main(String[] args) { | |
Person person = new Person(true); | |
Person.Eat eat = person.new Eat(); | |
eat.eatSomthing(); | |
} | |
} |
运行结果:
Eating!
# 局部内部类
Eat 类只有在 run 方法中使用过一次,像这种只使用一次的内部类,可以在方法中定义一个局部内部类。
public void run() { | |
class Eat { | |
public void eatSomthing() { | |
if (isHungry) { | |
System.out.println("Eating!"); | |
} | |
} | |
} | |
Eat eat = new Eat(); | |
eat.eatSomthing(); | |
} |
局部内部类的作用域声明这个局部类的块中,不能用 public 或 private 访问修饰符进行声明。
# 匿名内部类
如果只想要创建一个对象,并不关系这个类是什么,可以使用匿名内部类。
package com.example.demo.test; | |
import javax.swing.*; | |
import java.awt.*; | |
import java.awt.event.ActionEvent; | |
import java.awt.event.ActionListener; | |
import java.util.Date; | |
public class InnerClassTest { | |
public static void main(String[] args) { | |
Person person = new Person(true); | |
person.run(); | |
} | |
} | |
class Person { | |
private boolean isHungry; | |
public Person(boolean isHungry) { | |
this.isHungry = isHungry; | |
} | |
public void run() { | |
Man man = new Man() { | |
@Override | |
public void eat() { | |
if (isHungry) { | |
System.out.println("Eating!"); | |
} | |
} | |
}; | |
man.eat(); | |
} | |
} | |
interface Man { | |
void eat(); | |
} |
运行结果:
Eating!
# 静态内部类
当不需要内部类引用外部类对象时,可以将内部类声明为 static,即静态内部类。
package com.example.demo.test; | |
import java.util.ArrayList; | |
import java.util.Collections; | |
import java.util.List; | |
public class InnerClassTest { | |
public static void main(String[] args) { | |
Person.Number number = Person.run(new ArrayList<Integer>() |