JAVA内部类

内部类(必须重点掌握)程序员分层的节点必须记住

基本介绍:

一个类的内部又完整的嵌套了另一个类结构。被嵌套的类称为内部类【inner class】,嵌套其他类的类称为外部类【outer class】。是我们类第五大成员【思考:类的五大成员是哪些?【属性,代码块,构造器,方法,内部类】】

内部类最大的特点就是可以直接访问私有属性,并且可以体现类与类之间的包含关系

基本语法:

class Outer{ //外部类
	class Inner{}//内部类
}

class Other {}//外部其他类

内部类的快速入门:

package JAVA面向对象高级部分.innerClass;

public class InnerClass01 {//其他外部类
    public static void main(String[] args) {

    }
}

class Outer {//外部类
    private int n1 = 168;//属性
    
    {//代码块
        System.out.println("我是代码块!!!");
    }

    public Outer(int n1) {//构造器
        this.n1 = n1;
    }
    
    class Inner{}//内部类
}

内部类的分类

1.定义在外部类的局部位置上(比如方法或代码块内):

  1. 局部内部类(有类名)
  2. 匿名内部类(没有类名,重点最重要)

2.定义在外部类的成员位置上:

  1. 成员内部类(没有static修饰)
  2. 静态内部类(使用static修饰)

局部内部类使用LocalInnerClass.java

说明:局部内部类是定义在外部类的局部位置,比如方法中或者代码块,并且有类名

1.可以直接访问外部类的所有成员,包含私有的

2.不能添加访问修饰符,因为它的地位就是一个局部变量。局部变量是不能使用修饰符的。但是可以使用final修饰,因为局部变量也可以使用final修饰

3.作用域:仅仅在定义它的方法或代码块中

4.局部内部类 —》访问 —》外部类的成员【访问方式:直接访问】

5.外部类 —》访问 —》局部内部的成员

​ 访问方式:创建对象,再访问(注意:必须在使用域中)

​ 【就是先创建在方法中或代码块中创建局部内部类的对象,再调用内部类的成员,最后再创建外部类对象,调用内部类所在的方法或代码即可】

6.外部其他类 —》不能直接访问 —》局部内部类的【可以通过外部其他类访问外部类,外部类再访问局部内部类】

7.如果外部类和局部内部类的成员重名时,默认遵循就近原则,如果想访问外部类的成员【成员方法和属性】时,则可以使用【外部类名.this.成员名

package JAVA面向对象高级部分.innerClass;

public class LoaclInnerClass {
    public static void main(String[] args) {
        //5.外部类访问内部类的方法:在内部类所在的方法中或代码块中创建内部类的对象
        //对象调用内部类的成员
        //6.外部其他类是不能直接访问局部内部类的,只能通过访问外部类,外部类现访问内部类
        Outer02 outer02 = new Outer02();
        outer02.call();
        System.out.println("outer02的哈希值为:"+outer02);
        /**
         * 返回值:
         * num888
         * 外部类num=168
         * Outer02.this的哈希值为:JAVA面向对象高级部分.innerClass.Outer02@1b6d3586
         * 我是外部的show方法
         * outer02的哈希值为:JAVA面向对象高级部分.innerClass.Outer02@1b6d3586
         */
    }
}

/**
 * 局部内部类的使用细节五点:
 * 1.局部内部类是可以直接访问外部类的所有成员,包含私有的
 * 2.局部内部类是不能添加访问修饰符的,但是只能添加final修饰符,使该内部类不能被继承,和局部属性一样
 * 3.作用域是:局部内部类仅仅在定义所在方法内或代码块中
 * 4.局部内部类访问外部的成员是可以直接访问的
 * 5.外部类访问内部类的方法:在内部类所在的方法中或代码块中创建内部类的对象
 * 对象调用内部类的成员
 * 6.外部其他类  ---》不能直接访问  ---》局部内部类【因为局部内部类地位就是一个局部变量】
 * 7.如果外部类和局部内部类的成员重名时,默认遵循就近原则,如果想访问外部类的成员,则可以使用【外部类    名.this.成员名】去访问
 */

//外部类
class Outer02 {
    private int num = 168;//属性
    public void show(){//方法
        System.out.println("我是外部的show方法");
    }

