内部类
- 内部类既可以访问自身的数据域,也可以访问创建它的外部类对象的数据域
- 内部类对象总有一个隐式引用,它指向了创建它的外部类的对象
- 外部类的引用在内部类的构造方法中设置,不必手动设置,编译器会自动在构造方法中生成外部类引用
- 只有内部类可以是私有的,建议设置为私有的,这样只有外部类的方法才可以构造该对象。
- 在外部类的作用域中,可以通过
OuterClass.InnerClass
引用内部类 - 只有静态内部类可以有静态方法
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) { TalkingClock clock = new TalkingClock(1000, true); // 使用外部类对象创建一个内部类对象 TalkingClock.TimePrinter newClock = clock.new TimePrinter(); newClock.print_inner(); clock.start(); // keep program running until user selects "Ok" JOptionPane.showMessageDialog(null, "Quit program?"); System.exit(0); } } class TalkingClock { private int interval; private boolean beep; public TalkingClock(int interval, boolean beep) { this.interval = interval; this.beep = beep; } /** * Starts the clock. */ public void start() { ActionListener listener = new TimePrinter(); Timer t = new Timer(interval, listener); t.start(); } private void print() { System.out.println("hello"); } // public void setBeep(boolean beep) { // this.beep = beep; // } class TimePrinter implements ActionListener { public TimePrinter() { } public void actionPerformed(ActionEvent event) { Date now = new Date(); System.out.println("At the tone, the time is " + now); // print(); if (beep) { Toolkit.getDefaultToolkit().beep(); // setBeep(false); } } public void print_inner() { System.out.println("inner"); } } } |
局部内部类
局部类不能用public
或private
访问修饰符进行声明。它的作用域被限定在声明这个局部类的块中。
局部类只能访问的局部变量需要是不可变的。需要更改计数时,可以定义一个数组,对数组值进行更新。
局部类并不是直接调用方法传递的参数,而是利用自身的构造器对传入的参数进行备份,内部类的方法调用的实际上是自己的属性而不是外部方法传递进来的参数
为什么要将局部内部类访问的局部变量设置为final
?
简单理解: 拷贝引用,为了避免引用值发生改变,例如被外部类的方法修改等,而导致内部类得到的值不一致,于是用 final 来让该引用不可改变。
import javax.swing.*; import java.awt.*; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.util.Date; public class LocalInnerClassTest { public static void main(String[] args) { TalkingClock clock = new TalkingClock(); clock.start(1000, true); // keep program running until user selects "Ok" JOptionPane.showMessageDialog(null, "Quit program?"); System.exit(0); } } class TalkingClock { public void start(int interval,final boolean beep) { int[] arr = new int[1]; class TimePrinter implements ActionListener { public void actionPerformed(ActionEvent event) { Date now = new Date(); System.out.println("At the tone, the time is " + now); if (beep) Toolkit.getDefaultToolkit().beep(); arr[0]++; System.out.println(arr[0]); } } ActionListener listener = new TimePrinter(); Timer t = new Timer(interval, listener); t.start(); } } |
匿名内部类
- 使用匿名内部类时,我们必须是继承一个类或者实现一个接口,但是两者不可兼得,同时也只能继承一个类或者实现一个接口。
- 匿名内部类中是不能定义构造方法的。
- 匿名内部类中不能存在任何的静态成员变量和静态方法。
- 匿名内部类为局部内部类,所以局部内部类的所有限制同样对匿名内部类生效。
- 匿名内部类不能是抽象的,它必须要实现继承的类或者实现的接口的所有抽象方法。
import javax.swing.*; import java.awt.*; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.util.Date; public class AnonymousInnerClassTest { public static void main(String[] args) { TalkingClock clock = new TalkingClock(); clock.start(1000, true); // keep program running until user selects "Ok" JOptionPane.showMessageDialog(null, "Quit program?"); System.exit(0); } } class TalkingClock { public void start(int interval, final boolean beep) { // 匿名内部类 // ActionListener listener = new ActionListener() // { // public void actionPerformed(ActionEvent event) // { // Date now = new Date(); // System.out.println("At the tone, the time is " + now); // if (beep) Toolkit.getDefaultToolkit().beep(); // } // }; // 使用lambda表达式 ActionListener listener = event -> { Date now = new Date(); System.out.println("At the tone, the time is " + now); if (beep) Toolkit.getDefaultToolkit().beep(); }; Timer t = new Timer(interval, listener); t.start(); } } |
由于匿名内部类没有构造方法,所以只能通过构造代码块来进行构造
语法形式:
new 实现接口() { //匿名内部类类体部分 } new 父类构造器(实参列表) { //匿名内部类类体部分 } |
abstract class Person { public abstract void eat(); } interface Player { void play(); } public class Demo { public static void main(String[] args) { Person p = new Person() { @Override public void eat() { System.out.println("eating"); } }; p.eat(); Player player = new Player() { @Override public void play() { System.out.println("playing"); } }; player.play(); } } |
静态内部类
有时候使用内部类只是为了把一个类隐藏在另外一个类的内部,并不需要内部类引用外部类对象。为此,可以将内部类声明为
static
只能在内部类中定义静态类。静态内部类的对象除了没有对生成它的外部类对象的引用特权外,与其他所有内部类完全一样。
静态类只能引用外部类的static
成员变量或方法
只有静态内部类可以定义static
成员变量或方法,普通的内部类不行!
创建一般内部类和静态内部类的区别:
//假设类A有静态内部类B和非静态内部类C,创建B和C的区别为: A a=new A(); //创建B A.B b=new A.B(); //创建C A.C c=a.new C(); |
public class StaticInnerClassTest { public static void main(String[] args) { double[] d = new double[20]; for (int i = 0; i < d.length; i++) d[i] = 100 * Math.random(); ArrayAlg.Pair p = ArrayAlg.minmax(d); System.out.println("min = " + p.getFirst()); System.out.println("max = " + p.getSecond()); // 调用静态内部类的静态变量和静态方法 ArrayAlg.Pair.print(); System.out.println(ArrayAlg.Pair.NUMBER); } } class ArrayAlg { private static final boolean flag = false; public static void outerClassMethod(){ System.out.println("inner method"); } public static class Pair { private double first; private double second; public static final Integer NUMBER = 20; public Pair(double f, double s) { first = f; second = s; } public double getFirst() { return first; } public double getSecond() { return second; } // 静态内部类中可以定义静态方法 public static void print() { // 可以调用外部类的静态方法(变量) System.out.println("flag: " + flag); outerClassMethod(); System.out.println("static method"); } } public static Pair minmax(double[] values) { double min = Double.MAX_VALUE; double max = Double.MIN_VALUE; for (double v : values) { if (min > v) min = v; if (max < v) max = v; } return new Pair(min, max); } } |