内部类

在Java中,可以将一个类定义在另一个类里面或者一个方法里面,这样的类称为内部类。与之对应,包含内部类的类被称为外部类。
优势:内部类提供了更好的封装,可以把内部类隐藏在外部类之内,通过访问修饰符控制其他类对内部类的访问,更好的实现了信息隐藏
分类:成员内部类、静态内部类、方法内部类、匿名内部类

成员内部类

内部类中最常见的就是成员内部类,也称为普通内部类

public class Person {
    int age;
    //获取内部类对象方法
    public Heart getHeart(){
        return new Heart();
    }
    //成员内部类
    class Heart {
        public String beat(){
            return "心脏在跳动";
        }
    }
}
获取成员内部类对象实例

方式一:通过外部类对象创建内部类实例,即new 外部类().new 内部类()或者 外部类对象.new 内部类()
方式二:通过外部类定义的成员方法获取,即外部类对象.获取方法()

public class Test {
    public static void main(String[] args) {    
        Person ricky = new Person();
        //获取成员内部类对象实例,方式1:new 外部类.new 内部类
        Person.Heart heart = new Person().new Heart();
        System.out.println(heart.beat());
        //获取成员内部类对象实例,方式1:外部类对象.new 内部类
        heart = ricky.new Heart();
        //获取成员内部类对象实例,方式2:外部类对象.获取方法
        Person.Heart heart2 = ricky.getHeart();
        System.out.println(heart2.beat());
    }
}
注意事项

1、内部类在外部使用时,无法直接实例化,需要借由外部类信息才能完成实例化
2、内部类的访问修饰符,可以任意,但是访问范围会受到影响
3、内部类可以直接访问外部类的成员;如果出现同名属性或者方法,优先访问内部类中定义的
4、可以使用外部类.this.成员的方式,访问外部类中同名的信息(成员属性和成员方法)
5、外部类访问内部类信息,需要通过内部类实例,无法直接访问
6、内部类编译后.class文件的名称:外部类$内部类.class

public class Person {
    String name = "大大";
    //获取内部类对象方法
    public Heart getHeart(){
        //5.外部类访问内部类信息,需要通过内部类实例,无法直接访问name
        new Heart().name = "明明";
        return new Heart();
    }
    public void eat(){
        System.out.println("人会吃东西");
    }
    //2.访问修饰符可以任意,设置为private则只能在此外部类中创建实例
    private class Heart {
        String name = "小小";
        public String beat(){
            //3.同名属性这里优先访问的是内部类中的name
            String str = name + "的心脏在跳动";
            //4.访问外部类中的同名属性
            str = Person.this.name + "的心脏在跳动";
            //访问外部类中的同名方法,直接调用eat()优先访问的是内部类中定义的
            Person.this.eat();
            return str;
        }
        //同名方法
        public void eat(){
            System.out.println("吃东西");
        }
    }
}

静态内部类

静态内部类,使用static修饰,对象可以不依赖于外部类对象,直接创建
获取静态内部类对象实例:new 外部类名.静态类()

注意事项

1、静态内部类中,只能直接访问外部类的静态成员,如果需要调用非静态成员,可以通过对象实例
2、可以通过外部类.内部类.静态成员的方式,访问内部类中的静态成员
3、当内部类中静态成员与外部类静态成员同名时,默认直接调用内部类中的成员,可以通过 外部类.成员 的方式访问外部类的同名静态成员,而对于外部类中的非静态成员,不管同不同名,都需要通过外部类实例访问

public class Person {
    String name = "大大";
    public static int age = 22;
    //获取内部类对象方法
    public Heart getHeart(){
        return new Heart();
    }
    public void eat(){
        System.out.println("人会吃东西");
    }
    //静态内部类
    public static class Heart {
        String name = "小小";
        public static int age = 12;
        public String beat(){
            //2.静态内部类中,只能直接访问外部类的静态成员,如果需要调用非静态成员,可以通过对象实例
            //直接访问eat()会报错
            new Person().eat();
            //成员方法可以直接访问内部类中的非静态成员和静态成员
            String str = name + age + "岁的心脏在跳动";
            //4.访问外部类中的非静态成员和同名静态成员
            return new Person().name + Person.age + "的心脏在跳动";
        }
    }
    
    //测试
    public static void main(String[] args) {
        //1.获取静态内部类对象实例
        Person.Heart heart = new Person.Heart();
        System.out.println(heart.beat());
        //3可以通过外部类.内部类.静态成员的方式,访问内部类中的静态成员
        Person.Heart.age = 15;
    }
}

方法内部类

定义在外部类方法中的内部类,也称局部内部类(符合方法的相关规则)

注意事项

1、定义在方法内部,作用范围也在方法内
2、和方法内部成员使用规则一样,方法内部类不能使用任何访问修饰符,不能使用static修饰
3、类中不能包含静态成员,但可以包含finalabstract修饰的成员

public class Person {
    String name = "大大";
    public static int age = 22;

    public Object getHeart(){
        //方法内部类:不能使用任何访问修饰符,不能使用static修饰
        class Heart {
            String name = "小小";
            //类成员可以使用访问修饰符、final,但不能使用static修饰
            public final int age = 12;
            
            public String beat(){
                new Person().eat();
                return name + Person.age + "的心脏在跳动";
            }
        }
        return new Heart().beat();
    }
    public void eat(){
        System.out.println("人会吃东西");
    }
    //测试
    public static void main(String[] args) {
        Person ricky = new Person();
        //调用包含方法内部类的方法
        System.out.println(ricky.getHeart());   
    }
}