    public void call(){
        //2.局部内部类是不能添加访问修饰符的,但是只能添加final修饰符,使该内部类不能被继承
        //3.作用域是:局部内部类仅仅在定义所在方法内或代码块中
        class Inner02{//局部内部类(本质还是一个类具有类的五大特征)
            //7.如果外部类和局部内部类的成员重名时,默认遵循就近原则,如果想访问外部类的成员,
            //则可以使用【外部类名.this.成员名】去访问
            private int num = 888;
            public void f1(){
                //4.局部内部类访问外部的成员是可以直接访问的
                //1.局部内部类是可以直接访问外部类的所有成员,包含私有的
                System.out.println("num"+num);//访问是局部内部类的num【其实隐含着内部类的this】输出:888
                //要想访问外部类的num可以通过:外部类名.this.属性名
                //Outer02.this本质就是外部类的对象,即哪个对象调用num,Outer02.this就是代表那个对象
                //这里是代表是:outer02,可以使用哈希值检验
                System.out.println("外部类num="+Outer02.this.num);//168
                System.out.println("Outer02.this的哈希值为:"+Outer02.this);
                show();
            }
        }
        //5.外部类访问内部类的方法:在内部类所在的方法中或代码块中创建内部类的对象
        //对象调用内部类的成员
        //6.外部其他类是不能直接访问局部内部类的,只能通过访问外部类,外部类再访问内部类
        Inner02 inner02 = new Inner02();
        inner02.f1();
    }
}
匿名内部类的使用

基本介绍:

匿名内部类是定义在外部类的局部位置,比如方法中或代码块中,并且没有类名

  1. 匿名内部类本质还是类
  2. 匿名内部类是内部类
  3. 该类没有名字【但是在系统底层会分配一个名字:外部类名+$+匿名内部类的序号
  4. 同时还是一个对象

匿名内部类的基本语法:

new 类名或接口名(参数列表){类体};

基于接口的匿名内部类

package JAVA面向对象高级部分.innerClass;

/**
 * 匿名内部类的使用
 */
public class AnonymousInnerClass {
    public static void main(String[] args) {
        Outer03 outer03 = new Outer03();
        outer03.method();
    }
}

class Outer03 {//外部类
    private int n1 = 168;//属性
    public void method(){//方法
        /**
         * 基于接口的匿名内部类
         * 1.需求:想使用InterfaceA接口,并创建对象
         * 2.传统方式,是写一个类,实现该接口,并创建对象
         * 3.需求是:Tiger、Dog等类只上使用一次,后面就不再使用了
         * 4.可以使用匿名内部类来简化开发
         * 5.tiger的编译类型 ? InterfaceA
         * 6.tiger的运行类型 ? 就是匿名内部类  Outer03$1
         * 7.jdk底层在创建匿名内部类  Outer03$1,立即马上就创建了 Outer03$1实例,并且把地址返回给tiger
         * 8.匿名内部类使用一次,就不能再使用了,但是对象引用tiger可以反复使用
         */
        //由于下面的方式是如果很多类,都要实现InterfaceA调用cry()方法,并且只使用一次,这开发太复杂了
        //所以可以使用匿名内部类来解决
//        InterfaceA tiger = new Tiger();
//        tiger.cry();
//        InterfaceA dog  = new Dog();
//        dog.cry();
        //使用匿名内部类简化开发
        /**
         * 我们看看底层 会分配 类名 Outer03$1
         * class Outer03$1 implements InterfaceA {
         *      @Override
         *      public void cry(){
         *          System.out.println("老虎叫呵呵!!!");
         *      }
         * }
         */
        InterfaceA tiger = new InterfaceA(){

            @Override
            public void cry() {
                System.out.println("老虎叫了呵呵!!!");
            }
        };
        tiger.cry();
        //9.匿名内部类的类名是底层分配一个类名:外部类名+$+加上匿名类的序号
        System.out.println(tiger.getClass().getName());
    }
}

interface InterfaceA {//接口
    public void cry();//public可以省略
}
//
//class Tiger implements InterfaceA {
//    @Override
//    public void cry() {
//        System.out.println("老虎叫了呵呵!!!");
//    }
//}
//
//class Dog implements InterfaceA { 
//    @Override
//    public void cry() {
//        System.out.println("小狗汪汪叫了!!!");
//    }
//}

基于类的匿名内部类

package JAVA面向对象高级部分.innerClass;

/**
 * 类的匿名内部使用
 */
