Java内部类用法

前两天携程笔试,考到了内部类的一些知识点,已经有些模糊了,现在来通过《Java 编程思想》回顾一下

1. 普通内部类:

  • 必须使用外部类的对象来创建该内部类对象。
  • 内部类自动拥有对其外部类所有成员的访问权。

内部类的创建

在外部类的内部,可以直接的创建内部类对象,但如果是在外部类的静态方法,或别的类的方法中,就不能直接创建内部类对象,可以通过下面两种方法创建:

public class Parcel {
    class Contents{
        private int i =11;
        public int value(){
            return i;
        }
    }
    public Contents getContents(){
        return new Contents();
    }

    public static void main(String[] args) {
        Parcel parcel1 = new Parcel();
        Parcel.Contents contents1 = parcel1.new Contents();

        Parcel parcel2 = new Parcel();
        Parcel.Contents contents2 = parcel2.getContents();
    }
}

第一种,通过外部类对象调用 .new 进行创建;

第二种,通过外部类中的非静态方法返回一个新建的内部类对象。

注:如果是别的类的方法需要使用内部类,需要具体的指出这个内部类的类型 OuterClassName.InnerClassName;如果是外部类的方法中使用,可以直接使用:InnerClassName,就像上面例子中的 main 方法,可以将 Parcel.Contents 直接换成 Contents。
 

内部类获取外部类对象

内部类对象会跟创建它的外部类对象有一种联系,所以它能访问对应的外部类对象的所有成员,不需要任何条件。通过 .this 实现

public class Parcel {
    private int x = 5;
    protected int y = 10;
    public int z = 12;
    public void f(){
        System.out.println("调用f函数");
    }
    class Contents{
        private int i =11;
        public int value(){
            return i;
        }

        public Parcel getOuterObject(){
            Parcel parcel = Parcel.this;
            System.out.println(parcel.x);
            System.out.println(parcel.y);
            System.out.println(parcel.z);
            parcel.f();
            return Parcel.this;
        }
    }
}
public class Test {
    public static void main(String[] args) {
        Parcel parcel1 = new Parcel();
        Parcel.Contents contents1 = parcel1.new Contents();
        Parcel parcel = contents1.getOuterObject();
 //       System.out.println(parcel.x);     // 会因为访问权限报错
    }
}

输出结果

5
10
12
调用f函数

 
 

2. 局部内部类

在一个方法里面或者在任意的作用域内定义内部类,一般有两个理由:

  • 该内部类实现了某类型的接口,通过这个内部类对外部类的对象进行额外的操作。
  • 解决一个复杂问题,需要创建一个类来辅助你的解决方案,但又不希望这个类是公共可见的。

下面是一个局部内部类的例子

public class Parcel5 {
   private void internalTracking(boolean b) {
       if (b) {
           class TrackingSlip {
               private String id;
               TrackingSlip(String s) {
                   id = s;
               }
               String getSlip() {
                   return id;
               }
           }
           TrackingSlip ts = new TrackingSlip("slip");
           String s = ts.getSlip();
       }
       //TrackingSlip ts = new TrackingSlip("x");  //已经不在作用域范围,无法使用
   }
   public void track() {
       internalTracking(true);
   }
   public static void main(String[] args) {
       Parcel5 p = new Parcel5();
       p.track();
   }
}

 
 

3. 匿名内部类

匿名内部类属于局部内部类中的一种,可以直接来看一个例子:



public class NoNameInnerClass {
    class Contents{
        private int i = 11;
        public int value(){
            return i;
        }
        public Contents(int x){
            i = x;
            System.out.println("创建Contents,x="+x);
        }
        public Contents(){
            System.out.println("创建Contents");
        }
    }
    public Contents contents(int x){
        return new Contents(x){
            private int x = 11;
            public int value(){
                return super.i + x;
            }
        };
    }
    public Contents contents(){
        return new Contents(){
            private int x = 11;
            public int value(){
                return super.i + x;
            }
        };
    }

    public static void main(String[] args) {
        NoNameInnerClass noNameInnerClass = new NoNameInnerClass();
        Contents c = noNameInnerClass.contents();
        System.out.println(c.value());
    }
}
//output:
//创建Contents
//创建Contents,x=5
//22
//16

contents 方法中,return new Contents(){}这种语法的意思是,创建一个继承自 Contents 的匿名类的对象。上面的 contents 方法与下面的是等价的:

    public Contents contents(){
        class MyContents extends Contents{    //继承了Contents的局部内部类
            private int i = 11;
            public int value(){
                return i;
            }
        }
        return new MyContents();
    }

需要注意,因为匿名类没有类名,因此他只有系统提供的默认无参构造器,创建匿名类对象时提供的参数,是提供给它的基类的构造器使用的,比如带参数 x 的 contents 方法。
 
 
如果希望匿名内部类能使用一个在其外部定义的对象,那么要求这个对象是 final,如下所示:

public Contents contents(final int t){
    final int a = 6;
    return new Contents(){
        private int x = 11;
        public int value(){
            return super.i + x + a + t;
        }
    };
}

为什么需要 final 修饰,可以查看这篇文章:java匿名内部类使用外部变量时,外部变量必须是final,为什么?

注:jdk1.8 后已经可以不需要 final 修饰,但依旧无法在匿名内部类中对该对象进行修改。

PS:前面写的 Java 三种代理方式中的动态代理就有用到匿名内部类

4. 嵌套类(静态内部类)

嵌套类就是用 static 修饰的内部类,需要注意的是,嵌套类对象与外部类对象不存在任何联系,也就是说,嵌套类的创建不需要依赖于外部类对象,嵌套类无法访问外部类对象的非静态成员。它的用法与普通的类基本一致。

如下所示:

public class Parcel {

    public int x = 5;
    static int y = 10;

    static class Contents{
        private int i = 11;
        public int value(){
           // int sum = i + x;    //x不是静态成员,无法访问
            int sum = i + y;
            return sum;
        }
    }
}
public class Test{
    public static void main(String[] args) {
        Parcel.Contents contents = new Parcel.Contents();
        System.out.println(contents.value());
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值