鱼C论坛

 找回密码
 立即注册
查看: 2326|回复: 0

[学习笔记] Java-010内部类

[复制链接]
发表于 2018-12-22 14:04:39 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能^_^

您需要 登录 才可以下载或查看,没有账号?立即注册

x
1、基本概念
内部类(Inner Class): 也称为嵌套类(Nested Class),在一个类(或方法、语句块)的内部定义的另一个类。
使用内部类的主要原因有:
        ① 内部类可以访问外部类中的数据,包括私有的数据。
        ② 内部类可以对同一个包中的其他类隐藏起来。
        ③ 当想要定义一个回调函数且不想编写大量代码时,使用匿名(anonymous)内部类比较便捷。
        ④ 减少类的命名冲突。
内部类的访问规则:
        A:可以直接访问外部类的成员,包括私有
        B:外部类要想访问内部类成员,必须创建对象
内部类的分类:
        A:成员内部类
        B:局部内部类
public class Outer {
    private int size;
    public class Inner {
        private int counter = 10;
        public void doStuff() {
            size++;
        }
    }
    public static void main(String args[]) {
        Outer outer = new Outer();
        Inner inner = outer.new Inner();
        inner.doStuff();
        System.out.println(outer.size);
        System.out.println(inner.counter);
        // 编译错误,外部类不能访问内部类的变量
        System.out.println(counter);
    }
}
这段代码定义了一个外部类 Outer,它包含了一个内部类 Inner。将错误语句注释掉,编译,会生成两个 .class 文件:Outer.class 和 Outer$Inner.class。也就是说,内部类会被编译成独立的字节码文件。
        内部类是一种编译器现象,与虚拟机无关。编译器将会把内部类翻译成用 $ 符号分隔外部类名与内部类名的常规类文件,而虚拟机则对此一无所知。
注意:
        必须先有外部类的对象才能生成内部类的对象,因为内部类需要访问外部类中的成员变量,成员变量必须实例化才有意义。
内部类可以是静态(static)的,可以使用 public、protected 和 private 访问控制符,而外部类只能使用 public,或者默认。
2、成员内部类
        在外部类内部直接定义(不在方法内部或代码块内部)的类就是成员式内部类,它可以直接使用外部类的所有变量和方法,即使是 private 的。外部类要想访问内部类的成员变量和方法,则需要通过内部类的对象来获取
public class Outer{
    private int size;
    public class Inner {
        public void dostuff() {
            size++;
        }
    }
    public void testTheInner() {
        Inner in = new Inner();
        in.dostuff();
    }
}
① 成员式内部类如同外部类的一个普通成员。
② 成员式内部类可以使用各种修饰符,包括 public、protected、private、static、final 和 abstract,也可以不写。
③ 若有 static 修饰符,就为类级,否则为对象级。类级可以通过外部类直接访问,对象级需要先生成外部的对象后才能访问。
④ 非静态内部类中不能声明任何 static 成员。
⑤ 同一个类里的内部类可以相互调用,
成员内部类的访问:
内部类的对象以成员变量的方式记录其所依赖的外层类对象的引用,因而可以找到该外层类对象并访问其成员。该成员变量是系统自动为非 static 的内部类添加的,名称约定为“outClassName.this”。
1) 使用内部类中定义的非静态变量和方法时,要先创建外部类的对象,再由“outObjectName.new”操作符创建内部类的对象,再调用内部类的方法,如下所示:
public class Demo{
    public static void main(String[] args) {
        Outer outer = new Outer();
        Outer.Inner inner = outer.new Inner();
        inner.dostuff();
    }
}
class Outer{
    private int size;
    class Inner{
        public void dostuff() {
            size++;
        }
    }
}
2) static 内部类相当于其外部类的 static 成员,它的对象与外部类对象间不存在依赖关系,因此可直接创建。示例如下:
public class Demo{
    public static void main(String[] args) {
        Outer.Inner inner = new Outer.Inner();
        inner.dostuff();
    }
}
class Outer{
    private static int size;
    static class Inner {
        public void dostuff() {
            size++;
            System.out.println("size=" + size);
        }
    }
}
3) 由于内部类可以直接访问其外部类的成分,因此当内部类与其外部类中存在同名属性或方法时,也将导致命名冲突。所以在多层调用时要指明,如下所示:
public class Outer{
    private int size;
    public class Inner{
        private int size;
        public void dostuff(int size){
            size++;  // 局部变量 size;
            this.size;  // 内部类的 size
            Outer.this.size++;  // 外部类的 size
        }
    }
}
3、局部内部类
局部内部类(Local class): 定义在代码块中的类。它们只在定义它们的代码块中是可见的。
重要特性:
        ① 仅在定义了它们的代码块中是可见的;
        ② 可以使用定义它们的代码块中的任何局部 final 变量;
        ③ 局部类不可以是 static 的,里边也不能定义 static 成员;
        ④ 局部类不可以用 public、private、protected 修饰,只能使用缺省的;
        ⑤ 局部类可以是 abstract 的。
public class Outer {
    public static final int TOTAL_NUMBER = 5;
    public int id = 123;
    public void func() {
        final int age = 15;
        String str = "http://www.weixueyuan.net";
        class Inner {
            public void innerTest() {
                System.out.println(TOTAL_NUMBER);
                System.out.println(id);
                // System.out.println(str);不合法,只能访问本地方法的final变量
                System.out.println(age);
            }
        }
        new Inner().innerTest();
    }
    public static void main(String[] args) {
        Outer outer = new Outer();
        outer.func();
    }
}
4、匿名内部类
匿名内部类: 局部内部类的一种特殊形式,也就是没有变量名指向这个类的实例,而且具体的类实现会写在这个内部类里面。
注意:
        匿名类必须继承一个父类或实现一个接口。
不使用匿名内部类来实现抽象方法:
abstract class Person {
    public abstract void eat();
}
class Child extends Person {
    public void eat() {
        System.out.println("eat something");
    }
}
public class Demo {
    public static void main(String[] args) {
        Person p = new Child();
        p.eat();
    }
}
可以看到,我们用Child继承了Person类,然后实现了Child的一个实例,将其向上转型为Person类的引用。但是,如果此处的Child类只使用一次,那么将其编写为独立的一个类岂不是很麻烦?
这个时候就引入了匿名内部类。使用匿名内部类实现:
abstract class Person {
    public abstract void eat();
}
public class Demo {
    public static void main(String[] args){
       
        // 继承 Person 类
        new Person() {
            public void eat() {
                System.out.println("eat something");
            }
        }.eat();
    }
}
可以看到,匿名类继承了 Person 类并在大括号中实现了抽象类的方法。
内部类的语法比较复杂,实际开发中也较少用到,不是重点。

本帖被以下淘专辑推荐:

想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|手机版|Archiver|鱼C工作室 ( 粤ICP备18085999号-1 | 粤公网安备 44051102000585号)

GMT+8, 2024-11-15 12:47

Powered by Discuz! X3.4

© 2001-2023 Discuz! Team.

快速回复 返回顶部 返回列表