content:
The first quarter prints its own procedures second quarter to run the second virtual machine together to run the program Conclusion Reference Information About the author to the evaluation of this article
subscription:
DeveloperWorks News DeveloperWorks Subscribe (Subscribe CD and Download)
Chunsheng (Chuchuns@cn.ibm.com) IBM China Research Center January 2005
This article describes how to print out the program code itself.
The first section prints its own program Hearing such a programming topic: Output itself after the program executes itself. Of course, some conditional restrictions, the program refers to the program written in a source program file, the output is output to the console, only the most basic output function, such as the printf () function, Java system .out.println () function. Of course, you cannot read the source code file from the file system, which is a bit of Lai Lai. In short, it is a program that completes its source code with basic output functions with basic output functions. There is another limit that is not a restriction, the program always writes in the language, then there are several choices, let's use java!
The intuitive reflection of this issue sometimes has two extremes, one thinks too simple, and another very fast thinking will have a big conclude. There will be a person to point out the theory of this problem and the recursive function of the calculation theory (pay tribute!), Calculation theory, the map spirit is a distant thing, as if you can. But this problem is really a interesting question worth we are bored.
Try a matter, there is a class with Java, there is a main () function, grace, first look.
Listing 1. The simplest Java program
Public class printown {
Public static void main () {
//
}
}
Well, write a function to print out:
Public class printown {
Public static void main () {
P1 ();
}
Void p1 () {
System.out.println ("Public Class Printown {");
System.out.println ("Public Void Static Main ()");
System.out.println ("P1 ();");
System.out.println ("}");
}
}
Trouble, we print the program body with P1 (), but now the source code has changed, and the contents of the function p1 () is printed? Of course, P2 () can be written, which prints P1 (), but it is not getting rid of, but the problem becomes P2 () who is printed. If there is a "other person" to help me print this P2 () function content, then the problem solves it, I can go home. But now "others" have not come, the problem has to solve itself.
Wash it every morning, take the hair into the mirror, if you are enough and fully "scientific mind", do you realize that you observed the image inside the mirror? This is not "your real image, you observe the mirror. The image inside, the mirror feeds this "action" to your pupil, this result will be captured by the mirror ... This process is transmitted at speed. Of course, because of too much too fast, our eyes can't see this process. When I was a child, I played 2 face to face the face, and then observed the "mirror" in the mirror infinite extension? That is, we tried to observe the behavior of the object changed the observed object. What should I do if I have enough accurate observation? This is also good, take a photo, then you can see the photo. Ok! photo? ! The problem is a bit eyebrow. According to this idea, define a string array and function P1 () to save the program, and save it to the console in the process of saving.
STATIC STRING [] BUFF = New String [100];
Static int flag = 0;
STATIC VOID P1 (String S) {
BUF [Flag ] = S;
System.out.println (s);
}
In the main () function, save (photographed) by P1 () and output, now our program is like this, such as Listing 2.
Listing 2. Intermediate procedures
Package printown;
Public class mid {
STATIC STRING [] BUFF = New String [100];
Static int flag = 0;
STATIC VOID P1 (String S) {
BUF [Flag ] = S;
System.out.println (s);
}
Public static void main (String [] args) {
P1 ("package printown;");
P1 ("Public Class Mid {");
P1 ("static string [] buff = new string [100];");
P1 ("static int flag = 0;");
P1 ("");
P1 ("STATIC VOID P1 (String S) {");
P1 ("BUFF [Flag ] = S;");
P1 ("System.out.Println (s);");
P1 ("}");
P1 ("");
P1 ("Public Static void Main (String [] args) {");
}
}
Output result of the intermediate program of Listing 2
Package printown;
Public class mid {
STATIC STRING [] BUFF = New String [100];
Static int flag = 0;
STATIC VOID P1 (String S) {
BUF [Flag ] = S;
System.out.println (s);
}
Public static void main (String [] args) {
Well, it looks very good, now there is a bunch of P1 () calls, no output, because we have already saved the source code you need to output (note that this is the key to solving the problem), then do it, write one The P2 () function, simply take the saved thing, and put "P1 (" ", followed by" ")", after the output is OK. Here is a small problem that needs attention, if there is a string String S = "///" ";
In fact, the string only has 2 bytes, and the first 3rd "/" is a escape character. If you want to output four characters on the console, you have to conversion, it is not difficult to this, the following is the convert () function.
CONVERT () function
STATIC STRING Convert (String T) {
Char [] out = new char [t.length () * 3];
INT j = 0;
For (INT i = 0; i IF (T.Charat (I) == '//') {OUT [J] = '//'; OUT [J 1] = '//'; J = 2;} Else IF (t.Charat (i) == '/ ") {OUT [J] =' // '; OUT [J 1] =' /"; J = 2;} Else {OUT [J] = T.Charat (i); J ; } Return New String (Out, 0, J); } Now you can write the P2 () function to output that long string P1 (). P2 () function Static void p2 () { For (int i = 0; i System.out.println ("P1 (/" Convert (BUFF [I]) "/"); ") } } The P2 () function is executed immediately after a long string P1 ("×××××"). P1 ("Public Static void Main (String [] args) {"); P2 (); } } Execute it, ha, the result is good (limited to the space, you don't have it here), there is no output in the last 3 sentences. P2 (); } } So, where to output it, the P2 () function is undoubtedly the ideal. Last P2 () function Static void p2 () { For (int i = 0; i System.out.println ("P1 (/" Convert (BUFF [I]) "/"); ") } System.out.println ("p2 ();"); System.out.println ("}"); System.out.println ("}"); } Accordingly, we add corresponding P1 () execution statements in the main () function. Ok, we have completed our work. After the source program executes, we output yourself in the console, you can delete all source code at the source code editor, and then copy all from the console to copy again. I will do this, check whether the code is fully printed in the expected, if there is a problem, the editor will be keenly check. Don't worry about covering the initial work, WSAD5.0 provides a very good mechanism from "local history" to recover source code. The second quarter starts the second virtual machine to run the program and remember the expectation when the circle is in the circle when solving the last problem - if "others" can help me. After the programming entertainment after the previous section, this section will discuss a useful programming model: Start the second virtual machine in the program run to run the program part, and the two virtual machines communicate with each other, and finally complete the task. We will also discuss the scope and advantages and disadvantages of such a programming model. When do we need a second virtual machine? Through runtime.exec (), you can start the second virtual machine to run the Java program, then when you need this programming model instead of using a thread to complete it, an obvious use case is to run other Java as a container. When the program, this Java program runs in a separate virtual machine, with an independent process, such as test drivers. There are many discussions about processes and threads. This article does not intend to repeat this problem, but to note that threads are also called lightweight processes, and they have independent execution control like the process, and the operating system is responsible for scheduling The difference is that the thread has no independent storage space, but shares a storage space with other threads in the subsequent process, which makes the communication between the thread are far more than the process. Unless there is a special reason, the task of the program should be paid to the thread, not the re-open process is completed. The dual virtual machine model dual virtual machine model is running, as shown in the following figure, call Runtime.exec () in the primary class printown.TherVMMethod to start the second virtual machine, execute the printown.vmexecuter class, both sides come through Socket Communication, the primary class call sendMessage Send message to Vmexecuter, Vmexecuter feeds the result to the primary class. Thereby achieving cooperation between the two sides. Dual virtual machine model UML class diagram OtherVMMethod main execution class, create a Socket's Server side, and provides an interface to the VMExecuter sending a message, and finally, by sending a specific message indicates the Socket abort during the second virtual machine. Here is to send "over" messages. Vmexecuter is placed in the second virtual machine, except for its own execution, there is also an open, close Socket, read, write socket work. The readthread class is designed because the primary class needs to listen to messages from Vmexecuter, this action is blocking, so you need to put in the thread to perform monitoring. The streamout class is designed to receive the console output and exception information for the program running in the second virtual machine, and give the client a uniform transparent interface. The program is simple and implements the runnable interface to read the stream in the thread and output to the local console. Streamout class list Class Streamout Implements Runnable { String name; InputStream IS; Thread thread and THREAD THREAD; Public streamout (String Name, InputStream IS) { THIS.NAME = Name; this.is = IS; } Public void start () { Thread = new thread (this); Thread.start (); } Public void run () { Try { InputStreamReader ISR = New InputStreamReader (IS); BufferedReader Br = New BufferedReader (ISR); While (true) { String s = br.readline (); IF (s == NULL) Break; System.out.println ("[" Name "]" S); } Is.close (); } catch (exception ex) { System.out.println ("Problem Reading Stream" Name "...:" EX); EX.PrintStackTrace (); } } } Main control class Othervmmethod list Static final string main_class = "printown.vmexecute"; Static int port; Static PrintWriter Writer; Static BufferedReader Reader; / / Start a server socket and initialize the output stream Void connect () { Try { Serversocket Server; Server = new serversocket (port); Socket Socket = Server.Avept (); Writer = new printwriter (socket.getputstream (), true); New ReadThread (socket); } catch (ioexception e) { E.PrintStackTrace (); } } / / Send a message to the program executed in the second virtual machine Static void sendmessage (string s) { Writer.println (s); } // Used to read the standard console in the second virtual machine (System.out.Println ()) and exception output. Class readthread extends thread { PRIVATE SOCKET Socket; Public Readthread (Socket Socket) { This.socket = Socket; THIS.START (); } Public void run () { Try { ReadMessage (); } catch (exception e) { E.PrintStackTrace (); } } Void ReadMessage () throws oException { Reader = New BufferedReader New INPUTSTREAMREADER (Socket.getInputStream ())); Try { String line = NULL; WHILE ((line = reader.readline ())! = null) { System.out.println (line); } } finally { Reader.Close (); } } } Class Vmexecuter list in the second virtual machine Class vmexecuter { Private int port; private int flag = 0; PRIVATE SOCKET Socket; Private printwriter; Private buffredreader reader; Public static void main (String [] args) { New vmexecuter (). Run (args); } // Executive Private void run (string [] args) { Port = integer.parseint (args [0]); OpenClientSocket (); Try { String line = NULL; While (! (line = reader.readline ()). EqualsignoreCase ("over") { String OUT = ("P1 (/" Convert (Line) "/"); ") Writer.println (OUT); } } catch (ioexception e) { E.PrintStackTrace (); } finally { CloseClientSocket (); } } // Open the Socket Client, connect the Server terminal that is started in the first virtual machine Private void OpenClientSocket () { Try { Socket = New Socket ("LocalHost", Port); Writer = new printwriter (socket.getputstream (), true); Reader = New BufferedReader (socket.getinputStream ()); Return; } catch (unknownhostexception e) { E.PrintStackTrace (); } catch (ioexception e) { E.PrintStackTrace (); } } // Close Socket Private void closeclientsocket () { Try { Writer.close (); Reader.Close (); Socket.close (); } catch (ioexception e) { E.PrintStackTrace (); } } } When these are ready, we can string these work in the P2 () function of Printown.OtherVmmethod. Static void p2 () throws exception { Port = 6500; Runtime RT = runtime.getRuntime (); Process P = rt.exec ("Java Printown.Vmexecuter" port); Othervmmethod vm = new OtherVMMethod (); VM.Connect (); For (int i = 0; i SendMessage (BUFF [I]); } // Start 2 threads to receive the console output and error output of the second virtual machine, respectively. Streamout S1 = New Streamgobbler ("stdin", p.getinputStream ()); Streamout S2 = New StreamGobbler ("stderr", p.GeterrorStream ()); S1.Start (); s2.start (); SendMessage ("over"); p.WaitFor (); } We still string together throughout the programming model with tasks that implement the source code, although there is a bit of cow knife to kill chickens and is not a very suitable task. Another point is that in order not to violate the original restriction conditions, these classes have to be placed in a file, which makes the program look a bit long. Finally, since the procedure is longer, Write P1 ("") in the way of Ctrl C and Ctrl V, it is a bit inefficient. One principle is that any simple "physical strength" labor computer is very efficient, and computer that requires "brain" labor often difficult to respond, such as Go. I wrote such a small program, output P1 ("×××××") to the Result .txt file and then copy it, and may change the directory of the file accordingly on your machine. # Tool.java program list Package printown; Import java.io. *; Public class tool { Public static void main (String [] args) { Try { BufferedReader is = New BufferedReader (New InputStreamRead) New FileInputStream ("f: //ibm//printown//printown//othervmmethod.java")))); PrintWriter PW = New PrintWriter (New FileoutputStream ("f: //eclipse-workspace//printown//printown//Result.txt")); String line = NULL; While ((line = is.readline ())! = NULL) { String s = "p1 (/" vmexecuter.convert (line) "/"); "; PW.Println (s); } Is.close (); PW.Close (); } catch (exception e) { E.PrintStackTrace (); } } } Conclusion is the daily work of many IT people, share the fun of programming with everyone, happy work is the main reason I wrote these texts. This article discusses an interesting programming topic "print itself" and a dual virtual machine model, but it is important to pay attention to the resend of a lot of threads compared to the opening of a process. Reference The source code of this article. Refer to the API specification manual on the Java 2 platform (1.4 version of the standard): Java 2 API documentation. May 2004 "9CBS Development Master" "Print Self-Program" Talks. Michael C. Daconta discusses the defects and response of java.lang Runtime.exec () in the article "When Runtime.exec () WON't. It can be found on the JavaWorld website. Erich Gamma, Kent Beck, "Contributing to Eclipse: Principles, Patterns, and Plug-Ins" This book is great. The book can be found online.