内部类:
package innerClass; import javax.swing.*; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.util.Date; /** * Created by admin on 2017-3-29. */ 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{ private int interval; private boolean beep; 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(); } class TimePrinter implements ActionListener{ @Override public void actionPerformed(ActionEvent e) { System.out.println(new Date()); if (beep){ System.out.println("beep"); } } } }
非内部类:
package innerClass; import javax.swing.*; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.util.Date; /** * Created by admin on 2017-3-29. */ 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{ private int interval; private boolean beep; public TalkingClock(int interval, boolean beep) { this.interval = interval; this.beep = beep; } static boolean access$000(TalkingClock talkingClock){ return talkingClock.beep; } public void start(){ ActionListener listener = new TimePrinter(this); Timer t = new Timer(interval,listener); t.start(); } } class TimePrinter implements ActionListener{ private TalkingClock outer; public TimePrinter(TalkingClock clock) { outer = clock; } @Override public void actionPerformed(ActionEvent e) { System.out.println(new Date()); if (TalkingClock.access$000(outer)){ System.out.println("beep"); } } }
1.内部类可以访问该类定义所在作用域中数据,包括私有。是因为内部类的对象有一个隐式引用,他指向了创建它的外部类对象。外部类的引用在构造器中设置,构造器的参数为外部类引用。
2.内部类一种编译器现象,与虚拟机无关。编译器会把内部类翻译成用$(美元符号)分隔外部类名与内部类名的常规文件。编译器为了引用外部类,会生成一个附加的实例域this$0(名字是有编译器合成的,在自己的代码中不能引用它)。
3.内部类被翻译成名字怪异的常规类,对于域来说,每个域会自动生成一个静态方法access$000(或access$0),该方法接受所属类对象为参数,返回值传给域。可以利用这个在B类中调用A类的私有方法。
局部内部类:
package innerClass; import javax.swing.*; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.util.Date; /** * Created by admin on 2017-3-29. */ 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{ private int interval; private boolean beep; public TalkingClock(int interval, boolean beep) { this.interval = interval; this.beep = beep; } public void start(){ class TimePrinter implements ActionListener{ @Override public void actionPerformed(ActionEvent e) { System.out.println(new Date()); if (beep){ System.out.println("beep"); } } } ActionListener listener = new TimePrinter(); Timer t = new Timer(interval,listener); t.start(); } }
局部内部类不能用public或private访问说明符进行说明。它的作用域被限定在声明这个局部类的块中。优势:仅仅start方法指导该局部内部类的存在。
从外部方法访问变量:
package innerClass; import javax.swing.*; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.util.Date; /** * Created by admin on 2017-3-29. */ public class InnerClassTest { 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){ class TimePrinter implements ActionListener{ @Override public void actionPerformed(ActionEvent e) { System.out.println(new Date()); if (beep){ System.out.println("beep"); } } } ActionListener listener = new TimePrinter(); Timer t = new Timer(interval,listener); t.start(); } }
不仅能够访问包含他们的外部类,还可以访问局部变量。不过。局部变量必须被声明为final。(如果不设为final的话,start方法结束后,beep参数变量不复存在)。
实际上,当创建一个局部内部类对象时,ceep会被传递给构造器,并存储在val$beep域中。编译器必须检测对局部变量的访问,为每一个变量建立相应的数据域,并将局部变量拷贝到构造器中,以便将这些数据初始化为局部变量的副本(只有在构造器中调用一次,所以局部变量必须是final,不可改变的,否则很容易就不一致了)。但是有时会想要改变参数,比如计数器,考虑必须是final的,也必须是可以改变值的,所以用到了数组,final代表数组的对象不变,但是里面的只可以改变。
匿名内部类:
package innerClass; import javax.swing.*; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.util.Date; /** * Created by admin on 2017-3-29. */ public class InnerClassTest { 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){ Timer t = new Timer(interval, new ActionListener() { @Override public void actionPerformed(ActionEvent e) { System.out.println(new Date()); if (beep){ System.out.println("beep"); } } }); t.start(); } }
匿名内部类在jdk1.8中可以用lambda表达式来代替。
注:::t.invaite(new ArrayList<String>(){{ add.("Harry"); add("Tony");}})。双大括号初始化:外层:ArrayList的匿名类,内层:对象构造块。
静态内部类:
package innerClass; /** * Created by lyj on 2017-3-30. */ public class ArrayAlg { public static void main(String[] args) { double[] a = new double[10]; for(int i=0;i<a.length;i++){ a[i] = Math.random()*100;//0-100 } Pair pair = ArrayAlg.minmax(a); System.out.println(pair.getFirst()); System.out.println(pair.getSecond()); } public static Pair minmax(double[] values){ double max = Double.MIN_VALUE; double min = Double.MAX_VALUE; for (double v : values) { if(min > v){ min = v; } if(max < v){ max = v; } } System.out.println(min); System.out.println(max); return new ArrayAlg.Pair(min,max); } public static class Pair{ private double first; private double second; public Pair(double first, double second) { this.first = first; this.second = second; } public double getFirst() { return first; } public double getSecond() { return second; } } }
静态内部类的对象除了没有对生成它的外部类对象的引用特权之外,与其他所有内部类完全一样。在内部类不需要访问外部类对象时,应该使用静态内部类。
注:::生命在接口中的内部类自动成为static和public类。