java内部类

1、介绍

package level2.interClass;

/**
 * 1、介绍: 一个类的内部类 又完整的嵌套了另一个类结构,被嵌套的类称为内部类(inner class)
 *          嵌套其他类的类称为外部类,是我们类的第五大成员(属性、方法、构造器、代码块、内部类),
 *          内部类的最大特点就是可以直接访问私有属性,并且可以体现类与类之间的包含关系
 * 2、语法:
 *      class outer{        // 外部类
 *          class inner{    // 内部类
 *          }
 *      }
 *      class other{       // 外部其他类
 *      }
 * 4、内部类的分类:
 *    1) 定义在外部类的局部位置上(比如方法内):
 *      a. 局部内部类(有类名)
 *      b. 匿名内部类(没有类名,是重点)
 *    2) 定义在外部类的成员位置上:
 *      a. 成员内部类(没有static修饰)
 *      b. 静态内部类(使用static修饰)
 */
public class MyInterClass {
    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("代码块...");
    }
    class Inner{    //内部类

    }
}

2、局部内部类

package level2.interClass;

/**
 *  1、局部内部类:是定义在外部类的局部位置,比如方法中(通常),且有类名
 *      1) 可以直接访问外部类所有成员,包含私有的
 *      2) 不能添加访问修饰符,因为它的地位就是一个局部变量,局部变量是不能使用修饰符的。
 *         但是可以使用final修饰,因为局部变量也能使用final
 *      3) 作用域:仅仅在定义它的方法或代码块中 (本质仍然是个类)
 *      4) 局部内部类--访问-->外部类的成员-->[直接访问]
 *      5) 外部类--访问-->局部内部类的成员-->[创建对象再访问,必须在作用域内]
 *      6) 外部其他类--不能访问-->局部内部类
 *      7) 如果外部类和局部内部类重名,默认遵循就近原则,如果想访问外部类的成员,则可以使用
 *          (外部类名.this.成员)去访问
 *
 */
public class LocalInnerClass {
    public static void main(String[] args) {
        MyOuter myOuter = new MyOuter();
        myOuter.m1();
    }

}


class MyOuter{
    private int n1=210;
    public void m2(){
        System.out.println("MyOuter m2()...");
    }
    public void m1(){
        // 不能添加访问修饰符,但是可以使用final修饰
        // 作用域仅仅在m1方法体内
        final class MyInner{ // 本质仍是一个类
            private int n1 = 900;   // 内部类中含有同名的n1
            public void f1(){

                // 可以直接访问外部类的成员,包括私有属性
                // 若内部类中含有同名成员,一般遵循就近原则,若指定访问外部类成员,需要 外部类名.this.成员:
                // MyOuter.this 本质是外部类的对象,谁调用f1(),MyOuter.this就是谁
                System.out.println("MyOuter n1=" + MyOuter.this.n1);
                // 如无显式指定,则遵循就近原则
                System.out.println("MyInner n1="+n1);

                m2();
            }
        }
        // 外部类访问内部类的成员,需要创建对象再访问
        MyInner myInner = new MyInner();
        myInner.f1();


        // 若MyInner是public,则可以继承
        // class MyInner01 extends MyInner{}
    }

    {
        // 也可以在代码块中
        class MyInner02{}
    }
}

3、匿名内部类

package level2.interClass;

/**
 *  1、介绍:匿名内部类(重要)是定义在外部类的局部位置(方法/代码块),且没有类名
 *         (1)本质还是一个类 (2)内部类 (3)该类没有名字 (4)同时还是一个对象
 *  2、基本语法:
 *      class 类或接口(参数列表){
 *          类体
 *      };
 *  3、说明:
 *      1) 可以使用对象调用,也可以直接调用
 *      3) 作用域:仅仅在定义它的方法或代码块中 (本质仍然是个类)
 *      4) 匿名内部类--访问-->外部类的成员-->[直接访问]
 *      5) 外部类--访问-->匿名内部类的成员-->[创建对象再访问,必须在作用域内]
 *      6) 外部其他类--不能访问-->匿名内部类
 *      7) 如果外部类和匿名内部类重名,默认遵循就近原则,如果想访问外部类的成员,则可以使用
 *          (外部类名.this.成员)去访问
 */
public class AnoymousInnerClass {
    public static void main(String[] args) {

    }
}


class Outer01{  //外部类
    private int n1 = 10;

    public void  method() {
        // 基于接口的匿名内部类
        // 想使用IA接口中的方法,但是不想定义类和实例化对象
        // 1)tiger的编译类型是 IA,运行类型是 匿名内部类
        // 2)匿名内部类,代码在底层运行时,实际上会创建一个类去实现接口,且会分配一个类名: Outer01$1 (外部类+$i)
        // 3)jdk底层在创建了匿名内部类Outer01$1,立即就创建了对象实例,并且返回地址
        // 4)匿名内部类使用一次,就不能再使用,但是实例化出来的对象仍可以继续使用
        // 5)匿名内部类是Outer01$1,tiger是对象
        /* 6) 等价于
            class Outer01$1 implement tiger {}
         */
        IA tiger = new IA() {
            public void cry() {
                System.out.println("老虎叫...");
            }
        };
        System.out.println("tiger的运行类型 = " + tiger.getClass());
        tiger.cry(); // 调用


        // 基于类的匿名内部类
        // 1) tiger的编译类型是 Father,运行类型是 Outer01$2
        /* 2) 等价于:
            class Outer01$2 extends Father {}
         */
        // 3) 同时返回一个对象
        // 注意:参数列表也会传递给构造器
        Father father = new Father("tom") {
            @Override
            public void test() {
                System.out.println("匿名内部类重写了test方法");
            }
        };
        System.out.println("father的运行类型 = " + father.getClass());
        father.test();

        // 注意: 以下形式 不带{} 是实例化对象
        Father fa = new Father("tom");
    }
}



