成员内部类、局部内部类、匿名内部类

目录

成员内部类

练习与补充

局部内部类

匿名内部类

练习


成员内部类

 假设,现在我定义了一个Computer类,来描述一台计算机。对于一台计算机而言,最最核心的部分莫过于CPU了。而对于CPU而言,也只有计算机这个类才会包含CPU。对于其他所有类而言,应该是不会直按用到的。
我们希望,既然CPU这个类,只能被计算机使用,从代码的角度我们就合望,CPU能被Computer类访问到

public class Demo1 {
    public static void main(String[] args) {
        //正常CPU类可以被每一个类创建cpu对象,但是只希望被Computer类访问
        //定义在类内部就可以了
        Cpu cpu = new Cpu();

    }
}

class Computer {
    Cpu cpu;

    class Cpu {
        int coreNum;
        int requency;
    }
}
/*
class Cpu{
    int coreNum;
    int requency;
}*/

 

在Java语言中类可以嵌套定义
内部类:定义在其他类内部的类就称为内部类
内部类的访问特点:
内部类可以直接访问外部类的成员,包括私有。外部类要访问内部类的成员,必须创建对象

成员位置内部类:
约定:把包含内部类的类,称之为外部类

内部类的访问特点:
1.内部类可以直接访问外部类的成员,包括私有。
2.外部类要访问内部类的成员,必须创建对象。

如何理解成员位置内部类
成员位置内部类定义在外部类的成员位置,将内部类看成一个整体,就类比于成员变量或成员方法的一个普通成员。
内部类依赖于外部类对象而存在。而static不依赖于对象而存在

内部类的访问(外部类的外部):
1.在外部类的外部,访问内部类,创建内部类对象
外部类名.内部类名 对象名 = 外部类对象.内部类对象; (代码有两种方式)

public static void main(String[] args) {
	MemberOuter memberOuter = new MemberOuter();
	memberOuter.accessInner();
	//创建其他类内部定义的普通成员位置,内部类对象 第一种方式
	MemberOuter.MemberInner memberInner = memberOuter.new MemberInner();
	memberInner.accessOuter();
	//第二种方式
	MemberOuter.MemberInner memberInner1 = new MemberOuter().new MemberInner();
	memberInner.accessOuter();
}

2.静态成员位置内部类,作为外部类的一个静态成员,不在依赖于外部类对象而存在 外部类.内部类 对象名 = new 外部类.内部类();

public static void main(String[] args) {
	MemberOuter.staticMemberInner staticMemberInner = new MemberOuter.staticMemberInner();
	staticMemberInner.accessOuter();
}

静态上下文问题:在外部类的静态方法中,访问成员位置内部类

//在外部类的静态方法中,访问成员位置内部类
public static void accessInnerInStatic() {
    //new MemberInner();//静态上下文问题 可以用外部类对象this:this.new MemberInner();
    //MemberInner memberInner = this.new MemberInner();但是this没有当前对象,因为是static
    //但是我们可以自己创建一个外部类对象,在外部类对象上,创建内部类对象
    MemberOuter memberOuter = new MemberOuter();
    MemberInner memberInner = memberOuter.new MemberInner();
}

完整代码

package com.wolf.inner.basic;
/**
 * @create 2021-07-26 20:27
 */
public class Demo1 {
    public static void main(String[] args) {
        MemberOuter memberOuter = new MemberOuter();
        memberOuter.accessInner();
        //创建其他类内部定义的普通成员位置,内部类对象 第一种方式
        MemberOuter.MemberInner memberInner = memberOuter.new MemberInner();
        memberInner.accessOuter();
        //第二种方式
        MemberOuter.MemberInner memberInner1 = new MemberOuter().new MemberInner();
        memberInner.accessOuter();

        MemberOuter.staticMemberInner staticMemberInner = new MemberOuter.staticMemberInner();
        staticMemberInner.accessOuter();
    }
}

class MemberOuter {
    private int outerI;
    private static int staticI;

    private void outerPrivateMethod() {
        System.out.println("outer private");
    }

    //在外部类中创建内部类对象
    public void accessInner() {
        MemberInner memberInner = new MemberInner();
        System.out.println(memberInner.innerI);
        memberInner.innerMemberMethod();
    }

