Java 内部类

Effective Java中嵌套类定义:嵌套类(nested class)是指被定义在另一个类的内部的类。嵌套类存在的目的应该只是为它的外围类(enclosing class)提供服务。
嵌套类有四种:静态成员类(static member class)、非静态成员类(nonstatic member class)、匿名类(anonymous class)和局部类(local class)。除了静态成员类之外,其他的都被称为内部类(inner class)。

静态成员类(嵌套类)

嵌套类:

  • 要创建嵌套类的对象,并不需要其外围类的对象
  • 不能从嵌套类的对象中访问非静态的外围类对象

普通内部类的字段与方法,只能放在类的外部外部层次上,所以普通的内部类不能有static数据和static字段,也不能包含嵌套类。但是嵌套类可以包含以上。

public class Parcel11 {
    private static class ParcelContents implements Contents {

        private int i = 11;

        @Override
        public int value() {
            return i;
        }
    }

    protected static class ParcelDestination implements Destination {

        private String label;

        private static int i = 9;

        private ParcelDestination(String whereTo) {
            label = whereTo;
        }

        @Override
        public String readLable() {
            return label;
        }

        /**
         * 嵌套类可以包含其他静态元素
         */
        public static void f() {
        }

        static class AnotherLevel {
            public static void f() {

            }

            static int x = 10;
        }
    }

    public static Destination destination(String s) {
        return new ParcelDestination(s);
    }

    public static Contents contents() {
        return new ParcelContents();
    }

    public static void main(String[] args) {
        Contents c = contents();
        Destination d = destination("Tasmania");
    }
}

非静态成员类(成员内部类)
public class Parcel1 {
    class Contents {
        private int i = 11;

        public int value() {
            return i;
        }
    }

    private class Destination {
        private String label;


        public Destination(String whereTo) {
            label = whereTo;
        }

        String readLabel() {
            return label;
        }

        class DestinationInner{

        }
    }

    public void ship(String dest) {
        Contents c = new Contents();
        Destination d = new Destination(dest);
        System.out.println(d.readLabel());
    }

    public static void main(String[] args) {
        Parcel1 p = new Parcel1();
        p.ship("Tasmania");
    }
}

内部类的访问修饰符可以是private、protected、prublic、默认

匿名类

常见用法:

  • 实现接口的匿名类
  • 扩展了有非默认构造器的类
  • 执行字段初始化
  • 通过实例初始化实现构造
实现接口的匿名类

示例

interface Contents {
    int value();
}
public class Parcel7 {
    public Contents contents() {
        return new Contents() {
            private int i = 10;

            @Override
            public int value() {
                return i;
            }
        };
    }

    public static void main(String[] args) {
        Parcel7 p = new Parcel7();
        Contents c = p.contents();
    }
}
扩展了有非默认构造器的类

示例

class Wrapping {
    private int i;

    public Wrapping(int i) {
        this.i = i;
    }

    public int value(){
        return i;
    }
}
public class Parcel8 {
    public Wrapping wrapping(int x) {
        return new Wrapping(x) {
            @Override
            public int value() {
                return super.value() * 47;
            }
        };
    }

    public static void main(String[] args) {
        Parcel8 p = new Parcel8();
        Wrapping w = p.wrapping(10);
        System.out.println(w.value());
    }
}
赋值和实例初始化实现构造

简单赋值效果,示例

interface Destination {
    String readLable();
}
public class Parcel9 {
    // JDK8以下方法中的参数需要final修饰
    public Destination destination(final String dest){
        return new Destination() {
            private String label = dest;
            @Override
            public String readLable() {
                return label;
            }
        };
    }

    public static void main(String[] args) {
        Parcel9 p = new Parcel9();
        Destination d = p.destination("yy");
    }
}

通过实例初始化,就能够达到为匿名内部类创建一个构造器的效果。示例

abstract class Base {
    public Base(int i) {
        System.out.println("Base construct,i = " + i);
    }
    public abstract void f();
}

public class AnonymousConstructor {
    public static Base getBase(int i){
        return new Base(i) {
            // 用于匿名内部类的初始化
            {
                System.out.println("Inside instance initializer");
            }
            @Override
            public void f() {
                System.out.println("In anonymous f()");
            }
        };
    }

