zoukankan      html  css  js  c++  java
  • java内部类

    1简介

    内部类简单理解就是在外部类里面定义类。内部类是一个编译的概念,在外部类Outer里面定义内部类Inner,编译后会生成outer.Class和Outer$Inner.class两个class文件。

    2分类

    (1)成员内部类

    成员内部类,就是作为外部类的成员,可以直接使用外部类的所有成员和方法,即使是private的。同时外部类要访问内部类的所有成员变量/方法,则需要通过内部类的对象来获取。

    成员内部类不能含有static的变量和方法。因为成员内部类需要先创建了外部类,才能创建它自己的。

        public class Outer { 
            public static void main(String[] args) { 
                Outer outer = new Outer(); 
                Outer.Inner inner = outer.new Inner(); 
                inner.print("通过外部类对象new内部类对象"); 
    // 推荐使用此方法 // inner = outer.getInner(); // inner.print("编写外部类的成员方法获取内部类对象"); } public Inner getInner() { return new Inner(); } public class Inner { public void print(String str) { System.out.println(str); } } }

    在定义内部类的时候,可以在其前面加上一个权限修饰符static。此时这个内部类就变为了静态内部类(通常称为嵌套类)。静态内部类只能访问外部类的静态成员或方法。

    静态内部类与普通内部类区别主要有以下两点:

    • 静态内部类可以有静态成员和方法,而普通内部类不行。
    • 静态内部类的对象,并不需要其外围类的对象。
    //普通内部类创建对象
    OutClass oc = new OutClass();
    OutClass.InnerClass inner = oc.new InnerClass();
    //静态内部类创建对象
    OutClass.InnerClass inner = new OutClass.InnerClass();

    (2)局部内部类

    局部内部类,是指内部类定义在方法和作用域内。

     public class Outer { 
            public static void main(String[] args) { 
                Outer outer = new Outer(); 
                ImplInner inner = outer.getInner(); 
                inner.print("定义在方法的局部内部类"); 
            } 
         
            public ImplInner getInner() { 
                public class Inner implement ImplInner { 
                    public void print(String str) { 
                        System.out.println(str); 
                    } 
                 } 
                return new Inner(); 
            } 
        }         

    当然,上述代码中有一个前提,就是先要有个ImplInner 接口。

    (3)匿名内部类

    匿名内部类就是没有名字的内部类。有两种场景经常要使用匿名内部类:

    • 监听器
    • 直接new一个接口(或抽象类),由于没有具体实现类,常用的做法是直接在类体实现所有抽象方法。
        public class Outer { 
            public static void main(String[] args) { 
                Outer outer = new Outer(); 
                Inner inner = outer.getInner("Inner", "gz"); 
                System.out.println(inner.getName()); 
            } 
         
            public Inner getInner(final String name, String city) { 
                return new ImplInner() { 
                    private String nameStr = name; 
         
                    public String getName() { 
                        return nameStr; 
                    } 
                }; 
            } 
        } 
         
        //注释后,编译时提示类Inner找不到 
        /* interface ImInner { 
            String getName(); 
        } */ 

    注意getInner方法的形参,当所在的方法的形参需要被内部类里面使用时,该形参必须为final。这里可以看到形参name已经定义为final了,而形参city 没有被使用则不用定义为final。为什么要定义为final呢?

        内部类被编译的时候会生成一个单独的内部类的.class文件,这个文件并不与外部类在同一class文件中。  当外部类传的参数被内部类调用时,内部类并不是直接调用方法传进来的参数,而是内部类将传进来的参数通过自己的构造器备份到了自己的内部,自己内部的方法调用的实际是自己的属性而不是外部类方法的参数。 
    简单理解就是,拷贝引用,为了避免引用值发生改变,例如被外部类的方法修改等,而导致内部类得到的值不一致,于是用final来让该引用不可改变。
     
    注意:Java8之后,name形参不需要声明为final了但其实该变量实际上仍然是final的。(外形变了,内涵没变)
     
    (4)四个问题
    a)一般匿名内部类是没有参数的,若需要参数应该如何处理?
         如果需要参数,该类的声明中就需要显示的声明带参构造器。
    b)内部类的继承?(普通类 extents 内部类)
        public class InheritInner extends WithInner.Inner { 
         
            // InheritInner() 是不能通过编译的,一定要加上形参 
            InheritInner(WithInner wi) { 
                wi.super(); 
            } 
         
            public static void main(String[] args) { 
                WithInner wi = new WithInner(); 
                InheritInner obj = new InheritInner(wi); 
            } 
        } 
         
        class WithInner { 
            class Inner { 
         
            } 
        } 

    c)内部类的成员属性和外部类重了,会不会屏蔽?

    当然不会,可以通过Outer.this.xxx。

    d)匿名内部类没有构造函数怎么进行初始化?

    代码块。

    关于内部类问题,更多详细内容请参考:http://blog.51cto.com/android/384844

    3为什么使用内部类

    说了那么多,我们为什么要使用内部类?没什么用的话学他干啥~。

    用内部类是因为内部类与所在外部类有一定的关系,往往只有该外部类调用此内部类,所以没有必要专门用一个Java文件存放这个类。

    使用内部类还有如下几个优点:

    (1)隐藏你不想让别人知道的操作,也即封装性。
    下面举个例子,Outer是我们自己实现的核心代码
     public class Outer { 
    
            public ImplInner getInner() { 
                public class Inner implement ImplInner { 
                    public void print(String str) { 
                        System.out.println(str); 
                    } 
                 } 
                return new Inner(); 
            } 
        }    

    下面是别人的业务代码Test

     public class Test{ 
            public static void main(String[] args) { 
                Outer outer = new Outer(); 
                ImplInner obj= outer.getInner(); 
                obj.print("定义在方法的局部内部类"); 
            } 
        }        

    调用者甚至连内部类的类名都没有看见,直接从外部类的成员方法获得就行了。

    (2)一个内部类对象可以直接访问创建它的外部类对象的内容,甚至包括私有变量。
    (3)解决Java多继承的问题
    Java中的类是单继承的,接口是多继承的。那如果类想要达到多继承同样效果的话就可以通过内部类实现了。
    关于内部类优点更多详情:https://www.cnblogs.com/jpa2/archive/2012/04/24/2527538.html
  • 相关阅读:
    mysql-5.7.15-winx64免安装版配置
    db2 表授权语句
    java 调用 .net webservice 示例
    打印内存高解决方案
    eclipse快捷键调试总结【转】
    DevExpress GridControl 自定义 summary 算法
    GEMR: Get the parent window for view
    弹出窗口
    WPF UI虚拟化
    WPF应用程序最小化到系统托盘
  • 原文地址:https://www.cnblogs.com/ouym/p/8883076.html
Copyright © 2011-2022 走看看