在Bruce Eckel的com.bruceeckel.simpletest包里面,有两个文件Test.java和OutputVerifier.java.
类Test和类OutputVerifier互相引用了。编译时分别出错。请问Java里面(或者更进一步说,面向对象语言里面)是否允许类的互相引用的?如果可以引用那么应该怎样编译通过呢?如果不允许,那么Bruce Eckel先生是否犯了一个错误?Test.java(用到OutputVerifier处加了//*******注释)//: com:bruceeckel:simpletest:Test.java
// Simple utility for testing program output. Intercepts
// System.out to print both to the console and a buffer.
// From 'Thinking in Java, 3rd ed.' (c) Bruce Eckel 2002
// www.BruceEckel.com. See copyright notice in CopyRight.txt.
package com.bruceeckel.simpletest;
import java.io.*;
import java.util.*;
import java.util.regex.*;public class Test {
// Bit-shifted so they can be added together:
public static final int
EXACT = 1 << 0, // Lines must match exactly
AT_LEAST = 1 << 1, // Must be at least these lines
IGNORE_ORDER = 1 << 2, // Ignore line order
WAIT = 1 << 3; // Delay until all lines are output
private String className;
private TestStream testStream;
public Test() {
// Discover the name of the class this
// object was created within:
className =
new Throwable().getStackTrace()[1].getClassName();
testStream = new TestStream(className);
}
public static List fileToList(String fname) {
ArrayList list = new ArrayList();
try {
BufferedReader in =
new BufferedReader(new FileReader(fname));
try {
String line;
while((line = in.readLine()) != null) {
if(fname.endsWith(".txt"))
list.add(line);
else
list.add(new TestExpression(line));
}
} finally {
in.close();
}
} catch (IOException e) {
throw new RuntimeException(e);
}
return list;
}
public static List arrayToList(Object[] array) {
List l = new ArrayList();
for(int i = 0; i < array.length; i++) {
if(array[i] instanceof TestExpression) {
TestExpression re = (TestExpression)array[i];
for(int j = 0; j < re.getNumber(); j++)
l.add(re);
} else {
l.add(new TestExpression(array[i].toString()));
}
}
return l;
}
public void expect(Object[] exp, int flags) {
if((flags & WAIT) != 0)
while(testStream.numOfLines < exp.length) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
List output = fileToList(className + "Output.txt");
if((flags & IGNORE_ORDER) == IGNORE_ORDER)
OutputVerifier.verifyIgnoreOrder(output, exp); //***********
else if((flags & AT_LEAST) == AT_LEAST)
OutputVerifier.verifyAtLeast(output, //*************
arrayToList(exp));
else
OutputVerifier.verify(output, arrayToList(exp));
// Clean up the output file - see c06:Detergent.java
testStream.openOutputFile();
}
public void expect(Object[] expected) {
expect(expected, EXACT);
}
public void expect(Object[] expectFirst,
String fname, int flags) {
List expected = fileToList(fname);
for(int i = 0; i < expectFirst.length; i++)
expected.add(i, expectFirst[i]);
expect(expected.toArray(), flags);
}
public void expect(Object[] expectFirst, String fname) {
expect(expectFirst, fname, EXACT);
}
public void expect(String fname) {
expect(new Object[] {}, fname, EXACT);
}
} ///:~
OutputVerifier.java (用到Test处加了//******注释)//: com:bruceeckel:simpletest:OutputVerifier.java
// From 'Thinking in Java, 3rd ed.' (c) Bruce Eckel 2002
// www.BruceEckel.com. See copyright notice in CopyRight.txt.
package com.bruceeckel.simpletest;
import java.util.*;
import java.io.PrintStream;public class OutputVerifier {
private static void verifyLength(
int output, int expected, int compare) {
if((compare == Test.EXACT && expected != output) //******
|| (compare == Test.AT_LEAST && output < expected))
throw new NumOfLinesException(expected, output);
}
public static void verify(List output, List expected) {
verifyLength(output.size(),expected.size(),Test.EXACT);
if(!expected.equals(output)) {
//find the line of mismatch
ListIterator it1 = expected.listIterator();
ListIterator it2 = output.listIterator();
while(it1.hasNext()
&& it2.hasNext()
&& it1.next().equals(it2.next()));
throw new LineMismatchException(
it1.nextIndex(), it1.previous().toString(),
it2.previous().toString());
}
}
public static void
verifyIgnoreOrder(List output, Object[] expected) {
verifyLength(expected.length,output.size(),Test.EXACT);
if(!(expected instanceof String[]))
throw new RuntimeException(
"IGNORE_ORDER only works with String objects");
String[] out = new String[output.size()];
Iterator it = output.iterator();
for(int i = 0; i < out.length; i++)
out[i] = it.next().toString();
Arrays.sort(out);
Arrays.sort(expected);
int i =0;
if(!Arrays.equals(expected, out)) {
while(expected[i].equals(out[i])) {i++;}
throw new SimpleTestException(
((String) out[i]).compareTo(expected[i]) < 0
? "output: <" + out[i] + ">"
: "expected: <" + expected[i] + ">");
}
}
public static void
verifyAtLeast(List output, List expected) {
verifyLength(output.size(), expected.size(),
Test.AT_LEAST);
if(!output.containsAll(expected)) {
ListIterator it = expected.listIterator();
while(output.contains(it.next())) {}
throw new SimpleTestException(
"expected: <" + it.previous().toString() + ">");
}
}
} ///:~
类Test和类OutputVerifier互相引用了。编译时分别出错。请问Java里面(或者更进一步说,面向对象语言里面)是否允许类的互相引用的?如果可以引用那么应该怎样编译通过呢?如果不允许,那么Bruce Eckel先生是否犯了一个错误?Test.java(用到OutputVerifier处加了//*******注释)//: com:bruceeckel:simpletest:Test.java
// Simple utility for testing program output. Intercepts
// System.out to print both to the console and a buffer.
// From 'Thinking in Java, 3rd ed.' (c) Bruce Eckel 2002
// www.BruceEckel.com. See copyright notice in CopyRight.txt.
package com.bruceeckel.simpletest;
import java.io.*;
import java.util.*;
import java.util.regex.*;public class Test {
// Bit-shifted so they can be added together:
public static final int
EXACT = 1 << 0, // Lines must match exactly
AT_LEAST = 1 << 1, // Must be at least these lines
IGNORE_ORDER = 1 << 2, // Ignore line order
WAIT = 1 << 3; // Delay until all lines are output
private String className;
private TestStream testStream;
public Test() {
// Discover the name of the class this
// object was created within:
className =
new Throwable().getStackTrace()[1].getClassName();
testStream = new TestStream(className);
}
public static List fileToList(String fname) {
ArrayList list = new ArrayList();
try {
BufferedReader in =
new BufferedReader(new FileReader(fname));
try {
String line;
while((line = in.readLine()) != null) {
if(fname.endsWith(".txt"))
list.add(line);
else
list.add(new TestExpression(line));
}
} finally {
in.close();
}
} catch (IOException e) {
throw new RuntimeException(e);
}
return list;
}
public static List arrayToList(Object[] array) {
List l = new ArrayList();
for(int i = 0; i < array.length; i++) {
if(array[i] instanceof TestExpression) {
TestExpression re = (TestExpression)array[i];
for(int j = 0; j < re.getNumber(); j++)
l.add(re);
} else {
l.add(new TestExpression(array[i].toString()));
}
}
return l;
}
public void expect(Object[] exp, int flags) {
if((flags & WAIT) != 0)
while(testStream.numOfLines < exp.length) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
List output = fileToList(className + "Output.txt");
if((flags & IGNORE_ORDER) == IGNORE_ORDER)
OutputVerifier.verifyIgnoreOrder(output, exp); //***********
else if((flags & AT_LEAST) == AT_LEAST)
OutputVerifier.verifyAtLeast(output, //*************
arrayToList(exp));
else
OutputVerifier.verify(output, arrayToList(exp));
// Clean up the output file - see c06:Detergent.java
testStream.openOutputFile();
}
public void expect(Object[] expected) {
expect(expected, EXACT);
}
public void expect(Object[] expectFirst,
String fname, int flags) {
List expected = fileToList(fname);
for(int i = 0; i < expectFirst.length; i++)
expected.add(i, expectFirst[i]);
expect(expected.toArray(), flags);
}
public void expect(Object[] expectFirst, String fname) {
expect(expectFirst, fname, EXACT);
}
public void expect(String fname) {
expect(new Object[] {}, fname, EXACT);
}
} ///:~
OutputVerifier.java (用到Test处加了//******注释)//: com:bruceeckel:simpletest:OutputVerifier.java
// From 'Thinking in Java, 3rd ed.' (c) Bruce Eckel 2002
// www.BruceEckel.com. See copyright notice in CopyRight.txt.
package com.bruceeckel.simpletest;
import java.util.*;
import java.io.PrintStream;public class OutputVerifier {
private static void verifyLength(
int output, int expected, int compare) {
if((compare == Test.EXACT && expected != output) //******
|| (compare == Test.AT_LEAST && output < expected))
throw new NumOfLinesException(expected, output);
}
public static void verify(List output, List expected) {
verifyLength(output.size(),expected.size(),Test.EXACT);
if(!expected.equals(output)) {
//find the line of mismatch
ListIterator it1 = expected.listIterator();
ListIterator it2 = output.listIterator();
while(it1.hasNext()
&& it2.hasNext()
&& it1.next().equals(it2.next()));
throw new LineMismatchException(
it1.nextIndex(), it1.previous().toString(),
it2.previous().toString());
}
}
public static void
verifyIgnoreOrder(List output, Object[] expected) {
verifyLength(expected.length,output.size(),Test.EXACT);
if(!(expected instanceof String[]))
throw new RuntimeException(
"IGNORE_ORDER only works with String objects");
String[] out = new String[output.size()];
Iterator it = output.iterator();
for(int i = 0; i < out.length; i++)
out[i] = it.next().toString();
Arrays.sort(out);
Arrays.sort(expected);
int i =0;
if(!Arrays.equals(expected, out)) {
while(expected[i].equals(out[i])) {i++;}
throw new SimpleTestException(
((String) out[i]).compareTo(expected[i]) < 0
? "output: <" + out[i] + ">"
: "expected: <" + expected[i] + ">");
}
}
public static void
verifyAtLeast(List output, List expected) {
verifyLength(output.size(), expected.size(),
Test.AT_LEAST);
if(!output.containsAll(expected)) {
ListIterator it = expected.listIterator();
while(output.contains(it.next())) {}
throw new SimpleTestException(
"expected: <" + it.previous().toString() + ">");
}
}
} ///:~
class first
{
public static void main(String[] args)
{
System.out.println("Hello ");
new second().printStr();
}
public void printStr(){
System.out.println("Hello ");
}
}class second
{
public static void main(String[] args)
{
System.out.println("World!");
new first().printStr();
}
public void printStr(){
System.out.println("World!");
}
}
如果两个函数之间互相引用的话也会出现问题
就相当于出现了一个没有结束条件的递归
会报stack overflow的错误比如把 nanfengJava(楠枫JAVA)的函数改成这样:class first
{
public static void main(String[] args)
{
System.out.println("Hello ");
new second().printStr();
}
public void printStr(){
System.out.println("Hello ");
new second().printStr();
}
}
class second
{
public static void main(String[] args)
{
System.out.println("World!");
new first().printStr();
}
public void printStr(){
System.out.println("World!");
new first().printStr();
}
}
如zhangqingqi82所言,一个一个编译是可以的。
如nanfengjava的程序,编译first.java的时候,系统会把second.java也编译了(有点奇怪)。
但是,我编译thinkingInJava的例程的时候,同样是两个类互相引用,系统却不会把其他文件也一起编译。原因不清楚。class first
{
public static void main(String[] args)
{
System.out.println("Hello ");
new second().printStr();
}
public void printStr(){
System.out.println("Hello ");
}
}class second
{
public static void main(String[] args)
{
System.out.println("World!");
new first().printStr();
}
public void printStr(){
System.out.println("World!");
}
}
它只是在OutputVerifier类中用了Test类的一个静态常量...
以及在Test类中调用了OutputVerifier静态方法,像这种方法和变量是可以直接由类名.名称来调用的.
不存在互相引用..
如果在Test类的构造函数中生成OutputVerifier的对象,而在OutputVerifier类的构造函数又生成TestOutputVerifier的对象,刚构成互相引用.