    public static void main(String[] args) {
        Base base = getBase(47);
        base.f();
    }
}
局部内部类

常见用法:

  • 在方法的作用域内创建一个完整的类
  • 代码块中
在方法的作用域内创建一个完整的类

示例

interface Destination {
    String readLable();
}

public class Parcel5 {
    private int i = 5;
    public Destination destination(String s) {
        class PDestination implements Destination {
            private String label;

            private PDestination(String whereTo) {
                label = whereTo;
                System.out.println(i);
                // 使用外部类的i
                System.out.println(Parcel5.this.i);
            }

            @Override
            public String readLable() {
                return label;
            }
        }
        return new PDestination(s);
    }

    public static void main(String[] args) {
        Parcel5 p = new Parcel5();
        Destination d = p.destination("yy");
    }
}

注意事项

  • PDestination类是destination( )方法的一部分,而不是Parcel5的一部分。所以只能在destination( )方法体中使用。
  • 局部内部类访问外部类的成员使用:外部类名.this.成员名(Parcel5.this.i)。
  • 不能加访问修饰符,因为不是类成员
  • 局部内部类访问作用域内的局部变量,该局部变量需要使用final修饰(适用于JDK8以下)
  • 当需要一个已命名的构造器或者需要重载构造器
  • 使用局部内部类而不使用匿名内部类的另一个理由是,需要不止一个该内部类的对象
使用内部类的原因

每个内部类都能独立地继承自一个(接口的)实现,所以无论外围类是否已经继承了某个(接口的)实现,对于内部类都没有影响。
内部类使得多重继承的解决方案变得完整。

使用内部类可以获得的其他一些特性:

  1. 内部类可以有多个实例,每个实例都有自己的状态信息,并且与其外围类对象的信息相互独立。
  2. 在单个外围类中,可以让多个内部类以不同的方式实现同一个接口,或继承同一个类。
  3. 创建内部类对象的时刻并不依赖于外围类对象的创建。
  4. 内部类并没有令人迷惑的“is-a”关系;它就是一个独立的实体。
内部类的继承

实例1:

class WithInner {
    class Inner {

    }
}

public class InheritInner extends WithInner.Inner {
    /**
     * 当要生成一个构造器时,默认的构造器不能只是传递指向外围类对象的引用。必须在构造器内这样处理,程序才能编译通过。
     * @param wi
     */
    InheritInner(WithInner wi) {
        wi.super();
    }

    public static void main(String[] args) {
        WithInner wi = new WithInner();
        InheritInner ii = new InheritInner(wi);
    }
}

实例2:

class FirstOuter {
    FirstOuter(){
        System.out.println("Hello");
    }
    public class FirstInner {
        FirstInner(String s) {
            System.out.println("FirstOuter.FirstInner() " + s);
        }
    }
}

public class SecondOuter {
    public SecondOuter() {
        System.out.println("World");
    }

    public class SecondInner extends FirstOuter.FirstInner {
        SecondInner(FirstOuter x) {
            x.super("hello");
            System.out.println("SecondOuter.SecondInner()");
        }
    }

    public static void main(String[] args) {
        FirstOuter fo = new FirstOuter();
        SecondOuter so = new SecondOuter();
        SecondInner si = so.new SecondInner(fo);
    }
}
内部类覆盖
class Egg2 {
    public Egg2() {
        print("New Egg2");
    }

    protected class Yolk {
        public Yolk() {
            print("Egg2.Yolk()");
        }

        public void f() {
            print("Egg2.Yolk.f()");
        }
    }

    private Yolk y = new Yolk();



    public void insertYolk(Yolk yy) {
        y = yy;
    }

    public void g() {
        y.f();
    }
}

public class BigEgg2 extends Egg2 {
    public class Yolk extends Egg2.Yolk {
        public Yolk() {
            print("BigEgg2.Yolk()");
        }

        @Override
        public void f() {
            print("BigEgg2.Yolk.f()");
        }
    }

    public BigEgg2() {
        insertYolk(new Yolk());
    }

    public static void main(String[] args) {
        Egg2 e2 = new BigEgg2();
        e2.g();

        //Egg2 e = new Egg2();
    }
}

output:

Egg2.Yolk()
New Egg2
Egg2.Yolk()
BigEgg2.Yolk()
BigEgg2.Yolk.f()
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值