java中的内部类

来源:互联网 发布:数据库订单管理模板 编辑:程序博客网 时间:2024/06/15 03:31

可将一个类定义置入另一个类定义中。这就叫作“内部类”。内部类对我们非常有用,因为利用它可对那些逻辑上相互联系的类进行分组,并可控制一个类在另一个类里的“可见性”。

为何要使用内部类,有以下比较基本的原因:

(1) 我们准备实现某种形式的接口,使自己能创建和返回一个句柄。

(2) 要解决一个复杂的问题,并希望创建一个类,用来辅助自己的程序方案。同时不愿意把它公开。(通过内部类隐藏实施细节)

基本注意点

1.普通类(指的是非内部类)不可设为private或 protected——只允许 public或者“友好的”,而内部类可以,这么做可将具体的实施细节完全隐藏起来。

2.对于局部内部类和匿名类(尤其是if语句内的局部内部类),并不意味着内部类是有条件创建的——它会随同其他所有东西得到编译。然而,在定义它的那个作用域之外,它是不可使用的。

3.对于局部内部类和匿名类,和局部变量一样,不能被public,protected,private和static修饰。局部内部类(含匿名类)只能访问局部方法中定义的final类型的局部变量。(注意:这里说的是所处方法作用域内的局部变量,如果是外部类中的局部变量,可直接使用)

4.非static内部类不能定义static变量,除非是final类型。

5.内部类拥有对封装类所有元素的访问权限。(当然,如果内部类是static的,必须变量也是static的。究其原因,静态内部类没有指向外部的引用)

6.一般来说,接口中不能有具体实现。但内部类可以作为接口的一部分。(通常是static内部类,否则可能没有实际意义。)

Java中的内部类共分为四种

成员内部类member inner class

局部内部类local inner class

匿名内部类anonymous inner class

静态内部类static inner class (also called nested class)

下面详细介绍:

成员内部类

成员内部类基本用法

