Java内部类,看这一篇就够了!
闻道梅花坼晓风
雪堆遍满四山中
目录
内部类的概念
成员内部类
内部类访问外部类
外部类访问内部类
内部类中同名变量的优先级
小结:
静态内部类
内部类访问外部类
小结:
局部内部类
小结:
匿名内部类
内部类的概念
在 Java 中,我们通常将不同的类组织到一个包下,对于一个包中的类来说,它们是同一个层次,可以说在没有使用继承等条件下,类与类之间是没有联系的。还有一种类,它是定义在另一个类或者一个方法的内部,这样的类叫做内部类。内部类也是封装的一种体现 ~
//A是外部类
class A{//B是内部类class B{}
}
注意:
内部类和外部类共用同一个 java 源文件,但是经过编译之后,内部类会形成单独的字节码文件
一般来说,内部类分为成员内部类、局部内部类、匿名内部类和静态内部类
成员内部类
成员内部类是最普通的内部类,它的定义为位于另一个类的内部,形如下面的形式:
//外部类
class A{public int a = 10;private int b = 20;static int c = 30;//内部类class B{ public int d = 10;}}
看起来 内部类 B 就好像 A 的一个成员,成员内部类可以无限制访问外部类的所有成员属性
内部类访问外部类
//外部类
class A{public int a = 10;private int b = 20;static int c = 30;public void PrintA(){System.out.println("PrintA()");}//内部类class B{public int d = 10;void PrintB(){System.out.println("a = "+a);System.out.println("b = "+b);System.out.println("c = "+c);PrintA();}}
}class Test{public static void main(String[] args) {A a = new A();A.B b= a.new B();b.PrintB();}
}
注意:我们要初始化内部类的对象时,必须先初始化外部类的对象,因为内部类是依附于外部类的
不然编译器就会报错
下面这段代码的意思是:先创建 外部类A 的对象a ,再 [.] 符号引用外部类中 内部类B 的成员,最后在初始化内部类 B
A a = new A();A.B b= a.new B();
外部类访问内部类
虽然内部类访问可以随意的访问外部类,但是外部类想要访问内部类可就没那么容易了
我们发现外部类想要访问内部类是不能直接访问的,那该怎么访问呢?--- 可以先创建一个成员内部类的对象,再通过这个对象来访问:
//外部类
class A{public int a = 10;private int b = 20;static int c = 30;public void PrintA(){System.out.println("PrintA()");}public void PrintA_B(){B b = new B();System.out.println(b.d);System.out.println("-------------");b.PrintB();}//内部类class B{public int d = 10;void PrintB(){System.out.println("a = "+a);System.out.println("b = "+b);System.out.println("c = "+c);PrintA();}}
}class Test{public static void main(String[] args) {A a = new A();A.B b= a.new B();a.PrintA_B();}
}
内部类中同名变量的优先级
如果外部类与内部类相同的属性,如下图中的 a,那么我们调用 PrintB 时访问的是哪个 a 呢?
class A{public int a = 10;class B{public int a = 40;void PrintB(){System.out.println("a = "+a);}}
}class Test{public static void main(String[] args) {A a = new A();A.B b= a.new B();b.PrintB();}
}
所以:如果是同名变量,优先访问内部类中的
问:要是这种情况,该怎么访问外部类中的 a 呢?
System.out.println("a = "+ A.this.a);
PrintB 在内部类B中 ,所以 this.a = 当前 内部类B 对象的 this 引用,A.this.a = 外部类A 的 this 引用 |
这种创建内部类的方式在实际开发中并不常用,因为内部类和外部类紧紧地绑定在一起,使用起来非常不便
小结:
外部类中的任何成员都可以在实例内部类方法中直接访问 |
实例内部类对象必须在先有外部类对象前提下才能创建 |
实例内部类的非静态方法中包含了一个指向外部类对象的引用 |
外部类中,不能直接访问实例内部类中的成员,如果要访问必须先要创建内部类的对象 |
静态内部类
静态内部类其实就是在原来的内部类的基础上用 “static” 修饰,你看不要小看这个 static,加上后还是有不小的改变的
内部类访问外部类
以上面的代码为例,我们直接给内部类加上 static 修饰后:就不能只能访问外部类非静态成员,原因是静态的 内部类B 没有 外部类A 的 this 引用,那么有没有什么访问的方法呢?
-- 还是与之前一样,创建一个外部类对象,再进行调用
class A{public int a = 10;private int b = 20;static int c = 30;public void PrintA(){System.out.println("PrintA()");}static class B{public int d = 40;void PrintB(){A a1 = new A();System.out.println("a = "+a1.a);System.out.println("b = "+a1.b);System.out.println("c = "+c);System.out.println("d = "+d);a1.PrintA();}}
}class Test{public static void main(String[] args) {A.B b = new A.B();b.PrintB();}
}
A.B b = new A.B();
生成静态的内部类的时候,不需要外部类的引用,也就是说:我们可以不用先初始化外部类
小结:
在静态内部类中只能访问外部类中的静态成员 |
创建静态内部类对象时,不需要先创建外部类对象 |
局部内部类
局部内部类是定义在一个方法或者一个作用域里面的类,所以局部内部类的生命周期仅限于作用域内
class A {public int a = 0;public void PrintA(){class B {public int b;}}
}
注意,局部内部类就像是方法里面的一个局部变量一样,是不能有 public、protected、private 以及 static 修饰符的
class A {public int a = 10;public void PrintA(){class B {public int b = 20;public void PrintB(){System.out.println("a = "+a);System.out.println("b = "+b);}}B b = new B();b.PrintB();}
}class Test {public static void main(String[] args) {A a = new A();a.PrintA();}
}
切记 ~ 局部内部类只能在当前方法内部使用,出了该方法则不能被使用
小结:
局部内部类只能在所定义的方法体内部使用 |
不能被 public、protected、private 以及 static 修饰符修饰 |
编译器也有自己独立的字节码文件,命名格式:外部类名字$数字内部类名字 .class |
匿名内部类
匿名内部类应该是平时我们编写代码时用得最多的,尤其是启动多线程的时候,会经常用到,并且 IDEA 也会帮我们自动生成。
匿名对象一般运用于接口中,请看下面这段代码:
interface A{void Test();
}class Test{public static void main(String[] args) {new A(){@Overridepublic void Test(){System.out.println("Test()");}}.Test();}
}
这里相当于一个类实现了这个 A接口 同时重写了 Test() 方法,但是你不知道这个类叫什么,所以这就是匿名对象
[.Test()] 是一种调用方式
匿名内部类的作用主要是用来继承其他类或者实现接口,并不需要增加额外的方法,方便对继承的方法进行实现或者重写 |