Establishment method of Java library and examples

xiaoxiao2021-03-06  74

Any object-oriented language has its library. Any object-oriented language is also free of support. With our familiar object-oriented language as examples, C has STL, Java has API functions, specific to development tools, Visual C provides MFC, Borland C provides OWL. There are also many third-party libraries. When we develop applications, we also find that we may need some specific libraries to complete specific features. So how do you write your own library?

With Java's object-oriented properties such as encapsulation, inheritance, and some design patterns, we can build your own library with standard methods. I need to understand: When you need to complete a feature, don't write code with a proprietary, specific method, and to consider it all, so that after you have accumulated a certain number of libraries. You can reuse these libraries to complete new features without having to write code every time. This is also the benefit of the object-oriented language to provide us. You can also use J2EE's specifications as an example. J2EE provides a COMPONENT BASED Transaction, all components respect the J2EE specification, run in CBT, which is developed and reused standard universal component libraries, which can shorten the development cycle. Save costs and can be run in any application server that comply with the J2EE specification, and can be inherited, extended to complete new tasks or adapt new changes. In this article, I will first discuss how to build my own library, what standards need to be required, then give a simple example. In the second part, I will discuss further through a relatively perfect library. What is the library? The library is a reusable component that uses universal design, completes a common task, saving developers, and shortens development cycle cost development costs. A well-designed library is not just to complete a particular task, but can complete a variety of different tasks. Design a library is difficult. Write an algorithm is not difficult, but it is necessary to use a better structure when designing the library. It can be used in a variety of needs, but also performs a variety of different tasks, but cannot affect the program code structure that uses it. Why reuse code? Heavy development of a new software, the workload is very huge, no matter what the tool you use. The code reuse can save most of the time, and spend the time in the development of new features. In a certain sense, writing a new software is to use the existing code, re-assemble to achieve new features. From another perspective, even if you don't intend to turn your code into a universal library and distribute it to others, from the perspective of design, you can use a common general design method to make you The task to be completed has a better understanding and optimizes your design process to optimize your code structure. With development libraries and let others use it, help you discover its design defects or errors in your design when using it, and help you correct it. For example, you have written a library to make others to use, you have to consider universal design, because you can't foresee the purpose of using and use in any environment. During the process of using your library, you may have some problems, some may be your documentation is not clear enough, some may also be the mistake on your program, or it may be that the user feels in the structure. It is not convenient to use it up. Then you can continue some modifications, do some adjustments in the case of maintaining the structure and interface. At design libraries, you need to look at a problem with a user, consider how to design and implement it. You need to understand, 1, what is the problem that needs to be solved? What is the purpose of need to reach? 2, what is the problem that the user cares? What is the result of the user needs? 3, what is the problem that the user does not need to care? What details can be hidden with users? Below, we use a simple example to explain how to design and implement a library that uses place.

Design a web service program, we need to consider a few points: 1, listen to a port 2, accept the connection 3, read or write a stream 4, process the input data, and return a result for the library we want to implement. It is necessary to complete the first three points, and the last point will leave the user to achieve, which is also where users need to complete and care. The main class of the library is called Server, the class is called EchoServer. EchoServer implements a simple service, read data from the client, and returns the same data. Design Principle 1: Packaging a good library must be a compact relationship close to the overall overall, not a collection of scattered relationship loose objects. Package is a package mechanism for a class library provided by Java. A package is a collection of Java class files and stored in the same directory. Package has a proprietary name space. One advantage of a proprietary name space is that you don't have to worry about the conflict of the name. Because, if your name is conflict with the name of the class of others, they are not in the same package, using this to avoid the conflict of the name. Every package has a string to represent, such as java.lang, or javax.swing.plaf.basic. In fact, the full name of each class is represented by the name of the package of Package. Avoid conflicts of names, such as java.lang.object or javax.swing.plaf.basic.basicmenubarui. Note that there is a special package called Default Package. If you don't declare your class belong to any package, then it is assumed to belong to the default package. Each package name corresponds to a directory. For example, java.lang.object is stored in Java / Lang / Object.java, each. The directory where the corresponding /. Default package is stored is the current directory. Declare a package.// server.javaPackage Mylib; Public Class Server IMPLEments Runnable {// ...

