java 内部类的使用

http://www.cnblogs.com/wenruo/p/5387995.html

内部类 就是在类中嵌套的另一个类。

非静态内部类

创建内部类的方式就是把类定义在外部类里面。

 class Out { class In { } } 

内部类对于外部类是特殊的,内部类可以访问到外部类的所有成员,包括私有成员。

class Outer {
    private String str = "Outer";
    class Inner {
        public Inner() {str = "Inner";}
    }
}

当生成一个内部类对象的时候,它自动和它的外部类有联系,所以要创建内部类对象,必须先有外部类对象。

内部类的类型在外部类除外部类静态方法外不能直接使用内部类的名字,应为OuterClassName.InnerClassName。

内部类可以为私有权限,当内部类为私有时,外部类外对内部类是不可见的。内部类不能有static的域,除非是final的。

创建内部类的方法:

1,外部类方法发返回内部类的引用。

2,通过.new语法实现。

class Outer {
    class Inner { }
    
    public Inner getInner() {
        return new Inner();
    }
}

public class Test {
    public static void main(String args) {
        Outer out = new Outer();
        Outer.Inner in = out.new Inner();
        Outer.Inner in1 = out.getInner();
    }
}

 

在内部类通过OuterClassName.this可以访问外部类对象。

class Outer {
    int a = 17;
    class Inner {
        int a = 3;
        public void f() {
            System.out.println(this.a + " " + Outer.this.a);
        }
    }
}

public class Test {
    public static void main(String[] args) {
        Outer out = new Outer();
        Outer.Inner in = out.new Inner();
        in.f();
    }
}  // output:3 17

 

类也可以定义在代码块,包括方法内部。这样类的作用域也就限制在方法内部。此时内部类不能访问外部类,因为它不是外部类的一部分,但是它可以访问当前代码块的常量。

【名字实在是很糟糕

interface Inf {
    void f();
}

class Outer {
    public Inf f() {
        class Inner implements Inf {
            public void f() {
                System.out.println("Inner");
            }            
        }
        return new Inner();
    }
}

public class Test{
    public static void main(String[] args) {
        Outer out = new Outer();
        Inf inf = out.f();
        inf.f();
    }
}

在这个例子中,通过向上转型为接口类型,完全隐藏了具体实现。

匿名内部类

匿名内部类就是没有名字的内部类使用样例

interface Contents {
    int value();
}

public class AnonymousInnerClassTest {
    public Contents contents() {
        return new Contents() {
            private int i = 11;
            public int value() { return i; }
        };
    }
    public static void main(String[] args) {
        AnonymousInnerClassTest a = new AnonymousInnerClassTest();
        Contents c = a.contents();
        System.out.println(c.value());
    }
}

乍一看很奇怪,但其实很方便的使用方法。在需要使用类的地方直接写一个类的定义。

匿名内部类和在方法中定义类使用功能差不多,区别就是匿名内部类只能产生一个对象。

 

很容易想到因为匿名类没有名字,而构造器的名字需要和类名一样,所以……它没!有!构!造!器!

如果基类需要有参数的构造器怎么办?只需要在new的时候加上参数就可以了。

public class A {
    int i, j;
    A(int i, int j) { this.i = i; this.j = j; }
}

class B {
    public A f(int i, int j) {
        return new A(i, j) {
            //...
        };
    }
}

那么如果一个匿名内部类需要构造器来初始化的时候怎么办呢?

在学习类的初始化顺序的时候知道,在构建类对象时是先执行非静态代码段再执行构造器。所以这里可以用代码块带到类似构造器的效果。

class B {
    public void print() {}
}

public class A {
    public B getB() {
        return new B() {
            { System.out.println("Inside Instance initialize."); }
            public void print() { System.out.println("in anonymous f()"); }
        };
    }
    
    public static void main(String[] args) {
        B b = new A().getB();
        b.print();        
    }
}

 

如果定义一个匿名内部类,并且希望它使用一个在其外部定义的外部对象,那么编译器会要求其参数引用是final的。

Java8中,可以不是final了,但是默认是final的,在内部类不能改变。原因是在内部类,外部变量相当于形参,也就是在内部类改变对外部类无影响,就会造成数据不同步的问题。

interface I {}

public class A {
    public static void main(String[] args) {
        int x = 0;
        new I() {
            // x = 3; error
            void f() { System.out.println(x); }
        };
    }
}

 

Java8中匿名内部类可以用lambda表达式代替,感觉超简洁。语法糖,写代码方便,不过也增加了阅读代码的难度。

interface A1 { void print(); }

class A2 {
    public A1 f() {
        return () -> { System.out.println("lambda expression."); };
    }
}

public class Test {
    public static void main(String[] args) {
        A1 a1 = new A2().f();
        a1.print();
    }
}

略过略过,以后再学,,,

迭代器实现

interface Iterator {
    int next();
    boolean hasNext();
}

class Sequence {
    private int[] items;
    private int next = 0;
    public int size() {
        return items.length;
    }
    public Sequence(int size) {
        items = new int[size];
    }
    public void add(int x) {
        items[next++] = x;
    }
    public Iterator iterator() {
        return new Iterator() {
            int i = 0;
            public int next() {
                return items[i++]; 
            }
            public boolean hasNext(){
                if (i == next) return false;
                return true;
            }
        };
    }
}


public class Test {
    public static void main(String[] args) {
        Sequence s = new Sequence(10);
        s.add(1); s.add(3); s.add(5);
        Iterator it = s.iterator();
        while (it.hasNext()) {
            System.out.println(it.next());
        }
    }
}

 

静态内部类

静态内部类常被称作嵌套类。静态内部类和外部类联系不是很大。

创建静态内部类的对象,并不需要外部类的对象。

不能从嵌套类的对象中访问非静态的外围类对象。

普通的内部类不能有static数据和static字段,也不能包含嵌套类,但是嵌套类可以包含所有这些东西。

class B {
    static class C {    
    }
}

public class A {
    public static void main(String[] args) {
        B.C c = new B.C();
    }
}

 

内部类的继承

既然内部类对象一定要有某个关联外部类对象,那么继承自内部类的子类也一定需要外部类对象。

class WithInner {
    public WithInner() {
        System.out.println("外部类");
    }
    class Inner {
        public Inner() {
            System.out.println("内部类");
        }
    }
}

public class InheritInner extends WithInner.Inner {
    InheritInner(WithInner wi) {
        wi.super();// 必须使用这样的语法 外部类对象引用+.super
        System.out.println("继承自内部类的类");
    }
    public static void main(String[] args) {
        WithInner wi = new WithInner();
        InheritInner ii = new InheritInner(wi);
    }
} /*
外部类
内部类
继承自内部类的类*/

 

内部类不能被重写,如下,此时A.Inner 和 B.Inner是毫不相关的两个类。

class A { class Inner {} }
class B extends A { class Inner {} }

继承类的内部类可以继承自基类的内部类 此时不再需要上面继承内部类的构造器

class A {
    class B { }
}

class A1 extends A {
    class B extends A.B { }
}

 

内部类的名字

每个类都会生成一个.class文件。内部类的名字是:外部类名$内部类名.class,匿名内部类也有名字,外部类名$+一个数字来简单标识。

posted @ 2016-04-13 17:36  我不吃饼干呀  阅读(796)  评论(0编辑  收藏  举报