    /*    如何理解成员位置内部类?
        成员位置内部类定义在外部类的成员位置,将内部类看成一个整体,就类比于成员变量或成员方法的一个普通成员。
        内部类依赖于外部类对象而存在。而static不依赖于对象而存在*/
    //在外部类的静态方法中,访问成员位置内部类
    public static void accessInnerInStatic() {
        //new MemberInner();//静态上下文问题 可以用外部类对象this:this.new MemberInner();
        //MemberInner memberInner = this.new MemberInner();但是this没有当前对象,因为是static
        //但是我们可以自己创建一个外部类对象
        MemberOuter memberOuter = new MemberOuter();
        MemberInner memberInner = memberOuter.new MemberInner();
    }

    //成员位置内部类
    //private 不能直接访问
    class MemberInner {
        int innerI = 1;

        public void innerMemberMethod() {
            System.out.println("inner method");
        }

        public void accessOuter() {
            System.out.println(outerI);
            outerPrivateMethod();
        }
    }

    //静态内部类
    static class staticMemberInner {
        //外部类的静态上下文(静态内部类)中的方法也是静态上下文,无法直接访问外部类的非静态的成员变量和成员方法
        public void accessOuter() {
            //System.out.println(outerI);
            //outerPrivateMethod();
            System.out.println(staticI);
            accessInnerInStatic();
        }
    }
}

练习与补充

//在控制台分别输出10,20,30
class Outer {
    public int num = 10;

    class Inner {
        public int num = 20;

        public void show() {
            int num = 30;
            System.out.println( ?);
            System.out.println( ??);
            System.out.println( ???);
        }
    }
}

答案

System.out.println(Outer.this.num);//外部类当前对象成员变量值
//System.out.println(new Outer().num);//不推荐
System.out.println(this.num);
//System.out.println(Inner.this.num); //等同可省略
System.out.println(num);

/*
在静态中this对象和static是冲突的,但是在内部类中 类名.this  this仅仅指的是从哪个类嵌套的当前对象,和static没有关系*/

局部内部类

定义在其他类的方法体内部的类;

访问特征:1.只能在定义该类的方法体中访问该类

package com.wolf.inner.basic.localinner;
/**
 * @create 2021-07-27 10:04
 */
public class Demo1 {
}

class LocalOuter {
    private int privateI;

    private void privateMethod() {
        //new LocalInner();错误
    }

    public void local() {
        //定义一个局部内部类
        class LocalInner {
            int inner;
            public void access() {
                //在局部内部类中,直接访问外部类私有成员
                System.out.println(privateI);
                privateMethod();
            }
        }
        //只能在定义该类的方法体中访问该类
        LocalInner localInner = new LocalInner();
        System.out.println(localInner.inner);
        localInner.access();
    }
}

2.可以访问方法体中局部变量,但该局部变量必须被 final 修饰;生命周期冲突 

生命周期的冲突    局部内部类对象 vs 局部变量
1.局部变量的生命周期、随着方法的执行结束,即栈帧销毁,而从内存中消失
2.但是对于局部内部类对象而言,存储在堆上,对象的销毁和方法栈帧,没有直接关系简单来说,就是方法运行完,局部变最不存在了,但是对象还在
3.所以,如果方法运行完毕之后,还有人可以使用这个对象,那么就可以通过该局部内部类对象去访问这个局部变量,而此时,局部变量早已随着方法的执行完毕,而从内存中消失

匿名内部类

匿名内部类的前提:存在一个类(可以是抽象类,可以是具体类)或者接口

匿名内部类(通常是以局部内部类)对象格式
new 类名或者接口名( ) { 重写方法; }

本质:是(一个继承了类或者实现了接口的(匿名)子类)匿名对象

package com.wolf.inner.anonymouus;

/**
 * @create 2021-07-27 10:54  
 * day14 - 5 整齐及注释
 */
public class Demo {
    public static void main(String[] args) {
        //匿名对象
        //没有引用对象,使用一次就用不了了
        new MyClass().show();
        //1、(接口)同样的工作,利用匿名内部类一次完成
        new MyInterface() {

            //既定义了对象,又创建了该匿名内部类的一个对象
            @Override
            public void show() {
                System.out.println("内部类对象 show");
            }//在代码块中,所以是局部位置内部类
        }.show();
        //2、利用匿名内部类对象,创建一个MyOuter类,子类对象
        MyOuter myOuter = new MyOuter(1) {
            public void accessFather() {
                System.out.println(i);
                test();
            }

            @Override
            public void test() {
                System.out.println("匿名 test");
                System.out.println(i);
            }
        };
        //多态
        myOuter.test();
        //myOuter.accessFather();//编译看左面,无法访问子类方法


        //3、利用匿名内部类对象,创建抽象类的子类对象
        new AbstractClass() {

            @Override
            public void show() {
                System.out.println("匿名AbstractClass show");
            }
        }.show();
    }
}