If there is an IMPORT statement, you must put it behind the package statement.

Of course, you can also introduce other packages. For example:

Import mylib.server; // ... server server = new server (portnum);

Java allows you to decide which of the pairs of Package is visible externally. The PUBLIC class can be used outside of the code, and the private class will not.

For example, let the Server class can be used by external code:

// Server.javaPackage Mylib; import java.io. *; Import java.net. *; Public class server imports runnable {

If you don't want to use the external code, you can remove the public. For example, by the default attribute. For example:

// reporter.javaPackage mylib; Class Reporter imports runnable {

Design Principle II: Inheritance

In our example, Server is the main class. If you see this class code, you can see it, it is nothing wrong with it. The main loop is used to listen to the connection. When the connection is established, it handed the task that handles the connection to a function called HandleConnection ().

// Subclass Must Supply An Implementation

Abstract Public Void Handleconnection (socket s);

Because this function is not implemented, this class is declared as Abstract, and the user must implement this function. // This is called by the Server class when a connection // comes in "in" and "out" come from the incoming socket // connectionpublic void handleConnection (Socket socket) {try {InputStream in = socket.getInputStream ().; OutputStream out = socket.getOutputStream (); // Just Copy The Input to the OutputWhile (TRUE) Out.write (IOException IE);} catch (ioException ie) {system.out.println (IE);}}

It can be said that this inheritance process is called custom. Because in the Server class, there is no action of the function, but the process of this definition is left to the user, let them complete the specific features you need.

Another custom function: cleanup ().

When designing class, you can often take into account the functions you need, such as HandleConnection (). However, you also need to consider another customization, for example here, when Server exits the background, call this Cleanup () function, the implementation in the Server class is empty, nothing, this will leave the user, the user can use this function to do some clear work, this function can also be called "hook" .

Design principle three: debugging

No one can do a definitely perfect program, without any errors. Therefore, debugging is indispensable. Sometimes users may encounter a problem, which needs to know what happened in the code of the library. This error may be the problem of library code, or the user's code is caused by the problem in the library code.

If you provide the source code of the library, the user can debug errors with Debugger. However, you can't depend entirely on the debugger. Add a statement to print debug information in the library code, it is a good habit. It can help users understand, wherever they have happened.

The following example illustrates this technology. The user's code uses Server.SetDebugStream (), specifies a PrintStream object. Then, debug information is output to this stream.

// set this to a print stream if you want debug info // sent to it; otherwise, leave it nullstatic private PrintStream debugStream; // call this to send the debugging output somewherestatic public void setDebugStream (PrintStream ps) {debugStream = ps; }

When the user uses a debug flow, your library code can print an error:

// send debug info to the print stream, if there is oneStatic public void debug (string s) {if (debugstream! = null) debugstream.println (s);}

Here, take a look at this specific example:

EchoServer // $ Id $ import java.io *;. Import java.net *;. Import mylib *;. Public class EchoServer extends Server {public EchoServer (int port) {// The superclass knows what to do with the port number We // don't have to Care About it super (port);} // this is called by the server class when a connection // comes in. "in" and "come from the incoming socket // connection public void handleConnection (Socket socket) {try {InputStream in = socket.getInputStream (); OutputStream out = socket.getOutputStream (); // just copy the input to the output while (true) out.write (in.read () );} Catch (ioException IE) {system.out.println (IE);}} protected void cleanup () {system.out.println ("clean");} static public void main (string args []) THROWS Exception {// Grab the port number from the command-line int port = Integer.parseInt (args [0]); // Have debugging info sent to standard error stream Server.setDebugStream (System.err); // Create the server AN D it's up and running new echoserver (port);}} mylib.server // $ ID $ package mylib; import java.io. *; import java.net. *; Abstract public class server imports runnable {// the port w 'll be listening on private int port; // how many connections we've handled int numConnections; // the Reporter that's reporting on this Server private Reporter reporter; // set this to true to tell the thread to stop accepting // connections private boolean mustQuit = false; public Server (int port) {// remember the port number so the thread can // listen on it this.port = port; // the constructor starts a background thread new Thread (this) .start ( // and start a reporter reporter =

