《JAVA编程思想》学习备忘(p345 Inner Classes-1)

It's possible to place a class definition within another class definition.This is called an inner class.

The inner class is a valuable feature because it allows you to group classes that logically belong together and to control the visibility of one within the other.

creating inner classes

示例:

public class Parcel1 {
 class Contents{
  private int i = 11;
  public int value(){return i;}
 }
 class Destination{
  private String label;
  Destination(String whereTo){
   label = whereTo;
  }
  String readLabel(){return label;}
 }
 // Using inner classes looks just like
 // using any other class,within Parcel1:
 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");
 }
}

输出:

Tasmania

More typically,an outer class will have a method that returns a reference to an inner class:

public class Parcel2 {
 class Contents{
  private int i = 11;
  public int value(){return i;}
 }
 class Destination{
  private String label;
  Destination(String whereTo){
   label = whereTo;
  }
  String readLabel(){return label;}
 }
 public Destination to(String s){
  return new Destination(s);
 }
 public Contents contents(){
  return new Contents();
 }
 public void ship(String dest){
  Contents c = new Contents();
  Destination d = to(dest);
  System.out.println(d.readLabel());
 }
 public static void main(String[] args) {
  Parcel2 p = new Parcel2();
  p.ship("Tasmania");
  Parcel2 q = new Parcel2();
  // Defining references to inner classes:
  Parcel2.Contents c = q.contents();
  Parcel2.Destination d = q.to("Borneo");
 }
}

输出:

Tasmania
If you want to make an object of the inner class anywhere except from within a non-static method of the outer class,you must specify the type of that object as OuterClassName.InnerClassName,as seen in main().

 

The link to the outer class

...In addition,inner classes have access rights to all the elements in the enclosing class:

public interface Selector {
 boolean end();
 Object current();
 void next();
}

public class Sequence {
 private Object[] items;
 private int next = 0;

 public Sequence(int size) {
  items = new Object[size];
 }

 public void add(Object x) {
  if (next < items.length) {
   items[next++] = x;
  }
 }

 private class SquenceSelector implements Selector {
  private int i = 0;

  public Object current() {
   return items[i];
  }

  public boolean end() {
   return i == items.length;
  }

  public void next() {
   if (i < items.length)
    i++;
  }
 }

 public Selector selector() {
  return new SquenceSelector();
 }

 public static void main(String[] args) {
  Sequence sequence = new Sequence(10);
  for (int i = 0; i < 10; i++)
   sequence.add(Integer.toString(i));
  Selector selector = sequence.selector();
  while (!selector.end()) {
   System.out.print(selector.current() + " ");
   selector.next();
  }
 }
}

输出:

0 1 2 3 4 5 6 7 8 9

So an inner class has automatic access to the members of the enclosing class.

 

Using .this and .new

If you need to produce the reference to the outer-class object,you name the outer class followed by a dot and this.

示例:

public class DotThis {
 void f(){
  System.out.println("DotThis.f()");
 }
 public class Inner{
  public DotThis outer(){
   return DotThis.this;//A plain "this" would be Inner's "this"
  }
 }
 public Inner inner(){return new Inner();}
 public static void main(String[] args) {
  DotThis dt = new DotThis();
  DotThis.Inner dti = dt.inner();
  dti.outer().f();
 }
}

输出:

DotThis.f()

Sometimes you want to tell some other object to create an object of one of its inner classes.To do this you must provide a refrence to the other outer-class object in the new expression,using the .new syntax,like this:

public class DotNew {
 public class Inner{}
 public static void main(String[] args){
  DotNew dn = new DotNew();
  DotNew.Inner dni = dn.new Inner();
 }
}

Here,you see the use of .new applied to the "Parcel" example:

public class Parcel3 {
 class Contents{
  private int i = 11;
  public int value(){return i;}
 }
 class Destination{
  private String label;
  Destination(String whereTo){label=whereTo;}
  String readLabel(){return label;}
 }
 public static void main(String[] args) {
  Parcel3 p = new Parcel3();
  //Must use instance of outer class
  //to create an instance of the inner class:
  Parcel3.Contents c = p.new Contents();
  Parcel3.Destination d = p.new Destination("Tasmania");
 }
}

 

Inner classes and upcasting

示例:

public interface Destination {
 String readLabel();
}

public interface Contents {
    int value();
}

public class Parcel4 {
 private class PContents implements 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 destination(String s){
  return new PDestination(s);
 }
 public Contents contents(){
  return new PContents();
 }
}
public class TestParcel {
 public static void main(String[] args) {
  Parcel4 p = new Parcel4();
  Contents c = p.contents();
  Destination d = p.destination("Tasmania");
  // Illegal -- can't access private class:
  // !Parcel4.PContents pc = p.new PContents();
 }
}