interface MyInterface {
    void show();
}

class MyClass implements MyInterface {

    @Override
    public void show() {
        System.out.println("MyInterface show");
    }
}

class MyOuter {
    int i = 100;

    public MyOuter(int i) {
        this.i = i;
    }

    public void test() {
        System.out.println("MyOuter test");
    }
}

//已经存在的抽象类
abstract class AbstractClass {
    public abstract void show();
}

匿名内部类的使用

package com.wolf.inner.anonymouus;

/**
 * @create 2021-07-27 14:55
 */
public class Demo2 {
    public static void main(String[] args) {
        //给匿名内部类起一个名字,用父类引用变量只想它
        UseClass useClass =
                //创建匿名内部类
                new UseClass(){

            @Override
            public void method1() {
                System.out.println("method1");
            }

            @Override
            public void method2() {
                System.out.println("method2");
            }
            public void method3(){
                System.out.println("method3");
            }
        };//.method3();//只能访问一个方法,若要多次访问成员,故创建一个方法
        //有局限:子类自定义方法不能访问,因为多态编译看左面
        //useClass.method1();
        //useClass.method2();
        //useClass.method3();//访问不到
    }
}
abstract class UseClass{
    public abstract void method1();
    public abstract void method2();
}

1.首先回顾我们曾经讲过的方法的形式参数是引用类型的情况
重点是接口的情况,我们知道这里需要一个子类对象。
而匿名内部类对象  就是一个子类匿名对象,所以,可以使用匿名内部类改进以前的做法。
2.方法返同值是接口类型的情况

package com.wolf.inner.anonymouus;

/**
 * @create 2021-07-27 14:55
 */
public class Demo2 {
    public static void main(String[] args) {
        //创建匿名内部类
        //一次或多次使用匿名内部类对象
        useAnonymousInner();

        //在开发中,只调用一次某方法,该方法接收的参数类型,接口类型
        runMethod(new MyRunner() {
            @Override
            public void run() {
                System.out.println("development use");
            }
        });
        getRunner().run();

    }

    //因为return也是只运行一次
    public static MyRunner getRunner() {
        //作为方法接口类型的对象
        return new MyRunner() {
            @Override
            public void run() {
                System.out.println("return MyRunner");
            }
        };
    }

    public static void runMethod(MyRunner myRunner) {
        myRunner.run();
    }

    private static void useAnonymousInner() {
        //创建匿名内部类:通常在只使用一次类或接口的子类对象的情况下
        new UseClass() {

            @Override
            public void method1() {
                System.out.println("method1");
            }

            @Override
            public void method2() {
                System.out.println("method2");
            }

            public void method3() {
                System.out.println("method3");
            }
        }.method3();//只能访问一个方法,不能访问多个,每次访问都需要创建一次匿名内部类对象

        UseClass useClass = new UseClass() {

            @Override
            public void method1() {
                System.out.println("method1");
            }

            @Override
            public void method2() {
                System.out.println("method2");
            }

            public void method3() {
                System.out.println("method3");
            }
        };//只能访问一个方法,若要多次访问成员,故创建一个方法
        //有局限:子类自定义方法不能访问,因为多态编译看左面
        useClass.method1();
        useClass.method2();
        //useClass.method3();//访问不到
    }
}

abstract class UseClass {
    public abstract void method1();

    public abstract void method2();
}

interface MyRunner {
    void run();
}

练习

package com.wolf.inner.anonymouus;

/**
 * @create 2021-07-27 15:47
 * 要求在控制台输出 helloWorld 字符串
 */
public class Exercise {
    public static void main(String[] args) {
        Outer.method().show();
    }
}

interface Inter {
    void show();
}

class Outer {
    //补全代码
}

答案

package com.wolf.inner.anonymouus;

/**
 * @create 2021-07-27 15:47
 * 要求在控制台输出 helloWorld 字符串
 */
public class Exercise {
    public static void main(String[] args) {
        Outer.method().show();
        //分析: 类名.方法 的方法一定是静态方法 有返回值且一定是接口类型的子类对象
    }
}

interface Inter {
    void show();
}

class Outer {
    //补全代码
    //返回接口的子类对象
    public static Inter method() {
        return new Inter() {
            @Override
            public void show() {
                System.out.println("helloWorld");
            }
        };
    }
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值