内部类:一个类的内部定义的类
外部类:拥有内部类的类
成员内部类又分为静态成员内部内和非静态成员内部类
局部内部类可以位于方法内、块内、构造器内
成员内部类:分为成员内部类和局部内部类
成员内部类
(1) 成员内部类可以访问外部类的所有内容,包括静态和非静态的都可以访问
(2)静态成员内部类只能访问外部类的静态成员、静态方法,因为静态内部类是不依赖实例对象的,即便实例对象不存在也能运行,因此静态的只能访问静态的,避免出现问题
class Demo {
private static String dept;
private String name;
class InnerDemo {
public void InnerFunc() {
System.out.println("外部类的静态和非静态成员变量" + name + dept);
outerFunc();
outerStaticFunc();
}
}
/**
* 静态类是不依赖实例对象的,即便实例对象不存在也能运行,因此静态的只能访问静态的,避免出现问题
*/
static class StaticInnerDemo {
public void InnerFunc() {
System.out.println("只能访问外部类的静态方法和变量:" + dept);
outerStaticFunc();
}
}
public void outerFunc() {
System.out.println("外部类非静态方法");
}
public static void outerStaticFunc() {
System.out.println("外部类静态方法");
}
}
(3)外部类不能直接访问内部类的成员变量和方法,因为作用域不同,但可以通过内部类的实例对象进行调用,或者通过静态内部类.静态方法和成员变量进行调用
class Demo {
private static String dept;
private String name;
class InnerDemo {
public void InnerFunc() {
StaticInnerDemo.staticInnerFunc();
new StaticInnerDemo().InnerFunc();
}
}
/**
* 静态类是不依赖实例对象的,即便实例对象不存在也能运行,因此静态的只能访问静态的,避免出现问题
*/
static class StaticInnerDemo {
public void InnerFunc() {
System.out.println("只能访问外部类的静态方法和变量:" + dept);
outerStaticFunc();
}
public static void staticInnerFunc() {
System.out.println("内部类静态方法");
}
}
(4)内部类和外部类的变量名相同,调用方式如下:
class Demo {
private int num = 10;
class InnerDemo {
private int num = 20;
public void InnerFunc() {
int num = 30;
System.out.println(num); //30 就近原则
System.out.println(this.num);//20
System.out.println(Demo.this.num);//10
}
}
}
(5) 静态和非静态内部类对象的创建方式如下:
public class Main {
public static void main(String[] args) {
//非静态内部类创建方式
Demo demo = new Demo();
Demo.InnerDemo innerDemo = demo.new InnerDemo();
System.out.println(innerDemo);
//静态内部类创建方式
Demo.StaticInnerDemo staticInnerDemo = new Demo.StaticInnerDemo();
System.out.println(staticInnerDemo);
}
}
局部内部类
- 方法内的内部类【包括匿名内部类】使用的局部变量,必须是final修饰,1.8之前的JDK必须在局部变量前加final修饰,1.8版本开始final修饰符可以省略。
原因: 因为局部变量会随着方法的调用结束而消失,局部内部类对象并没有立马从堆内存中消失,还需要使用这个变量,为了让这个局部变量的数据还能继续被使用,就使用final修饰,这样堆内存中会存储这个常量值。常量在类编译时期载入常量池中。
public class Main {
public static void main(String[] args) {
int i = 100;
class Demo {
public void test() {
System.out.println(i);
}
}
//局部内部类,必须先定义再使用
new Demo().test();
}
}
- 如果某个类只在某个方法中使用一次,就可以使用局部内部类
匿名内部类实际就是内部类简化写法,只要存在一个类或接口就可以使用
匿名内部类实际就是局部内部类的定义和对象创建过程的代码集合
public class TestA {
@Test
public void test(){
int j=10;
Runnable a=new Runnable() {
@Override
public void run() {
//j=100;//此处不能这些写,匿名内部类方法访问外层的局部变量,要求局部变量必须是final修饰的
System.out.println(j);
}
};
a.run();
}
}
类中定义接口
- 内部接口不管有没有修饰static,都是static修饰的
- 一般而言,内部接口更多的是针对类的内部使用,但普通接口一般是公有接口,我们可以内部接口是对类或接口的进一步逻辑拆分,如JDK接口Map中的内部接口Entry