内部类笔记(Java)

韩顺平老师的零基础30天学会Java,(小白自学)自己看的写的当记忆,如有不对地方感谢指教

内部类介绍

  1. 内部类:在一个类的内部定义的类。
  2. 成员内部类格式如:class Outer{//外部类 class Inner{}//内部类 }
 public class l6 {// 外部其他类
    public static void main(String[] args) {

    }
}

class Outer {// 外部类
    private int n1 = 100;// 属性

    public Outer(int n1) {// 构造器
        this.n1 = n1;
    }

    public void m1() {// 方法
        System.out.println("m1()");
    }

    {// 代码块
        System.out.println("代码块la");
    }

    class Innter {// 内部类,在Outer类的内部

    }
    }

  1. 类的五大成员:属性,方法,构造器,代码块,内部类
  2. 内部类分类:局部内部类,匿名内部类,成员内部类,静态内部类

局部内部类

  1. 局部内部类:定义在外部类的局部位置,比如方法中+有类名(LocalInnterClass)
  2. 可以直接访问外部类的所有成员,包含私有的
class Outer {// 外部类
    private int n1 = 100;// 属性

    public void m1() {// 方法
        // 1.局部内部类是定义在外部类的局部位置,通常是在方法里
        System.out.println("m1()");
        class Innter {// 本质还是一个类:内部类
            // 2.可以直接访问外部类的所有成员,包含私有
            public void f1() {
                System.out.println("n1" + n1);
                m1();
            }
        }
    }

}
  1. 不能添加访问修饰符,因为他的地位就是一个局部变量,局部变量不能使用。但是可以用final修饰
        class Innter {// 本质还是一个类:内部类
            // 2.可以直接访问外部类的所有成员,包含私有
            public void f1() {
                System.out.println("n1" + n1);
                m1();
            }
        }
        class Innter1 extends Innter {

        }
    }

在这里插入图片描述

  1. 作用域:仅在定义它的方法中或代码块中
  2. 外部类如何使用Innter呢?——外部类在方法中,可以创建Innter对象,然后调用方法即可
// 6.外部类调用内部类可在方法中,创建Innter对象,再调用方法即可
        Innter innter = new Innter();
        innter.f1();
  • 局部内部类定义在方法中/代码块中
  • 作用域在方法体或代码块中
  • 本质仍是个类
public class l6 {
    public static void main(String[] args) {
        Outer outer = new Outer();
        outer.m1();
    }
}

class Outer {// 外部类
    private int n1 = 100;// 属性

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

    public void m1() {// 方法
        // 1.局部内部类是定义在外部类的局部位置,通常是在方法里
        // 4.作用域:仅在此方法中或代码块
        System.out.println("m1()");
        final class Innter {// 本质还是一个类:内部类
            // 2.可以直接访问外部类的所有成员,包含私有
            public void f1() {
                System.out.println("n1" + n1);
                m2();

            }
        }
        // 6.外部类调用内部类可在方法中,创建Innter对象,再调用方法即可
        Innter innter = new Innter();
        innter.f1();
    }

}
  1. 外部其他类不能访问局部内部类(因为局部内部类地位是一个局部变量)
    7.如果外部类和局部内部类的成员重名时,默认遵循就近原则。如果想访问外部类的成员,则可以使用(外部类名.this.成员)去访问

Outer.this本质上就是外部类的对象,哪个对象调用了m1,Outer.this就是哪个对象,这里就是outer对象

public class l6 {
    public static void main(String[] args) {
        Outer outer = new Outer();
        outer.m1();
    }
}

class Outer {// 外部类
    private int n1 = 100;// 属性

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

    public void m1() {// 方法
        // 1.局部内部类是定义在外部类的局部位置,通常是在方法里
        // 4.作用域:仅在此方法中或代码块
        System.out.println("m1()");
        final class Innter {// 本质还是一个类:内部类
            // 2.可以直接访问外部类的所有成员,包含私有
            private int n1 = 10;

            public void f1() {
                // 7.如果外部类和内部类的成员重名时,就近原则。如果要使用外部类的成员(外部类名.this.成员)
                System.out.println("n1=" + n1 + "外部类的n1" + Outer.this.n1);
                m2();

            }
        }
        // 6.外部类调用内部类可在方法中,创建Innter对象,再调用方法即可
        Innter innter = new Innter();
        innter.f1();
    }

}
  1. 这里用hashcode显示地址来证明到底对应是不是outer在这里插入图片描述在这里插入图片描述地址一致地址一致,对滴