public class AnonymousInnerClass02 {
    public static void main(String[] args) {

    }
}

class Outer04 {//外部类

    /**
     * 演示基于类的匿名内部类
     * 分析:
     * 1.father编译类型是Father
     * 2.father运行类型是Outer04$1
     */
    public void method(){
        /**
         * 3.底层分析:
         * class Outer04$1 extends Father {
         *      @Verride
         *      public void test(){
         *          System.out.println("匿名内部类重写了test方法");
         *      }
         * }
         */
        //4.同时也直接返回了匿名内部类Outer04$1的对象
        //5.注意参数的传递是传给Father类的构造器
        Father father = new Father("海康"){
            //匿名内部类重写了test方法
            public void test(){
                System.out.println("匿名内部类重写了test方法");
            }
        };
        father.test();
        System.out.println("father对象的运行类型="+father.getClass());//返回:Outer04$1
    }

    /**
     * 基于抽象的匿名内部类,注意必须要实现抽象类中所有抽象方法
     */

    Animal animal = new Animal() {
        @Override
        public void show() {
            System.out.println("小猪猪。。。");
        }
    };
}

class Father {

    public Father(String name){//构造器
        System.out.println("接收到了名字="+name);
    }

    public void test(){
        System.out.println("Father类中的test()方法!!!");
    }
}

abstract class Animal {
    public abstract void show();
}

匿名内部类注意事项和使用细节(必须记住8点)

1.匿名内部类的语法比较奇特,因为匿名内部类既是一个类的定义,同时它本身也是一个对象,因为从语法上看,它既有定义类的特征,也有创建对象的特征,对前面的代码分析可以看出这个特点,因此可以调用匿名内部类的方法。

2.可以直接访问外部类的所有成员,包含私有的

3.不能添加访问修饰符,因为它的地位就是一个局部变量

4.作用域:仅仅在定义的方法或代码块中使用

6.匿名内部类可以直接访问外部类的成员【成员方法和属性】

7.外部其他类不能直接访问匿名内部类,要创建外部类对象,再通过外部类访问匿名内部类【因为匿名内部类地位就是一个局部变量】

8.如果外部类和匿名内部类的成员重名时,匿名内部类访问的话,默认遵循就近原则,如果想访问外部类的成员,则可以使用【外部类名.this.成员名【成员方法或属性】】去访问

package JAVA面向对象高级部分.innerClass;

public class AnonymousInnerClassDetailed {
    public static void main(String[] args) {
        Outer05 outer05 = new Outer05();
        outer05.method();
        System.out.println("main方法的outer05 hashCode值="+outer05);
        /**
         * 返回值:
         * 匿名内部类的cry()方法。。。
         * 这是输出的是匿名内部类的num=888
         * 使用外部类名.this.成员名访问外部类成员=168
         * Outer05.this  hashCode=JAVA面向对象高级部分.innerClass.Outer05@1b6d3586
         * main方法的outer05 hashCode值=JAVA面向对象高级部分.innerClass.Outer05@1b6d3586
         */
    }
}

//外部类
class Outer05 {
    //3.可以直接访问外部类的所有成员【成员方法和属性】包含私有的
    //4.不能添加访问修饰符,因为它的地位就是一个局部属性
    private int num = 168;
    public void method(){
        //5.作用域:仅仅是在定义的方法或代码块中
        //匿名内部的访问方式一:
        Person person = new Person(){
            //重写cry方法
            private int num = 888;
            public void cry(){
                System.out.println("匿名内部类的cry()方法。。。");
                //6.匿名内部类访问外部类的成员【成员方法或属性】是直接访问的
                //8.如果外部类和匿名内部类的成员重名时,匿名内部类访问的话,默认遵循就近原则
                //如果想访问外部类的成员,则可以使用【外部类名.this.成员名】去访问
                System.out.println("这是输出的是匿名内部类的num=" + num);//888
                System.out.println("使用外部类名.this.成员名访问外部类成员="+Outer05.this.num);//168
            }
        };
        //7.外部其他类,不能直接访问匿名内部类,可以通过创建外部类的对象,外部类再访问匿名内部类
        person.cry();
        //Outer05.this就是代表调用cry方法的对象
        System.out.println("Outer05.this  hashCode="+Outer05.this);

//        //匿名内部类访问方式二:
//        new Person(){
//            //重写show方法
//            @Override
//            public void show(String name){
//                System.out.println(name+"匿名内部类重写show方法。。。");
//            }
//        }.show("海康");
    }
}

