内部类( Inner Class )就是定义在另外一个类里面的类。与之对应,包含内部类的类被称为外部类(Outer Class)。
内部类的声明格式:
标识符 class 外部类的名称 {
//外部类的成员
标识符 class 内部类的名称 {
//内部类的成员
}
}
如下例子:
class Outer{
private String info = "Outer";
public class Inner {
public void print() {
System.out.println(info);
}
};
public void fun() {
new Inner().print();
}
};
public class InnerClassDemo {
public static void main(String[] args) {
new Outer().fun();
}
}
程序运行结果:
Outer
都说类是由属性和方法构成的,现在在一个类中又增加一个类,会不会矛盾呢?其实并不矛盾,但是内部类的确破坏了一个类的基本结构,那为什么还要使用内部类呢?其实内部类的使用有如下几个优点:
- 内部类提供了更好的封装,可以把内部类隐藏在外部类之内,不允许同一个包中的其他类访问该类。
- 内部类的方法可以直接访问外部类的所有数据,包括私有的数据。
- 内部类所实现的功能使用外部类同样可以实现,只是有时使用内部类更方便。
看看如下代码:
class Outer {
private String info = "Outer";
public String getInfo() {
return this.info;
}
public void fun() {
new Inner(this).print();
}
}
class Inner {
private Outer out = null;
public Inner(Outer out) {
this.out = out;
}
public void print() {
System.out.println(out.getInfo());
}
}
public class InnerClassDemo {
public static void main(String[] args) {
new Outer().fun();
}
}
运行结果:
Outer
对比一中用内部类实现的,发现没有用内部类实现的复杂了很多。
内部类分为如下四种:
- 成员内部类
- 静态内部类
- 方法内部类
- 匿名内部类
成员内部类一旦定义就相当于外部类的一个成员变量,内部类可以使用任意访问修饰符修饰,public、private、protected等。
内部类中定义的方法可以直接访问外部类的数据,而不受访问修饰符影响,如访问外部类的私有属性。
编译如下程序会生成三个 .class 文件,Outer.class Outer$Inner.class InnerClassDemo.class (成员内部类的 .class 文件总是这样:外部类名$内部类名.class)
注意:
1. 外部类是不能直接使用内部类的成员和方法。可先创建内部类的对象,然后通过内部类的对象来访问其成员变量和方法。
2. 如果外部类和内部类具有相同的成员变量或方法,内部类默认访问自己的成员变量或方法,如果要访问外部类的成员变量,可以使用 this 关键字。
class Outer{ private String info = "Outer"; public class Inner { private String info = "Inner"; public void print() { System.out.println(info); } }; public void fun() { new Inner().print(); } }; public class InnerClassDemo { public static void main(String[] args) { Outer out = new Outer(); Outer.Inner in = out.new Inner(); in.print(); } }
运行结果:
Inner
class Outer{
private String info = "Outer";
public class Inner {
public void print() {
System.out.println(info);
}
};
public void fun() {
new Inner().print();
}
};
public class InnerClassDemo {
public static void main(String[] args) {
Outer out = new Outer();
Outer.Inner in = out.new Inner();
in.print();
}
}
对于成员内部类,不能直接new一个内部类对象,必须用外部类对象来创建内部类对象,即“外部类名.内部类名 = 外部类对象.new 内部类名()”
对于如下情况,应使用“内部类名 = 外部类对象.new 内部类名()”
public class InnerClassDemo {
private String info = "Outer";
public class Inner {
public void print() {
System.out.println(info);
}
};
public void fun() {
new Inner().print();
}
public static void main(String[] args) {
InnerClassDemo out = new InnerClassDemo();
Inner in = out.new Inner();
in.print();
}
}
静态内部类是 static 修饰的内部类。其特点有:
- 静态内部类不能直接访问外部类的非静态成员,但可以通过“new 外部类().成员”的方式访问 。
- 如果外部类的静态成员与内部类的成员名称相同,可通过“类名.静态成员”访问外部类的静态成员;如果外部类的静态成员与内部类的成员名称不相同,则可通过“成员名”直接调用外部类的静态成员。
- 创建静态内部类的对象时,不需要外部类的对象,可以直接创建“内部类 对象名= new 内部类()”。
如下代码:
class Outer{ private String info = "Outer"; private static int num = 1; public static class Inner { private int num = 2; public void print() { System.out.println(new Outer().info); System.out.println(Outer.num); } }; public void fun() { new Inner().print(); } }; public class InnerClassDemo { public static void main(String[] args) { Outer out = new Outer(); Outer.Inner in = new Outer.Inner(); in.print(); } }
运行结果:
Outer 1
方法内部类就是内部类定义在外部类的方法中,方法内部类只在该方法的内部可见,即只在该方法内可以使用。
注意:
1. 由于方法内部类不能在外部类的方法以外的地方使用,因此方法内部类不能使用访问控制符和 static 修饰符。
class Outer{ private String info = "Outer"; private static int num = 1; public void fun() { class Inner { private int num = 2; public void print() { System.out.println(new Outer().info); System.out.println(Outer.num); } }; new Inner().print(); } }; public class InnerClassDemo { public static void main(String[] args) { Outer out = new Outer(); out.fun(); } }
运行结果:
Outer 1
2. 在方法中定义的内部类不能直接访问方法中的参数,如果方法中的参数要想被内部类所访问,则参数前必须加上 final关键字。
class Outer{ public void fun(final int tmp) { class Inner { public void print() { System.out.println(tmp); } }; new Inner().print(); } }; public class InnerClassDemo { public static void main(String[] args) { Outer out = new Outer(); out.fun(3); } }
PS:我试了一下不加final也是可以的,但是不能再修改这个值了,不然就会报错。看如下代码就会报错:
class Outer{ public void fun(int tmp) { class Inner { public void print() { System.out.println(tmp); //这行会报错,Local variable tmp defined in an enclosing scope must be final or effectively final } }; tmp = 2; new Inner().print(); } }; public class InnerClassDemo { public static void main(String[] args) { Outer out = new Outer(); out.fun(3); } }
可以参考这个地址看看为什么方法内部类访问方法中的数据时需要使用final关键字
还有这个匿名内部类的final