• 技术文章 >Java >java教程

    内部类和匿名内部类的用法

    高洛峰高洛峰2016-12-15 13:15:18原创1984
    一、内部类: 

    (1)内部类的同名方法

    内部类可以调用外层类的方法,如果内部类有同名方法必须使用"OuterClass.this.MethodName()"格式调用(其中OuterClass与MethodName换成实际外部类名及其方法;this为关键字,表示对外部类的引用);若内部类无同名方法可以直接调用外围类的方法。
    但外围类无法直接调用内部类的private方法,外部类同样无法直接调用其它类的private方法。注意:内部类直接使用外部类的方法与该方法的权限与是否static无关,它取决于内部类是否有同名方法。

    package innerclass;
    public class OuterClass {
        private void outerMethod() {
            System.out.println("It's Method of OuterClass");
        }
        public static void main(String[] args) {
            OuterClass t = new OuterClass();
            OuterClass.Innerclass in = t.new Innerclass();
            in.innerMethod();
        }
     
        class Innerclass {
            public void innerMethod() {
               OuterClass.this.outerMethod();// 内部类成员方法与外部类成员方法同名时,使用this调用外部类的方法
               outerMethod();// 内部类没有同名方法时执行外部类的方法
            }
            private void outerMethod() {
                System.out.println("It's Method of Innerclass");
            }
        }
    }

    输出结果为:

    It's Method of OuterClass
    It's Method of Innerclass

    (2)内部类的实例化

    内部类实例化不同于普通类,普通类可以在任意需要的时候实例化,而内部类必须在外层类实例化以后方可实例化,并与外部类建立关系

    因此在外部类中的非static方法中,是可以实例化内部类对象

    private void outerMethod() {
        System.out.println("It's Method of OuterClass");
        Innerclass in = new Innerclass();//在外部类的outerMethod方法中实例化内部类是可以啊
    }

    但在static方法中,就要注意啦!!!!不能在static方法中直接new内部类,否则出现错误:

    No enclosing instance of type OuterClass is accessible. Must qualify the allocation with an enclosing instance of type OuterClass (e.g. x.new A() where x is an instance of OuterClass).

    这是因为静态方法是在类实例化之前就可以使用的,通过类名调用,这时动态内部类都还没实例化呢,怎么用,总不能调用一个不存在的东西吧。

    如果想在Static方法中new内部类,可以把内部类声明为Static

    public class OuterClass {
        private void outerMethod() {
            System.out.println("It's Method of OuterClass");
        }
     
        public static void main(String[] args) {
            Innerclass in = new Innerclass();
            in.innerMethod();
        }
     
        static class Innerclass {//把内部类声明为static
            public void innerMethod() {
                System.out.println("It's Method of innerMethod");
     
            }
        }
     
    }

    当然,一般不使用static的方式,而是推荐这种方法:x.new A() ,其中 x是外部类OuterClass的实例,A是内部类Innerclass

    package innerclass;
    public class OuterClass {
        private void outerMethod() {
            System.out.println("It's Method of OuterClass");
        }
        public static void main(String[] args) {
            OuterClass.Innerclass in = new OuterClass().new Innerclass();//使用x.new A()的方式
            in.innerMethod();
        }
        class Innerclass {
            public void innerMethod() {
                System.out.println("It's Method of innerMethod");
            }
        }
    }

    x.new A() ,其中 x是外部类OuterClass的实例,A是类部类Innerclass,当然可以拆分如下,这样就显然很明白啦:

    public static void main(String[] args) {
        OuterClass out = new OuterClass();//外部实例
        OuterClass.Innerclass in = out.new Innerclass();//外部实例.new 外部类
        in.innerMethod();
    }

    (3)什么情况下使用内部类
    典型的情况是,内部类继承自某个类或实现某个接口,内部类的代码操作创建其的外层类的对象。所以你可以认为内部类提供了某种进
    入其外层类的窗口。
    使用内部类最吸引人的原因是:每个内部类都能独立地继承自一个(接口的)实现,所以无论外层类是否已经继承了某个(接口的)实
    现,对于内部类都没有影响。如果没有内部类提供的可以继承多个具体的或抽象的类的能力,一些设计与编程问题就很难解决。从这个角
    度看,内部类使得多重继承的解决方案变得完整。接口解决了部分问题,而内部类有效地实现了“多重继承”。

    (4)在静态方法中实例化内部类例子:(内部类放在静态方法中)

    package javatest2;
    public class JavaTest2 {
        public static void main(String[] args) {
            class Boy implements Person {
                public void say() {// 匿名内部类自定义的方法say
                    System.out.println("say方法调用");
                }
                @Override
                public void speak() {// 实现接口的的方法speak
                    System.out.println("speak方法调用");
                }
            }
            Person per = new Boy();
            per.speak();// 可调用
            per.say();// 不能调用
        }
    }
    interface Person {
        public void speak();
    }

    per.speak()可调用,而per.say()不能调用,这时因为per是Person对象,要想调用子类的方法,可以强制向下转型为:((Boy) per).say();或者直接改为Boy per = new Boy();。从中可发现,要想调用内部类的自定义的方法,必须通过内部类的对象来调用。那么,匿名内部类连名字都没有,怎么调用内部类自定义的方法?

    (二)匿名内部类

    匿名内部类也就是没有名字的内部类正因为没有名字,所以匿名内部类只能使用一次,它通常用来简化代码编写,但使用匿名内部类还有个前提条件:必须继承一个父类或实现一个接口,但最多只能继承一个父类,或实现一个接口。
    关于匿名内部类还有如下两条规则:
    1)匿名内部类不能是抽象类,因为系统在创建匿名内部类的时候,会立即创建内部类的对象。因此不允许将匿名内部类定义成抽象类。
    2)匿名内部类不等定义构造器(构造方法),因为匿名内部类没有类名,所以无法定义构造器,但匿名内部类可以定义实例初始化块,

    怎样判断一个匿名类的存在啊?看不见名字,感觉只是父类new出一个对象而已,没有匿名类的名字。
    先看段伪代码

    abstract class Father(){
    ....
    }
    public class Test{
       Father f1 = new Father(){ .... }  //这里就是有个匿名内部类
    }

    一般来说,new 一个对象时小括号后应该是分号,也就是new出对象该语句就结束了。但是出现匿名内部类就不一样,小括号后跟的是大括号,大括号中是该new 出对象的具体的实现方法。因为我们知道,一个抽象类是不能直接new 的,必须先有实现类了我们才能new出它的实现类。上面的伪代码就是表示new 的是Father的实现类,这个实现类是个匿名内部类。
    其实拆分上面的匿名内部类可为:

    class SonOne extends Father{
      ...       //这里的代码和上面匿名内部类,大括号中的代码是一样的
    }
    public class Test{
       Father f1 = new SonOne() ;
    }

    先看一个例子,体会一下匿名内部类的用法:

    1.png

    php入门到就业线上直播课:进入学习

    运行结果:eat something
    可以看到,我们直接将抽象类Person中的方法在大括号中实现了,这样便可以省略一个类的书写。并且,匿名内部类还能用于接口上

    public class JavaTest2 {
        public static void main(String[] args) {
            Person per = new Person() {
                public void say() {// 匿名内部类自定义的方法say
                    System.out.println("say方法调用");
                }
                @Override
                public void speak() {// 实现接口的的方法speak
                    System.out.println("speak方法调用");
                }
            };
            per.speak();// 可调用
            per.say();// 出错,不能调用
        }
    }
     
    interface Person {
        public void speak();
    }

    这里per.speak()是可以正常调用的,但per.say()不能调用,为什么呢?注意Person per = new Person()创建的是Person的对象,而非匿名内部类的对象。其实匿名内部类连名字都没有,你咋实例对象去调用它的方法呢?但继承父类的方法和实现的方法是可以正常调用的,本例子中,匿名内部类实现了接口Person的speak方法,因此可以借助Person的对象去调用。

    若你确实想调用匿名内部类的自定义的方法say(),当然也有方法:

    (1)类似于speak方法的使用,先在Person接口中声明say()方法,再在匿名内部类中覆写此方法。

    (2)其实匿名内部类中隐含一个匿名对象,通过该方法可以直接调用say()和speak()方法;代码修改如下:

    public class JavaTest2 {
        public static void main(String[] args) {
            new Person() {
                public void say() {// 匿名内部类自定义的方法say
                    System.out.println("say方法调用");
                }
     
                @Override
                public void speak() {// 实现接口的的方法speak
                    System.out.println("speak方法调用");
                }
            }.say();// 直接调用匿名内部类的方法
        }
    }
    interface Person {
        public void speak();
    }


    更多内部类和匿名内部类的用法相关文章请关注PHP中文网!

    声明:本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn核实处理。

    前端(VUE)零基础到就业课程:点击学习

    清晰的学习路线+老师随时辅导答疑

    自己动手写 PHP MVC 框架:点击学习

    快速了解MVC架构、了解框架底层运行原理

    专题推荐:匿名内部类
    上一篇:Java之线程(匿名内部类) 下一篇:自己动手写 PHP MVC 框架(40节精讲/巨细/新人进阶必看)

    相关文章推荐

    • ❤️‍🔥共22门课程,总价3725元,会员免费学• ❤️‍🔥接口自动化测试不想写代码?• 实例详解Java顺序表和链表• Java数据结构之单链表与OJ题• 详细介绍Java正则表达式之单字符匹配和预定义字符• Java总结分享之反射、枚举、Lambda表达式• 深入分析Java的序列化与反序列化
    1/1

    PHP中文网