内部类介绍及使用细节

内部类

内部类分为局部内部类,匿名内部类,成员内部类,静态成员内部类

局部内部类和匿名内部类,是在外部类的方法或代码块中

成员内部类和静态成员内部类,顾名思义,就是在外部类的成员位置上,可以理解为一个属性或方法

局部内部类三个重点:

  1. 局部内部类的本质还是一个类
  2. 局部内部类的作用域(局部类使用在方法体或代码块中)
  3. 局部内部类相当于一个局部变量

局部内部类的使用细节及代码

     局部内部类的作用域是在方法体内或代码块,出了其作用范围就不能使用

  1. 局部内部类不能使用public 等 修饰符修饰,但可以用 final 进行修饰
  2. 局部内部类可以调用外部类的任何成员
  3. 当内部类和外部类重名时,则遵循就近原则使用,如想调用外部类成员,则可以           类名.this.成员名
  4. 其他外部类不能创建局部内部类的实例对象
  5. 外部类访问局部内部类时,则可以通过创建实例对象来访问

public class LocalInnerClass {
    public static void main(String[] args) {
        Outer02 outer02 = new Outer02();
        outer02.m2();
        System.out.println(outer02);
    }
}
class Outer02 {
    {
        System.out.println("Outer02 代码块");
    }

    private int n1 = 10;

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

    public void m2() {
        //1.局部内部类,不能使用修饰符进行修饰,但可以使用final
        //2.局部内部类,可以使用外部类的私有成员
        //4.当内部类的成员 和 外部类成员 名称一致时,遵循就近原则访问
        //  当想访问外部类成员时,调用方法 外部类名.this.成员名
        //
        // 5.外部其他类不能访问局部内部类

        class Inner02 {
            String name = "局部内部类属性";

            int n1 = 99;


            public void hi() {
                //4.当内部类的成员 和 外部类成员 名称一致时,遵循就近原则访问
                //  当想访问外部类成员时,调用方法 外部类名.this.成员名

                //使用细节:如果取消了类名 this.n1
                // 则相当于 this 这里调用的局部类的全局变量,
                // 相当于谁创建了该内部类类对象,调用了该方法。则是谁,
                // 这里则是 inner02 对象,我们可以使用 hashCode值来查看
                System.out.println(n1 + "外部类 n1= " + Outer02.this.n1);
                m1();

                //这里的哈希值 和 主方法中创建了 外部类 outer02对象的哈希值是一致的
                //代表着 那个对象 调用 hi()方法,Outer02.this.n1 则就是那个对象
                System.out.println("Outer02.this  hashCode = " + Outer02.this);

                //这里此刻的哈希值 和 inner02的哈希值是一致的
                //System.out.println("hashCode = " + this);
            }
        }
        //3.外部类访问内部类时,可以通过创建内部类实例对象来访问
        Inner02 inner02 = new Inner02();
        inner02.hi();
        System.out.println(inner02);
    }

    public void m3() {
        //5.其他类不能访问局部内部类
        //Inner02 inner02 = new Inner02();
    }
}

 

匿名内部类

相当于整个类被创建后,就会在堆中开辟一个对象空间,接着这个类 和对象空间,就会被JVM 隐藏在最底层。

该类的对象只能只能被创建一次,但其创建后的对象,可以赋值给其他变量

匿名内部类的语法 new 类名() {

};

匿名内部类的使用细节

public class AnonymousInnerClass {
    public static void main(String[] args) {
        Outer04 outer04 = new Outer04();
        outer04.method();
    }
}
class Outer04 {
    private int n1 = 10;