New reporter (this);} // this is Our background thread public void run () {serversocket ss = null; try {// get ready to listen ss = new serversocket (port); while (! mustquit) {// Give out some debugging info debug ( "Listening on" port); // wait for an incoming connection Socket s = ss.accept (); // record that we got another connection numConnections ; // more debugging info debug ( "Got connection ON " s); // process the connection - this is itmented // by the subclass handleconnection (s);}} catch (IE.TOSTRING ());} debug (" Shutting Down " ss); cleanUp ();} // the default implementation does nothing abstract public void handleConnection (Socket s); // tell the thread to stop accepting connections public void close () {mustQuit = true; reporter.close (); } // put any last-minute clean-up stuff in here protected void cleanup () {} // everything below provides a Simple Debug System for // This package // set this to a print stream if you want debug info // sent to it; otherwise, leave it null static private PrintStream debugStream; // we have two versions of this ... static public void setDebugStream (PrintStream ps) { debugStream = ps;} // ... just for convenience static public void setDebugStream (OutputStream out) {debugStream = new PrintStream (out);} // send debug info to the print stream, if there is one static public void debug ( String s) {if (debugStream = null) debugStream.println (s);!}} mylib.Reporter // $ Id $ package mylib; class Reporter implements Runnable {// the Server we are reporting on private Server server;

// our background thread private Thread thread; // set this to true to tell the thread to stop accepting // connections private boolean mustQuit = false; Reporter (Server server) {this.server = server; // create a background thread thread = New Thread (this); thread.start ();} public void run () {while (! mustquit) {// do the reporting server.debug ("Server HAS HAD" Server.NUMCONNACTIONS "Connections"); / / THREAD.SLEP (5000);} catch (interruptedException IE) {}}} // tell the background thread to quit public void close () {mustquit = true;}} below, we take a specific There is a class library with actual use to further discuss the design method of the library. This library is JREGEX. (JREGEX.SourceForge.Net). This is a library that is compatible with Perl 5.6 implemented with Java. There are many such libraries, such as gnu.Regexp, com.stevesoft.pat, and J2SE SDK 1.4 newly adding regex. Why choose JREGEX? It is because it is currently the regular expression of PERL 5.6 in the regex library of current source code, and has just updated excessive code, and is a stable version, and another is that its kernel algorithm uses NFA (NOT Finite Automata).

To understand a package, you should look at it before you see the source code is its API document. So what should I see when I see the first step of the document? Of course it is a tree structure.

Class Hierarchy class java.lang.Object class jregex.Matcher (implements jregex.MatchResult) class jregex.Optimizer class jregex.util.io.PathPattern class jregex.Pattern (implements jregex.REFlags, java.io.Serializable) class jregex.PerlSubstitution (implements jregex.Substitution) class jregex.Replacer class jregex.RETokenizer (implements java.util.Enumeration) class java.lang.Throwable (implements java.io.Serializable) class java.lang.Exception class java.lang.RuntimeException class java .lang.IllegalArgumentException class jregex.PatternSyntaxException class jregex.util.io.WildcardFilter (implements java.io.FilenameFilter) interface Hierarchy interface jregex.MatchIterator interface jregex.MatchResult interface jregex.REFlags interface jregex.Substitution interface jregex.TextBuffer interface jregex.Replacer .Writerwrap ------------------------------------------------ --------------------------------

In a regular expression, we know that there are two elements important, the first is Pattern, the second is Matcher (matching result string). In Jregex, the Pattern class implements JREGEX.REFLAGS Interface, and java.io.serializable. Let's take a look at the description of JREGEX.REFLAGS. JREGEX.REFlags defines some static constants that looks some logo. Pattern implements JREGEX.REFLAGS, that is, the pattern class contains these static constants.

