浅谈Java内部类

Java的内部类可以获得其外围类的所有成员访问权限,可以很方便的对外围类进行操作。非static内部类都含有一个隐藏的外围类引用,这个引用可以通过 OuterClass.this 来获得使用。通常如果我们的一组操作需要遵循某些规范(例如接口,抽象类),就可以把这一组操作封装成一个内部类来供外部使用,而又不会脱离外围类。参见如下代码:

public interface Selector<E> {

    boolean hasNext();

    E next();

}



public class Sequence {

    private int[] seq;

    private Selector<Integer> obverseSelector;    // 正序遍历器

    private Selector<Integer> reverseSelector;    // 逆序遍历器



    public Sequence(int[] seq) {

        this.seq = seq;

        obverseSelector = new Selector<Integer>() {

            int counter = -1;

            

            @Override

            public Integer next() {

                return Sequence.this.seq[counter];

            }

            

            @Override

            public boolean hasNext() {

                return (++counter < Sequence.this.seq.length);

            }

        };

        

        reverseSelector = new Selector<Integer>() {

            int counter = Sequence.this.seq.length;

            

            @Override

            public Integer next() {

                return Sequence.this.seq[counter];

            }

            

            @Override

            public boolean hasNext() {

                return (--counter >= 0);

            }

        };

    }

    

    public Selector<Integer> getObverseSelector() {

        return obverseSelector;

    }

    

    public Selector<Integer> getReverseSelector() {

        return reverseSelector;

    }

}



public class Test {

    public static void main(String args[]) {

        int[] a = {1, 2, 3, 4, 5};

        

        Sequence sequence = new Sequence(a);

        Selector<Integer> obSelector = sequence.getObverseSelector();

        Selector<Integer> reSelector = sequence.getReverseSelector();

        while (obSelector.hasNext()) {

            System.out.print(obSelector.next() + " ");

        }

        System.out.println();

        while (reSelector.hasNext()) {

            System.out.print(reSelector.next() + " ");

        }

    }

}

这个例子通过内部类实现Selector接口,让Sequence类拥有属于自己的正序遍历器和逆序遍历器。注意匿名内部类如果需要访问外围类的成员,需要使用 Outer.this 前缀来访问。

可以想象如果不用内部类来实现遍历器会有什么不同,如果我们不用内部类来实现,就必须定义个Selector的具体类,并且将Sequence类的seq数组作为参数传进去。如果说需要将Selector作为一个共用的遍历器,可以这么做,但如果遍历器是针对Sequence类来实现的,则用内部类更为方便。

下面的代码是使用非匿名内部类实现的Selector

public class Sequence2 {

    private int[] seq;

    

    public Sequence2(int[] seq) {

        this.seq = seq;

    }

    

    public class ObverseSelecter implements Selector<Integer> {

        int counter = -1;

        

        @Override

        public Integer next() {

            return seq[counter];

        }

        

        @Override

        public boolean hasNext() {

            return (++counter < seq.length);

        }

    }

    

    public class ReverseSelecter implements Selector<Integer> {

        int counter = seq.length;

        

        @Override

        public Integer next() {

            return seq[counter];

        }

        

        @Override

        public boolean hasNext() {

            return (--counter >= 0);

        }

    }

}



public class Test {

    public static void main(String args[]) {

        int[] a = {1, 2, 3, 4, 5};

        

        Sequence2 sequence2 = new Sequence2(a);

        Selector<Integer> obSelector2 = sequence2.new ObverseSelecter();

        Selector<Integer> reSelector2 = sequence2.new ReverseSelecter();

        while (obSelector2.hasNext()) {

            System.out.print(obSelector2.next() + " ");

        }

        System.out.println();

        while (reSelector2.hasNext()) {

            System.out.print(reSelector2.next() + " ");

        }

    }

}

此处仅需要注意一下生成遍历的时候的new语法 sequence2.new ,容易看出内部类的实例其实是和外围类的实例紧密相关的,正如匿名内部类的 Outer.this 语法一样

 

值得一提的是局部内部类如果要使用局部变量,那么局部变量必须为final,否则编译会不通过,参见如下代码

public interface Flyable {

    void fly();

}



public class FinalTest {

    public static Flyable getFlyable(int speed) {

        final int finalSpeed = speed * 2;

        return new Flyable() {

            @Override

            public void fly() {

                System.out.println("I can fly with speed " + finalSpeed + " km/h");

            }

        };

    }

    

    public static void main(String[] args) {

        Flyable flyable = getFlyable(50);

        flyable.fly();

    }

}

可见finalSpeed为final变量,为什么有这种要求呢?

是因为局部变量的生命周期仅仅在方法执行作用域内,当方法执行完毕,局部变量自然就被销毁。但是内部类却作为一个实例被返回来了,如果说这个内部类实例以后还需要访问这个已销毁的局部变量,显然是不可以的。所以在内部类里需要访问的局部变量都会定义成常量,一起被编译进内部类里。

你可能感兴趣的:(java内部类)