If I were to tell you directly what generics are, I really can’t. Here is a question:
Define a coordinate point class that can save various types of data, such as integers, floating point types, and string types.
Since the variable type is uncertain at first, it is easy to think of using the parent class of all types, that is, the Object class instead.
No more nonsense, use code to reflect it
Example 1: Use Object to implement uncertain data type input
//Use Object to represent uncertain types
public Point(Object x, Object y) {
this.setX(x);
this.setY(y);
}
public void setX(Object x) {
this.x = x;
}
public Object getX() {
return x;
}
public void setY(Object y) {
this.y = y;
}
public Object getY() {
return y;
}
}
//test class
public class Demo {
public static void main(String[] args) {
System.out.println("Use floating point numbers to represent coordinates: ");
Point p = new Point(12.23,23.21);
//Here, the Object class is converted to the Double class, and then automatically unboxed. The following two are the same.
System.out.println("X coordinates" + (Double)p.getX());
System.out.println("Y coordinates" + (Double)p.getY());
System.out.println();
System.out.println("Use integers to represent coordinates: ");
Point p2 = new Point(12, 23);
System.out.println("Coordinates of X" + (Integer)p2.getX());
System.out.println("Y coordinates" + (Integer)p2.getY());
System.out.println();
System.out.println("Representing coordinates as a string: ");
Point p3 = new Point("29 degrees north latitude", "113 degrees east longitude");
System.out.println("X coordinates" + (String)p3.getX());
System.out.println("Y coordinates" + (String)p3.getY());
}
}
You must clearly understand what type you are passing in, and then down-cast it before you can use it.
Although this meets the demand, it also implies an unsafe factor. Why is it said to be implicit?
For example, we use new Point(12.23, "29 degrees north latitude") to construct a Point object
Then use (Double) to transform it downward. What will be the result?
Yes, the compilation will pass, but once run, a type conversion exception will occur
It is also very simple to avoid class conversion exceptions. Just replace the Object declaration with a fixed type declaration (such as: String x, String y), so that an error will be reported during compilation.
Then you can find the mistakes and make corrections
But then we won't be able to meet the demand.
In order to avoid security risks and substitute various data types, those talented people introduced the concept of generics in JDK1.5
Let’s see how to rewrite the above code using generics
Example 2: Generic class
public class Demo {
public static void main(String[] args) {
System.out.println("Use floating point numbers to represent coordinates: ");
//After rewriting with generics, there is no need to perform downward transformation on the data used.
Point<Double> p = new Point<Double>(12.23,23.21);
System.out.println("X coordinates" + p.getX());
System.out.println("Y coordinates" + p.getY());
System.out.println();
System.out.println("Use integers to represent coordinates: ");
Point<Integer> p2 = new Point<Integer>(12, 23);
System.out.println("X coordinates" + p2.getX());
System.out.println("Y coordinates" + p2.getY());
System.out.println();
System.out.println("Representing coordinates as a string: ");
Point<String> p3 = new Point<String>("29 degrees north latitude", "113 degrees east longitude");
System.out.println("X coordinate" + p3.getX());
System.out.println("Y coordinates" + p3.getY());
}
}
If we deliberately pass in different data types at this time:
Point<Double> p = new Point<Double>("29 degrees north latitude",12.22);
Then, an error will be reported during compilation
Although generics are defined, if you do not use the generic mechanism in the constructor, it will treat the data as Object.
The purpose of this is mainly to be compatible with old codes before JDK1.4, such as
Point p = new Point(22.11,23.21);
The final running result is the same, but a warning message will be prompted during compilation.
Example 3: Generic methods
As you can see from the above example, once the object type is specified in the constructor, the same type will be used in the entire class
The most typical example is used in the collection framework, such as: ArrayList<Integer> al = new ArrayList<Integer>();
At this time, all object types operated in al are Integer.
However, sometimes we do not want to fix the object of operation, but want to use generic technology more flexibly.
At this time, you can try the generic method
public <E> void show(E e) {
System.out.println(e);
}
}
public class Demo {
public static void main(String[] args) {
Print p = new Print();
p.print(12);
p.print("hello");
p.show(new Integer(33));
p.show(23);
}
}
In fact, in this way, there is no big difference from using Object objects in methods.
What's more, after JDK1.5, the automatic unboxing function was added, eliminating the need for downward transformation.
Example 4: Generic interface
//Implementation method one:
class InterDemo1 implements Inter<String> {
public void print(String t) {
System.out.println("print: " + t);
}
}
//Implementation method two:
class InterDemo2<T> implements Inter<T> {
public void print(T t) {
System.out.println("print: " + t);
}
}
class Demo {
public static void main(String[] args) {
InterDemo1 id1 = new InterDemo1();
id1.print("hello");
InterDemo2<Integer> id2 = new InterDemo2<Integer>();
id2.print(new Integer(23));
}
}
There are two ways to implement a generic interface. One is to specify the generic type when implementing it.
The other is to still use generics and determine the generic type during construction.