//Person类
class Person {
    public void cry(){
        System.out.println("Person cry()方法。。。");
    }

    public void show(String name){
        System.out.println("Person show()方法。。。");
    }
}

匿名内部类的使用场景InnerExercise

1.匿名内部类当做实参直接传递,简洁高效

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-l0B9ud04-1644043372483)(E:\Typora笔记\java笔记\img\image-20220128185137098.png)]

package JAVA面向对象高级部分.innerClass.inerClassExercise;

public class InnerClassExercise01 {
    public static void main(String[] args) {
        //传统方法:编程领域【硬编码方式】
        //类 --》实现myInterface接口 --》编程领域【硬编码】
        method(new Student());

        //直接使用匿名内部方式
        method(new myInterface() {
            @Override
            public void show() {
                System.out.println("我是一个学生,会干的不只是写代码");
            }
        });
    }

    //静态方法:形参是接口
    public static void method(myInterface myInterface){
        myInterface.show();
    }
}

//匿名内部类当做实参直接传递,简洁高效
interface myInterface {
    public void show();//public 可以省略
}

//传统方法当做实参
class Student implements myInterface{

    @Override
    public void show() {
        System.out.println("我是一个只会写代码的学生");
    }
}

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-NZ23pyNI-1644043372485)(E:\Typora笔记\java笔记\img\image-20220128185432979.png)]

package JAVA面向对象高级部分.innerClass.inerClassExercise;

public class InnerClassExercise02 {
    public static void main(String[] args) {

        CellPhone cellPhone = new CellPhone();
        //3.通过匿名内部类(对象)作为参数,打印:懒猪起床了
        cellPhone.alarmClock(new Bell() {
            @Override
            public void ring() {
                System.out.println("懒猪起床了!!!");
            }
        });

        //4.传入另一个匿名内部类(对象),打印:小伙伴上课了
        cellPhone.alarmClock(new Bell() {
            @Override
            public void ring() {
                System.out.println("小伙伴上课了!!!");
            }
        });
    }
}

/**
 * 1.有一个铃声接口Bell,转而有个ring方法
 * 2.有一个手机类CellPhone类,具有闹钟功能alarmclock,参数是Bell类型
 * 3.测试手机类的闹钟功能,通过匿名内部(对象)作为参数,打印:懒猪起床了
 * 4.再传入另一个匿名内部类(对象),打印小伙伴上课了
 */

interface Bell {
    void ring();
}

class CellPhone {
    public void alarmClock(Bell bell){
        bell.ring();//动态绑定
    }
}

成员内部类的使用MemberInnerClass

基本介绍:

成员内部类是定义在外部类的成员位置上,并且没有static修饰的

1.可以直接访问外部类的所有成员,包含私有的

2.可以添加任意的访问修饰符【public protected 默认 private】,因为它的地位就是一个成员

3.作用域和外部类的其他成员一样,为整个类体比如前面案例,在外部类的成员方法中创建成员内部类对象,再调用方法

4.成员内部类 ----》访问 ----》外部类成员【比如:属性】直接访问

5.外部类 ----》访问成员内部类【访问方式:创建对象,再访问】

6.外部其他类 ----》访问 ----》成员内部类【有三种方式】

7.如果外部类和内部类的成员重名时,内部类访问的话,默认遵循就近原则,如果想访问外部类的成员,则可以使用【外部类名.this.成员名】去访问

package JAVA面向对象高级部分.innerClass.memberInnerClass;

public class MemberInnerClass01 {
    public static void main(String[] args) {
//        Outer06 outer06 = new Outer06();
//        outer06.print();
        /**
         * 返回值:
         * num=168	name=海康
         * 我是外部类的show方法
         */

        //外部其他类访问成员内部类有三种方式
        //方式一:
//        Outer06 outer06 = new Outer06();
//        Outer06.Inner06 inner06 = outer06.new Inner06();
//        inner06.method();
        /**
         * 返回值:
         * num=168	name=海康
         * 我是外部类的show方法
         */
        /**
         * 方式二:
         */
//        Outer06 outer06 = new Outer06();
//        Outer06.Inner06 inner06 = outer06.getInner06();
//        inner06.method();

        //方式三:
        Outer06.Inner06 inner06 = new Outer06().new Inner06();
        inner06.method();

    }
}