Next, let's take a look at Pattern's API description:

Pattern is a representation of a precompiled good regular expression. To match a regular expression, create a Pattern instance:

Pattern P = New Pattern (MyExpr);

Then get the instance of Matcher

Matcher matcher = p.matcher (mytext);

Matcher's instance is an automatic matching and search object. It provides the following methods:

Search match results: matcher.find () or matcher.findall ();

Monitoring Whether the full-text match: matcher.matches ();

Monitoring does the beginning: matcher.isstart ();

Find: Matcher.Find (Int Options)

Sign

The flag (reference reflags) changed the meaning of the regular expression symbol when precompilated. These markers are:

Reflags.Ignore_case - ignore the case

Reflags.Multiline - use ^ and $ to show the beginning and end of a line of text

REFLAGS.DOTALL - Use. To reply to the carriage return reflags.ignore_Spaces - ignore spaces

Reflags.Unicode - Use Unicode, which W, D is no longer interpreted as the meaning of regular expression, but is interpreted as Unicode.

REFLAGS.XML_SCHEMA - uses XML semantics.

Thread

Pattern is a thread safe. That is, you can use the same pattern in different threads.

In the API function description, we can also see the PUBLIC method for the Pattern class. This will be useful below. Let's take a look at:

Constructor

Pattern (java.lang.String regex) Compiles an expression with default flags. Pattern (java.lang.String regex, int flags) Compiles a regular expression using REFlags. Pattern (java.lang.String regex, java.lang.String flags ) Compiles a regular expression using perl5-style flags.

method

int groupCount () How many capturing groups this expression includes? java.lang.Integer groupId (java.lang.String name) Get numeric id for a group name. Matcher matcher () Returns a targetless matcher. Matcher matcher (char [] data , int start, int end) Returns a matcher for a specified region. Matcher matcher (MatchResult res, int groupId) Returns a matcher for a match result (in a performance-friendly way). Matcher matcher (MatchResult res, java.lang. String groupName) Just as above, yet with symbolic group name. Matcher matcher (java.io.Reader text, int length) Returns a matcher taking a text stream as target. Matcher matcher (java.lang.String s) Returns a matcher for a specified string. Replacer replacer (java.lang.String expr) Returns a replacer of a pattern by specified perl-like expression. Replacer replacer (Substitution model) Returns a replacer will substitute all occurences of a pattern through applying a user-defined substitution Model. Retokenizer tokenizer (char [] data, int OFF, INT LE n) Tokenizes a specified region by an occurences of the pattern. RETokenizer tokenizer (java.io.Reader in, int length) Tokenizes a specified region by an occurences of the pattern. RETokenizer tokenizer (java.lang.String text) Tokenizes a text By an occupials of the pattern. java.lang.string TOSTRING_D () Returns a less or more readable representation of a bytecode for the pattern. java.lang.string toString () Next, let's take a look at the contents of the Pattern class. There are two ways here, one is to read the source code directly, and the other is the first tool to analyze the contents of the Pattern class. Here, I use the second method to see the content of the class with javap.

