Subclass identification during Java Runtime

Source: Internet
Author: User

Java image API (reflection API) and Java interface for the compilation of reusableCodeProvides excellent tools. Take a common command starter as an example: Suppose you have a group of classes that execute various tasks, such as turning off or turn on the lights, turning on, off, or locking the door, etc. The names of these classes are lighton, lightoff, dooropen, doorclose, and doorlock. All these classes implement the command interface.

The command interface is defined as follows:

Public interface command {

Public void process ();

}

You can write a simple universal starter, as shown below:

Public class launcher {

Public static void main (string [] ARGs ){

If (ARGs. length> 0 ){

Try {

Command command =

(Command) class. forname (ARGs [0]). newinstance ();

Command. Process ();

} Catch (exception ex ){

System. Out. println ("invalid command ");

}

} Else {

System. Out. println ("Usage: launcher <command> ");

}

}

// Launcher


ThisProgramUse the class. forname method to obtain the Class Object of the specified class in the parameter, and then use the newinstance () method to create an instance of the class. As required, this class implements the command interface, so the program converts the object cast into command, then calls the process () method, and the process method executes the actual task. If an exception occurs, for example, the program displays an "invalid command" message due to misspelling of the class name or security issues.

The command initiator can be used as follows:

% Java launcher lighton


If some new tasks are implemented in the future, the command initiator does not need to be modified. From the programmer's point of view, this is really good. But what about it for users? Assume that a user has entered the following command:

% Java launcher opendoor

Invalid Command


"Invalid Command" means the user cannot open the door? No, it only indicates a class name error (dooropen becomes opendoor ). Therefore, the program should allow users to view the list of available commands. To ensure the versatility of the command initiator, you should be able to find these commands at runtime.

The Java image API can provide a large amount of information about the specified class at runtime: We can easily learn all the superclasses of the specified class, the interfaces, methods, constructors, and domains it implements, and so on. But here, we are interested in all classes that implement specific interfaces. Such information cannot be obtained directly from the Java image API. The rest of this article describes how to obtain information about classes that implement specific interfaces.

In Java, the package corresponds to the directory. It is easy to obtain all classes contained in the package through the list () method of the file object. We use the instanceof statement to check whether the command interface is implemented for each class file in the package. This means that only the public classes of each class file are checked, and the interface and its implementation must be in a package. The following code is used:

Public static void find (string pckgname ){

// Convert the package name to an absolute path

String name = new string (pckgname );

If (! Name. startswith ("/")){

Name = "/" + name;

}

Name = Name. Replace ('.','/');

// Obtain a file object

URL url = launcher. Class. getresource (name );

File directory = new file (URL. GetFile ());

If (directory. exists ()){

// Obtain the file list in the package

String [] files = directory. List ();

For (INT I = 0; I & lt; files. length; I ++ ){

// We are only interested in. class files

If (files [I]. endswith (". Class ")){

// Delete the. Class File Extension

String classname = files [I]. substring (0, files [I]. Length ()-6 );

Try {

// Try to create an instance of this object

Object o = Class. forname (pckgname + "." + classname). newinstance ();

If (O instanceof command ){

System. Out. println (classname );

}

} Catch (classnotfoundexception cnfex ){

System. Err. println (cnfex );

} Catch (instantiationexception iex ){

// We try to instantiate an interface or

// An object without default constructor

} Catch (illegalaccessexception iaex ){

// This class is not a public class

}

}

}

}

}

To execute the task at hand, we only need to slightly modify the original starter. Now, we can imagine that the interface and its implementation are in a commands package:

Public static void main (string [] ARGs ){

If (ARGs. Length & gt; 0 ){

Try {

Command command = (command) class. forname ("commands." +

ARGs [0]). newinstance ();

Command. Process ();

} Catch (exception ex ){

System. Out. println ("invalid command ");

System. Out. println ("available commands :");

Find ("commands ");

}

} Else {

System. Out. println ("Usage: launcher & lt; command & gt ;");

}

}


The following is the result of the improved starter when an incorrect command is executed:

% Java launcher opendoor

Invalid Command

Available commands:

Lighton

Lightoff

Dooropen

Doorclose

Doorlock


We can modify the find () method so that it can find any subclass of the specified class. To this end, we need to use the dynamic version of instanceof, that is, isinstance (). Replace (tosubclass. isinstance (O) with (O instanceof command), where tosubclass is the class specified in the find () method parameter. Now we have a method that can find any subclass of the specified class in the specified package. We can improve this method so that it can search for subclasses in the currently loaded package. Therefore, we need to use the package. getpackages () method, which accurately returns the packages loaded by the current class loader. Then, we only need to call the find () method for each package:

Public static void find (string tosubclassname ){

Try {

Class tosubclass = Class. forname (tosubclassname );

Package [] pcks = package. getpackages ();

For (INT I = 0; I & lt; pcks. length; I ++ ){

Find (pcks [I]. getname (), tosubclass );

}

} Catch (classnotfoundexception ex ){

System. Err. println ("class" + tosubclassname + "not found! ");

}

}

The returned results of this method mainly depend on the time when it is called. For the General Command starters in this article, the find () method is called and only a few packets are imported into the memory. For example, the following is the package loaded before calling find () on my NT machine:

Package java.util.zip, Java platform API specification, version 1.3

Package java. Security, Java platform API specification, version 1.3

Package java. Io, Java platform API specification, version 1.3

Package sun.net. www. Protocol. File, Java platform API specification, version 1.3

Package sun.net. www. Protocol. jar, Java platform API specification, version 1.3

Package sun.net. WWW, Java platform API specification, version 1.3

Package java. util. jar, Java platform API specification, version 1.3

Package sun. Security. Action, Java platform API specification, version 1.3

Package java. Lang, Java platform API specification, version 1.3

Package sun. Io, Java platform API specification, version 1.3

Package java. util, Java platform API specification, version 1.3

Package sun. Misc, Java platform API specification, version 1.3

Package java. Security. cert, Java platform API specification, version 1.3

Package java. Lang. Reflect, Java platform API specification, version 1.3

Package java.net, Java platform API specification, version 1.3

Package sun. Security. util, Java platform API specification, version 1.3

Package java. Lang. Ref, Java platform API specification, version 1.3

Package sun. Security. provider, Java platform API specification, version 1.3

Package com. Sun. rsajca


In the command initiator, the interface and all its implementations are in the same package. After the class is loaded, the loaded package can be obtained. Therefore, we can search for subclasses in the package. This is the only way to find related packages. Complete rtsi classSource codeYou can find the resource at the end of this article. After unzipping the downloaded package, run the following command to test the Code:

% Java-CP classes rtsi commands. Command


The Code discussed above can run smoothly when the package exists as an operating system directory and file. However, if the class file is in one or more jar files, the code is no longer valid. In the download code in this article, you will find a solution to this problem. You can use the following command to test the program's ability to process jar files:

% Java-jar rtsi. Jar commands. Command

■ Conclusion

In this articleArticleIn, we discuss how to dynamically extract subclass of all specified classes from a specified package (or from a mounted package. This function is useful not only for designing general programs, but also for users as shown in the Command initiator instance in this article.

The author states: Some readers point out that the program in this article can only detect sub-classes with Default constructors. They suggest replacing isinstance () with the isassignablefrom () method of class ().

■ Reference resources:

  • Complete source code of this Article
  • Java class document
  • Java package document

      (Responsible editor Wu bei jiaoxq@staff.ccidnet.com)

    • Contact Us

      The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

      If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

      A Free Trial That Lets You Build Big!

      Start building with 50+ products and up to 12 months usage for Elastic Compute Service

      • Sales Support

        1 on 1 presale consultation

      • After-Sales Support

        24/7 Technical Support 6 Free Tickets per Quarter Faster Response

      • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.