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
原文地址:https://www.cnblogs.com/ouym/p/8883076.html