今天学习的内容是内部类
内部类就是将一个类的定义放在另一个类的内部。内部类的知识点如下:
- 内部类分为成员内部类、局部内部类和匿名内部类
- 编译期过后,每个内部类都会生成一个字节码文件
- 成员内部类:外部类名$内部类名.class
- 局部内部类:外部类名$数字标识+内部类名.class
- 匿名内部类:外部类名$数字标识.class
- 在外部类的非静态方法中创建内部类对象的格式:内部类 引用=new 内部类();
- 在别的类或者外部类的静态方法中必须借助外部类对象来创建内部类对象,格式:外部类.内部类 引用=外部类引用.new 内部类()
- 内部类可以直接访问外部类的内容,包括private内容。原因是内部类持有外部类.this,也就是说编译器帮着自动添加了外部类.this
- 外部类不能直接访问内部类的内容,必须先创建内部类对象。注意在外部类中也可以访问内部类的private内容
- 成员内部类还可以是private、protected和static的
- private内部类只能在外部类访问,所以要在别的类使用private内部类有点类似使用private构造方法。一般先让private内部类实现某个接口,然后设置一个getter方法用来获得内部类对象(方法返回值为接口)。通过此方法获得内部类对象之后再向上转型为接口类型即可。protected内部类与之类似,只是访问权限有些不同。这就是内部类最基本用途!!
- 创建静态内部类对象不需要借助外部类对象;如果内部类中定义了静态内容,该内部类必须是静态内部类
- 在定义局部内部类的方法的外部不能访问该内部类,但是该内部类可以访问该方法的局部变量以及外部类的所有成员
- JDK1.7时,局部内部类和匿名内部类只能访问方法的final局部变量,而在JDK1.8取消了这个限制(主要是Lamda和方法引用的出现造成的)
- 使用匿名内部类的前提:匿名内部类必须继承或实现某外部类或接口
- 匿名内部类实质上就是向上转型
- 不要在匿名内部类中定义接口没有的方法,因为即使你定义了,接口引用也不能调用(但是匿名内部类对象本身可以调用)
- 匿名内部类既可以扩展类,也可以实现接口,但不能两者兼备。而且如果实现接口,也只能实现一个接口。(要不实现一个接口,要不就继承一个类)
- 匿名内部类的使用场景通常是:当方法参数是接口类型,且接口中的方法不超过三个,可以使用匿名内部类作为实参进行传递(swing中监听经常使用匿名内部类)
- 使用局部内部类而不是匿名内部类的理由有两个:第一,我们需要一个已命名的构造函数。第二,需要不止一个该内部类对象
示例程序:
public class Outer {
private int a = 1;
public void show() {
//在外部类的非静态方法中创建内部类对象的格式:内部类 引用=new 内部类();
Inner_1 inner_1 = new Inner_1();
inner_1.print();
//注意在外部类中也可以访问内部类的private内容
System.out.println("内部类的private变量b = " + inner_1.b);
}
//成员内部类,成员内部类可以是private、包访问权限和protected的,还可以是static的
class Inner_1 {//字节码文件名Outer$Inner_1.class
private int b = 1;
public void print() {
//内部类可以直接访问外部类的内容,包括private内容
System.out.println("外部类的private变量a = " + a);
//原因:内部类持有了外部类.this,编译器自动帮着添加了外部类.this
System.out.println("外部类的private变量a = " + Outer.this.a);
}
}
//成员内部类也可以是private的,如果要在别的类使用内部类对象,就要设置一个getter(protected差不多,就是权限扩大了点)
private class Inner_2 implements A {
}
//要在别的类使用private内部类,必须有getter
public Inner_2 getInner_2(){
return new Inner_2();
}
//静态内部类,如果内部类中定义了静态内容,该内部类必须是静态内部类
static class Inner_3{
private static int i;
private int x;
}
//定义局部内部类的方法
public void method(final int z){
int x=10;
final int y=10;
//局部内部类
class Inner_4{//字节码文件名Outer$1Inner_4.class
private void go(){
System.out.println("外部类中的a="+Outer.this.a);//局部内部类也可以访问外部类成员
System.out.println(x); //JDK1.7时,局部内部类只能访问方法的final局部变量,JDK1.8取消了这个限制
System.out.println(y);
System.out.println(z);
}
}
Inner_4 inner_4=new Inner_4();
inner_4.go();
}
public static void main(String[] args) {
Outer outer = new Outer();
outer.show();
//在外部类的静态方法中必须借助外部类对象来创建内部类对象,格式:外部类.内部类 引用=外部类引用.new 内部类()
Outer.Inner_1 inner_1 = outer.new Inner_1();
inner_1.print();
//private内部类对象在本类中随意获取
Outer.Inner_2 inner_2 = outer.new Inner_2();
//在外部类的静态方法中创建静态内部类对象不需要借助外部类
Inner_3 inner_3 = new Inner_3();
outer.method(1);
}
}
interface A {
}
class OuterTest{
public static void main(String[] args) {
Outer outer = new Outer();
//在别的类必须借助外部类对象来创建内部类对象,格式:外部类.内部类 引用=外部类引用.new 内部类()
Outer.Inner_1 inner_1 = outer.new Inner_1();
inner_1.print();
//!System.out.println("内部类中的b="+inner_1.b);//注意:在别的类不能访问内部类的private成员
//获取private内部类的对象
A a = outer.getInner_2();
//在别的类创建静态内部类对象
Outer.Inner_3 inner_3 = new Outer.Inner_3();
}
}
public class Frame {
private JFrame frame;
private JButton button;
public void gui(){
frame=new JFrame();
button=new JButton("button");
frame.setVisible(true);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(button);
showClick();
}
public void showClick(){
//匿名内部类
//前提:匿名内部类必须继承或实现某外部类或接口,在这里就是实现了ActionListener接口
//格式:new 父类/接口(){子类/实现类内容}
//通常使用场景:当方法参数是接口类型,且接口中的方法不超过三个,可以使用匿名内部类作为实参进行传递
button.addActionListener(new ActionListener() {//字节码文件名Outer$1.class
@Override
public void actionPerformed(ActionEvent e) {
// TODO Auto-generated method stub
button.setText("I'm clicked!");
}
});//注意:实际上这是向上转型
}
public static void main(String[] args){
new Frame().gui();
}
}