Java内部类

内部类:

什么是内部类?

  1. 将一个类A定义在另一个类B里面,里面的那个类A就称为内部类,B则称为外部类

内部类都有哪些形式?

1)成员内部类:

  1. 静态成员内部类
  2. 非静态成员内部类

2)局部内部类:

  1. 有名字的局部内部类
  2. 匿名的内部类

非静态成员内部类

【修饰符】 class 外部类{
    【修饰符】 class 内部类{
    }
}

非静态内部类的特点:

  • 和外部类一样,它只是定义在外部类中的另一个完整的类结构

    • 可以继承自己的想要继承的父类,实现自己想要实现的父接口们,和外部类的父类和父接口无关

    • 可以在非静态内部类中声明属性、方法、构造器等结构,但是不允许声明静态成员,但是可以继承父类的静态成员,而且可以声明静态常量

    • 可以使用abstract修饰,因此它也可以被其他类继承

    • 可以使用final修饰,表示不能被继承

    • 编译后有自己的独立的字节码文件,只不过在内部类名前面冠以外部类名和$符号。

  • 和外部类不同的是,它可以允许四种权限修饰符:public,protected,缺省,private

    • 外部类只允许public或缺省的

  • 还可以在非静态内部类中使用外部类的所有成员,哪怕是私有的

  • 在外部类的静态成员中不可以使用非静态内部类哦

    • 就如同静态方法中不能访问本类的非静态成员变量和非静态方法一样

  • 在外部类的外面必须通过外部类的对象才能创建非静态内部类的对象

    • 因此在非静态内部类的方法中有两个this对象,一个是外部类的this对象,一个是内部类的this对象

public class TestInner{
    public static void main(String[] args){
        Outer out = new Outer();
        Outer.Inner in= out.new Inner();
        in.inMethod();
        
        Outer.Inner inner = out.getInner();
        inner.inMethod();
    }
}
class Father{
    protected static int c = 3;
}
class Outer{
    private static int a = 1;
    private int b = 2;
    protected class Inner extends Father{
//        static int d = 4;//错误
        int b = 5;
        void inMethod(){
            System.out.println("out.a = " + a);
            System.out.println("out.b = " + Outer.this.b);
            System.out.println("in.b = " + b);
            System.out.println("father.c = " + c);
        }
    }
    
    public static void outMethod(){
//        Inner in = new Inner();//错误的
    }
    public Inner getInner(){
        return new Inner();
    }
}
View Code

静态内部类

【修饰符】 class 外部类{
    【其他修饰符】 static class 内部类{
    }
}

静态内部类的特点:

  • 和外部类一样,它只是定义在外部类中的另一个完整的类结构

    • 可以继承自己的想要继承的父类,实现自己想要实现的父接口们,和外部类的父类和父接口无关

    • 可以在静态内部类中声明属性、方法、构造器等结构,包括静态成员

    • 可以使用abstract修饰,因此它也可以被其他类继承

    • 可以使用final修饰,表示不能被继承

    • 编译后有自己的独立的字节码文件,只不过在内部类名前面冠以外部类名和$符号。

  • 和外部类不同的是,它可以允许四种权限修饰符:public,protected,缺省,private

    • 外部类只允许public或缺省的

  • 可以在静态内部类中使用外部类的静态成员,哪怕是私有的

    • 在静态内部类中不能使用外部类的非静态成员哦

  • 在外部类的外面不需要通过外部类的对象就可以创建静态内部类的对象

public class TestInner{
    public static void main(String[] args){
        Outer.Inner in= new Outer.Inner();
        in.inMethod();
        
        Outer.Inner.inTest();
    }
}

class Outer{
    private static int a = 1;
    private int b = 2;
    protected static class Inner{
        static int d = 4;//可以
        void inMethod(){
            System.out.println("out.a = " + a);
//            System.out.println("out.b = " + b);//错误的
        }
        static void inTest(){
            System.out.println("out.a = " + a);
        }
    }
}
View Code

局部内部类

【修饰符】 class 外部类{
    【修饰符】 返回值类型  方法名(【形参列表】){
            【final/abstract】 class 内部类{
    	}
    }    
}

局部内部类的特点:

  • 和外部类一样,它只是定义在外部类的某个方法中的另一个完整的类结构

    • 可以继承自己的想要继承的父类,实现自己想要实现的父接口们,和外部类的父类和父接口无关

    • 可以在局部内部类中声明属性、方法、构造器等结构,但不包括静态成员,除非是从父类继承的或静态常量

    • 可以使用abstract修饰,因此它也可以被同一个方法的在它后面的其他内部类继承

    • 可以使用final修饰,表示不能被继承

    • 编译后有自己的独立的字节码文件,只不过在内部类名前面冠以外部类名、$符号、编号。

      • 这里有编号是因为同一个外部类中,不同的方法中存在相同名称的局部内部类

  • 和成员内部类不同的是,它前面不能有权限修饰符等

  • 局部内部类如同局部变量一样,有作用域

  • 局部内部类中使用能访问外部类的静态还是非静态的成员,取决于所在的方法

  • 局部内部类中还可以使用所在方法的局部常量,即用final声明的局部变量

    • JDK1.8之后,如果某个局部变量在局部内部类中被使用了,自动加final

class Outer{
	private static int a = 1;
	private int b = 2;
	
	public static void outMethod(){
		final int c = 3;
		class Inner{
			public void inMethod(){
				System.out.println("out.a = " + a);
//				System.out.println("out.b = " + b);//错误的,因为outMethod是静态的
				System.out.println("out.local.c = " + c);
			}
		}
		
		Inner in = new Inner();
		in.inMethod();
	}
	
	public void outTest(){
		final int c = 3;
		class Inner{
			public void inMethod(){
				System.out.println("out.a = " + a);
				System.out.println("out.b = " + b);//可以,因为outTest是飞静态的
				System.out.println("method.c = " + c);
			}
		}
		
		Inner in = new Inner();
		in.inMethod();
	}
	
}

为什么在局部内部类中使用外部类方法的局部变量要加final呢?  

public class TestInner{
    public static void main(String[] args) {
        A obj = Outer.method();
        //因为如果c不是final的,那么method方法执行完,method的栈空间就释放了,那么c也就消失了
        obj.a();//这里打印c就没有中可取了,所以把c声明为常量,存储在方法区中
    }
}

interface A{
    void a();
}
class Outer{
    public static A method(){
        final int c = 3;
        class Sub implements A{
            @Override
            public void a() {
                System.out.println("method.c = " + c);
            }
        }
        return new Sub();
    }
}
View Code

匿名内部类

补充:

其实匿名内部类是一种特色的局部内部类,只不过没有名称而已。因此

  • 在匿名内部类中要访问访问外部类的静态还是非静态的成员,取决于所在的方法;

  • 匿名内部类中还可以使用所在方法的局部常量,即用final声明的局部变量

    • JDK1.8之后,如果某个局部变量在局部内部类中被使用了,自动加final

本文为原创文章,转载请标明出处
原文地址:https://www.cnblogs.com/harden13/p/14550054.html