内部类(nested classes),面向对象程序设计中,可以在一个类的内部定义另一个类。内部类是JAVA语言的主要附加部分。内部类几乎可以处于一个类内部任何位置,可以与实例变量处于同一级,或处于方法之内,甚至是一个表达式的一部分。因此,内部类可以分为三种:
- 成员内部类
- 局部内部类
- 匿名内部类
内部类仍然是一个独立的类,在编译之后内部类会被编译成为独立的.class文件,但是全面冠以外部类的类名和$符号。
内部类不能用普通的方式访问。内部类是外部类的一个成员,因此内部类可以自由地访问外部类的成员变量,无论是否是private。
一、成员内部类
成员内部类在类的成员位置,和成员变量以及成员方法所在的位置是一样的,在内部类中,可以直接访问外部类的成员,包括私有成员。
1、创建非静态成员内部类
public class Test {
public static void main(String[] args) {
//调用内部类的方法有两种方式
//方法一:在外部类中写方法,在方法中创建内部类的对象,并调用内部类的方法
Outer o = new Outer();
o.method();
//方法二:通过外部类.内部类创建内部类的对象,并调用方法
Outer.Inner i = new Outer().new Inner();
i.function();
}
}
//定义一个外部类
class Outer {
private int num = 100;
//定义外部类的无参构造
public Outer() {
}
//定义一个成员内部类
class Inner {
//在内部类中定义一个方法,访问外部类的私有成员变量
public void function() {
System.out.println(num);
}
}
//定义一个方法,创建内部类的对象,并调用内部类的方法
public void method() {
Inner i = new Inner();
i.function();
}
}
2、创建静态成员内部类
public class Test2 {
public static void main(String[] args) {
// 方式一:创建对象调用内部方法
Outer2.Inner2 i = new Outer2.Inner2();
i.function();
// 方式二:不创建对象直接调用内部方法
Outer2.Inner2.function();
}
}
class Outer2 {
//创建一个静态成员内部类
static class Inner2 {
//创建一个静态方法
public static void function() {
System.out.println("function");
}
}
}
二、局部内部类
局部内部类相当于一个局部变量,只能在该方法中使用,其他方法无法使用,所以很少使用局部内部类。
public class Test3 {
public static void main(String[] args) {
//创建外部类的对象,调用方法
Outer3 o = new Outer3();
o.method();
}
}
class Outer3 {
//创建一个方法
public void method() {
//在方法中创建一个类
class Inner3 {
//在局部内部类中创建一个方法
public void function() {
System.out.println("function");
}
}
//创建局部内部类的对象,并调用方法
Inner3 i = new Inner3();
i.function();
}
}
三、匿名内部类
匿名内部类其实就是没有名字的局部内部类。
由于匿名内部类没有名字,所以我们没法使用它,只能在定义的时候创建它的对象。
格式:
new 类/接口{
如果是创建了继承者类的子类对象,我们可以重写父类的方法
如果是创建了实现这个接口的子类对象,我们必须重写这个接口中的所有方法
};
原理:
其实是创建了继承这个类的子类对象或者是创建了实现这个接口的子类对象。
public class Test4 {
public static void main(String[] args) {
// 创建外部类的对象,调用方法
Outer4 o = new Outer4();
o.method();
}
}
// 定义一个接口
interface Inner {
public void function();
}
class Outer4 {
public void method(){
//创建实现Inner接口的子类对象并调用function方法
//方式一:有名字的实现类
class Inner4 implements Inner{
@Override
public void function() {
System.out.println("function");
}
}
//方式二:创建匿名内部类对象直接调用方法
new Inner(){
@Override
public void function() {
System.out.println("function");
}
}.function();
//方式三:用变量接受匿名内部类的对象,用的是多态的思想
Inner in = new Inner(){
@Override
public void function() {
System.out.println("function");
}
};
//可以多次调用方法
in.function();
}
}
应用场景:
作为参数进行传递时使用。如果把类当做参数传递,并且只用一次的话,就可以选择匿名内部类。
四、匿名内部类实现线程的两种方式
public class Test {
public static void main(String[] args) {
Outer o =new Outer();
o.method1();
o.method2();
}
}
class Outer{
//方法一,继承Thread类
public void method1(){
new Thread(){
@Override
public void run(){
for (int i = 0; i < 100; i++) {
System.out.println("hello");
}
}
}.start();
}
//方法二:继承Runnable接口
public void method2(){
Runnable r = new Runnable(){
@Override
public void run() {
for (int i = 0; i < 100; i++) {
System.out.println("world");
}
}
};
new Thread(r).start();
}
}