内部类是定义在另一个类中的类,为什么需要内部类呢?其主要原因有以下三点:
1、内部类方法可以访问该类定义所在的作用域中的数据,包括私有数据。
2、内部类可以对同一个包中的其他类隐藏起来。
3、当要定义一个回调函数且不想编写大量代码时,使用匿名内部类比较便捷。
内部类的共性:
1、内部类仍然是一个独立的类,在编译之后内部类会被编译成独立的.class文件,但是前面冠以外部类的类名和$符号 。
2、内部类不能用普通的方式访问。内部类是外部类的一个成员,因此内部类可以自由地访问外部类的成员变量,无论是否是private的 。
3、内部类声明成静态的,就不能随便的访问外部类的成员变量了,此时内部类只能访问外部类的静态成员变量 。
java内部类分为: 成员内部类、方法内部类(局部内部类)、匿名内部类、静态嵌套类 。
成员内部类:
通俗的说就是把内部类当做外部类的成员
package com.stone.InnerClassTest; import java.awt.*; import java.awt.event.*; import java.util.*; import javax.swing.*; import javax.swing.Timer; public class InnerClassTest { public static void main(String[] args) { TalkingClock clock = new TalkingClock(1000, true); clock.start(); JOptionPane.showMessageDialog(null, "Quit program?"); System.exit(0); } } class TalkingClock { public TalkingClock(int interval, boolean beep) { this.interval = interval; this.beep = beep; } public void start() { ActionListener listener = new TimePrinter(); Timer t = new Timer(interval, listener); t.start(); } private int interval; private boolean beep; public 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(); } } }
局部内部类:
class Outer { public void doSomething() { class Inner { public void seeOuter() { } } } }
(1)、局部内部类只能在定义该内部类的方法内实例化,不可以在此方法外对其实例化。
(2)、局部内部类对象不能使用该内部类所在方法的非final局部变量。
因为方法的局部变量位于栈上,只存在于该方法的生命期内。当一个方法结束,其栈结构被删除,局部变量成为历史。但是该方法结束之后,在方法内创建的内部类对象可能仍然存在于堆中!例如,如果对它的引用被传递到其他某些代码,并存储在一个成员变量内。正因为不能保证局部变量的存活期和方法内部类对象的一样长,所以内部类对象不能使用它们。
下面是完整的例子:
package com.stone.LocalInnerClassTest; import java.awt.*; import java.awt.event.*; import java.util.*; import javax.swing.*; import javax.swing.Timer; public class LocalInnerClassTest { public static void main(String[] args) { TalkingClock clock = new TalkingClock(); clock.start(1000, true); JOptionPane.showMessageDialog(null, "Quit program?"); System.exit(0); } } class TalkingClock { public void start(int interval, final boolean beep) { final String methodname="methodname"; //不声明为final,编译报错 class TimePrinter implements ActionListener { public void actionPerformed(ActionEvent event) { Date now = new Date(); System.out.println("At the tone, the time is " + now); System.out.println(methodname); if (beep) Toolkit.getDefaultToolkit().beep(); } } ActionListener listener = new TimePrinter(); Timer t = new Timer(interval, listener); t.start(); } }
匿名内部类
new SuperType(construction parameters){ inner class methods and data }
什么情况下需要使用匿名内部类?如果满足下面的一些条件,使用匿名内部类是比较合适的。
1、只用到类的一个实例 。
2、类在定义后马上用到。
3、类非常小(SUN推荐是在4行代码以下)
4、给类命名并不会导致你的代码更容易被理解。
在使用匿名内部类时,要记住以下几个原则:
1、匿名内部类不能有构造方法。
2、匿名内部类不能定义任何静态成员、静态方法。
3、匿名内部类不能是public,protected,private,static。
4、只能创建匿名内部类的一个实例。
5、一个匿名内部类一定是在new的后面,用其隐含实现一个接口或实现一个类。
6、因匿名内部类为局部内部类,所以局部内部类的所有限制都对其生效。
匿名内部类根据其实现方式的不同分为三类:继承式的匿名内部类、接口式的匿名内部类、参数式的匿名内部类。
继承式的匿名内部类:
package com.stone.AnonymousInnerClassTest; public class ExtendsAnonyInnerClass { public void drive() { System.out.println("Driving a car!"); } public static void main(String[] args) { ExtendsAnonyInnerClass car = new ExtendsAnonyInnerClass() { public void drive() { System.out.println("Driving another car!"); } }; car.drive(); } }
输出结果:
Driving another car!
接口式的匿名内部类
package com.stone.AnonymousInnerClassTest; interface Vehicle { public void drive(); } public class InterfaceAnonyInnerClass { public static void main(String[] args) { Vehicle v = new Vehicle() { public void drive() { System.out.println("Driving a car!"); } }; v.drive(); } }
输出结果:
Driving a car!
参数式的匿名内部类
package com.stone.AnonymousInnerClassTest; public class ParaAnonyInnerClass { public static void main(String[] args) { Bar b = new Bar(); b.doStuff(new Foo() { public void foo() { System.out.println("foofy"); } }); } } class Bar { void doStuff(Foo f) { f.foo(); } } interface Foo { void foo(); }
我们根据以上的定时器的例子来重写一个匿名内部类实现,此实现方式为接口匿名内部类
package com.stone.AnonymousInnerClassTest; import java.awt.*; import java.awt.event.*; import java.util.*; import javax.swing.*; import javax.swing.Timer; public class AnonymousInnerClassTest { public static void main(String[] args) { TalkingClock clock = new TalkingClock(); clock.start(1000, true); 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(); } }; Timer t = new Timer(interval, listener); t.start(); } }
静态嵌套类
有的时候内部类只为试了把一个类隐藏在另一个类的内部,并不需要内部类引用外部类的对象。为此,可以将内部类声明为static,以便取消产生的引用。
package com.stone.StaticInnerClassTest; 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()); } } class ArrayAlg { public static class Pair { public Pair(double f, double s) { first = f; second = s; } public double getFirst() { return first; } public double getSecond() { return second; } private double first; private double second; } 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); } }
在内部类不需要使用外围类的对象时,应该使用静态内部类。
为什么需要内部类?
典型的情况是,内部类继承自某个类或实现某个接口,内部类的代码操作创建其的外围类的对象。所以你可以认为内部类提供了某种进入其外围类的窗口。
使用内部类最吸引人的原因是:每个内部类都能独立地继承自一个(接口的)实现,所以无论外围类是否已经继承了某个(接口的)实现,对于内部类都没有影响。如果没有内部类提供的可以继承多个具体的或抽象的类的能力,一些设计与编程问题就很难解决。从这个角度看,内部类使得多重继承的解决方案变得完整。接口解决了部分问题,而内部类有效地实现了“多重继承”。