【自学】Java核心技术卷1_6.4内部类

内部类:定义在另一个类中的类。分为成员内部类(定义在成员位置)、局部内部类(定义在外部类方法中)、匿名内部类(没有类名,只用一次)、静态内部类(static修饰)

1、内部类特性

2、语法规则

  • 对外部类的引用:OuterClass.this
  • 在外部类的作用域之外引用内部类:OuterClass.InnerClass
  • 成员位置的内部类(除局部和匿名)被修饰为private时只对本类可见(一般是private);无修饰符(默认)时只对包可见;被修饰为protected时对本包和所有子类可见;被修饰为public时对所有类可见;被修饰为static时为静态内部类,没有this
  • 当内部类声明为private类时,只有外部类的方法能够构造内部类的实例对象。
  • 当内部类为public类时,外部类的方法和实例都可以构造内部类的实例对象。
  • 内部类中声明的所有静态域必须是final,保证静态域的唯一性
  • 内部类是一种编译器现象,与虚拟机无关。编译器会把内部类翻译成用“OuterClass$InnerClass”类名的常规类文件,而虚拟机对此一无所知。编译器为了引用外部类,生成了一个附加的实例域“this$0”

内部类对象的建立

1、在同包其他类 以及main方法中(前提要内部类没有被修饰成private,private内部类只能被外部类的方法访问)

  • 1)先创建外部类对象,再通过外部类对象创建内部类
  • Out outer = new Out();
  • Out.In inner = outer.new In(); //第一个Out是为了说明该内部类到底属于哪个外部类
  • 2)通过匿名外部类创建内部类
  • Out.In inner = new Out().new In();
  • 2、在外部类里

  • 可直接创建对象,如 In inner = new In(); 或者直接new In();

内部类的访问

  • 重名时:对外部类的静态成员通过 外部类名.静态成员变量名 访问;内部类访问自己的非静态成员通过this.变量名。访问外部类的非静态成员通过 外部类名.this.变量名 访问 。
  • 不重名时:无论静态非静态,内部类直接通过变量名访问外部成员变量。

外部类的访问

  • 内部类为非静态时:外部类访问内部类,必须建立内部类对象
  • 内部类为静态时:外部类访问非静态成员通过(外部类对象名.内部类名.方法名)访问外部类访问静态成员直接通过(外部类名.内部类名.方法名
  • PS:当内部类中定义了静态成员时,内部类必须是静态的;当外部静态方法访问内部类时,内部类也必须是静态的才能访问。

3、成员内部类

  • 引用方式为Outter.Inner
  • 最普通的内部类,定义在外部类的成员(域/方法)位置
  • 可以像类成员一样被private、protected、public修饰,从而拥有对应的可见性
  • 可以访问外部类所有成员,不论何种修饰
  • 成员内部类依附外部类而存在,对象的建立依赖于外部类对象(外部类对象直接或通过外部方法调用内部类构造函数)

4、局部内部类

  • 只在某个方法中创建某类对象
  • 局部类不能用private、protected、public、static修饰
  • 访问权限被限定在声明这个局部类的作用域中,即使外部类的方法也不能访问,对外界完全隐藏
  • 局部类不仅可以访问其外部类,还可以访问局部变量(final的局部变量)
  • 编译器会检测局部内部类对局部变量的访问,为每一个要访问的变量建立相应的局部内部类数据域,将局部变量拷贝到局部内部类的构造器中,以便将其数据域初始化为局部变量的副本

5、匿名内部类

 

  • 一般用于继承其他类或实现接口,不需要增加额外方法,只需要创建一个对象并重写或实现继承的方法,因此不必给类命名
  • 匿名内部类必须继承一个外部类或者实现接口,因为匿名内部类没有类名,而构造器又必须和类名相同,所以匿名类不能有构造器,只能将构造器参数传递给超类构造器,如果匿名类实现的是接口,则没有构造参数()不过还是要提供括号
  • 如果构造参数的括号 () 后面跟一个大括号 {},则定义的是匿名内部类
  • 匿名内部类可以访问局部final变量

双括号初始化:

invite(new ArrayList<String>() { {add(“Harry”); add(“Tony”);} } ); //构建并初始化匿名数组列表传递给invite()方法,外层{}:new ArrayList<String>(){};建立ArrayList的匿名子类;内层括号{}是一个对象构造块(即第四章的初始化块,在构造类对象的时候执行)

6、静态内部类

  • 不依赖于外部类,在没有外部类对象的情况下也可以创建静态内部类的对象
  • 不能使用外部类的非static成员(因为非static成员要依赖于具体的对象)
  • 在接口中声明的内部类自动成为static和public类
  • 若内部类的对象是在静态方法中构造的,则必须使用静态内部类
  • 只有内部类可声明为static

静态内部类与非静态内部类的区别

  • 非静态内部类没有static域和方法;只有静态内部类可以有静态域和方法
  • 非静态内部类可以调用外部类的任何成员,不论是否静态;静态内部类不能使用外部类的非static域和非static方法
  • 非静态内部类在编译完成后会隐含的保存指向创建它的外部类的引用,但静态内部类没有这个引用,这意味着非静态内部类必须依赖于外部类的创建而创建,静态内部类的创建不依赖于外部类

编程练习

// InnerClassTest.java

public class InnerClassTest {
    public static void main(String args[]) {
        
        OuterClass outer = new OuterClass("Outer", 0);

        OuterClass.InnerClass inner = outer.new InnerClass(); //外部类作用域之外引用内部类
        inner.display();  
        outer.getPrivateInnerClass();  //private内部类,只能由外部类的方法new实例对象

        System.out.println("LocalInnerClass: compare int " + "1 and 2 = " + outer.func().compare(1, 2));

        String s1 = "Hello";
        String s2 = "Java";
        outer.compare2String(s1, s2);

        OuterClass.StaticInnerClass s_inner = new OuterClass.StaticInnerClass(); //对比创建inner
        s_inner.display();
    }
}
//OuterClass.java

import java.time.LocalDate;
import java.util.Comparator;

public class OuterClass {
    private String str; //final
    private int num;

    OuterClass(String str, int num) {
        this.str = str;
        this.num = num;
    }

    public class InnerClass {
        public void display() {
            System.out.println("InnerClass: visit OuterClass field str is " + str);
        }
    }

    private class PrivateInnerClass {
        public void display() {
            System.out.println("PrivateInnerClass: visit OuterClass field num is " + OuterClass.this.num);
        }
    }
    public void getPrivateInnerClass() {
        PrivateInnerClass p_inner = new PrivateInnerClass();
        p_inner.display();
    }

    public Comparator func() {
        class LocalInnerClass implements Comparator<Integer> {
            public int compare(Integer o1, Integer o2) {
                return o1.compareTo(o2);
            }
        }
        return new LocalInnerClass();
    }

    public void compare2String(String s1, String s2) {
        Comparator<String> cmp = new Comparator<String>() {  //匿名内部类必须是某个已经存在的接口或超类的子类
            @Override
            public int compare(String o1, String o2) {
                return o1.compareTo(o2);
            }
        }; //不要忘了这里的分号
        System.out.println("AnonymousInnerClass: compare String " + s1 + " and " + s2 + " = " + cmp.compare(s1, s2));
    }

    public static class StaticInnerClass {
        public void display() {
            System.out.println("StaticInnerClass: display()");
        }
    }

}

输出:

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值