Java基础之内部类

内部类

可以将一个类的定义放在另一类的定义内部,这就是内部类。

创建内部类

public class Parcel {
    class Contents{
        private int i=11;
        public int getI(){
            return i;
        }
    }
    class Destination{
        private String label;
        Destination(String label){
            this.label=label;
        }
        String getLabel()
        {
            return label;
        }
    }
    public Contents contents()
    {
        return new Contents();
    }
    public Destination destination(String s)
    {
        return new Destination(s);
    }
    public void ship(String dest)
    {
        Contents c=contents();
        Destination d=destination(dest);
        System.out.println(d.getLabel());
    }

    public static void main(String[] args) {
        Parcel parcel=new Parcel();
        parcel.ship("Tasmania");
        Parcel q=new Parcel();
        Parcel.Contents c= q.new Contents();
        Parcel.Destination d= q.new Destination("Bomb");
    }
}

可以看出我们在使用内部类的时候和普通类没什么区别。但是在我们也可以看出,非静态内部类的对象创建是需要依赖于外部类的对象,所以我们需要先创建出外部类才能创建出内部类。
从上面的例子中可以看出在使用.new创建内部类的时候,需要使用外部类的对象来创建内部类,这样也解决了内部类作用域的问题

为什么需要内部类

在我们知道如何创建内部类后可能会有个疑问,内部类看起来没有比在外部创建一个类更加实用,那我我们为什么需要内部类呢?
一般来说来说内部类继承或者实现某个接口,或者继承某个类,每个内部类都能独立的继承一个接口的实现,所以无论外围类是否已经被继承了,对内部类都没有影响,内部类提供了一个可以继承多个具体或者抽象类的能力,每个内部类都可以继承一个具体或者抽闲的类,那么使用多个内部类的话,就能优先的实现多重继承。

链接到外围对象

当创建一个内部类对象时,次对象与创造他的外围对象之间存在一种联系,所以不需要任何特殊条件,就能范围其外围对象的所有成员,下面我们来看一个例子:

public class Sequence {
    private Object[] items;
    private int next=0;
    public Sequence(int size){
        items=new Object[size];
    }
    public void add(Object item){
        items[next]=item;
        next++;
    }
    private class SequenceSelector{
        private int i=0;
        public boolean end(){
            return i==items.length;
        }
        public Object current(){
            return items[i];
        }
        public void next(){
            if(i<items.length) i++;
        }
    }
    public SequenceSelector sequenceSelector()
    {
        return new SequenceSelector();
    }

    public static void main(String[] args) {
        Sequence sequence=new Sequence(10);
        for(int i=0;i<10;i++)
        {
            sequence.add(Integer.toString(i));
        }
        SequenceSelector Selector=sequence.sequenceSelector();
        while (!Selector.end())
        {
            System.out.println(Selector.current()+" ");
            Selector.next();
        }
    }
}
输出结果:
0
1
2
3
4
5
6
7
8
9

在上面这个例子中,Seqence只是一个固定大小的Object数组,以类的形式包装了起来,而且其中的items是private类型,而我们的内部类中的end current等函数可以直接对items进行访问,从而可以遍历整个items数组。 内部类可以访问外围类的方法和字段就像自己的一样,这带来了很大的方便。
那么内部类对象在创建的时候,会自动的捕获一个指向外围类的引用,当我们访问外围对象时就是用那个引用来获取外围对象的成员。

匿名内部类

我们先来看一个例子

public interface Content {
    public int value();
}
public class Pracel2 {
    public Content contents(){
        return new Content(){
            private int i=11;
            public int value() {return i;}
        };
    }

    public static void main(String[] args) {
        Pracel2 p=new Pracel2();
        Content c=p.contents();
    }
}

上面这个例子似乎有点奇怪,我们可以看到,contents方法是将返回值的生成与返回值的类的定义结合在了一起,并且这个类是匿名的。
这种写法的实际含义就是,创建一个继承自Content的匿名类对象,然后通过new的表达式返回的引用被自动向上转型为对Content的引用,上述例子就是对下面这个例子的简化

public interface Content {
    public int value();
}
public class Pracel2 {
	class MyContent implements Content{
    private int i=11;
    public int value() {return i;}
    }
    public Content contents(){
        return new MyContent();
    }

    public static void main(String[] args) {
        Pracel2 p=new Pracel2();
        Content c=p.contents();
    }
}

在匿名内部类定义字段的时候,还能对其执行初始化操作

public interface Destination {

    String getLabel();

}
public class Parcel3 {
    public Destination destination(final String dest){
        return new Destination() {
            private String label=dest;
            public String getLabel() {
                return label;
            }
        };
    }

    public static void main(String[] args) {
        Parcel3 p=new Parcel3();
        Destination d=p.destination("Tom");
        System.out.println(d.getLabel());
    }
}
输出结果是:
TOM

如果定义一个内部类希望他使用外部定义的对象的话,那么编译器会要去这个参数的引用是final的,不过这个限制在JAVA8以后就放宽了,不过还是要求不能重复修改。

嵌套类

如果不需要内部类对象与其外围对象之间有联系,那么可以将内部类声明为static,这通常称为嵌套类。嵌套类也意味着:
1、要创建嵌套类的对象,并不需要其外围类的对象
2、不能从嵌套类的对象中范围非静态的外围类对象
看下面这个例子:

public class Parcel4 {
    private static class ParcelContents implements Content{
        private int i;
        public int value(){
            return i;
        }
    }
    protected static class ParcelDestination implements Destination{
        private String label;
        private ParcelDestination(String whereto){
            label=whereto;
        }
        public String getLabel(){
            return label;
        }
    }

    public static void main(String[] args) {
        Content c=new ParcelContents();
        ParcelDestination p=new ParcelDestination("Tsa");
        System.out.println("i: "+c.value()+" label: "+p.getLabel());
    }
}
out:
i: 0 label: Tsa

从这个例子中可以看出,嵌套类的创建不依赖与外部类就可以创建出该对象。

正常情况下,是不能在接口内放置任何代码的,但是嵌套类可以作为接口的一部分,且放到接口中的任何类都自动的是public和static的,因为类是static的,只是将嵌套类置于接口的命名空间内,这并不违反接口的规则,甚至可以在内部类中实现其外围接口。

public interface ClassInInterface {
    void howdy();
    class Test implements ClassInInterface{
        public void howdy(){
            System.out.println("Howdy");
        }

        public static void main(String[] args) {
            new Test().howdy();
        }
    }
}

局部内部类

内部类不仅仅可以创建在类中,也可以创建在一个方法体中,如下所示例子:

public class Parcel6 {
    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("chenssy");
            String string = ts.getSlip();
        }
    }
    
    public void track(){
        internalTracking(true);
    }
    
    public static void main(String[] args) {
        Parcel6 parcel6 = new Parcel6();
        parcel6.track();
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值