class Outer02{
    private int n1=100;
    public void f1(){

        // 第一种调用方式:对象调用
        Person p = new Person(){
            @Override
            public void hi() {
                System.out.println(" Outer02 中的 第1个hi");
            }
        };
        p.hi();

        // 第二种调用方式: 直接调用(可传参)
        new Person(){
            @Override
            public void hi() {
                System.out.println(" Outer02 中的 第2个hi");
            }
        }.hi();
    }
}

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

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

class Father {
    public Father(String name) { // 构造器

    }

    public void test() {

    }
}

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

3.1、匿名内部类练习01

package level2.interClass;

/**
 *  使用场景
 *      1、将匿名内部类 作为实参传递
 *      
 */
public class InnerClassExercise {
    public static void main(String[] args) {

        // 将匿名内部类 作为参数传递
        f1(new AA() {
            @Override
            public void show() {
                System.out.println("f1() 中的show");
            }
        });


    }

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

interface AA{
    void show();
}

3.2、匿名内部类练习02

package level2.interClass;

public class InnerClassExercise01 {
    public static void main(String[] args) {
        //
        new CellPhone().alarmclock(new Bell() {
            @Override
            public void ring() {
                System.out.println("懒猪起床了...");
            }
        });

        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.ring();
    }
}

4、成员内部类

package level2.interClass;

/** 成员内部类
 *  1、介绍:定义在外部类的成员位置,并且没有 static 修饰
 *  2、说明
 *      1) 可以直接访问外部类的所有成员,包括私有的
 *      2) 可以添加任意修饰符(public、protected、默认、private),因为它的地位就是类中的一个成员
 *      3) 作用域: 和外部类的其他成员一样,作用域是整个类体;
 *      4) 成员内部类--访问-->外部类的成员-->[直接访问]
 *      5) 外部类--访问-->成员内部类的成员-->[创建对象再访问,必须在作用域内]
 *      6) 外部其他类--访问-->成员内部类
 *      7) 如果外部类和成员内部类重名,默认遵循就近原则,如果想访问外部类的成员,则可以使用
 *          (外部类名.this.成员)去访问
 */
public class MemberInnerClass {

    public static void main(String[] args) {
        Outer03 outer03 = new Outer03();
        outer03.f1();

        // 外部其他类 使用成员内部类的2种方式
        Outer03.Inner03 inner03 = outer03.new Inner03();    // 注意,这里outer03.new是: 对象实例.new 而非 类名Outer03.new

        // 在外部类中写一个方法,可以返回一个 Inner03 的对象实例
        Outer03.Inner03 inner031 = outer03.getInner();

        //
    }
}

class Outer03{

    private int n1 = 10;
    public String name = "张三";

    // 成员内部类 是定义在外部类成员的位置
    public class Inner03{
        private int n2 = 20;
        public void say(){
            // 可以直接访问外部类的所有成员,包括私有的
            System.out.println("n1=" + n1);
        }
    }

    // 方法返回 Inner03 的实例
    public Inner03 getInner(){
        return new Inner03();
    }

    public void f1(){
        // 使用成员内部类中的属性--> 先实例化对象,再调用方法
        Inner03 inner03 = new Inner03();
        inner03.say();
        System.out.println(inner03.n2); // 可以直接调用属性
    }
}

5、静态内部类

package level2.interClass;

/** 静态内部类
 *  1、介绍:静态内部类定义在外部类中成员位置,且有static修饰
 *  2、说明:
 *      1) 可以直接访问外部类的所有静态成员,包含私有的,但不能直接访问非静态成员
 *      2) 可以添加任意修饰符(public、protected、默认、private),因为它的地位就是类中的一个成员
 *      3) 作用域: 和外部类的其他成员一样,作用域是整个类体;
 *      4) 静态内部类--访问-->外部类的成员-->[直接访问 所有的静态成员]
 *      5) 外部类--访问-->静态内部类-->[创建对象再访问,必须在作用域内]
 *      6) 外部其他类--访问-->静态内部类
 *      7) 如果外部类和成员内部类重名,默认遵循就近原则,如果想访问外部类的成员,则可以使用
 *          (外部类名.成员)去访问
 */
public class StaticInnerClass {
    public static void main(String[] args) {
        Outer05 outer05 = new Outer05();
        outer05.m1();

        // 外部其他类 使用静态内部类
        // 1. 静态内部类,可以通过类名直接访问
        Outer05.Inner05 inner05 = new Outer05.Inner05();
        inner05.say1();

        // 在外部类中写一个方法,可以返回一个 Inner03 的对象实例
        Outer05.Inner05 inner051 = outer05.getInner();
        inner051.say1();

        // 在外部类中写一个静态方法,可以返回一个 Inner03 的对象实例
        Outer05.Inner05 inner052 = Outer05.getInner01();
        inner052.say1();
    }
}

class Outer05{
    private int n1=10;
    public static String name = "张三";

    // 放在外部类的成员位置,有 static 修饰
    public static class Inner05{

        public void say1(){
            System.out.println("name = " + name);   // 不能直接访问n1

        }
        private void say(){
            System.out.println("name = " + name);   // 不能直接访问n1
        }
    }

    public static Inner05 getInner01(){
        return new Inner05();
    }

    public Inner05 getInner(){
        return new Inner05();
    }

    public void m1(){
        Inner05 inner05 = new Inner05();
        inner05.say();
    }


}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值