Java内部类-成员内部类、局部内部类、匿名内部类、静态内部类

本文为joshua317原创文章,转载请注明:转载自joshua317博客 Java内部类-成员内部类、局部内部类、匿名内部类、静态内部类 - joshua317的博客

在 Java 中,可以将一个类定义在另一个类里面或者一个方法里面,这样的类称为内部类。广泛意义上的内部类一般来说包括这四种:成员内部类、局部内部类、匿名内部类和静态内部类。我们知道类的五大成员:属性、方法、构造器、代码块、内部类。内部类最大的特点就是可以直接访问私有属性,并且可以体现类与类之间的包含关系。

从定义的位置上看:

(1)定义在外部类的方法体内/代码块

  • 局部内部类(有类名)
  • 匿名内部类(没有类名)

(2)定义在外部类的成员位置上

  • 静态内部类(有static修饰符)
  • 成员内部类(没有static修饰符)

1.成员内部类

成员内部类是最普通的内部类,它的定义为位于另一个类的内部

成员内部类语法格式

/**
 * @author joshua317
 */
public class Outer {//外部类

    class Inner {//内部类

    }
}

类Inner像是类Outer的一个成员,Outer称为外部类。成员内部类可以无条件访问外部类的所有成员属性和成员方法(包括private成员和静态成员)

package com.joshua317;

/**
 * @author joshua317
 */
public class Outer {//外部类
    private String name;
    public static void main(String[] args) {
        Outer outerObj = new Outer("joshua317");
        Outer.Inner inner = outerObj.new Inner();
        inner.InnerFun1();
    }

    public Outer(String name) {
        this.name = name;
    }

    public void OuterFun1() {
        System.out.println("外部类成员方法");
    }

    class Inner {//内部类
        public void InnerFun1() {
            System.out.println(name);
        }
    }
}

虽然成员内部类可以无条件地访问外部类的成员,而外部类想访问成员内部类的成员却不是这么随心所欲了。在外部类中如果要访问成员内部类的成员,必须先创建一个成员内部类的对象,再通过指向这个对象的引用来访问。

当成员内部类拥有和外部类同名的成员变量或者方法时,会根据就近原则,即默认情况下访问的是成员内部类的成员。如果要访问外部类的同名成员,需要以下面的形式进行访问:

外部类.this.成员变量
外部类.this.成员方法
package com.joshua317;

/**
 * @author joshua317
 */
public class Outer {//外部类
    private String name;
    public static void main(String[] args) {
        Outer outerObj = new Outer("joshua317");
        Outer.Inner inner = outerObj.new Inner();
        inner.InnerFun1();
    }

    public Outer(String name) {
        this.name = name;
    }

    public void OuterFun1() {
        System.out.println("外部类成员方法");
    }

    class Inner {//内部类
        String name;
        public void InnerFun1() {
            //访问外部类的同名成员属性
            System.out.println("我是内部类的成员属性name:"+ name + " 我是外部类的成员属性name:"+Outer.this.name);
        }
    }
}

成员内部类是依附外部类而存在的,也就是说,如果要创建成员内部类的对象,前提是必须存在一个外部类的对象。创建成员内部类对象的一般方式如下:

package com.joshua317;
public class TestInner {
    public static void main(String[] args)  {
        //第一种方式:
        Outter outter = new Outter();
        Outter.Inner inner = outter.new Inner();  //必须通过Outter对象来创建
         
        //第二种方式:
        Outter.Inner inner1 = outter.getInnerInstance();
    }
}
 
class Outter {
    private Inner inner = null;
    public Outter() {
         
    }
     
    public Inner getInnerInstance() {
        if(inner == null)
            inner = new Inner();
        return inner;
    }
      
    class Inner {
        public Inner() {
             
        }
    }
}

成员内部类可以拥有 private 访问权限、protected 访问权限、public 访问权限及包访问权限。比如上面的例子,如果成员内部类 Inner 用 private 修饰,则只能在外部类的内部访问,如果用 public 修饰,则任何地方都能访问;如果用 protected 修饰,则只能在同一个包下或者继承外部类的情况下访问;如果是默认访问权限,则只能在同一个包下访问。这一点和外部类有一点不一样,外部类只能被 public 和包访问两种权限修饰。由于成员内部类看起来像是外部类的一个成员,所以可以像类的成员一样拥有多种权限修饰。

2.局部内部类

局部内部类是定义在一个方法或者一个作用域里面的类,它和成员内部类的区别在于局部内部类的访问仅限于方法内或者该作用域内。

局部内部类语法格式:

/**
 * @author joshua317
 */
public class Outer {//外部类

    public void OuterFun1() {
        System.out.println("外部类成员方法");
        class Inner {//局部内部类
            
        }
    }
}

**局部内部类就像是方法里面的一个局部变量一样,是不能有 public、protected、private 以及 static 修饰符的。**总结下来有这几点:

(1)局部内部类可以直接访问外部类的所有成员,包含私有的;

(2)不能添加修饰符,因为它是一个局部变量,局部变量是不能使用修饰符的,但是可以用final修饰,因为局部变量是可以使用final修饰的。

(3)作用域仅仅在定义它的方法或者代码块中。

(4)局部内部类访问外部类的成员属性或者方法时,直接访问;

(5)外部类访问局部内部类的成员属性或者方法时,通过先创建对象,再访问,且必须要在作用域内。

package com.joshua317;

/**
 * @author joshua317
 */
public class Outer {//外部类
    private String name;
    public static void main(String[] args) {
        Outer outerObj = new Outer("joshua317");
        outerObj.OuterFun1();
    }

