Java内部类和匿名类

内部类:在其他类中类

匿名类:一种特殊的内部类,它没有类名

内部类的定义

  1. 将类的定义置于一个类的内部即可
  2. 编译器生成xxx$xxx(外部类名$内部类名)这样的class文件
  3. 内部类不能够与外部类同名

内部类的使用:

  1. 在封装它的类的内部使用内部类,与使用普通类的使用方式相同
  2. 在其他地方使用
    1. 类名前要冠以外部类的名字
    2. 在用new创建内部类时,也要在new前面冠以对象变量(外部对象.new 内部类名(参数))
package study;

public class TestInnerClass {
    public static void main(String[] args){
        Parcel p = new Parcel();
        p.testShip();

        Parcel.Contents c = p.new Contents(33);     // 外面使用内部类
        Parcel.Destination d = p.new Destination("Hawii");
        p.setProperty(c, d);
        p.ship();
    }
}

class Parcel{
    private Contents c;
    private Destination d;
    class Contents{
        private int i;
        Contents(int i){ this.i = i;}
        int value(){return i;}
    }
    class Destination{
        private String label;
        Destination(String whereTo){ label = whereTo;}
        String readLabel(){ return label; }
    }
    void setProperty(Contents c, Destination d){
        this.c = c; this.d = d;
    }
    void ship(){
        System.out.println("move " + c.value() + " to " + d.readLabel());
    }
    public void testShip(){
        c = new Contents(22);       // 里面使用内部类
        d = new Destination("Beijing");
        ship();
    }
}

/*
move 22 to Beijing
move 33 to Hawii
*/

在内部类中使用外部类的成员

  1. 内部类中可以直接访问外部类的字段及方法,即使private也可以
  2. 如果内部类中有与外部类同名的字段和方法,则可以使用【外部类名.this.字段或方法】
package study;

public class TestInnerThis {
    public static void main(String [] args){
        A a = new A();
        A.B b = a.new B();
        b.mb(333);
    }
}

class A{
    private int s = 111;

    public class B {
        private int s = 222;
        public void mb(int s){
            System.out.println(s);  // 局部变量s
            System.out.println(this.s); // 内部类对象属性s
            System.out.println(A.this.s);   // 外层类对象属性s
        }
    }
}

/*
333
222
111
*/

内部类的修饰符

  1. 内部类与类中的字段、方法一样是外部类的成员,它的前面也可以有访问控制符和其他修饰符
  2. 访问控制符:public、protected、默认以及private(外部类只能够使用public或默认修饰)
  3. final和abstract:分别表示不可继承的和抽象的

static修饰内部类

  1. 用static修饰内部类,表明该内部类实际是一种外部类,因为它与外部类的实例无关
  2. 有人认为static的类是嵌套类,不是内部类(和普通的内部类区分)
  3. static类在使用时:
    1. 实例化static类时,在new前面不需要用对象实例变量
    2. static类中不能访问其外部类的非static的字段及方法,即只能够访问static成员
  4. static方法中不能访问非static的域及方法,也不能够不带前缀地new一个非static的内部类
    package study;
    
    public class TestInnerStatic {
        public static void main(String[] args){
            A.B a_b = new A().new B();  // ok
            A a = new A();
            A.B ab = a.new B();
    
            Outer.Inner oi = new Outer.Inner();
            // Outer.Inner oi2 = Outer.new Inner();     // !!! error
            // Outer.Inner oi3 = new Outer().new Inner();   // !!! error
        }
    }
    
    class A
    {
        private int x;
        void m(){
            new B();
        }
        static void sm(){
            // new B(); // error!!!
        }
        class B
        {
            B(){x=5;}
        }
    }
    
    class Outer
    {
        static class Inner{}
    }

局部类:在一个方法中也可以定义类,这种类称为方法中的内部类,或者叫局部类

  1. 和局部变量一样,方法中的内部类不能用public、private、protected、static修饰,但可以被final或者abstract修饰
  2. 可以访问其外部类的成员,但不能访问该方法的局部变量,除非是final局部变量
class Outer{
    private int size = 5;
    public Object makeTheInner(int localVar)
    {
        final int finalLocalVar = 99;
        class Inner
        {
            public String toString()
            {
                return ("InnerSize: " + size +
                        // "localVar: " + localVar +    // error!
                        " finalLocalVar: " + finalLocalVar);
            }
        }
        return new Inner();
    }
}

匿名类:一种特殊的内部类,它没有类名,在定义类的同时就生成该对象的实例,是“一次性使用”的类

class Outer{
    private int size = 5;
    public Object makeTheInner(int localVar)
    {
        final int finalLocalVar = 99;
        return new Object()
        {
            public String toString()
            {
                 return ("InnerSize: " + size +
                        " finalLocalVar: " + finalLocalVar);
            }
        }
    }
}

匿名类的使用

  1. 不取名字,直接用其父类或接口的名字。也就是说该类是父类的子类,或者实现了一个接口,编译器自动生成xxx$1之类的名字
  2. 类的定义的同时就创建实例,即类的定义前面还有一个new关键字
    1. new 类名或接口名(){...}
    2. 不使用关键词class,也不使用extends及implements
  3. 在构造对象时使用父类的构造方法
    1. 不能定义构造方法,因为它没有名字
    2. 如果new对象时,要带参数,则使用父类的构造方法

你可能感兴趣的:(Java)