匿名内部类!!!

  1. 匿名内部类:1)本质是类2)内部类3)该类没有名字【其实系统底层是给分配的名字,隐藏起来的】4)同时还是个对象Anonymous
  2. 匿名内部类基本语法:new 类或接口(参数列表){类体};
  3. 基于接口的匿名内部类
    (1)需求:想使用接口,并创建对象
    (2)传统方法,写一个类实现该接口,并创建对象
public class l6 {
    public static void main(String[] args) {
        Outer outer = new Outer();
        outer.method();
    }
}

class Outer {
    private int n1 = 10;// 属性

    public void method() {// 方法
        // 基于接口的匿名内部类
        IA tiger = new Triger();
        tiger.cry();
    }
}

interface IA {// 接口
    public void cry();
}

class Triger implements IA {

    @Override
    public void cry() {
        System.out.println("老虎咆哮");

    }

}

class Father {

    public Father() {// 构造器
    }

    public void test() {// 方法

    }
}

(3)如果需求是Tiger类只使用一次以后再不使用,这样话每次。。。繁琐
(4)使用匿名类来简化

public class l6 {
    public static void main(String[] args) {
        Outer outer = new Outer();
        outer.method();
    }
}

class Outer {
    private int n1 = 10;// 属性

    public void method() {// 方法
        // 基于接口的匿名内部类
        IA tiger = new IA() {

            @Override
            public void cry() {
                System.out.println("老虎咆哮");

            }

        };
        tiger.cry();
        // IA tiger = new Triger();
        // tiger.cry();
    }
}

interface IA {// 接口
    public void cry();
}

// class Triger implements IA {

// @Override
// public void cry() {
// System.out.println("老虎咆哮");

// }

// }

class Father {

    public Father() {// 构造器
    }

    public void test() {// 方法

    }
}

(5)tiger的编译类型:IA
(6)tiger的运行类型:匿名内部类在这里插入图片描述
class Outer$1。以后看到XXX$1就是匿名内部类getClass就是获取到该对象的运行类型

  • 编译时类型由声明该变量时使用的类型决定,运行时类型由实际赋给该变量的对象决定。

在这里插入图片描述
(7)jdk底层在创建匿名内部类 Outer$1,立刻马上就创建了 Outer$1实例,并且把地址返回给tiger
(8)匿名内部类使用一次,就不能载使用的

  1. 演示基于类的匿名内部类
    father编译类型 Father
    father运行类型 Outer$2
   Father father = new Father(){};

father编译类型 Father
father运行类型 Father

Father father = new Father() ;

在这里插入图片描述

  1. 基于抽象类的匿名内部类
abstract class Animal {// 抽象类
    abstract void eat();
}

这里就不能省省略不写方法。。。抽象。。。有点像父类和子类

   Father father = new Father("jack") {

            @Override
            public void test() {
                System.out.println("iuyinm");

            }

        };
class Father {

    public Father(String name) {// 构造器
        System.out.println("name=" + name);
    }

    public void test() {// 方法

    }
}

编译结果:name=jack

  1. 两种调用方法
    (1)通过对象调用
public class l6 {
    public static void main(String[] args) {
        Outer05 outer = new Outer05();
        outer.f1();
    }
}

class Outer05 {
    private int n1 = 90;

    public void f1() {
        // 创建一个基于类的匿名内部类
        Person person = new Person() {

            @Override
            public void hi() {
                System.out.println("匿名内部类重写了hi方法");
            }

        };
        person.hi();// 动态绑定,真实运行类型是Outer05$1
    }
}

class Person {
    public void hi() {
        System.out.println("Person hi");
    }
}

(2)直接调用其本身也是返回对象

public class l6 {
    public static void main(String[] args) {
        Outer05 outer = new Outer05();
        outer.f1();
    }
}

class Outer05 {
    private int n1 = 90;

