- 一、内部类的概念
- 二、 实例内部类
- 三、静态内部类
- 四、局部内部类
- 五、匿名内部类
一、内部类的概念
当一个事物的内部,还有一个部分需要一个完整的结构进行描述,而这个内部的完整的结构又只为外部事物提供服务,那么整个内部的完整结构最好使用内部类。在 Java 中,可以将一个类定义在另一个类或者一个方法的内部,
前者称为内部类,后者称为外部类。内部类也是封装的一种体现。
public class OutClass {
class InnerClass{
}
}
// OutClass是外部类
// InnerClass是内部类
内部类分为:
1.实例内部类
2.静态内部类
3.局部内部类
4.匿名内部类
【注意】:
内部类和外部类共用同一个java源文件,但是经过编译之后,内部类会形成单独的字节码文件
内部类的应用场景:
内部类表是"有一个"的含义,例如:链表是由节点构成的,就可以将节点抽象成一个内部类
二、 实例内部类
public class OutClass {
private int a;
static int b;
int c;
public void methodA(){
a = 10;
System.out.println(a);
}
public static void methodB(){
System.out.println(b);
}
private void methodC(){
System.out.println("private方法");
}
// 成员内部类:未被static修饰
class InnerClass{
int c;
public void methodInner(){
// 在内部类中可以直接访问外部类中:任意访问限定符修饰的成员
a = 100;
b =200;
methodA();
methodB();
methodC();
// 如果外部类和内部类中具有相同名称成员时,优先访问的是内部类自己的
c = 300;
System.out.println(c);
// 如果要访问外部类同名成员时候,必须:外部类名称.this.同名成员名字
OutClass.this.c = 400;
System.out.println(OutClass.this.c);
}
}
public static void main(String[] args) {
// 外部类:对象创建 以及 成员访问
OutClass outClass = new OutClass();
System.out.println(outClass.a);
System.out.println(OutClass.b);
System.out.println(outClass.c);
outClass.methodA();
outClass.methodB();
System.out.println("=============内部类的访问=============");
// 要访问普通内部类中成员,必须要创建普通内部类的对象
// 而普通内部类定义与外部类成员定义位置相同,因此创建普通内部类对象时必须借助外部类
// 创建内部类对象
OutClass.InnerClass innerClass1 = new OutClass().new InnerClass();
// 上述语法比较怪异,也可以先将外部类对象先创建出来,然后再创建内部类对象
OutClass.InnerClass innerClass2 = outClass.new InnerClass();
}
}
【注意】
- 外部类中的任何成员都可以被在实例内部类中直接访问
- 实例内部类所处的位置与外部类成员位置相同,因此也受public、private等访问限定符的约束
- 在实例内部类方法中访问同名的成员时,优先访问自己的,如果要访问外部类同名的成员,必须:外部类名称.this.同名成员 来访问
- 实例内部类对象必须在先有外部类对象前提下才能创建
- 实例内部类的非静态方法中包含了一个指向外部类对象的引用
- 外部类中,不能直接访问实例内部类中的普通成员,如果要访问必须先要创建内部类的对象,可以在外部类中通过内部类.变量名的方式访问实例内部类中的静态变量
public class Test {
class Student{
int a=10;
static final int b=100;
private int c=999;
public void eat(){
System.out.println("eat");
}
public Student(){
System.out.println("Jingtaifan");
}
}
public void play(){
Student student=new Student();
System.out.println(student.b);
}
public void eat(){
//在外部类中访问实例内部类中的静态成员
//可直接用内部类.变量名的方法
System.out.println(Student.b);
//要想在外部类中访问实例内部类的普通成员
//需要创建内部类对象
Student student=new Student();
System.out.println(student.a);
//内部类中被private修饰的变量,在外部类中
//仍能被访问
System.out.println(student.c);
student.eat();
}
public static void main(String[] args) {
Test test=new Test();
Test.Student student=test.new Student();
System.out.println(student.c);//合法
}
}
- 实例内部类中不能定义静态方法,因为静态方法是不依赖对象的
- 实例内部类中不能定义静态成员变量,要想定义必须加final修饰
内部类中声明的所有静态域都必须是 final。原因很简单。我们希望一个静态域只有一个实例, 不过对于每个外部对象, 会分别有一个单独的内部类实例。如果这个域不是 final , 它可能就不是唯一的。
内部类不能有 static 方法。Java 语言规范对这个限制没有做任何解释。也可以允许有静态方法,但只能访问外围类的静态域和方法。
三、静态内部类
public class OutClass {
// 成员位置定义:被static修饰 ---> 静态内部类
static class InnerClass2{
}
}
public class Test {
public int data1=1;
private int data2=20;
private static int data3=88;
public void method1(){
Student.fun3(); //可以在外部类中访问静态内部类的静态成员方法
System.out.println("外部类普通方法");
}
public static void method2(){
Student.fun3();
System.out.println("外部类静态方法");
}
public void method3(){
System.out.println(Student.b);
Student.fun3();
}
static class Student {
int a = 10;
static final int b = 100;
private int c = 999;
static int d=888;
public void fun1() {
//System.out.println(data1); err
//静态内部类中只能访问外部类中的静态成员变量
System.out.println(data3);
}
public void fun2() {
//method1();编译失败,静态内部类中只能访问外部类中的静态方法
method2();
}
public static void fun3(){
System.out.println("静态内部类中的静态方法");
}
}
public static void main(String[] args) {
Test.Student student=new Student();
System.out.println(student.a);
System.out.println(Student.b);
System.out.println(student.c);
System.out.println(Student.d);
}
}
【注意】
- 在静态内部类中只能访问外部类中的静态成员,如果想访问外部类当中的非静态成员变量和方法需要实例化外部类对象,通过对象的引用访问
- 创建静态内部类对象时,不需要先创建外部类对象
- 内部类,经过编译之后会生成独立的字节码文件,命名格式为:外部类名称$内部类名称
- 在外部类中,如果想访问静态内部类中的静态成员变量,可以用内部类.静态成员变量的方式,访问内部类中的静态成员变量
- 在外部类中,如果想访问静态内部类中的普通成员变量,需要创建内部类对象
四、局部内部类
public class OutClass {
public void method(){
// 方法中也可以定义内部类 ---> 局部内部类:几乎不用
class InnerClass5{
}
}
}
【注意事项】
- 局部内部类只能在所定义的方法体内部使用
- 不能被public、static等修饰符修饰
- 几乎不会使用
五、匿名内部类
匿名你内部类的本质是一个重写或实现了父类或接口的子类对象
应用示例:
假设有一个A接口,里面有一个未被实现的drink方法,如果我们想要在main中调用drink方法,需要这样做:
public class Interface01 {
public static void main(String[] args) {
B b = new B();
b.drink();
}
}
interface A{
public void drink();
}
//创建B类是实现A接口中的方法
class B implements A{
@Override
public void drink() {
System.out.println("调用drink方法");
}
}
如果我们只想调用一次drink方法,使用匿名内部类会更简洁:
public class Interface01 {
public static void main(String[] args) {
new A(){
@Override
public void drink() {
System.out.println("调用drink方法");
}
}.drink();
}
}
interface A{
public void drink();
}
此时的匿名内部类相当于是一个对象,可直接调用drink方法
如果接口A中有多个未被实现的方法都需要被调用,可按照下面的方式:
public class Interface01 {
public static void main(String[] args) {
A a=new A(){
@Override
public void drink() {
System.out.println("调用drink方法");
}
@Override
public void eat() {
System.out.println("调用eat方法");
}
};
a.drink();
a.eat();
}
}
interface A{
public void drink();
public void eat();
}
为什么管他叫匿名内部类呢?
正常情况下,如果想调用接口中的方法,需要创建一个类实现接口并重写方法,但此时并没有这么做,便实现了里面的方法,所以称之为匿名内部类
【注意】:
- 使用匿名内部类时,我们必须是继承一个类或者实现一个接口,但是两者不可兼得,同时也只能继承一个类或者实现一个接口
- 匿名内部类中是不能定义构造函数的
- 匿名内部类为局部内部类,所以局部内部类的所有限制同样对匿名内部类生效
- 匿名内部类不能是抽象的,它必须要实现继承的类或者实现的接口的所有抽象方法
- 匿名内部类中不能存在任何的静态成员变量和静态方法