Java:四大内部类详解及总结

声明

1)该文章部分内容整理自网上的资料,如不小心侵犯了大家的权益,还望海涵,并联系博主删除。

2)博主是萌新上路,文中如有不当之处,请各位大佬指出,共同进步,谢谢。


在Java中,可以将一个类定义在另一个类里面或者一个方法里面,这样的类称为内部类。广泛意义上的内部类一般来说包括这四种:成员内部类、局部内部类、匿名内部类和静态内部类。下面就先来了解一下这四种内部类的用法。

成员内部类

成员内部类是最普通的内部类,它的定义为位于另一个类的内部,形如下面的形式:

class Animal {
    String name;

    public Animal(String name) {
        this.name = name;
    }

    class Rabbit {                              //内部类
        public void myRabbit() {
            System.out.println("Rabbit.");
        }
    }
}

这样看起来,类Rabbit像是类Animal的一个成员,Animal称为外部类。成员内部类可以无条件访问外部类的所有成员属性和成员方法(包括private成员和静态成员)。

class Animal {
    private String name = "rabbit";
    public static int age =1;
    public Animal() {
    
    }

    class Rabbit {                                                 //内部类
        public void Message() {
            System.out.println("The animal's name is "name);       //外部类的private成员
            System.out.println("He is "age);                       //外部类的静态成员
        }
    }
}

不过要注意的是,同名的成员变量或者方法时,会发生隐藏现象,即默认情况下访问的是成员内部类的成员。如果要访问外部类的同名成员,需要以下面的形式进行访问:

外部类.this.成员变量
外部类.this.成员方法

虽然成员内部类可以无条件地访问外部类的成员,而外部类想访问成员内部类的成员却不是这么随心所欲了。在外部类中如果要访问成员内部类的成员,必须先创建一个成员内部类的对象,再通过指向这个对象的引用来访问:

public class Animal {
    private String name = "rabbit";
    public static int age =1;
    public Animal() {
        getRabbitInstance().Message();  //必须先创建成员内部类的对象,再进行访问
    }

    private Rabbit getRabbitInstance(){
        return new Rabbit();
    }

    class Rabbit {     //内部类
        public void Message() {
            System.out.println(name);  //外部类的private成员
            System.out.println(age);   //外部类的静态成员
        }
    }
}

成员内部类是依附外部类而存在的,也就是说,如果要创建成员内部类的对象,前提是必须存在一个外部类的对象。创建成员内部类对象的一般方式如下:

public class Test {
    public static void main(String[] args)  {
        Outter outter = new Outter();
        //第一种方式:
        Outter.Inner inner = outter.new Inner();  //必须通过Outter对象来创建
         
        //第二种方式:
        Outter.Inner inner1 = outter.getInnerInstance();
    }
}
 
class Outter {
    private Inner inner = null;
    public Outter() {
         
    }
     
    public Inner getInnerInstance() {
        if(inner == null)
            inner = new Inner();
        return inner;
    }
      
    class Inner {
        public Inner() {  
        
        }
    }
}

内部类可以拥有private访问权限、protected访问权限、public访问权限及包访问权限。

比如上面的例子,如果成员内部类Inner用private修饰,则只能在外部类的内部访问;如果用public修饰,则任何地方都能访问;如果用protected修饰,则只能在同一个包下或者继承外部类的情况下访问;如果是默认访问权限,则只能在同一个包下访问。

这一点和外部类有一点不一样,外部类只能被public和包访问两种权限修饰。我个人是这么理解的,由于成员内部类看起来像是外部类的一个成员,所以可以像类的成员一样拥有多种权限修饰。

局部内部类

局部内部类是定义在一个方法或者一个作用域里面的类,它和成员内部类的区别在于局部内部类的访问仅限于方法内或者该作用域内。

class People{
    public People() {
         
    }
}
 
class Man{
    public Man(){
         
    }
     
    public People getWoman(){
        class Woman extends People{       //局部内部类
            int age =0;
        }
        return new Woman();
    }
}

注意,局部内部类就像是方法里面的一个局部变量一样,是不能有public、protected、private以及static修饰符的。

匿名内部类

匿名内部类应该是平时我们编写代码时用得最多的,在编写事件监听的代码时使用匿名内部类不但方便,而且使代码更加容易维护。

匿名内部类是唯一一种没有构造器的类。正因为其没有构造器,所以匿名内部类的使用范围非常有限,大部分匿名内部类用于接口回调。匿名内部类在编译的时候由系统自动起名为Outter$1.class。一般来说,匿名内部类用于继承其他类或是实现接口,并不需要增加额外的方法,只是对继承方法的实现或是重写。

静态内部类

静态内部类也是定义在另一个类里面的类,只不过在类的前面多了一个关键字static。静态内部类是不需要依赖于外部类的,这点和类的静态成员属性有点类似,并且它不能使用外部类的非static成员变量或者方法,这点很好理解,因为在没有外部类的对象的情况下,可以创建静态内部类的对象,如果允许访问外部类的非static成员就会产生矛盾,因为外部类的非static成员必须依附于具体的对象。

public class Test {
    public static void main(String[] args)  {
        Outter.Inner inner = new Outter.Inner();
    }
}
 
class Outter {
    public Outter() {
         
    }
     
    static class Inner {
        public Inner() {
             
        }
    }
}

内部类总结

普通内部类

非static的类,定义在某个类的成员变量位置

定义后,在类里面均可以使用

可继承类实现接口

-普通内部类不能定义静态变量(除非是常量 public final static int a = 5;)

-不允许没有关联的单独的普通内部类对象 (必须得先创建实例 外部包围类.new方法创建)

-可用private/package private/protected/public 控制外界访问

编译后会在文件中产生对应的类 :类名+$+内部类名称

局部内部类

定义在代码块中的非静态的类,如方法,for循环,if语句等

定义后 有名→可创建对象使用,可加入构造函数

-局部内部类不能定义静态变量(除非是常量 public final static int a = 5;)

-可访问外围包围类的成员

但仅能在该代码块中使用

编译后会在文件中产生对应的类 :类名+$+序号+内部类名称

不能定义一个接口

匿名内部类

-可以继承、改写、补充父类/父接口的构造函数(可带参数)

-匿名内部类不能定义静态变量(除非是常量 public final static int a = 5;)

-匿名内部类不能定义静态方法

-访问该类的外围的变量时应加上类名(可以访问到外围包围类的成员变量和方法)

-若该匿名内部类定义在一个静态方法中,那么他们只能访问外围包围类的静态成员

-匿名 →外部包围类和其他类无法访问到匿名内部类

编译后会在文件中产生对应的类 :类名+$+数字编号

静态嵌套类

-层级和包围类的成员变量/方法一样

-第三方需要通过外部包围类才可以访问到静态嵌套类 例:Outer1.Inner1 obj = new Outer1.Inner1();

-静态嵌套类可以直接访问包围类的静态成员

-静态嵌套类可以通过对象访问包围类的非静态成员

-可用private/package private/protected/public 控制外界访问 本质上和顶层类没有区别

  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

sid10t.

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值