[Games] $ javap -classpath .. -private jregex.PatternCompiled from jregex / Pattern.javapublic class jregex.Pattern extends java.lang.Object implements java.io.Serializable, jregex.REFlags {java.lang.String stringRepr; jregex. Term root; jregex.Term root0; int memregs; int counters; int lookaheads; java.util.Hashtable namedGroupMap; private jregex.Pattern () throws jregex.PatternSyntaxException; public jregex.Pattern (java.lang.String) throws jregex.PatternSyntaxException ; public jregex.Pattern (java.lang.String, java.lang.String) throws jregex.PatternSyntaxException; public jregex.Pattern (java.lang.String, int) throws jregex.PatternSyntaxException; private void compile (java.lang.String , int) throws jregex.PatternSyntaxException; public int groupCount (); public java.lang.Integer groupId (java.lang.String); public jregex.Matcher matcher (); public jregex.Matcher matcher (java.lang.String); Public jregex.matcher matcher (char [], int, int); public jregex.matcher matcher (jregex.matchresult, int); public jregex.matcher ma tcher (jregex.MatchResult, java.lang.String); public jregex.Matcher matcher (java.io.Reader, int) throws java.io.IOException; public jregex.Replacer replacer (java.lang.String); public jregex. Replacer replacer (jregex.Substitution); public jregex.RETokenizer tokenizer (java.lang.String); public jregex.RETokenizer tokenizer (char [], int, int); public jregex.RETokenizer tokenizer (java.io.Reader, int) throws java.io.IOException; public java.lang.String toString (); public java.lang.String toString_d (); static int parseFlags (java.lang.String) throws jregex.PatternSyntaxException; static int parseFlags (char [], INT, INT) THROWS JREGEX.PATTERNSYNTAXEXCEPTION; Private Static Int getflag (char) THROWS JREGEX.PATTERNSYNTAXEXCEPTION;

Among them, we must care about Private and Protected members, because when you use the class, we only need to care for the public member, but to read the source code, understand the composition of the class, you must pay attention to Private and protected members. private Pattern () throws PatternSyntaxException {} public Pattern (String regex) throws PatternSyntaxException {this (regex, DEFAULT);} public Pattern (String regex, String flags) throws PatternSyntaxException {stringRepr = regex; compile (regex, parseFlags (flags)) PUBLIC PATTERN (String Regex, Int Flags) throws patternsyntaxexception {stringrepr = regex; Compile (regex, flags);

It can be seen that in the constructor, there is a default constructor is private. The second call has called the last constructor and uses this (). The third and last one are tasks that use a function compile to complete the constant expression. We can also see the output of JAVAP above, Compile is a private function.

Let's take a look at it:

Private void compile (string regex, int flags) throws patternysyntaxexception {term.maketree (regex, flags, this);

Specific to the Term class, beyond the scope of this article, which uses HashTable and other methods to construct a regular expression and return. And we care about the structure of the library. From here we can understand that constructor often needs to call another constructor to complete, without having the same code to be implemented in each constructor. At the same time, another private function can be used to complete the functionality of the constructor, and as long as it is called in the constructor.

From the Matcher API document, we can see that there are two ways to construct a Matcher instance through the Pattern instance, and in the output of Java, there are several different Matcher functions.

Public matcher matcher () {return new matcher (this);} public matcher matcher (string s) {matcher m = new matcher (this); M.SetTarget (s); return m;} public matcher matcher (char [] data , int start, int end) {matcher m = new matcher (this); M.SetTarget (DATA, START, END); RETURN M;} public matcher matcher (matcher m = new matcher) {matcher m = new matcher (this ); If (res instanceof matcher) {M.SetTarget ((Matcher) res,} else {m.settarget (res. stationchars (), res.start (GroupID) res. TargetStart (), res.length (GroupID);} return m;} public matcher matcher (reader text, int length) throws ooException {matcher m = new matcher (this); M.SetTarget (text, length); return m;} Implement the first method of returning Matcher. It can be seen that these implementations are through the New Matcher instance, with this (ie the pattern instance) as a parameter, and then call the Matcher.SetTarget () method according to the parameters.

. Public Matcher matcher (MatchResult res, String groupName) {Integer id = res.pattern () groupId (groupName); if (id == null) throw new IllegalArgumentException ( "group not found:" groupName); int group = id Return matcher (res, group);}

This is the second way to return to Matcher.

From here we can find a better way: When you need two inter-associated classes, a class instance needs to construct an instance of another class, you can use a public method in the first class, the method is implemented as a call. The second class constructor, and can be called other methods with the configuration of the constructed instance, and an example of the second class is set according to the data of the first class.

Similarly, there is also the construction method of Replacer, and Tokenizer.

public Replacer replacer (String expr) {return new Replacer (this, expr);} / ** * Returns a replacer will substitute all occurences of a pattern * through applying a user-defined substitution model * @param model a Substitution object which. is in charge for match substitution * @see Replacer * / public Replacer replacer (Substitution model) {return new Replacer (this, model);} public RETokenizer tokenizer (String text) {return new RETokenizer (this, text);} / * * * Tokenizes a specified region by an occurences of the pattern * Note that a series of adjacent matches are regarded as a single separator * The same as new RETokenizer (pattern, char [], int, int);.. * @see RETokenizer * @see retokenizer # Retokenizer (Jregex.pattern, Char [], int, int) * / public retokenizer tokenizer (char [] data, int off, int LEN) {Return New Retokenizer (this, DATA, OFF, LEN); } / ** * tokenizes a specified region by an occupitution of the pattern. * Note That A Series of Adjacent Matches Are Regarded AS A Si ngle separator * The same as new RETokenizer (Pattern, Reader, int);. * @see RETokenizer * @see RETokenizer # RETokenizer (jregex.Pattern, java.io.Reader, int) * / public RETokenizer tokenizer (Reader in, int LENGTH) THROWS IOEXCEPTION {Return New Retokenizer (this, in, length); Collection of loose objects. "The tree structure of this library displayed from the API document does not see the connection between these classes. From the perspective of the source code, we can clearly see this. In this part of the discussion, We also understand two points:

1, how to write a heavy duty constructor

2. Return another class of instances in an example of a class

Next, look at the Matcher class. This class implements MatchResult Interface. Take a look at MatchResult's definition:

JREGEX.MatchResult defines some Abstract functions. what's the effect? We will discuss it later.

Take a look at Matcher's implementation.

[Games] $ javap -classpath .. -s jregex.MatcherCompiled from jregex / Matcher.javapublic class jregex.Matcher extends java.lang.Object implements jregex.MatchResult {public static final int ANCHOR_START; / * I * / public static final int Anchor_lastmatch; / * i * / public static final int anchor_end; / * i * / public static final int access_incomplete; / * i * / jregex.matcher (jregex.pattern); / * (ljregex / pattern;) v * / public Final void setTarget (Jregex.matcher, Int); / * (Ljregex / Matcher; i) v * / public void settarget (java.lang.string); / * (ljava / language;) v * / public void settarget (Java.lang.String, Int, int); / * (ljava / lang / string; ii) v * / public void settarget (char [], int, int); / * ([cii) v * / public final Void setTarget (Char [], int, int, boolean; / * ([CIIZ) V * / public void settarget (java.io.reader, int) THROWS JAVA.IOEXCEPTION; / * (Ljava / IO / Reader ; I) v * / public final boolean isstart (); / * () z * / public final boolean matches (); / * () z * / Public final boolean matches (java.lang.string); / * (ljava / lang / string;) z * / public void setPosition (int); / * (i) v * / public final boolean find (); / * ( Z * / public final boolean find (int); / * (i) z * / public jregex.matchiterator FindAll (); / * () ljregex / matchitrator; * / public jregex.matchiterator Findall (int); / * ( I) ljregex / matchiterator; * / public final boolean proceed (); / * () z * / public final boolean proceed (int); / * (i) z * / public final void Skip (); / * () V * / Public java.lang.String toString (); / * () ljava / lang / string; * / public jregex.pattern pattern (); / * () ljregex / pattern; * / public java.lang.string target ); / * () Ljava / lang / string; * / public char targetchars () [];

/ * () [C * / public int targetstart (); / * () i * / public int target (); / * () i * / public char charat (int); / * (i) c * / public Char Charat (int, int); / * (ii) c * / public final int length (); / * () i * / public final int start (); / * () i * / public final int end () ; / * () I * / public java.lang.string prefix (); / * () ljava / lang / string; * / public java.lang.String suffix (); / * () ljava / lang / string; * / Public int groupcount (); / * () i * / public java.lang.String Group (int); / * (i) ljava / lang / string; * / public java.lang.string group (java.lang .String); / * (ljava / lang / string;) ljava / lang / string; * / public boolean getGroup (int, jregex.textbuff); / * (iljregex / textbuffer;) z * / public boolean getGroup (Java. Lang.String, Jregex.TextBuffer; / * (Ljava / Lang / String; Ljregex / TextBuffer;) z * / public boolean getGroup (int, java.lang.stringBuffer); / * (iljava / lang / stringbuffer;) z * / Public boolean getGroup (java.lang.string, java.lang.stringbuff); / * (Ljava / L Ang / string; ljava / lang / stringbuffer;) z * / public java.lang.string groups () []; / * () [ljava / language / string; * / public java.util.Vector Groupv (); / * () Ljava / util / vector; * / public final boolean iscaptured (); / * () z * / public final boolean iScaptured (int); / * (i) z * / public final boolean iscaptured (java.lang. String); / * (Ljava / Lang / String;) z * / public final INT Length (int); / * (i) i * / public final int start (int); / * (i) i * / public final INT End (int); / * (i) i * / public java.lang.string toString_d (); / * () ljava / lang / string; * / static {}; / * () v * / first Look at its constructor, this function is called in Pattern to construct an instance of the Matcher class.

Matcher (Pattern Regex) {// Note the following line, it shows the inside of the Matcher class with a reference to the Pattern instance. This.re = regex; // int eventgcount = (MemRegs = new memreg [regex.MemRegs]). Length; // for (int i = 0; I // this.Memregs [i] = new memreg (-1); // unikely to searchry, in this case we know memory indegies by D

efinition

//}

// counters = new int rt [regex.counters];

// int Lookaheadcount = (Lookaheads = New lantry [regex.lookaheads]).

// for (int i = 0; i

// this.lookaheads [i] = new lantry ();

//}

// Define some internal data, MemReg is a class with three integers. The statement of the class is shown.

Int Memregcount, Countercount, LookaheadCount;

IF (MemRegcount = regex.MemRegs> 0) {

MemReg [] MemRegs = new memreg [memregcount];

For (int i = 0; i

MemRegs [i] = new memreg (-1); // unikely to searchry, in this case we know memory indegies by defin

Ition

}

THIS.MEMREGS = MemRegs;

}

IF ((countercount = regex.counters> 0) counters = new int [counterCount];

// Define some internal data. The statement of the class is shown.

IF (LookaheadCount = regex.lookaheads)> 0) {

Laectry [] lookaheads = new lantry [lookaheadcount];

For (int i = 0; i

Lookaheads [i] = new lantry ();

}

THISLOOKAHEADS = LOOKAHEADS;

}

THIS.MEMREGCOUNT = MemRegcount;

THIS.COUNTERCOUNT = Countercount;

THISLOKAHEADCOUNT = LOOKAHEADCOUNT;

First = New SearchenTry (Memregcount, Countercount);

DEFAULTENTRY = New SearchenTry (Memregcount, Countercount);

Minqueuelength = regex.stringrepr.length () / 2; // evataization !!!

}

Describe these two classes as a default property, indicating that these two classes are visible inside the JREGEX package, and they are invisible at the outside. These two classes are proprietary, not common. Recalling the package of this article, the package package, "If you don't want to use the external code to be used, you can remove the public."

Class memreg {int index; int = -1, out = -1; int TMP = -1; // for assuming at group_in memreg (int index) {this.index = index;} void reset () {in = OUT = -1;}} class lantry {int index; searchry top, actual;} In addition, we are interested in the relationship between the structure and classes in the package, matchiterator.

[Games] $ javap -classpath .. -s jregex.MatchIteratorCompiled from jregex / MatchIterator.javapublic interface jregex.MatchIterator / * ACC_SUPER bit NOT set * / {public abstract boolean hasMore (); / * () Z * / public abstract jregex .MatchResult nextmatch (); / * () ljremex / matchResult; * / public abstract int count (); / * () i * /}

This is an interface that defines the common way of Iterator, lists all MatchResult instances.

As you can see here, define a MatchResult Interface and then use Matcher to implement this interfab is a better way. Because this defines a better hierarchy, there is a relatively good benefit for the update development of the program. It can also be seen here that Matchiterator's way is also MatchResult Interface instead of the Matcher class. At the same time, you can see that the MatchIterator itself is also an interface. This reflects another important issue we need to understand: Programming for Interface, rather than programming. Specifically, if a new class is renovated later, it is also a MatchResult Interface, which is also possible to use the method to return a Matchiterator instance, which may be an instance of the Matcher class, or anothermatcher Examples of classes. However, although we have made a lot of changes, there is no impact on the previous procedure, and there is no need to make any changes to previous procedures. From the user's point of view, if he just uses the method defined in the two interfaces of MatchResult and MatchIterator, then, whether it is Matcher or Anothermatcher, he does not need to modify his code.

The next function you need is Findall ().

// Call the overloaded function of the parameter Findall (int) public matchiterator Findall () {return FindAll (0);} / ** * Returns an itrator over the matches found by Subsequently Calling Find (Options), The Search Starts from The zero position. * / public matchiterator FindAll (Final Int Options) {// setPosition (0); // Do not care about the specific implementation method, but we can see where it defines an Anonymous Inner Class, this Inner Class Implement Matchiterator to return the results that match the match in Matcher one by one. The Reference of the object instance of this INNER Class is returned by the FindAll () method. Can be used for an external REFERENCE and can read these results. This is also a way to pay attention to. return new MatchIterator () {private boolean checked = false; private boolean hasMore = false; public boolean hasMore () {if check () (checked!); return hasMore;} public MatchResult nextMatch () {if (! checked) check ( ); If (! Hasmore) throw new nosuchelementexception (); checked = false; return matcher.this;} private final void check () {HASMORE = Find (options); checked = true;} public int count () {IF Check (); if (! Hasmore) Return 0; INT C = 1; While (Find (Options)) C ; Checked = FALSE; RETURN C;}};} In the above code, we understand As follows 3 points:

1. Program it for Interface instead of programming.

2, how to write an Iterator (iterator). Two functions that need to be at least: Hasmore (), nextElement (). In this way, the user can read the contents in the iter with the following loop:

Iterator.hasmore ();)

Iterator.nexTelement ();

3. Separate the processing method and processing results. Use Matcher to represent the specific implementation of the matching method, and put the result in another class. The advantage of doing this is how to process methods and results, more flexible, can be modified, and the results are not affected. You can also change the reading method of the result class, but does not affect the implementation of the processing method class. This approach has been used by many set classes in J2se SDK. It is also possible to refer to their implementation methods.

Of course, there is still something to pay attention to using anonymous Inner Class method.

There are still many problems that can be discussed in JREGEX, such as the NOT Finite Automata method it uses, and the regular expression specification used in it. However, as the scope discussed herein, how to design and implement a library, it can be displayed. Interested readers can download its source package, binary packages, use examples, and documentation instructions for further research. summary:

In this article, we discussed several principles designed and implemented in a Java library, and use a simple example to illustrate these principles. Subsequently, we discussed other questions that needed attention using a wide range of libraries.

Design principle 1: Package

A good library must be a compact relationship close to the overall whole, not a collection of diffused objects.

Design Principle II: Inheritance

Using the Abstract function, Interface, and "Hook" function.

Design principle three: debugging

Add a statement to print debug information in the library code.

And some design methods:

1. How to write an overloaded constructor.

2. Return another class of instances in an example of a class

3, programming the interface, not the class programming.

4. How to write an Iterator (iterator).

5. Separate the processing method and processing results.

6, how to use Inner Class.

At the same time, we also discuss how to read a Java library source code:

1. Read the API documentation, the tree structure of the library, understand the relationship between classes, interfab.

2. Use javap to list the functions, variables, constants defined in the interface, and the like defined in the interface.

3, pay attention to the private, protected function.

转载请注明原文地址:https://www.9cbs.com/read-120401.html

New Post(0)