Java 内部类
内部类:指的是定义在另一个类的内部,或者方法的内部,甚至是表达式的内部的类。
作用:将相关的类组织在一起,从而降低了命名空间的混乱。通常是一个类只需要在另一个类中使用,并且需要访问另一个类的成员时才会定义为内部类。
由于内部类破坏的代码的结构,降低了代码的可读性。所以只在必要的时候使用即可。
内部类的实现方式:
1、静态内部类:static inner class、 nested class
定义在一个类内部,这个类就是它的外部类。
不能和普通类同名,被编译成一个完全独立的.class文件,名称为OuterClass$InnerClass.class
它可以访问外部类的静态成员和静态方法。包括私有的静态成员和方法。
生成静态内部类对象的方式为:OuterClass.InnerClass inner = new OuterClass.InnerClass();
可以看到它和普通的类差不多。可以和类的静态成员类比,用它生成对象时,可以直接使用InnerClass ic = new InnerClass();的形式。
它和普通的类并没什么区别,并且可以访问外部类的静态属性。
2、成员内部类 member inner class
定义在一个类内部,但是没有用static修饰。
成员内部类和静态内部类可以类比为非静态的成员变量和静态的成员变量。
成员内部类就像一个实例变量。
它可以访问他的外部类的所有成员变量和方法,不管是静态的还是非静态的都可以。
在外部类里面创建成员内部类的实例:
this.new InnerClass();
在外部类之外创建内部类的实例:
(new OuterClass()).new InnerClass();
在内部类里访问外部类的成员:
OuterClass.this.member
示例代码:
编译后为:
3、局部内部类 local inner class
局部内部类定义在方法中,比方法的范围还小。是内部类中最少用到的一种类型。
像局部变量一样,不能被public,protected,private和static修饰。
只能访问方法中定义的final 类型的局部变量。
局部内部类在方法中定义,所以只能在方法中使用,即只能在方法当中生成局部内部类的实例并且调用其方法。
示例代码:
编译后再反编译:
4、匿名内部类 anonymous inner class
没有给出类名的内部类,不能使用关键字class、extends,implement等关键字,没有构造方法。
匿名内部类隐式地继承了一个父类或者实现了一个接口
通常是作为一个方法的参数。
生成的class文件中,匿名内部类会生成OuterClass$1.class文件。
匿名内部类的方法中可以访问它所在方法的局部变量。
示例说明:
对比一下编译之后class的实现:
内部类:指的是定义在另一个类的内部,或者方法的内部,甚至是表达式的内部的类。
作用:将相关的类组织在一起,从而降低了命名空间的混乱。通常是一个类只需要在另一个类中使用,并且需要访问另一个类的成员时才会定义为内部类。
由于内部类破坏的代码的结构,降低了代码的可读性。所以只在必要的时候使用即可。
内部类的实现方式:
1、静态内部类:static inner class、 nested class
定义在一个类内部,这个类就是它的外部类。
不能和普通类同名,被编译成一个完全独立的.class文件,名称为OuterClass$InnerClass.class
它可以访问外部类的静态成员和静态方法。包括私有的静态成员和方法。
生成静态内部类对象的方式为:OuterClass.InnerClass inner = new OuterClass.InnerClass();
示例代码:
class OuterClass {
// 外部类的属性
private int field = 3;
private int field1 = 4;
// 外部类的方法
public int getField() {
return field;
}
public void fun() {
System.out.println("this is out!");
}
// 定义普通的内部类
static class InnerClass {
int na = 2;
public void gun() {
//fun(); 无法访问外部类中的非静态成员方法
//na = na + field+ field1; // 也无法访问外部类中的非静态属性。因为静态内部类中是没有外部类的指针的
System.out.println("Inner!");
}
}
}
编译之后在反编译: static class OuterClass$InnerClass
{
int na;
public void gun()
{
System.out.println("Inner!");
}
OuterClass$InnerClass()
{
na = 2;
}
}可以看到它和普通的类差不多。可以和类的静态成员类比,用它生成对象时,可以直接使用InnerClass ic = new InnerClass();的形式。
它和普通的类并没什么区别,并且可以访问外部类的静态属性。
2、成员内部类 member inner class
定义在一个类内部,但是没有用static修饰。
成员内部类和静态内部类可以类比为非静态的成员变量和静态的成员变量。
成员内部类就像一个实例变量。
它可以访问他的外部类的所有成员变量和方法,不管是静态的还是非静态的都可以。
在外部类里面创建成员内部类的实例:
this.new InnerClass();
在外部类之外创建内部类的实例:
(new OuterClass()).new InnerClass();
在内部类里访问外部类的成员:
OuterClass.this.member
示例代码:
class OuterClass {
// 外部类的属性
private int field = 3;
// 外部类的方法
public int getField() {
return field;
}
public void fun() {
System.out.println("this is out!");
}
// 定义普通的内部类
class InnerClass {
int na = 2;
public void gun() {
fun();
na = na + field; // 内部类中可以使用外部类的成员, 原因是在内部类对象中会自动生成一个外部类的对象指针。
System.out.println("Inner!");
}
}
}编译后为:
class OuterClass$InnerClass
{
int na;
final OuterClass this$0; //自动添加this$0 指针
public void gun()
{
fun();
na += OuterClass.access$0(this$0); // 查看字节码文件可以看到,access$0是外部类自动生成的一个静态方法,对应的第一个外部类的成员变量。同样access$1对应第2个外部变量
System.out.println("Inner!");
}
OuterClass$InnerClass()
{
this$0 = OuterClass.this;
super(); // 以前我们说构造函数中的第一行会自动调用父类的构造方法,这里出现了特殊情况^^
na = 2;
}
}3、局部内部类 local inner class
局部内部类定义在方法中,比方法的范围还小。是内部类中最少用到的一种类型。
像局部变量一样,不能被public,protected,private和static修饰。
只能访问方法中定义的final 类型的局部变量。
局部内部类在方法中定义,所以只能在方法中使用,即只能在方法当中生成局部内部类的实例并且调用其方法。
示例代码:
class OuterClass {
// 外部类的属性
private int field = 3;
private int field1 = 4;
// 外部类的方法
public int getField() {
return field;
}
public void fun() {
int no = 123;
// 定义普通的内部类
class InnerClass {
int ni = 2;
public void gun() {
ni += no;
System.out.println("Inner!");
}
}
System.out.println("this is out!");
}
}编译后再反编译:
class OuterClass$1InnerClass
{
int ni;
final OuterClass this$0; // 可以看到他不仅添加了外部类的引用
private final int val$no; // 并且还添加了它所在方法的局部变量,并且是final类型的,所以就不能进行改写了。
public void gun()
{
ni += val$no;
System.out.println("Inner!");
}
OuterClass$1InnerClass()
{
this$0 = final_outerclass;
val$no = I.this;
super();
ni = 2;
}
}4、匿名内部类 anonymous inner class
没有给出类名的内部类,不能使用关键字class、extends,implement等关键字,没有构造方法。
匿名内部类隐式地继承了一个父类或者实现了一个接口
通常是作为一个方法的参数。
生成的class文件中,匿名内部类会生成OuterClass$1.class文件。
匿名内部类的方法中可以访问它所在方法的局部变量。
示例说明:
abstract class Person{ // 定义一个抽象类, 或者一个接口(普通类也一样,一般不用),然后我们用它来创建匿名内部类,创建类是Person的子类或者实现。
public abstract void eat();
public void say(){
System.out.println("saying Person!");
}
}
public class TestInnerClass {
public static void main(String[] args) {
int na = 1;
Person p = new Person(){ // 以这种方式定义内部类,然后在{} 里面重写(实现)方法,和 定义成员变量, new 出来的是匿名内部类的对象。
public int na = 3;
public void eat() {
na++;
System.out.println("eating!");
}
public void say(){
System.out.println("saying Inner!");
}
};
p.eat();
p.say();
}
}对比一下编译之后class的实现:
class TestInnerClass$1 extends Person
{
public int na;
public void eat()
{
na++;
System.out.println("eating!");
}
public void say()
{
System.out.println("saying Inner!");
}
TestInnerClass$1()
{
na = 3;
}
}
本文详细介绍了Java内部类的概念、作用及四种实现方式:静态内部类、成员内部类、局部内部类和匿名内部类。每种内部类的特点和使用场景都有具体示例。

被折叠的 条评论
为什么被折叠?