...the private inner class provides a way for the class designer to completely prevent any type-coding dependencies and to completely hide details about implementation.

 

Inner classes in methods and scopes

使用内置类的两个原因:

1.As shown previously,you're implementing an interface of some kinkd of that you can create and return a reference.

2.You're solving a complicated problem and you want to create a class to aid in your solution,but you don't want it publicly available.

The first example shows the creation of an entire class within the scope of a method(instead od the scope of another class).This is called a local inner class:

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

The next example shows how you can nest an inner class within any arbitary scope:

public class Parcel6 {
 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();
  }
  // Can't use it here! Out of scope:
  // ! TrackingSlip ts = new TrackingSlip("x");
 }

 public void track() {
  internalTracking(true);
 }

 public static void main(String[] args) {
  Parcel6 p = new Parcel6();
  p.track();
 }
}

Anonymous inner classes

下边的例子看起来有点奇怪:

public class Parcel7 {
 public Contents contents(){
  return new Contents(){
   //Insert a class definition
   private int i = 11;
   public int value(){return i;}
  };// Semicolon required in this case
 }
 public static void main(String[] args) {
  Parcel7 p = new Parcel7();
  Contents c = p.contents();
 }
}

The contents() method combines the creation of the return value with the definition of the class that represents that return value!In addition,the class is anonymous;it has no name.

What this strange syntax means is "Create an object of an anonymous class that's inherited from Contents."

public class Parcel7b {
 class MyContents implements Contents{
  private int i = 11;
  public int value() {return i;}
 }
 public Contents contents(){return new MyContents();};
 public static void main(String[] args) {
  Parcel7b p = new Parcel7b();
  Contents c = p.contents();
 }
}

In the anonymous inner class,Contents is created by using a default constructor.

The following code shows what to do if your base class needs a constructor with an argument:

public class Wrapping {
 private int i;
 public Wrapping(int x){i = x;}
 public int value(){return i;}
}

public class Parcel8 {
 public Wrapping wrapping(int x){
  //Base constructor call:
  return new Wrapping(x){// Pass constructor argument.
    public int value(){
     return super.value()*47;
    }
  };
 }
 public static void main(String[] args) {
  Parcel8 p = new Parcel8();
  Wrapping w = p.wrapping(10);
 }
}

That is,you simply pass the appropriate argument to the base-class constructor,seen here as the x passed in new Wrapping(x).Although it's an ordinary class with an implementation,Wrapping is also being used as a common "interface" to its derived classes:

public class Wrapping {
 private int i;
 public Wrapping(int x){i = x;}
 public int value(){return i;}
}

 

You can also perform initialization when you define fields in an anonymous class:

public class Parcel9 {
 // Argument must be final to use inside
 // anonymous inner class:
 public Destination destination(final String dest){
  return new Destination(){
   private String label = dest;
   public String readLabel(){return label;}
  };
 }
 public static void main(String[] args) {
  Parcel9 p = new Parcel9();
  Destination d = p.destination("Tasmania");
 }
}

If you're defining an anonymous inner class and want to use an object that's defined outside the anonymous inner class,the compiler requires that the argument reference be final.

As long as you're simply assigning a field,the approach in this example is fine.But what if you need to perform some constructor-like activity?You can't have a named constructor in an anonymous class(since there's no name!),but with instance initialization,you can,in effect,create a constructor for an anonymous inner class,like this:

abstract class Base {
 public Base(int i){
  System.out.println("Base constructor, 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");}
   public void f() {
    System.out.println("In anonymous f()");
   }};
 }
 public static void main(String[] args) {
  Base base = getBase(47);
  base.f();
 }
}

输出:

Base constructor, i = 47
Inside instance initializer
In anonymous f()

Here's the "parcel"theme with instance initialization.Note that the arguments to destination() must be final since they are used within the anonymous class:

public class Parcel10 {
 public Destination destination(final String dest, final float price) {
  return new Destination() {
   private int cost;
   // Instance initialization for each object:
   {
    cost = Math.round(price);
    if (cost > 100)
     System.out.println("Over budget!");
   }
   private String label = dest;

   public String readLabel() {
    return label;
   }
  };
 }

 public static void main(String[] args) {
  Parcel10 p = new Parcel10();
  Destination d = p.destination("Tasmania", 101.395F);
 }
}
输出:

Over budget!

(待续)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值