Java内部类
内部类简介
Java 一个类中可以嵌套另外一个类,语法格式如下:
class OuterClass { // 外部类
// ...
class NestedClass { // 嵌套类,或称为内部类
// ...
}
}
嵌套类有如下几种类型:
成员内部类
最简单的一种内部类,形式如下,跟其他变量一样,是一个类中的一个成员
class Outer {
String str = "hello";
public Outer(String str) {
this.str = str;
}
/* 内部类 */
class Inner {
public void showStr() {
System.out.println(str);
}
}
}
- 成员内部类可以无条件地访问外部类的所有元素
- 外部类访问内部类需要先创建一个内部类对象
- 成员内部类是依附外部类而存在
可以访问外部类原理
编译器会在编译时生成外部类和内部类两个字节码文件,还会给内部类的无参构造函数增加一个参数,为外部类的一个应用,且指向了外部类,故可以随意使用外部类一切。
侧面说明成员内部类依赖于外部类的优先创建,不然会初始化失败
局部内部类
定义在一个方法或者一个作用域里面的类,局部内部类的访问仅限于方法内或者该作用域内
class MyClass{
public MyClass() {
}
}
class Outer{
public Outer(){
}
public MyClass getInner{
/* 局部内部类 */
class Inner extends MyClass{
int age = 0;
}
return new Inner();
}
}
局部内部类就像是方法里面的一个局部变量一样,是不能有 public、protected、private 以及 static 修饰符的
匿名内部类
先看一下官方给的例子
public class HelloWorldAnonymousClasses {
/**
* 包含两个方法的HelloWorld接口
*/
interface HelloWorld {
public void greet();
public void greetSomeone(String someone);
}
public void sayHello() {
// 1、局部类EnglishGreeting实现了HelloWorld接口
class EnglishGreeting implements HelloWorld {
String name = "world";
public void greet() {
greetSomeone("world");
}
public void greetSomeone(String someone) {
name = someone;
System.out.println("Hello " + name);
}
}
HelloWorld englishGreeting = new EnglishGreeting();
// 2、匿名类实现HelloWorld接口
HelloWorld frenchGreeting = new HelloWorld() {
String name = "tout le monde";
public void greet() {
greetSomeone("tout le monde");
}
public void greetSomeone(String someone) {
name = someone;
System.out.println("Salut " + name);
}
};
// 3、匿名类实现HelloWorld接口
HelloWorld spanishGreeting = new HelloWorld() {
String name = "mundo";
public void greet() {
greetSomeone("mundo");
}
public void greetSomeone(String someone) {
name = someone;
System.out.println("Hola, " + name);
}
};
englishGreeting.greet();
frenchGreeting.greetSomeone("Fred");
spanishGreeting.greet();
}
public static void main(String... args) {
HelloWorldAnonymousClasses myApp = new HelloWorldAnonymousClasses();
myApp.sayHello();
}
}
匿名类表达式包含以下内部分:
- 操作符:new;
- 一个要实现的接口或要继承的类,案例一中的匿名类实现了HellowWorld接口,案例二中的匿名内部类继承了Animal父类;
- 一对括号,如果是匿名子类,与实例化普通类的语法类似,如果有构造参数,要带上构造参数;如果是实现一个接口,只需要一对空括号即可;
- 一段被"{}"括起来类声明主体;
- 末尾的";"号(因为匿名类的声明是一个表达式,是语句的一部分,因此要以分号结尾)。
本部分参考JAVA匿名内部类(Anonymous Classes)
静态内部类
静态内部类是不需要依赖于外部类的,并且它不能使用外部类的非static成员变量或者方法,这个和普通静态方法不能访问非静态方法或变量的原理一样,具体可以了解一下类的加载生命周期。
简单地说就是静态变量或方法是属于类的,非静态方法或变量是属于对象的,jvm加载类的时候就为类的静态变量或方法分配内存的,而非静态的需要等到要初始化对象时候才给分配内存,而这个过程是动态的,也就是等到我们什么时候想用,才会有累的初始化过程。
简单举个例子:
class Outer {
int a = 1
static int a = 2;
public Outter() {
}
/* 静态内部类 */
static class Inner {
public Inner() {
System.out.println(a); // 编译会报错
System.out.println(b);
}
}
}
使用:
public class Test {
public static void main(String[] args) {
Outer.Inner inner = new Outer.Inner();
}
}
内部类简单应用
为什么在 Java 中需要内部类?总结一下主要有以下四点内部类的使用场景和好处:
- 1.每个内部类都能独立的继承一个接口的实现,所以无论外部类是否已经继承了某个(接口的)实现,对于内部类都没有影响。内部类使得多继承的解决方案变得完整。
- 2.方便将存在一定逻辑关系的类组织在一起,又可以对外界隐藏。
- 3.方便编写事件驱动程序。
- 4.方便编写线程代码。