• java学习面向对象之匿名内部类


    之前我们提到“匿名”这个字眼的时候,是在学习new对象的时候,创建匿名对象的时候用到的,之所以说是匿名,是因为直接创建对象,而没有把这个对象赋值给某个值,才称之为匿名。

    匿名对象回顾:

    class NoObject
    {
    
    	void method()
    	{
    
    		System.out.println("Hello NoNameObj");
    
    	}
    
    
    }
    
    class NoName
    {
    
    	public static void main(String[] args) {
    		
    		new NoObject().method();//这里创建完对象之后,并没有把对象直接赋值给某个值,而是创建完对象之后,直接调用对象,之后这个对象就不能被其他对象调用了
                           //因为要调用一个对象必须知道他的名字吧,没有名字怎么调用,这个就是匿名的概念。完事之后就成垃圾了不能再调用了。 } }

    因为在使用匿名对象的时候,那个对象只需要调用一次就好了,为了简写我门采用了匿名的写法。那么这里的匿名内部类也不例外,这里的匿名内部类也是内部类的一个简写,因为只需要调用一次就好了。那我们来看下日常内部类都是怎么调用的。

     1 class Outer
     2 {
     3 
     4     int num = 10;
     5 
     6     class Inner
     7     {
     8 
     9         void method()
    10         {
    11 
    12             System.out.println("The Outer Num is "+num);
    13 
    14         }
    15 
    16     }
    17 
    18     void sayInner()
    19     {
    20 
    21         new Inner().method();
    22 
    23     }
    24 
    25 }
    26 
    27 
    28 class InnerClassDemo2
    29 {
    30 
    31     public static void main(String[] args) {
    32         
    33         new Outer().sayInner();
    34 
    35     }
    36 
    37 }

    我们正常调用内部类是这个样子调用的,如果是匿名内部类又是怎样的呢,我们按照匿名对象的思维来思考一下:

    匿名对象没有把创建的值赋给指定类型的引用变量,还有就是这个对象用一次之后就不能用第二次了。相应的:

    匿名类,第一个就是没有类名,第二个就是这个类用完一次之后,不能被实例化第二次,也就是匿名应用的时候采用,但是这个类不是真实存在的。

    但是这里就存在一个问题了,一个类没有名字我们如何去实例化这个类?所以说要使用匿名内部类是有条件的:

    使用匿名对象的条件:

    内部类必须继承或者实现一个外部类接口,满足这个条件我们才能使用内部类。代码示例:

     1 abstract class AbsDemo
     2 {
     3 
     4     abstract void demo();
     5 
     6 }
     7 
     8 class Outer
     9 {
    10 
    11     int num = 10;
    12 
    13 
    14     void sayInner()
    15     {
    16         /**
    17         *这个地方我们直接new了一个父类或者接口类,但是这里有一点需要注意,那就是在new完了父类或者实现的接口之后,
    18         *后面要加上大括号,加上大括号的意义是在于表示,这是一个类,并且是new关键字后面的类或者接口的子类或者实现
    19         *之后我们在大括号后直接覆盖或者实现了类或者接口的方法
    20         */
    21         new AbsDemo()
    22         {
    23 
    24             void demo()
    25             {
    26 
    27                 System.out.println("This is a NoNameInnerClass Demo");
    28 
    29             }
    30 
    31         }.demo();//这个地方是非常容易出错的,往往我们new abs(){}之后就忘了调用,因为我们只是单纯的new abs(){}这个样子是没有
    32                  //任何意义的,为什么因为这个是个匿名的类,也就是说没有类名,你匿名定义之后完了,就不能再引用了。只能立即调用
    33                  //这个方法后才会变的有意义。还有一点就是这个匿名类定义调用完之后,不要忘了后面的分号结束语句,因为new之后就是
    34                  //一个语句了,而不是class声明了。
    35 
    36     }
    37 
    38 }
    39 
    40 
    41 class InnerClassDemo2
    42 {
    43 
    44     public static void main(String[] args) {
    45         
    46         new Outer().sayInner();
    47 
    48     }
    49 
    50 }

    匿名内部类通俗来说就是:就是一个匿名子类对象。定义的方法是:new 父类or接口(){子类内容}

    匿名内部类的应用:

    场景一:当函数参数是接口类型时,且接口方法不超过3个,此时我们可以采用匿名内部类来当参数传递。比如:

     1 interface InterfaceDemo
     2 {
     3 
     4     public void show1();
     5     public void show2();
     6 
     7 }
     8 
     9 class InnerClassDemo2
    10 {
    11 
    12     public static void main(String[] args) {
    13         
    14         method(new InterfaceDemo(){
    15 
    16             public void show1()
    17             {
    18 
    19                 System.out.println("Show 1");
    20 
    21             }
    22 
    23             public void show2()
    24             {
    25 
    26                 System.out.println("Show 2");
    27 
    28             }
    29 
    30         });
    31 
    32     }
    33 
    34     static void method(InterfaceDemo demo)
    35     {
    36 
    37         demo.show1();
    38         demo.show2();
    39     }
    40 
    41 }

    这里method()方法需要一个接口类型的对象传入,为了简便期间,我们直接用了匿名内部类对象进行了传递,这样是不是很方便呢?但是这里还有一个地方需要注意,就是假如有现在这样的情况:

     1 class InnerClassDemo2
     2 {
     3 
     4     class Inner
     5     {
     6 
     7 
     8     }
     9 
    10     public static void main(String[] args) {
    11         
    12         new Inner();
    13 
    14     }
    15 
    16 
    17 }

    如果我们此时这么运行的话就会报下面的错误:

    InnerClassDemo2.java:21: 错误: 无法从静态上下文中引用非静态 变量 this
    new Inner();
    ^
    1 个错误

    为什么呢?因为我们知道main函数是静态的,他无法调用静态上下文当中的非静态成员,此时class Inner{}在这个类当中就相当于一个成员,但是是非静态的自然而然会报错的。

    在这里还有一个多态的问题需要我们注意:比如

     1 interface InterfaceDemo
     2 {
     3 
     4     public void show1();
     5     public void show2();
     6 
     7 }
     8 
     9 class DuoTaiFalse
    10 {
    11 
    12     void method()
    13     {
    14 
    15         /**
    16         *这个地方发生了向上转型。即多态
    17         */
    18         InterfaceDemo inface = new InterfaceDemo(){
    19 
    20             public void show1()
    21             {
    22 
    23                 System.out.println("Show1");
    24 
    25             }
    26             public void show2()
    27             {
    28 
    29                 System.out.println("Show2");
    30 
    31             }
    32 
    33             public void show3()
    34             {
    35 
    36                 System.out.println("Show3");
    37 
    38             }
    39 
    40         };
    41 
    42         inface.show1();
    43         inface.show2();
    44         /**这个地方就是错误的,因为InterfaceDemo inface = new InterfaceDemo(){}当进行到这个地方的时候,就已经发生了
    45         *向上转型,也就是说这个时候,不能够调用除父类当中已经有的其他的方法。所以调用inface.show3()会提示错误
    46         */
    47         //inface.show3();
    48 
    49     }
    50 
    51 
    52 }
    53 
    54 class InnerClassDemo2
    55 {
    56 
    57     public static void main(String[] args) {
    58         
    59         new DuoTaiFalse().method();
    60 
    61     }
    62 
    63 }

    待续.....

  • 相关阅读:
    Android应用视觉效果设计技巧
    Android实现图片缩放与旋转
    schema 对象的简单介绍
    Index Scans 索引扫描
    Oracle Database Transaction Isolation Levels 事务隔离级别
    第一篇博客,纪念一下,终于开通啦!
    Linux 开机引导流程
    springBoot中tomcat默认端口修改
    面向服务架构之RPC原理与实例
    vs2008中xlslib与libxls库的编译及使用
  • 原文地址:https://www.cnblogs.com/sunchuanzhen/p/3357982.html
Copyright © 2020-2023  润新知