
class KusoString {
    public KusoString(String text) {
		this.text = text;
		this.hashValue = this.hashCode();
	}

	private final int hashValue;
	private final String text;

	@Override
	public boolean equals(Object arg0) {
		if ( arg0 == null || !(arg0 instanceof KusoString) )
			return false;
		KusoString other = (KusoString)arg0;

		if ( this.hashValue != 0 && other.hashValue != 0 && this.hashValue != other.hashValue )
			return false;

		if ( this.text == null && other.text == null )
			return true;
		if ( this.text == null && other.text != null )
			return false;
		if ( this.text != null && other.text == null )
			return false;

		assert this.text != null && other.text != null;
		if ( this.text.length() != other.text.length() )
			return false;

		for ( int i = 0; i < this.text.length(); i++ ) {
			if ( this.text.charAt(i) != other.text.charAt(i) )
				return false;
		}
		
		return true;
	}

	@Override
	public int hashCode() {
		return this.text.hashCode();
	}
}

class Program {
	public static void main(String[] args) throws Exception {
		StringBuilder sb = new StringBuilder();
		for ( int i = 0; i < 256 * 1024; i++ )
			sb.append('a');
		KusoString t1 = new KusoString(sb.toString() + '1');
		KusoString t2 = new KusoString(sb.toString() + '1');
		KusoString t3 = new KusoString(sb.toString() + '2');
		System.out.printf("%s\n", t1.equals(t2));
		
		System.out.printf("ちょっとテスト\n");
		test(t1, t2);

		System.out.printf("全比較したとき\n");
		test(t1, t2);
		System.out.printf("ハッシュ比較で済んだとき\n");
		test(t1, t3);
	}

	private static void test(KusoString t1, KusoString t2) {
		final int N = 1000 * 1;
		long ts = System.currentTimeMillis();

		boolean b = false;
		for ( int i = 0; i < N; i++ )
			b |= t1.equals(t2);
		
		long te = System.currentTimeMillis();
		System.out.printf("    %.1fus\n", (double)(te - ts) / N * 1000, b);
	}
}

