We know that you define a variable by specifying its data type and what kind of data type is assigned to it before you use it.
If we now want to define a class to represent coordinates, the data type that requires the coordinates can be integers, decimals, and strings, for example:
x = 10, y = ten
x = 12.88, y = 129.65
x = "Tokyo 180 Degrees", y = "Latitude 210 degrees"
For different data types, in addition to the use of method overload, you can also use automatic boxing and upward transformation. We know that basic data types can be automatically boxed and converted to the corresponding wrapper class; object is the ancestor class of all classes, and instances of any class can be transformed up to type Object, for example:
int--> Integer--> Object
Double-->double--> Object
String--> Object
This allows you to receive all types of data by simply defining a method. Take a look at the following code:
public class Demo {public
static void Main (string[] args) {point
p = new Point ();
P.setx (10); int-> Integer-> Object
p.sety (m);
int x = (Integer) p.getx (); Must be transformed down
int y = (Integer) p.gety ();
System.out.println ("This point is:" + x + "," + y);
P.setx (25.4); Double-> Integer-> Object
p.sety ("Tokyo 180 Degrees");
Double m = (double) p.getx (); Must be transformed down
double n = (double) p.gety ();//During run throws an exception
System.out.println ("This point is:" + M + "," + N);
}
}
Class point{
Object x = 0;
Object y = 0;
Public Object GetX () {return
x;
}
public void SetX (Object x) {
this.x = x;
}
Public Object GetY () {return
y;
}
public void Sety (Object y) {
this.y = y;
}
}
In the code above, there is no problem generating coordinates, but when you take out the coordinates, you want to go down, and in the context of the type conversion of the Java Polymorphic object, we're talking about the risk of downward transitions, and it's not easy to find during compilation that exceptions are thrown only during run time, so try to avoid using downward transitions. Run the above code, the 12th row throws a Java.lang.ClassCastException exception.
So is there a better way to minimize risk by not using overloads (with duplicate code)?
There, you can use a generic class (Java Class), which can accept data of any type. The so-called "generics", is "broad data type", arbitrary data type.
Change the code above to use a generic class:
public class Demo {public
static void Main (string[] args) {
//instantiated generic class
Point<integer, integer> p1 = new P Oint<integer, integer> ();
P1.setx (ten);
P1.sety (a);
int x = P1.getx ();
int y = p1.gety ();
System.out.println ("This point is:" + x + "," + y);
Point<double, string> p2 = new point<double, string> ();
P2.setx (25.4);
P2.sety ("Tokyo 180 Degrees");
Double m = P2.getx ();
String n = p2.gety ();
System.out.println ("This point is:" + M + "," + N);
}
Define generic class
point<t1, t2>{
T1 x;
T2 y;
Public T1 GetX () {return
x;
}
public void SetX (T1 x) {
this.x = x;
}
Public T2 GetY () {return
y;
}
public void Sety (T2 y) {
this.y = y;
}
}
Run Result:
This is point is:10,
is:25.4, Tokyo 180 degrees
Compared to the definition of the normal class, the above code has a <t1 after the class name, T2>,T1, T2 is the custom identifier, is also the parameter, is used to pass the data the type, but is not the data value, we call the type parameter. In generics, not only the value of the data can be passed through parameters, but also the type of the data can be passed by parameter. T1, T2 is just a placeholder for the data type, and the runtime is replaced with the real data type.
The value-passing parameter (our usual argument) is surrounded by parentheses, such as (int x, double y), and type parameters (generic parameters) are surrounded by angle brackets, with multiple arguments separated by commas, such as <T> or <t, e>.
The type parameter needs to be given after the class name. Once the type parameter is given, it can be used in the class. The type parameter must be a valid identifier, accustomed to using a single uppercase letter, typically K denotes a key, V represents a value, and E represents an exception or error, and T represents a data type in general.
A generic class must indicate a specific type when instantiated, that is, a value to the type parameter, in the form of:
ClassName variable<datatype1, datatype2> = new Classname<datatype1, datatype2> ();
You can also omit the data type on the right side of the equal sign, but a warning is generated:
ClassName variable<datatype1, datatype2> = new ClassName ();
Because the data type is indicated when the generic class is used, assigning other types of values throws an exception that requires neither downward transition nor potential risk, which is more practical than the automatic boxing and upward transitions introduced at the beginning of this article.
Attention:
Generics are a new feature of Java 1.5, which is referenced by a C + + template and is essentially an application of a parameterized type (parameterized type).
Type parameters can only be used to represent reference types and cannot be used to represent basic types, such as int, double, char, and so on. However, passing the base type does not cause an error because they are automatically boxed into the corresponding wrapper class.
generic Method
In addition to defining generic classes, you can also define generic methods, such as a generic method that defines a print coordinate:
public class Demo {public
static void Main (string[] args) {
//instantiated generic class
Point<integer, integer> p1 = new P Oint<integer, integer> ();
P1.setx (ten);
P1.sety (a);
P1.printpoint (P1.getx (), p1.gety ());
Point<double, string> p2 = new point<double, string> ();
P2.setx (25.4);
P2.sety ("Tokyo 180 Degrees");
P2.printpoint (P2.getx (), p2.gety ());
}
Define generic class
point<t1, t2>{
T1 x;
T2 y;
Public T1 GetX () {return
x;
}
public void SetX (T1 x) {
this.x = x;
}
Public T2 GetY () {return
y;
}
public void Sety (T2 y) {
this.y = y;
}
Defines a generic method public
<t1, t2> void Printpoint (T1 x, T2 y) {
T1 m = x;
T2 n = y;
System.out.println ("This point is:" + M + "," + N);
}
Run Result:
This is point is:10,
is:25.4, Tokyo 180 degrees
The above code defines a generic method Printpoint (), which has both normal and type arguments, and the type parameter needs to be placed behind the modifier, before the return value type. Once a type parameter is defined, it can be used in the argument list, the method body, and the return value type.
Unlike using a generic class, you do not have to specify the parameter type when using a generic method, and the compiler automatically finds the specific type based on the parameters that are passed. Generic methods are called just like normal methods, except for different definitions.
Note: Generic methods are not necessarily associated with generic classes, and generic methods have their own type parameters, and generic methods can also be defined in normal classes. The type parameter T1 in the generic Method Printpoint (), T2 is not necessarily associated with the T1 in the generic class point, T2, or other identifiers can be used instead:
public static <v1, v2> void Printpoint (V1 x, V2 y) {
V1 m = x;
V2 n = y;
System.out.println ("This point is:" + M + "," + N);
}
Generic interface
A generic interface can also be defined in Java, where it is no longer redundant, just to produce sample code:
public class Demo {public
static void Main (String arsg[]) {
info<string> obj = new Infoimp<string> ("W Ww.weixueyuan.net ");
System.out.println ("Length of String:" + Obj.getvar (). Length ());
}
Define generic interface
interface info<t> {public
T GetVar ();
}
Implement interface
class Infoimp<t> implements info<t> {
private T var;
Defines the generic construct method public
Infoimp (T var) {
This.setvar (VAR);
}
public void SetVar (T var) {
This.var = var;
}
Public T GetVar () {return
this.var;
}
}
Run Result:
Type Erase
If you do not specify a data type when using generics, the generic type is erased, see the following code:
public class Demo {public
static void Main (string[] args) {point
p = new Point ();//Type Erase
p.setx (a);
P.sety (20.8);
int x = (Integer) p.getx (); Downward transition
Double y = (double) p.gety ();
System.out.println ("This point is:" + x + "," + y);
}
}
Class Point<t1, t2>{
T1 x;
T2 y;
Public T1 GetX () {return
x;
}
public void SetX (T1 x) {
this.x = x;
}
Public T2 GetY () {return
y;
}
public void Sety (T2 y) {
this.y = y;
}
}
Run Result:
This is point is:10, 20.8
Because the data type is not specified when using generics, the compiler converts all data up to Object in order to avoid errors, so that when you take out coordinates, you want to transition downward, which is no different from using generics at the beginning of this article.
restricting the available types of generics
In the above code, the type parameter can accept any data type, as long as it is defined. However, most of the time we need only a subset of data types is enough, the user passing other data types may cause errors. For example, write a generic function to return the maximum value in a different type of array (Integer, Double, Character, etc.):
Public <T> t Getmax (t array[]) {
t max = null;
for (T element:array) {
max = Element.doublevalue () > Max.doublevalue ()? Element:max;
}
return max;
}
The above code will complain, Doublevalue () is the number class method, not all classes have this method, so we want to limit the type parameter T, so that it can only accept number and its subclasses (Integer, Double, Character, etc.).
You can limit the type of generics by using the extends keyword to improve the code above:
Public <t extends number> t Getmax (t array[]) {
t max = null;
for (T element:array) {
max = Element.doublevalue () > Max.doublevalue ()? Element:max;
}
return max;
}
<t extends number> indicates that T only accepts number and its subclasses, and passing in other types of data can be an error. The qualifier here uses the keyword extends, which can be either a class or an interface. But the extends here is not the meaning of inheritance, it should be understood that T is inherited from the number class type, or T is the type that implements the XX interface.
Range of type parameters
In generics, if the type parameter is not restricted, it can accept any data type, as long as it is defined. However, most of the time we need only a subset of data types is enough, the user passing other data types may cause errors. For example, write a generic function to return the maximum value in a different type of array (Integer, Double, and so on):
Public <T> t Getmax (t array[]) {
t max = null;
for (T element:array) {
max = Element.doublevalue () > Max.doublevalue ()? Element:max;
}
return max;
}
The above code will complain, Doublevalue () is the number class and its subclasses, not all classes have the method, so we want to limit the type parameter T, so that it can only accept number and its subclasses (Integer, Double, Character, etc.).
The extends keyword allows you to limit the upper bounds of a generic type and improve the above code:
Public <t extends number> t Getmax (t array[]) {
t max = null;
for (T element:array) {
max = Element.doublevalue () > Max.doublevalue ()? Element:max;
}
return max;
}
<t extends number> indicates that T only accepts number and its subclasses, and passing in other types of data can be an error. The qualifier here uses the keyword extends, which can be either a class or an interface. If it is a class, there can be only one, but the interface may have multiple, separated by "&", such as <t extends Interface1 & interface2>.
The extends keyword here is no longer the meaning of inheritance, it should be understood that T is inherited from the number class type, or T is the type that implements the XX interface.