JAVA成员内部类,静态内部类,局部内部类,匿名内部类

目录

1. 成员内部类

1.1. 成员内部类的代码如何书写?

1.2. 如何创建成员内部类的对象?

1.3. 成员内部类如何获取外部类的成员变量?

2. 静态内部类

2.1. 什么是静态内部类?

2.2. 创建静态内部类的对象的格式:

2.3. 调用静态内部类里的方法:

3. 局部内部类

4. 匿名内部类(重要)

4.1. 什么是匿名内部类?

4.2. 定义格式:

4.3. 格式的细节:

4.4. 格式分析:

4.5. 字节码检验

4.6. 使用场景:

4.7. 拓展:


1. 成员内部类

1.1. 成员内部类的代码如何书写?

  • 写在成员位置,属于外部类的成员。(与外部其他成员同等地位,平等受到权限修饰符的限制)
  • 成员内部类可以被一些修饰符所修饰,比如:private,默认,protected,public,static等

  • 注意一点,当成员内部类被static修饰就不叫成员内部类了,叫静态内部类(后面介绍)。
  • 在成员内部类里面,JDK16之前不能定义静态变量,JDK16开始才可以定义静态变量。

1.2. 如何创建成员内部类的对象?

方式一(当内部类被private修饰时使用):

在外部类中编写方法,对外提供内部类的对象。

// 外部类
class Outer{
    String name;
    // 内部类
    class Inner{
        int a=10;
    }
    // 定义一个方法用来创建内部类的对象(返回值类型+方法名)
    Inner getInstance(){
        return new Inner();
    }
}

//测试类 
class Test{
    main{
        //首先创建外部类对象
        Outer outer=new Outer();
        //  然后用外部类对象调用getInstance方法,并可使用多态接收
        Object inner = outer.getInstance();

    }
}

方式二(被非private修饰时使用):

直接创建对象

格式:外部类名 . 内部类名 对象名=外部类对象 . 内部类对象;

范例:Outer.Inner oi=new Outer().new Inner();

第一种方法我可以在集合中的迭代器中得到印证:


1.3. 成员内部类如何获取外部类的成员变量?

由面试题引出问题:

解答如下:

System.out.println(Outer.this.a);Outer.this表示外部类对象的地址值

System.out.println(this.a);

System.out.println(a);


2. 静态内部类

静态内部类中只能访问外部类中的静态变量和静态方法,如果要访问非静态的需要先创建外部类对象

如下

public class Outer {
   static int a;
    int b;
//静态内部类
    static class Inner {
//        非静态方法
        public void show1() {
            Outer out=new Outer();
            System.out.println(a);
            System.out.println(out.b);//非静态字段“b”不能直接从静态上下文中引用
        }
//静态方法
        public static void show2(){
            Outer out=new Outer();
            System.out.println(a);
            System.out.println(out.b);//非静态字段“b”不能直接从静态上下文中引用
        }
        }
    }
}

2.1. 什么是静态内部类?

在成员内部类前加 static 的类叫静态内部类,它是成员内部类中的一种。

定义如下:


2.2. 创建静态内部类的对象的格式:

外部类名.内部类名 对象名 =new 外部类名.内部类名();

Car.Engine oi=new Car.Engine()

因为静态内部类是 static 修饰的,所以 new 的是 Car 里面的 Engine

注意要和成员内部类对象创建格式要区别开


2.3. 调用静态内部类里的方法:

  1. 若调用非静态方法:

先创建内部类对象,再用对象调用

如下:

public class Outer {
//静态内部类
    static class Inner {
//        非静态方法
        public void show1() {
            System.out.println("非静态方法被调用");
        }
//          静态方法
        public static void show2(){
            System.out.println("静态方法被调用");
        }
    }
}

//测试
class Test{
    main{
        // 创建内部类对象
 Outer.Inner oi=new Outer.Inner();
        // 调用非静态方法
        oi.show1();

    }

  1. 若要调用静态方法:

外部类名.内部类名.方法名();

Outer.Inner.show2();一直 . 即可

3. 局部内部类

定义在外部类的方法内,所以定义局部内部类的前提是定义一个方法,和局部变量同等级; //public protected private不可修饰成员变量,因此同样不可修饰局部内部类

定义如下:

public class Outer {
    // show方法
    public void show(){ 
        // 局部内部类
        class Inner {

        }
    }
}

特性:

  • 外界无法直接使用局部内部类里的内容,需要在外部类的方法内创建局部内部类的对象并调用。
  • 局部内部类可以直接访问外部类的成员,也可以访问方法内的局部变量

如下:

public class Outer {
    int b = 20;
    //方法
    public void show() {
        int a = 10;
        //        局部内部类
        class Inner {
            public void method1() {
                System.out.println("局部内部类中的方法1");
                System.out.println(a);//访问方法内的局部变量
                System.out.println(b);//访问外部类的成员
            }
        }
        // 创建对象,并调用show
        Inner inner=new Inner();
        inner.method1();
    }
}

//测试
public class Test {
    public static void main(String[] args) {
        Outer outer=new Outer();
        outer.show();
        /*
            局部内部类中的方法1
            10
            20
        */
    }
}

4. 匿名内部类(重要)

4.1. 什么是匿名内部类?

隐藏了名字的内部类,可以写在成员位置,也可以写在局部位置。

4.2. 定义格式:

4.3. 格式的细节:

包含三个关系:

继承或实现、方法重写、创建对象

所以代码整体其实是一个父类的子类,或则说是一个接口的实现类的对象。

4.4. 格式分析:

// 首先我们的要有一个接口或父类,这里以接口为例
public interface Swim{
    public abstract void swim();
}

// 按以前我们要实现一个接口的,我们是这样写的;
public class Student implements Swim{
    @Override
    public void swim(){
        System.out.println("重写Swim接口中的游泳方法")
    }
}

//现在的写法:
public class Test{
    main{
        
        new Swim (){
            @Override
            public void swim(){
                System.out.println("重写Swim接口中的游泳方法")
            }
        };   //注意这里要加分号
        
    }

紫线圈起来的其实才是那个没有名字的类

它实现了 Swim 接口

new 的作用是:创建了这个类的对象。

(括号代表无参创建)


4.5. 字节码检验

为了检验说法的正确性,我们检查字节码文件:

找到

这个路径

发现原来匿名内部类是有名字的:

外部类$序号

接着我们再当前路径下打开 cmd

分别输入 javap Test$1.class 、 javap Test$2.class

和之前的推断完全一致。


4.6. 使用场景:

由问题引出:

在测试类中如何调用下面的 method 方法?

以前的方式如何调用?

要先写一个子类来继承 Animal 类再在测试类中创建子类对象,传递给 method 方法

Dog d=new Dog();

method(d);

弊端:如果我只使用一次 Dog,那么单独创建一个子类太麻烦了。

这时就可以用匿名内部类简化代码

/如下可在method中 使用匿名内部类的对象,

//括号内的实参表示是一个继承了Animal并重写了eat方法的子类

// 先创建一个父类
public abstract class Animal{
    // 抽象方法
    public abstract void eat();
}
// -------------------------------------------------------

//测试类
public class Test{
   public static void main(String []args){
       
method(
    new Animal (){
        public void eat(){
            System.out.println("狗吃骨头")
        }
    }
);//注意这里要加分号
        
    }
    //成员方法
    public static void method (Animal a){
        a.eat();
    }

}


4.7. 拓展:

  1. 可用多态方式接收

2.可直接用对象调用其中的方法

  • 20
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

成果、

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

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

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

打赏作者

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

抵扣说明:

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

余额充值