    public Outer(String name) {
        this.name = name;
    }

    public void OuterFun1() {
        System.out.println("外部类成员方法");
        class Inner {//内部类
            String name;
            public void InnerFun1() {
                //访问外部类的同名成员属性
                System.out.println("局部内部类的成员属性name:"+ name + " 我是外部类的成员属性name:"+Outer.this.name);
            }
            public void setName(String name) {
                this.name = name;
            }

        }
        Inner inner = new Inner();
        inner.setName("innerName");
        inner.InnerFun1();
        System.out.println("局部内部类的成员属性name:" + inner.name);
    }
}

3.匿名内部类

Java 中可以实现一个类中包含另外一个类,且不需要提供任何的类名直接实例化。主要是用于在我们需要的时候创建一个对象来执行特定的任务,可以使代码更加简洁。匿名类是不能有名字的类,它们不能被引用,只能在创建时用 new 语句来声明它们。

匿名内部类语法格式:

package com.joshua317;

/**
 * @author joshua317
 */
public class Outer {//外部类
    Object obj = new Inner(){
        @Override
        public void innerFun1() {
            
        }
    };
}

interface Inner {
    public void innerFun1();
}

匿名内部类也是不能有访问修饰符和 static 修饰符的。

匿名内部类是唯一一种没有构造器的类。正因为其没有构造器,所以匿名内部类的使用范围非常有限,大部分匿名内部类用于接口回调。

匿名内部类在编译的时候由系统自动起名为 Outer$1.class。

匿名内部类主要用于继承其他类或是实现接口,并不需要增加额外的方法,只是对继承方法的实现或是重写。

匿名内部类使用一次,就不再使用。

package com.joshua317;

/**
 * @author joshua317
 */
public class Outer {//外部类

    public static void main(String[] args) {

        /**
         * 底层会分配一个类名Outer$1,去实现Inner接口
         * class Outer$1 implements Inner {
         *             @Override
         *             public void innerFun1() {
         *                 System.out.println("实现接口Inner,匿名内部类方法innerFun1()");
         *             }
         *         }
         */
        Inner inner = new Inner(){
            @Override
            public void innerFun1() {
                System.out.println("实现接口Inner,匿名内部类方法innerFun1()");
            }
        };
        System.out.println(inner);
        inner.innerFun1();

        /**
         * 底层会分配一个类名Outer$2,去继承InnerClass
         * class Outer$1 extends InnerClass {
         *             @Override
         *             public void innerFun1() {
         *                 System.out.println("匿名类继承了 InnerClass 类,匿名内部类方法innerFun1()");
         *             }
         *         }
         */
        Inner inner2 = new InnerClass(){
            @Override
            public void innerFun1() {
                System.out.println("匿名类继承了 InnerClass 类,匿名内部类方法innerFun1()");
            }
        };
        System.out.println(inner2);
        inner2.innerFun1();
    }
}

class InnerClass implements Inner {
    @Override
    public void innerFun1() {

    }
}

interface Inner {
    public void innerFun1();
}

4.静态内部类

静态内部类也是定义在另一个类里面的类,只不过在类的前面多了一个关键字static。静态内部类是不需要依赖于外部类的,这点和类的静态成员属性有点类似,并且它不能使用外部类的非static成员变量或者方法,这点很好理解,因为在没有外部类的对象的情况下,可以创建静态内部类的对象,如果允许访问外部类的非static成员就会产生矛盾,因为外部类的非static成员必须依附于具体的对象。可以添加任意的访问修饰符public、protected、private 以及默认,因为它就是类的成员。作用域和其他类成员一样,为整个类体。

静态内部类语法格式:

/**
 * @author joshua317
 */
public class Outer {//外部类

    static class Inner {//内部类

    }
}
package com.joshua317;
/**
 * @author joshua317
 */
public class Outer {//外部类
    static String name = "joshua317";
    public static void main(String[] args) {
        Outer outer = new Outer();
        //方式一:内部直接访问
        Inner inner1 = new Inner();
        inner1.innerFun();
        //方式二:因为是静态内部类,可以通过类名直接访问(前提是满足访问权限)
        Outer.Inner inner2 = new Outer.Inner();
        inner2.innerFun();
        //方式三:通过普通成员方法,返回静态内部类的实例
        Inner inner3 = outer.getInnerInstance();
        inner3.innerFun();
        //方式三:通过静态方法,返回静态内部类的实例
        Outer.Inner inner4 = Outer.getInnerInstance2();
        inner4.innerFun();
    }
    static class Inner {//内部类
        static String name = "joshua317-inner";
        public void innerFun () {
            System.out.println("内部类静态成员" + name + "  外部类静态成员" + Outer.name);
        }
    }

    /**
     * 通过方法,返回静态内部类的实例
     * @return Inner
     */
    public Inner getInnerInstance() {
        return new Inner();
    }

    public static Inner getInnerInstance2() {
        return new Inner();
    }
}

5.内部类的使用好处

  • 1.每个内部类都能独立的继承一个接口的实现,所以无论外部类是否已经继承了某个(接口的)实现,对于内部类都没有影响。内部类使得多继承的解决方案变得完整;
  • 2.方便将存在一定逻辑关系的类组织在一起,又可以对外界隐藏;
  • 3.方便编写事件驱动程序;
  • 4.方便编写线程代码。

本文为joshua317原创文章,转载请注明:转载自joshua317博客 Java内部类-成员内部类、局部内部类、匿名内部类、静态内部类 - joshua317的博客

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值