Adding generics to the Java language adds complexity to the type system and increases the verbosity of many variables and method declarations. Because there is no "typedef" tool to define the short name of the type, some developers turn to the extension as "the poor typedef", and the results are good.
A common complaint about the new generics tool in Java 5.0 is that it makes the code too verbose. A variable declaration that is sufficient in one row is no longer present, and the repetition associated with declaring a parameterized type is annoying, especially if the IDE is not well supported for automatic replenishment. For example, if you want to declare a MAP whose key is a Socket and the value is Future<string>, the old method is:
Much more compact than the new method:
Map<socket, future<string>> socketowner = new Hashmap<socket, future<string>> ();
Of course, the new method has built-in more types of information, reduces programming errors, and improves the readability of the program, but it does bring more upfront work on declaring variables and method signatures. Repetition of type parameters in declaration and initialization seems especially unnecessary; sockets and future<string> need to be entered two times, which forces us to violate the "DRY" principle (don't repeat yourself).
to synthesize something similar to a typedef.
Adding generics adds some complexity to the type system. Before Java 5.0, "Type" and "class" were almost synonymous, and parameterized types, especially those that were bound, made a significant difference between the concepts of subtypes and subclasses. Type arraylist<?>, arraylist<? Extends number> and arraylist<integer> are different types, although they are implemented by the same class ArrayList. These types form a hierarchical structure;arraylist<?> is arraylist<? Extends number> of the super type, while arraylist<? Extends number> is a super type of arraylist<integer>.
For the original simple type system, features like C's typedef have no meaning. But for more complex type systems, the TypeDef tool may offer some benefits. I don't know if it's good or bad, anyway, when generics join, the typedef doesn't join the Java language.
One of the (bad) practices that some people use as the "typedef of the Poor" is a small extension: Create a class, extend a generic type, but do not add functionality, such as the Socketusermap type, as shown in Listing 1:
Listing 1. Pseudo-typedef anti-mode--don't do that.
I refer to this technique as
Pseudo-typedef anti-mode, it implements this (problematic) goal of simplifying the Socketowner definition to one line, but some side effects are ultimately a hindrance to reuse and maintenance. (For classes with explicit constructors rather than parameterless constructors, derived classes also need to declare each constructor, because constructors are not inherited.) )
pseudo-type problems
In C, using typedef to define a new type is more like a macro than a type declaration. A typedef that defines an equivalence type that can be freely interchanged with the original type. Listing 2 shows an example of a definition of a callback function where a typedef is used in the signature, but the caller provides the callback with an equivalence type that the compiler and runtime can accept:
Listing 2. A typedef example of the C language
Define a type called "callback" is a function pointer typedef void (*CALLBACK) (int); void DoSomething (Callback Callback) {}//This function conforms to of type defined by Callback void callbackfunction (in T arg) {}//So a caller can pass the address of callbackfunction to dosomething void Usecallback () { dosomething (&am P;callbackfunction);
extension is not a type definition
An equivalent program written in the Java language that attempts to use a pseudo typedef can cause trouble. The stringlist and userlist types in Listing 3 extend a common superclass, but they are not equivalent types. This means that any code that wants to invoke Lookupall must pass a stringlist, not list<string> or userlist.
Listing 3. How pseudo types limit customers to only pseudo types
Class Stringlist extends Arraylist<string> {} class UserList extends Arraylist<string> {} ... class Someclas s {public void Validateusers (userlist users) {...}
This limit is much stricter than it initially appears. In small programs, there may not be much difference, but when a program becomes larger, the need to use pseudo types is constantly causing problems. If the variable type is stringlist, it cannot be assigned a normal list<string>, because List<string> is a stringlist super type, so it is not stringlist. Just as you cannot assign an Object to a variable of type String, you cannot assign list<string> to a variable of type stringlist (however, you can, for example, assign the stringlist to a type of list< String> variable, because list<string> is the stringlist type of the superclass.
The same case applies to the parameters of the method, and if a method parameter is a stringlist type, then the ordinary list<string> cannot be passed to it. This means that if you do not require a pseudo type for each use of this method, then the pseudo type cannot be used as a method parameter, which in practice means that pseudo types cannot be used at all in the library API. And most of the library APIs come from code that wasn't meant to be library code, so "This code is just for me, no one else will use it" is not a good excuse (as long as your code is a bit useful, others may use it; If your code stinks, you might be right).
The
pseudo type infects the
This "virus" nature is one of the difficult factors in making C code reusable. Almost every C-bag has a header file that defines the tool macros and types, like Int32, Boolean, True, false, and so forth. If you want to use a few packages within an application that do not use the same definitions for these public entries, you will need to spend a long time on the header file Hell issue even if you are compiling an empty program that contains only all header files. If you write a C application that uses many different packages from different authors, it is almost certain to involve some of these kinds of pain. On the other hand, it is very common for Java applications to use many or more packages without such pain. If packages are to use pseudo types in their APIs, then we may have to relive the problems that have long been left in painful memories.
As an example, suppose that there are two different packages, each of which defines the stringlist with a pseudo type inverse pattern, as shown in Listing 4, and each package defines the tool method that operates stringlist. The fact that all two packages define the same identifier is a small source of inconvenience; The client must choose to import a definition and another definition to use the fully qualified name. But the bigger problem is that the clients of these packages are now unable to create objects that can be passed to sortlist and passed to Reverselist because two different stringlist types are different types and incompatible with each other. Customers must now choose between using one package or another, otherwise they will have to do a lot of work to convert between different types of stringlist. What is convenient for the author of the package becomes a prominent impediment to the use of this package in all places, except in the most restricted environments.
Listing 4. How the use of pseudo types prevents reuse
Package A; Class Stringlist extends Arraylist<string> {} class Listutilities {public static void Sortlist (Stringlist list ) {}} package B; Class Stringlist extends Arraylist<string> {} class Someotherutilityclass {public static void Reverselist (STR Inglist list) {}} ... class Client {public void SomeMethod () { stringlist list = ...; Can ' t do this listutilities.sortlist (list); Someotherutilityclass.reverselist (list);
pseudo types are usually too specific
A further problem with pseudo-type anti-pattern is that it loses the benefit of using interfaces to define variable types and method parameters. Although stringlist can be defined as an extension list<string> interface, and then define a specific type stringarraylist to extend arraylist<string> and implement Stringlist, most pseudo The user of a typedef pattern is generally not up to this level, since the purpose of this technique is primarily to simplify and shorten the name of a type. As a result, APIs are less useful and more vulnerable because they use specific types such as ArrayList rather than abstract types such as List.
more secure tricks.
A more secure way to reduce the amount of typing required to declare a generic collection is to use
type inference (types inference)。 The compiler can use the type information embedded in the program very intelligently to assign type parameters. If you define a tool method such as the following:
public static <K,V> map<k,v> Newhashmap () {return new hashmap<k,v> ();
So you can safely use it to avoid typing two parameters:
This method works because the compiler can deduce the values of K and V based on the location called by the generic Method Newhashmap ().
Concluding remarks
The motivation for pseudo-typedef patterns is simple-developers want a way to define more compact type identifiers, especially when generics make type identifiers more verbose. The problem is that this approach creates a tight coupling between the customers who use its code and code, which hinders reuse. It's understandable that you don't like the verbosity of generic type identifiers, but that's not the way to solve the problem.