/**
 * 成员内部类
 * 1.可以直接访问外部的所有成员,包含私有的
 * 2.可以添加任意访问修饰符【public protected 默认 private】,因为它是一个成员
 * 3.作用域和外部类的其他成员一样,为整个类体比如下面的print方法,在外部类的成员方法中创建成品同内部类对象,再调用方法
 * 4.成员内部类可以直接访问外部类的成员包含私有
 * 5.外部类访问成员内部类:访问方式:创建对象,再访问
 * 6.外部其他类访问成员内部类有三种方式
 * 7.
 */

class Outer06 {//外部类

    private int num = 168;
    String name = "海康";
    public void show(){
        System.out.println("我是外部类的show方法");
    }

    class Inner06 {
        //可以直接访问外部类的所有成员
        private int num = 888;
        public void method(){
            System.out.println("这是使用成员内部的num="+num +"\tname=" + name );
            //7.如果外部类和内部类的成员重名时,内部类访问的话,默认遵循就近原则,如果想访问外部类的成员,则可以使用【外部类名.this.成员名】去访问
            System.out.println("成员内部类的num="+Outer06.this.num);
            show();
        }
    }
    //访问成员内部类的方式
    public void print(){
        Inner06 inner06 = new Inner06();
        inner06.method();
    }

    //获取成员内部类的对象
    public Inner06 getInner06(){
        return new Inner06();
    }
}

静态内部类使用

基本介绍:

静态内部类是定义在外部类的成员位置,并且有static修饰

细节说明:

  1. 可以直接访问外部类的所有静态成员,包含私有的,但不能直接访问非静态成员
  2. 可以添加八部访问修饰符【public protected 默认 private】,因为它的地位就是一个成员
  3. 作用域:同其他的成员,为整个类体
  4. 外部其他类 —》访问 ----》静态内部类
  5. 如果外部类和静态内部类的成员重名时,静态内部类访问时,默认遵循就近原则,如果想访问外部类的成员,则可以使用【外部名.成员】去访问
package JAVA面向对象高级部分.innerClass.staticInnerClass;

public class StaticInnerClass01 {
    public static void main(String[] args) {
//        Outer8 outer8 = new Outer8();
//        outer8.show();
        //外部其他类访问静态内部类有三种方法
        //方式一:
        Outer8.Inner8 inner8 = new Outer8.Inner8();
        inner8.say();
        //方式二:在外部类中编写一个方法返回静态内部类
        Outer8 outer8 = new Outer8();
        Outer8.Inner8 inner08 = outer8.getInner08();
        inner8.say();
        //方式三:在外部类中编写一个静态方法返回静态内部类
        Outer8.Inner8 iNer08 = Outer8.getINer08();//此方法不用创建外部类的对象
        iNer08.say();
    }
}

//外部类
class Outer8 {
    private int num = 168;
    private static String name = "海康";

    static class Inner8 {
        //静态成员内部类可以直接访问所有静态成员,包含私有的,不能访问非私有的成员
        private static String name = "湛江";
        public void say(){
            //不能直接访问非静态的成员
//            System.out.println(num);//报错
            //如果外部类和静态内部类的成员重名时,静态内部类访问的时,默认遵守就近原则,如果想访问外部类的成员,则可以使用
            //【外部类名.成员】去访问
            System.out.println("静态成员内部类"+name);
            System.out.println("外部类的name"+Outer8.name);//注意不能使用this关键字,因为是静态,对象可能还不存在
        }
    }

    public void show(){
        Inner8 inner8 = new Inner8();
        inner8.say();
    }

    //返回内部类对象
    public Inner8 getInner08(){
        return new Inner8();
    }

    //静态方法返回内部类对象
    public static Inner8 getINer08(){
        return new Inner8();
    }
}

练习题目:

public class Test{//外部类
	public Test(){
		Inner s1 = new Inner();
		s1.a = 10;
		Inner s2 = new Inner();
		System.out.println("s2.a");
	}
	class Inner{
		public int a = 5;
	}
}

public static void main(String[] args){
	Test t = new Test();
	Inner r = t.new Inner();
	System.out.println("r.a");
}

/**
 * 写出输出结果:
 * 返回值:
 * 5
 * 5
 */
  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值