    public void f1() {
        // 创建一个基于类的匿名内部类
        // Person person = new Person() {

        // @Override
        // public void hi() {
        // System.out.println("匿名内部类重写了hi方法");
        // }
        // };
        // person.hi();// 动态绑定,真实运行类型是Outer05$1
        // 也可以直接调用,匿名内部类本身也是返回对象
        new Person() {

            @Override
            public void ok(String str) {
                super.ok(str);
            }

            @Override
            public void hi() {
                System.out.println("匿名内部类重写了hi方法。。。");
            }

        }.ok("jack");
        ;
    }
}

class Person {
    public void hi() {
        System.out.println("Person hi");
    }

    public void ok(String str) {
        System.out.println("Person ok()" + str);
    }
}
  1. 总结一些点
    在这里插入图片描述
    在这里插入图片描述
  2. 匿名内部类的实践
    当作实参直接传递,简洁高效
public class l6 {
    public static void main(String[] args) {
        // 当作实参直接传递,简洁高效
        f1(new IL() {

            @Override
            public void show() {
                System.out.println("这是一幅名画");

            }

        });
    }

    // 静态方法,形参是接口类型
    public static void f1(IL il) {
        il.show();
    }
}

// 接口
interface IL {
    void show();
}

再看看传统写法

 public static void main(String[] args) {
        // 当作实参直接传递,简洁高效
        // f1(new IL() {

        //     @Override
        //     public void show() {
        //         System.out.println("这是一幅名画");

        //     }

        // });
        // 传统方法
        f1(new Car());

    }

    // 静态方法,形参是接口类型
    public static void f1(IL il) {
        il.show();
    }
}

// 接口
interface IL {
    void show();
}

// 类实现IL 编程领域中被称为硬编码
class Car implements IL {

    @Override
    public void show() {
        System.out.println("这也是一副名画");
    }

}

比如说。要是改了Car里面的”这也是一副名画“,那上面调用静态方法那调用都影响
在这里插入图片描述
// 1.传递的是实现了Bell接口的匿名内部类 l6$1 l6$2
// 2.重写了ring方法
// 3.Bell bell=new Bell() {

    // @Override
    // public void ring() {
    // System.out.println("懒猪起床了");

    // }

    // }
     bell.ring();// 动态绑定
public class l6 {
    public static void main(String[] args) {
        Cellphone cellphone = new Cellphone();
        cellphone.alarmclock(new Bell() {

            @Override
            public void ring() {
                System.out.println("懒猪起床了");

            }

        });
        cellphone.alarmclock(new Bell() {

            @Override
            public void ring() {
                System.out.println("小伙伴们上课了");
            }

        });
    }
}

interface Bell {// 接口
    public void ring();// 方法
}

class Cellphone {// 类
    public void alarmclock(Bell bell) {// 形参是Bell接口类型
        bell.ring();
    }
}

成员内部类

  1. 成员内部类定义:定义在外部类的成员位置,且没有static修饰(MemberInnerClass)
  2. 可直接访问外部类的所有成员,包含私有
  3. 可以添加任意修饰符(public,protected,默认,private),因为其就是一个成员
public class l6 {
    public static void main(String[] args) {
        Outer08 outer08 = new Outer08();
        outer08.ti();
    }
}

class Outer08 {// 外部类
    private int n1 = 10;
    public String name = "凌不疑";

    protected class Innter08 {// 1.成员内部类(即不再方法中也不在代码块中,在成员的位置上写)
        // 2.可以添加任意修饰符(public,protected,默认,private),因为他本身地位就是成员
        public void say() {

            System.out.println("Outer的n1=" + n1 + "Outer的name=" + name);
        }
    }

    // 写方法
    public void ti() {
        // 使用了成员内部类
        Innter08 innter08 = new Innter08();
        innter08.say();
    }
}
  1. 作用域:在外部类里面
  2. 成员内部类—访问—外部类成员—直接访问
  3. 外部类—访问—成员内部类—创建对象,再访问(使用相关方法)
  4. 外部其他类—访问成员内部类—2种方式
public class l6 {
    public static void main(String[] args) {
        Outer08 outer08 = new Outer08();
        outer08.ti();
        // 外部内部类访问成员内部类3种方式
        // 1.outer08.new Innter08();相当于把new Innter08()当成outer08的成员
        Outer08.Innter08 innter08 = outer08.new Innter08();
        innter08.say();
        // 2.写一个方法在外部类中,可以返回Innter08对象
        Outer08.Innter08 innter08Instance = outer08.getInner08Instance();
        innter08Instance.say();
    }
}

