// Examples from "The Java Programming Language", 3rd edition
import java.util.*;
import java.io.*;

//----------
// 5.2.2: Extending inner classes

class Outer {
	public int x;
	class Inner {
		Inner() { x = 1; }
	}
}

// Normal case: extend both Outer and Inner
class ExtendedOuter extends Outer {
	class ExtendedInner extends Inner {}
	Inner ref = new ExtendedInner();
}

// Strange case: unrelated class extends Inner, must provide context
class Unrelated extends Outer.Inner {
	Unrelated() {
		// In order for the superclasses' constructor to work,
		// it needs a reference to its enclosing scope; a reference to the 
		// left hand side of the x.super() below is saved behind the
		// scenes.
		(new Outer()).super();
		// x = 5;       doesn't compile
	}
}


//----------
// 5.6.1: Interfaces can do work!

interface SharedData {
	class Data {
		private int x = 0;
		public int getX() { return x; }
		public void setX(int newX) { x = newX; }
	}
	Data data = new Data();		// final by default, since this is an interface
}

// Another way interfaces can do work - use a static inner class.

//: c08:IInterface.java
// From 'Thinking in Java, 2nd ed.' by Bruce Eckel
// www.BruceEckel.com. See copyright notice in CopyRight.txt.
// Static inner classes inside interfaces.

interface IInterface {
  static class Inner {
    int i, j, k;
    public Inner() {}
    void f() {}
  }
} ///:~

//---------
// 6.1.1: \u0065 same as \uu0065, backslash u without four digits illegal even in comments!

class Demo {
	public static void main(String args[]) {
		// multiple u's allowed to enable transforming source
		// code between character sets without losing distinction
		// between 'A' and '\u0065'; see 6.1.1
		System.out.println("Is this legal: '\uuuuuuuuuuuuuuuuuuuuu0065'");
		// Note: \ u processing happens very early, *before* comment or quote processing!
		System.out.println("Is this legal: '\u0022);
	}
}

//---------
// Arrays are subclasses of java.lang.Object!

class Demo2 {
	public static void main(String args[]) {
		int bar[] = new int[10];
		bar[0] = 3;
		System.out.println("bar[0] = " + bar[0]);
		// Yes, you can clone arrays.  You have to cast the result.  It's a shallow clone.
		int bletch[] = (int []) bar.clone();
		System.out.println("bletch[0] = " + bletch[0]);
	}
}

//------------------------------
// Examples from "Thinking in Java", 2nd ed

//---------
// this is a bit odd, considering Strings are immutable,
// and finalness doesn't *really* insulate you from trouble...
// I bet they really wanted 'immutable' but couldn't have it.

//: c08:Parcel8.java
// From 'Thinking in Java, 2nd ed.' by Bruce Eckel
// www.BruceEckel.com. See copyright notice in CopyRight.txt.
// An anonymous inner class that performs 
// initialization. A briefer version
// of Parcel5.java.

public 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");
  }
} ///:~

//---------
// p. 476: Comparator or Comparable: comparing two int's is best done with
// if, not by subtracting their value... otherwise you can have overflow.
// (Not unique to java.)

//---------
// If an exception happens while processing another exception,
// the first exception is totally lost!
//: c10:LostMessage.java
// From 'Thinking in Java, 2nd ed.' by Bruce Eckel
// www.BruceEckel.com. See copyright notice in CopyRight.txt.
// How an exception can be lost.

class VeryImportantException extends Exception {
  public String toString() {
    return "A very important exception!";
  }
}

class HoHumException extends Exception {
  public String toString() {
    return "A trivial exception";
  }
}

public class LostMessage {
  void f() throws VeryImportantException {
    throw new VeryImportantException();
  }
  void dispose() throws HoHumException {
    throw new HoHumException();
  }
  public static void main(String[] args) 
      throws Exception {
    LostMessage lm = new LostMessage();
    try {
      lm.f();
    } finally {
      lm.dispose();
    }
  }
} ///:~


//---------
// p. 561: constructors don't have to declare the exceptions they throw;
// they can throw absolutely anything they want.

class MyException extends Exception { };
class YourException extends Exception { };
class ThrowSomething {
	public ThrowSomething() throws MyException {};
	public void blort() throws MyException {};
}
public class ThrowAnything extends ThrowSomething {
	// constructors can add exceptions that the base class doesn't throw
	public ThrowAnything() throws MyException, YourException {
		throw new YourException();
	}
	// but regular methods can't; following won't compile
	public void blort() throws MyException, YourException {};
}

//-------
// Contributed by x@xman.org
// foo.equals(bar) is by default (foo == bar), which only returns
// true if foo and bar are the same Object -- sometimes not what you expected.

public class ArrayEquals {
	static class foo {
		int x;
		public foo(int a) { x = a; }
	};

	public static boolean contentsAreEqual(final foo[] listA, final foo[] listB) {
		if (listA.length != listB.length)
			return false;
		for (int i = 0; i < listA.length; i++)
			if (!listA[i].equals(listB[i]))
				return false;
		return true;
	}

	public static void main(String args[]) {
		foo[] listA = new foo[1];
		listA[0] = new foo(8);
		foo[] listB = new foo[listA.length];
		System.arraycopy(listA, 0, listB, 0, listA.length);

		System.out.println("listA == listB:" + (listA == listB));
		System.out.println("listA.equals(listB): " + listA.equals(listB));
		System.out.println("contentsAreEqual(listA,listB): " + contentsAreEqual(listA, listB));
	}
}

//--------
// From http://gee.cs.oswego.edu/dl/html/javaCodingStd.html
/* 
 Avoid overloading methods on argument type. (Overriding on arity is OK,
 as in having a one-argument version versus a two-argument version). If
 you need to specialize behavior according to the class of an argument,
 consider instead choosing a general type for the nominal argument type
 (often Object) and using conditionals checking instanceof. Alternatives
 include techniques such as double-dispatching, or often best,
 reformulating methods (and/or those of their arguments) to remove
 dependence on exact argument type.

 Rationale: Java method resolution is static; based on the listed
 types, not the actual types of argument. This is compounded
 in the case of non-Object types with coercion charts. In both
 cases, most programmers have not committed the matching rules to
 memory. The results can be counterintuitive; thus the source of
 subtle errors. 
 For example, try to predict the output of this. Then compile and run.
*/
      class Classifier {
        String identify(Object x)  { return "object"; }
        String identify(Integer x) { return "integer"; }
      }

      class Relay {
        String relay(Object obj) { return (new Classifier()).identify(obj); }
      }

      public class App {
        public static void main(String[] args) {
          Relay relayer = new Relay();
          Integer i = new Integer(17);
          System.out.println(relayer.relay(i));
        }
      }