abstract class Contents {abstract public int value();}interface Destination {String readLabel();}class Parcel3 {private class PContents extends Contents {private int i = 11;public int value() {return i; }    }protected class PDestination implements Destination {private String label;private PDestination(String whereTo) {label = whereTo;}public String readLabel() {return label; }}    public Destination dest(String s) {    return new PDestination(s);}public Contents cont() {return new PContents();}} public static void Test2(){    Parcel3 p = new Parcel3();    Contents c = p.cont();    Destination d = p.dest("Tanzania");    // Illegal -- can't access private class:    //! Parcel3.PContents c = p.new PContents();    }

局部内部类

在一个方法内定义内部类

class Parcel4 {public Destination dest(String s) {class PDestination implements Destination {private String label;private PDestination(String whereTo) {label = whereTo;}public String readLabel() { return label; }}return new PDestination(s);}public static void main(String[] args) {Parcel4 p = new Parcel4();Destination d = p.dest("Tanzania");}}

在任意作用域内定义内部类

class Parcel5 {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("slip");String s = ts.getSlip();}// TrackingSlip ts = new TrackingSlip("x");//不可访问,超出作用域}public void track() { internalTracking(true);}public static void main(String[] args) {Parcel5 p = new Parcel5();p.track();}}

匿名内部类

匿名内部类就是没有名字的局部内部类,不使用关键字class, extends, implements, 没有构造方法。匿名内部类隐式地继承了一个父类或者实现了一个接口。也就是说,匿名类可以继承一个基础类,也可以实现一个接口,但不需要使用关键字,而是直接覆盖父类。但匿名内部类不能同时实现一个接口和继承一个类,也不能实现多个接口。如果匿名类实现了一个接口,该类是Object类的直接子类。

匿名内部类基本用法

class Wrapping {private int i;public Wrapping(int x) { i = x; }public int value() { return i;}} interface Wrapping2 {public int value();}//匿名类class Parcel7 {public Wrapping wrap(int x) {// Base constructor call:return new Wrapping(x){public int value() {return super.value() * 47;}}; // Semicolon required}public Wrapping2 wrap2() {//既可以是一个基础类,也可以是一个接口return new Wrapping2(){public int value() {return 0;}};}public static void main(String[] args) {Parcel7 p = new Parcel7();Wrapping w = p.wrap(10);Wrapping2 w2=p.wrap2();}}

匿名内部类不可以有构造方法,但还是可以对变量进行初始化的。

匿名类变量初始化

class Parcel8 {// Argument must be final to use inside// anonymous inner class:public Destination dest(final String dest) {return new Destination() {private String label = dest;public String readLabel() {return label;}};}public static void main(String[] args) {Parcel8 p = new Parcel8();Destination d = p.dest("Tanzania");System.out.println(d.readLabel());}}
利用构造代码块初始化
class Parcel9 {public Destination dest(final String dest) {return new Destination() {{   System.out.println("代码块初始化!");}private String label = dest;public String readLabel() { return label;}};}public static void main(String[] args) {Parcel9 p = new Parcel9();Destination d = p.dest("Tanzania");}}
但构造代码块毕竟不是构造器,不能进行过载。

静态内部类

static内部类并不是说一个内部类是static 的。static内部类意味着:

(1) 创建一个 static内部类的对象,我们不需要一个外部类对象。

(2) 不能从 static内部类的一个对象中访问一个外部类对象。(除非该对象是static的)

静态内部类基本用法

class Parcel10 {//public int a=0;public static int a=0;private static class PContents extends Contents {private int i = 11;public int value() { return i; }}protected static class PDestination implements Destination {private String label;private PDestination(String whereTo) {label = whereTo;}public String readLabel() { return label; }}public static Destination dest(String s) {return new PDestination(s);}public static Contents cont() {return new PContents();}public static Parcel101 getP(){return new Parcel101();}public static int getA(){return a; //a也必须是static}public static void main(String[] args) {Contents c = cont();Destination d = dest("Tanzania");//这里没有显示调用static内部类,但方法是static,所以内部类必须是static的Parcel101 p= getP();//外部类没有static一说,可直接使用int b=getA();//变量同理,由于方法是static,因此变量必须是static}}

接口中的静态内部类

以下为接口中内部类的一种用法,利用内部类编写公用测试方法。

class QuestionMain implements ITest{    public static void main(String[] args) {        ITest.TestInternal.test(new QuestionMain());    }    public void print() {        System.out.println("QuestionMain.print");    }}//接口中的内部类interface ITest {    void print();    public static class TestInternal {        public static void test(ITest test) {            test.print();        }    }}

除此之外,内部类还有一些其它特性


链接到外部类

interface Selector {boolean end();Object current();void next();}class Sequence {private Object[] o;private int next = 0;public Sequence(int size) {o = new Object[size];}public void add(Object x) {if(next < o.length) {o[next] = x;next++;}}private class SSelector implements Selector {int i = 0;public boolean end() {return i == o.length;}public Object current() {return o[i];}public void next() {if(i < o.length) i++;}}public Selector getSelector() {return new SSelector();}public static void main(String[] args) {Sequence s = new Sequence(10);for(int i = 0; i < 10; i++)s.add(Integer.toString(i));Selector sl = s.getSelector();while(!sl.end()) {System.out.println((String)sl.current());sl.next();}}}

引用外部类对象

class Parcel11 {int a=1;int b=1;class Contents {private int i = 11;public int value() {return i; }}class Destination {int a=2;private String label;Destination(String whereTo) {label = whereTo;}                       String readLabel() {return label; }void getValue(){System.out.println(this.a);//this指向的是内部类//System.out.println(this.b); //内部类中无此值}}public static void main(String[] args) {Parcel11 p = new Parcel11();Parcel11.Contents c = p.new Contents();//非static的内部类必须通过外部类引用Parcel11.Destination d =p.new Destination("Tanzania");//不能绕过外部类直接为非static的开辟空间,所以采用这种写法d.getValue();//Parcel11.Contents c2 = new Parcel11.Contents(); //报错}}

内部类继承

内部类继承比较特殊,子类必须有一个构造方法,且把外部类的一个对象作为参数。只有这样,才能保证内部类正常创建。

class WithInner {class Inner {}}class InheritInner extends WithInner.Inner {//! InheritInner() {} // Won't compileInheritInner(WithInner wi) {wi.super();    }public static void main(String[] args) {WithInner wi = new WithInner();InheritInner ii = new InheritInner(wi);}<strong>}</strong>

外部类被继承,内部类是否被覆盖

例子如下,被继承的只是外部类,子类中有一个和内部类同名的内部类,但这两个内部类并不存在继承关系

class Egg {protected class Yolk {public Yolk() {System.out.println("Egg.Yolk()");}}private Yolk y;public Egg() {System.out.println("New Egg()");y = new Yolk();}}class BigEgg extends Egg {public class Yolk {public Yolk() {System.out.println("BigEgg.Yolk()");}}public static void main(String[] args) {new BigEgg();}} 

输出如下,Yolk并没有被继承

New Egg()Egg.Yolk()

如果希望内部类也被继承,需要改动程序(这里是内部类继承内部类,同时外部类继承外部类,注意与上文的外部类继承内部类区分开来。)

class Egg2 {protected class Yolk {public Yolk() {System.out.println("Egg2.Yolk()");}public void f() {System.out.println("Egg2.Yolk.f()");}}private Yolk y = new Yolk();public Egg2() {System.out.println("New Egg2()");}public void insertYolk(Yolk yy) { y = yy; }public void g() { y.f();}}class BigEgg2 extends Egg2 {public class Yolk extends Egg2.Yolk {public Yolk() {System.out.println("BigEgg2.Yolk()");}public void f() {System.out.println("BigEgg2.Yolk.f()");}}public BigEgg2() { insertYolk(new Yolk());}public static void main(String[] args) {Egg2 e2 = new BigEgg2();e2.g();}}

输出如下,Yolk方法被覆盖

Egg2.Yolk()New Egg2()Egg2.Yolk()BigEgg2.Yolk()BigEgg2.Yolk.f()

利用内部类控制框架


内部类可以做这些事情:

(1) 在单独一个类里表达一个控制框架应用的全部实施细节,从而完整地封装与那个实施有关的所有东西。内部类用于表达多种不同类型的action(),它们用于解决实际的问题。除此以外,后续的例子使用了private内部类,所以实施细节会完全隐藏起来,可以安全地修改。
(2) 内部类使我们具体的实施变得更加巧妙,因为能方便地访问外部类的任何成员。若不具备这种能力,代码看起来就可能没那么使人舒服,最后不得不寻找其他方法解决。

例子:

abstract class Event {private long evtTime;public Event(long eventTime) {evtTime = eventTime;}public boolean ready() {return System.currentTimeMillis() >= evtTime;}abstract public void action();abstract public String description();}class EventSet {private Event[] events = new Event[100];private int index = 0;private int next = 0;public void add(Event e) {if(index >= events.length)return; // (In real life, throw exception)events[index++] = e;}public Event getNext() {boolean looped = false;int start = next;do {next = (next + 1) % events.length;// See if it has looped to the beginning:if(start == next) looped = true;// If it loops past start, the list// is empty:if((next == (start + 1) % events.length)&& looped)return null;} while(events[next] == null);return events[next];}public void removeCurrent() {events[next] = null;}}class Controller {private EventSet es = new EventSet();public void addEvent(Event c) { es.add(c);}public void run() {Event e;while((e = es.getNext()) != null) {if(e.ready()) {e.action();System.out.println(e.description());es.removeCurrent();}}}} class GreenhouseControls extends Controller {private boolean light = false;private boolean water = false;private String thermostat = "Day";private class LightOn extends Event {LightOn(long eventTime) {super(eventTime);}public void action() {// Put hardware control code here to// physically turn on the light.light = true;}public String description() {return "Light is on";}}private class LightOff extends Event {public LightOff(long eventTime) {super(eventTime);}public void action() {// Put hardware control code here to// physically turn off the light.light = false;}public String description() {return "Light is off";}}private class WaterOn extends Event {public WaterOn(long eventTime) {super(eventTime);}public void action() {// Put hardware control code herewater = true;}public String description() {return "Greenhouse water is on";}}private class WaterOff extends Event {public WaterOff(long eventTime) {super(eventTime);}public void action() {// Put hardware control code herewater = false;}public String description() {return "Greenhouse water is off";}}private class ThermostatNight extends Event {public ThermostatNight(long eventTime) {super(eventTime);}public void action() {// Put hardware control code herethermostat = "Night";}public String description() {return "Thermostat on night setting";}}private class ThermostatDay extends Event {public ThermostatDay(long eventTime) {super(eventTime);}public void action() {// Put hardware control code herethermostat = "Day";}public String description() {return "Thermostat on day setting";}}// An example of an action() that inserts a// new one of itself into the event list:private int rings;private class Bell extends Event {public Bell(long eventTime) {super(eventTime);}public void action() {// Ring bell every 2 seconds, rings times:System.out.println("Bing!");if(--rings > 0)addEvent(new Bell(System.currentTimeMillis() + 2000));}public String description() {return "Ring bell";}}private class Restart extends Event {public Restart(long eventTime) {super(eventTime);}public void action() {long tm = System.currentTimeMillis();// Instead of hard-wiring, you could parse// configuration information from a text// file here:rings = 5;addEvent(new ThermostatNight(tm));addEvent(new LightOn(tm + 1000));addEvent(new LightOff(tm + 2000));addEvent(new WaterOn(tm + 3000));addEvent(new WaterOff(tm + 8000));addEvent(new Bell(tm + 9000));addEvent(new ThermostatDay(tm + 10000));// Can even add a Restart object!addEvent(new Restart(tm + 20000));}public String description() {return "Restarting system";}}public static void main(String[] args) {GreenhouseControls gc =new GreenhouseControls();long tm = System.currentTimeMillis();gc.addEvent(gc.new Restart(tm));gc.run();}} 

0 0
原创粉丝点击