    public void method(){
        /* 基于接口的匿名内部接口
   需求:1.想使用IA接口,并创建对象
        2.传统方法,写一个类。创建对象,并调用
        3.需求是Tiger/Gou类,只调用一次,后面不再使用
        这种方式向上转型,编译类型是IA,运行类型是Tiger。当代码编译时,
        调用的是IA中的cry方法
        但因运行时,运行类型是Tiger,所以最终运行的是Tiger中的cry方法
        IA tiger = new Tiger();
        tiger.cry();

        4.可以使用匿名内部类来简化开发
        5.tiger的编译类型 ? IA
        6.tiger的运行类型 ? 就是匿名内部类 Outer04$1  其实就是  外部类名 + $1

        我们看底层 会分配 类名 Outer04$1  其实就是  外部类名 + $1
        class XXXXX implements IA {
            @Override
            public void cry() {
                System.out.println("老虎 吼吼吼...");
            }
        };
        7.jdk底层在创建匿名内部类 Outer04$1, 并且立即马上创建 Outer04$1 的实例对象,
        并把其地址赋值给 tiger
        8.匿名内部类使用一次,就不能在使用。但其对象还可以继续使用
        可以理解为匿名内部类new 该一个实例对象后,就被锁定了,不能在创建其他实例对象
        但其对象还可以继续使用。可以理解不能在创建其他实例对象来调用该类中的方法

         */

        /*
        new IA() {
            @Override
            public void cry() {
                System.out.println("老虎 吼吼吼...");
            }
        };

        1.new IA() {}; = new XXXX implements IA  xxxx= 外部类名&数字 -> Outer04&1

        2.  class Outer04&1  implements IA{
                @Override
                public void cry() {
                    System.out.println("老虎 吼吼吼...");
                }
        3.现在底层创建了一个匿名内部类 实现了 IA接口,接着创建了该匿名内类的实例对象,
          之后JVM将其类和堆中对象空间删除
          所以是只会创建其一个开辟其一个对象空间

         */
        IA tiger = new IA() {
            @Override
            public void cry() {
                System.out.println("老虎 吼吼吼...");
            }

            public void eat() {
                System.out.println(n1);
            }
        };
        tiger.cry();
        System.out.println(tiger.getClass());
        tiger.cry();
        tiger.cry();
        tiger.cry();

        //匿名内部类
        //匿名内部类和普通的创建对象的区别就在于是否有大括号冒号
        //father的编译类型: Father
        //father的运行类型: 外部类名 + $2(根据顺序来的,因为上面有一个1)。 Outer04$2
        //现在其本质就是clss Outer04$2 extends Father;
        //("jack"):可以理解为构造列表。自动传送给Father构造器(父类构造器)
        // 是因为父类Father中有一个name的构造器,而这相当于
        //子类构造器中一般要重写父类的构造器一样
        //
        Father father = new Father("jack") {
            @Override
            public void test() {
                System.out.println("匿名内部类重写了test方法");
            }
        };
        System.out.println("father对象的运行类型=" + father.getClass());
        father.test();



    }
}
interface IA {
    public void cry();
}


class Father    {
    public Father(String name) {
        System.out.println("接收到 name= " + name);
    }
    public void test() {

    }
}

class Cat2 extends Father {

    public Cat2(String name) {
        super(name);
    }
}

 

 

/**
 * 匿名内部类的使用细节
 *
 * 3.匿名内部类 不能在 外部其他类创建
 * 4.匿名内部类 相当于 局部变量, 所以其使用/生效的范围 就是在该方法体内 或 代码块内
 * 5.外部类 不能调用其 内部类所有成员, 除了是在其作用域内
 * 6.当外部类 和 内部类 成员重名时,则调用遵从的是就近原则,
 * 如想要调用其外部类成员时 外部类名.this.成员名
 *
 * 7.当其父类 和 外部类 都有其成员重名时,则会优先调用其父类
 * 如父类的因修饰符调用不了 则会调用外部类的。如 父类的n1 是 私有的时,
   则会调用其外部类
 * 这点和继承有所区别,继承则是父类的因其访问权限,则会直接报错,不
   会向上一层的父类查找
 *
 * 但方法重名时,则其父类方法是其私有的,则会直接报错,而不会再调其外部类
 *
 *
 *
 */
public class AnonymousInnerClassDetail {
    public static void main(String[] args) {

        Outer05 outer05 = new Outer05();
        outer05.f1();


    }

}

class Outer05 {


    private int n1 = 88;

    public void m1() {
        System.out.println("外部类 m1方法");
    }


    public void f1() {
        //匿名内部类的方法调用细节
        Person p = new Person() {
            @Override
            public void hi() {
                //2.匿名内部类 可以调用类的外部成员
                //细节:当其父类 和 外部类 的属性同名时,则是优先调用父类的,
                // 如父类的因修饰符调用不了 则会调用外部类的
                //这点和继承有所区别,继承则是父类的因其访问权限,则会直接报错,不会向上一层的父类查找
                System.out.println("匿名内部类重写了 hi方法  n1= " + n1);

            }
        };
        p.hi();


        //第二种调用方法 因其匿名内部类 本质是类
        // 也是可以一个对象,所以可以直接调用
//        new Person() {
//            @Override
//            public void hi() {
//                System.out.println("hi 哈哈哈哈");
//            }
//        }.hi();

        //方法中也可以和普通方法一样,传入参数
        new Person() {

        }.ok("jack");
    }
}

class Person {
    //刚开始这里有一个n1 我要调用,但调用失败,
    // 这是因为我用的是 私有修饰符 修饰所以调用不了 如果不修饰,也可以调用
    //但此时的调用 就是属于继承中的调用
    private int n1 = 99;

    public void hi() {
        System.out.println("Person 中的 hi方法");
    }

    public void ok(String str) {
        System.out.println(str);
    }

    private void m1() {
        System.out.println("Person类 m1方法");
    }
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值