class Outer08 {// 外部类
    private int n1 = 10;
    public String name = "凌不疑";

    protected class Innter08 {// 1.成员内部类(即不再方法中也不在代码块中,在成员的位置上写)
        // 2.可以添加任意修饰符(public,protected,默认,private),因为他本身地位就是成员
        public double sal = 9.9;

        public void say() {

            System.out.println("Outer的n1=" + n1 + "Outer的name=" + name);
        }
    }

    // 方法,返回一个Innter08实例
    public Innter08 getInner08Instance() {
        return new Innter08();
    }

    // 写方法
    public void ti() {
        // 使用了成员内部类
        // 创建成员内部类对象,然后使用相关的方法
        Innter08 innter08 = new Innter08();
        innter08.say();
        System.out.println(innter08.sal);
    }
}
  1. 如果外部类和局部内部类的成员重名时,默认遵循就近原则。如果想访问外部类的成员,则可以使用(外部类名.this.成员)去访问

静态内部类

  1. 静态内部类定义:定义在外部类的成员位置,并且有static修饰(StaticlnnerClass)
  2. 静态内部类可以直接访问外部类的所有静态成员,包括私有,但是不能直接访问非静态成员
  3. 可以添加任意访问修饰符(public,protected,默认,private),其本身地位是成员
  4. 作用域:同其他成员,为整个类体

public class l6 {
    public static void main(String[] args) {
        Outer10 outer10 = new Outer10();
        outer10.show();
    }
}

class Outer10 {// 外部类
    private int n1 = 10;
    private static String name = "袁善良";

    // Inner10静态内部类
    // 1.放在外部类成员位置
    // 2.使用static修饰
    // 3.可以直接访问外部类的所有静态成员,包含私有,但不能直接访问非静态成员name
    // 4.可以添加任意访问修饰符(public,protected,默认,private),其本身地位是成员
    static class Inner10 {
        public void say() {
            System.out.println(name);
        }
    }

    public void show() {
        Inner10 inner10 = new Inner10();
        inner10.say();
    }
}
  1. 成员内部类—访问—外部类成员—直接访问
  2. 外部类—访问—成员内部类—创建对象,再访问(使用相关方法)
  3. 外部其他类—访问—静态内部类3种方法
public class l6 {
    public static void main(String[] args) {
        Outer10 outer10 = new Outer10();
        outer10.show();
        // 外部其他类 使用静态内部类
        // 1.因为静态内部类可以通过类名直接访问,但是得通过访问权限
        Outer10.Inner10 inner10 = new Outer10.Inner10();
        inner10.say();
        // 2.编写一个方法(非静态),可以返回静态内部类的对象实例
        Outer10.Inner10 inner102 = outer10.getInner10();
        inner102.say();
        System.out.println("-----------");
        // 静态,这没有再创建对象,直接用外部类名来用
        Outer10.Inner10 inner103 = Outer10.getInner101();
        inner103.say();
    }
}

class Outer10 {// 外部类
    private int n1 = 10;
    private static String name = "袁善良";

    // Inner10静态内部类
    // 1.放在外部类成员位置
    // 2.使用static修饰
    // 3.可以直接访问外部类的所有静态成员,包含私有,但不能直接访问非静态成员name
    // 4.可以添加任意访问修饰符(public,protected,默认,private),其本身地位是成员
    static class Inner10 {
        public void say() {
            System.out.println(name);
        }
    }

    public void show() {
        Inner10 inner10 = new Inner10();
        inner10.say();
    }

    public Inner10 getInner10() {
        return new Inner10();

    }

    public static Inner10 getInner101() {
        return new Inner10();

    }
}
  1. 如果外部类和局部内部类的成员重名时,默认遵循就近原则。如果想访问外部类的成员,则可以使用(外部类名.成员)去访问

课堂测试题

写出输出结果:

class Test {// 外部类
    public Test() {// 构造器
        Innter s1 = new Innter();
        s1.a = 10;
        Innter s2 = new Innter();
        System.out.println(s2.a);
    }

    class Innter {// 内部类。成员内部类
        public int a = 5;
    }

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

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值