匿名内部类

顾名思义,就是没有名字,隐藏名字的意思,通常我们使用类都是通过class 类名定义类,然后使用时通过new 构造方法进行实例化,但是在一些场景下,对某个类的实例只会使用一次,那么这个类的名字对于程序而言就可有可无了。此时我们就可以将类的定义与类的创建,放到一起完成,简化程序的编写。
所以匿名内部类也就是没有名字的类,通常情况下我们可以通过匿名内部类来简化对于抽象类和接口实现的操作。

示例:完成一个不同人进行阅读的操作

//定义抽象父类
public abstract class Person {
    //阅读方法
    public abstract void read();
}
//定义子类
public class Man extends Person{
    @Override
    public void read() {
        System.out.println("男生喜欢看科幻类书籍");       
    }
}
public class Women extends Person{
    @Override
    public void read() {
        System.out.println("女生喜欢读言情小说");        
    }
}

使用传统的多态方式实现以及匿名内部类实现

public class Test {
    //需求:根据传入的不同的人的类型,调用对应的read方法
    //方案1:利用多态调用对应子类的实现
    public void getRead(Person person){
        person.read();
    }
    public static void main(String[] args) {
        //方案一
        Test test = new Test();
        Man one=new Man();
        Woman two=new Woman();
        test.getRead(one);
        test.getRead(two);  
        //方案二:不定义任何子类,使用匿名内部类完成具体的read方法实现
        test.getRead(new Person(){
            @Override
            public void read() {
                System.out.println("男生喜欢看科幻类书籍");
            }
        });
        test.getRead(new Person(){
            @Override
            public void read() {
                System.out.println("女生喜欢读言情小说");
            }
        });
    }
}

匿名内部类在合适的场景下对于内存的损耗和对系统的性能影响就会相对较小,弊端就是只能使用一次,无法重复使用。

适用场景
  • 只用到类的一个实例
  • 类在定义后马上用到
  • 给类命名并不会导致代码更容易被理解
典型应用

继承式的匿名内部类

public class Demo {
    public static void main(String[] args) {
        //继承式的匿名内部类(相当于定义了一个匿名的Thread子类,目的是重写其方法)
        Thread thread = new Thread() {
            @Override
            public void run() {
                for (int i = 0; i <= 5; i++) {
                    System.out.println(i + " ");
                }
            }
        };
        thread.start();
    }
}

接口式的匿名内部类

public class Demo {
    public static void main(String[] args) {
        //接口式的匿名内部类(相当于创建了一个实现了接口的匿名类)
        Runnable r = new Runnable() {
            @Override
            public void run() {
                for (int i = 0; i <= 5; i++) {
                    System.out.println(i + " ");
                }
            }
        };
        Thread thread = new Thread(r);
        thread.start();
    }
}

参数式的匿名内部类

public class Demo {
    public static void main(String[] args) {
        //参数式的匿名内部类
        Thread thread = new Thread(new Runnable() {
            @Override
            public void run() {
                for (int i = 0; i <= 5; i++) {
                    System.out.println(i + " ");
                }
            }
        });
        thread.start();
    }
}

结论:由上面三个例子可以看出,匿名内部类可以继承一个具体的父类,也可以实现某个接口。只要一个类是抽象的或是一个接口,那么其子类中的方法都可以使用匿名内部类来实现

注意事项

1、匿名内部类没有类型名称、实例对象名称
2、编译后的文件命名:外部类$数字.class
3、无法使用访问修饰符、也无法使用abstractstatic修饰
4、无法编写构造方法,可以添加构造代码块,通过代码块完成匿名内部类的初始化
5、不能出现静态成员,不能出现抽象方法
6、匿名内部类可以实现接口也可以继承父类,但是不可兼得

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 215,923评论 6 498
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,154评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 161,775评论 0 351
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,960评论 1 290
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,976评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,972评论 1 295
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,893评论 3 416
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,709评论 0 271
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,159评论 1 308
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,400评论 2 331
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,552评论 1 346
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,265评论 5 341
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,876评论 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,528评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,701评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,552评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,451评论 2 352

推荐阅读更多精彩内容

  • Java 内部类 分四种:成员内部类、局部内部类、静态内部类和匿名内部类。 1、成员内部类: 即作为外部类的一个成...
    ikaroskun阅读 1,230评论 0 13
  • 问:Java 常见的内部类有哪几种,简单说说其特征? 答:静态内部类、成员内部类、方法内部类(局部内部类)、匿名内...
    Little丶Jerry阅读 1,915评论 0 1
  • 本文转载自: java:内部类与外部类的区别和联系 注意事项一:在内部类中可以随意使用外部类的成员方法以及成员变...
    caoxinyiyi阅读 313评论 0 1
  • 一、继承 当两个事物之间存在一定的所属关系,即就像孩子从父母那里得到遗传基因一样,当然,java要遗传的更完美,这...
    玉圣阅读 1,050评论 0 2
  • 睡眠少是很多老年人最大的困扰。《黄帝,内经》有言道,人的精气不能进入营阴之中,常常滞留在表阳之中,这样会造成阴气虚...
    灰灰菜的夏天阅读 708评论 5 5