reason generics were introduced in java 5
Can someone explain what were the reasons generics were introduced in Java?
As far as I understand they were introduced s开发者_C百科o that you don't accidentally add the wrong type of object to a collection.
I kind of like the generics for collection but can't see why they were added for other classes too. I have seen some generic classes that make your head hurt and your eyes bleed.
So what are all the reasons generics were introduced (mainly for non collections)?
TIA!
Essentially type safety and convenience.
Java implements its generics by a mechanism known as type erasure which effectively replaces the generic definition with a non-generic definition at compile time. The reason this was done was to maintain API compatability between 1.4 and 1.5 - the collections API may well have been updated but if you accessed it in a non-generic way in 1.5 it would work the same.
The difference was that if you intended a collection to only contain particular types of objects you could explictly encode that requirement in your APIs and avoid issues such as receiving a list with the wrong type of objects in it - and also the need to have to explictly cast those objects making your code simpler to read and less error prone.
You would use the generics for essentially the same reasons as when they are used with collections - when you need to say that an object is a composite of other objects, but that there may be a range of types possible for that composition and that once bound the addition of these new objects implies a new composite type disimilar to other similar composites. That is to say a list of strings is similar in type to a list of integers but they are no longer compatible with each other.
One example of this is in the Future
where you are waiting for an asynchronous result. The Future
class encapsulates the concept of the asynchronous result, but the specific type of Future
such as Future<String>
futher specifies what type of result you can expect - and makes it distinct from Future<Integer>
.
The Java Collection Framework is nothing special from a Java perspective, so there's no reason or need to add a new language feature to this framework only.
Look at generics from a user perspective: Now if you have a collection you know what kind of objects are in it. That's a great advantage. Just compare the following snippets, without and with generics:
With Java 1.5+
List<Animal> zoo = new ArrayList<Animal>();
for(Animal animal:zoo) {
feed(animal);
}
Before Java 1.5-
List zoo = new ArrayList();
for (int i = 0; i < zoo.size(); i++) {
if (!(zoo.get(i) instanceof Animal)) {
continue;
} else {
Animal animal = (Animal) zoo.get(i);
feed(animal);
}
}
From users perspective, it's more the old style that hurts the eye.
They were added because the only way to make a truly generic placeholder in the original Java was to have a field of type Object. This can take any object.
Unfortunately when you NEED it again it is of type Object which doesn't hold any interesting methods, so you need to cast it to the type you happen to know it has. These runtime casts were a frequent source of error and - by nature - happened at runtime.
Generics move this to the compiler, and cause a LOT less ClassCastExceptions which improve quality. The actual syntax is a bit verbose - here the C# keyword 'var' would help a lot - but the bit of extra labor gives a lot of payoff.
I believe you have to had programmed in a strongly typed language like Haskell to know what is possible, and why it is desirable.
Generics afford the programmer some type safety. The most obvious use is to prevent a user inadvertantly passing the wrong type into a function. They can also be used to avoid a lot of noisy casting.
Here is a non collection example that would benefit from a generic. If we have lots of views which are associated with a model, we might define an interface to represent a view. The interface might have a getModel() method:
public interface View {
Model getModel();
}
Anyone that calls the method has to cast the result which is a pain:
MyView view = new MyView();
MyModel model = (MyModel) view.getModel();
So instead we specify interface using as generic:
public interface View<M extends Model> {
M getModel();
}
A concrete class called MyView
class MyView implements View<MyModel> {
MyModel getModel();
}
Then the client code is a bit cleaner:
MyView view = new MyView();
MyModel model = view.getModel();
With careful crafting generics can make code a lot more readable. However generic type info doesn't get compiled into the class file so there is still potential for abuse at runtime.
Anyplace where you want to do generic programming ;-)
It is, you don't mind (too much) about the type of some object, but want to restrict its type to function properly.
Imaging pipe&filters. Imagine each pipe has a specific output. One outputs bytes, other strings, and other numbers. It would be nice each pipe has its specific type and you could only hook a pipe of an X output to a pipe of an X input.
Byte -> Filter -> String -> Filter -> Integer
So your first Filter will be Filter<Byte, String>
and its hookOutputPipe will receive a Pipe<String>
.
Maybe your eyes bleed with over parametrized types, but in some situations it's a pretty good allied for an API developer. If you start to use them in appropiate situations you'll feel the usefulness of them.
One example from real world: event types and handler types in GWT.
Two main objectives of Generics concepts are
1. To provide type safety to the collection so that they can hold only particular type of object
2.To resolve type casting problems
ArrayList<String> ob=new ArrayList<String>();
ob.add("shail");
ob.add("ball");
ob.add(10); //compile time error
At the time of retrival does not require type casting
String s1=ob.get(0);
JDK 5.0 introduces several new extensions to the Java programming language, one of these is the introduction of Generics.
Generics provides the abstraction over types. Here is a typical usage of that sort:
List l1 = new LinkedList(); // 1
l1.add(new Integer(10)); // 2
Integer x = (Integer) l1.iterator().next(); // 3
The cast on line 3 is slightly annoying. Typically, the programmer knows what kind of data has been placed into a particular list. However, the cast is essential. To ensure the assignment to a variable of type Integer is type safe, the cast is required.
Of course, the cast not only introduces clutter. It also introduces the possibility of a run time error, since the programmer may be mistaken.
What if programmers could mark a list as being restricted to contain a particular data type? This is the core idea behind generics.
Here is a example of the above given program using generics:
List <Integer> l1 = new LinkedList <Integer>(); // 1
l1.add(new Integer(10)); // 2
Integer x = l1.iterator().next(); // 3
Notice the type declaration for the variable l1. It specifies that this is not just an arbitrary List, but a List of Integer, written List. We say that List is a generic interface that takes a type parameter–in this case, Integer. We also specify a type parameter when creating the list object.
enter link description here
Generics are indeed particularly useful in collection classes, but their usefulness is not limited to that. I can't imagine how the generic capability could have been made available to collection classes and yet not be made generally available - generics are a fundamental language feature not a specific patch for collections. Would you want the compiler to have logic like:
if this is a collection class
allow generics
and how could the compiler spot that it has a collection class - after I can write my own collections.
Like many sharp tools generics can be misapplied and overused, that doesn't make the tool itself a bad thing.
Lets say, we want to write a method to find the maximum of two comparable objects, similar to Math.max():
public static <T extends Comparable<T>> T max(T arg0, T arg1) {
return arg0.compareTo(arg1) > 0 ? arg0 : arg1;
}
Now you can call the method like this,
int maxNum = max(5 ,3);
String maxString = max("AAA", "BBB");
File maxFile = max(new File("path/to/file1"), new File("path/to/file2"));
Try defining this functionality without generics. Here the return type is inferred and you dont need any type casting at all. Further the type is checked at compile time rather than resulting in ClassCastException at runtime.
- Elimination of explicit cast
- Stronger type checking at compile time
Elimination of explicit cast
Without generics:
List a = new LinkedList();
a.add(new Integer(5));
Integer i = (Integer)a.get(0); //Manual type conversion
With generics:
List<Integer> a = new LinkedList();
a.add(new Integer(5));
Integer i = a.get(0);
This restricts the data types the list can contain at first place.
Stronger type checking at compile time
Without generics:
List a = new LinkedList();
a.add("asia");
Integer i = (Integer)a.get(0); //compiles successfully
The above code compiles successfully but throws ClassCastException
at runtime.
With generics:
List<String> a = new LinkedList();
a.add("asia");
Integer i = a.get(0); //compile time error
The above code will break at compilation itself and save us from runtime error.
Java Generics is only a compile time concept.During run-time all type information is erased and this is called Type erasure.
Essentially to prevent bugs, by detecting type errors at compile time. Generics allow you to follow the DRY principle while maintaining type safety.
Quoting Oracle's Java documentation on Generics:
Generics add stability to your code by making more of your bugs detectable at compile time.
And the Introduction of the Generics tutorial by Gilad Bracha:
The net effect, especially in large programs, is improved readability and robustness.
Not only collections can make use of generics, you can easily think of decorators, proxies, and much more cases.
From JavaDocs
In a nutshell, generics enable types (classes and interfaces) to be parameters when defining classes, interfaces and methods. Much like the more familiar formal parameters used in method declarations, type parameters provide a way for you to re-use the same code with different inputs. The difference is that the inputs to formal parameters are values, while the inputs to type parameters are types.
Code that uses generics has many benefits over non-generic code:
Stronger type checks at compile time. A Java compiler applies strong type checking to generic code and issues errors if the code violates type safety. Fixing compile-time errors is easier than fixing runtime errors, which can be difficult to find.
Elimination of casts. The following code snippet without generics requires casting:
List list = new ArrayList(); list.add("hello"); String s = (String) list.get(0);
When re-written to use generics, the code does not require casting:
List<String> list = new
ArrayList<String>(); list.add("hello"); String s = list.get(0);
- Enabling programmers to implement generic algorithms. By using generics, programmers can implement generic algorithms that work on collections of different types, can be customized, and are type safe and easier to read.
精彩评论