Detailed explanation of generics in Java – Java programming idea

Generics in Java refer to C + + templates. The boundary of Java is the limitation of Java generics.

One of the most compelling reasons for generics is to create container classes.

First, look at a class that can only hold a single object. This class can explicitly specify the type of object it holds

The reusability of the above class is not very good. It cannot hold any objects of other types. The following is implemented by holding objects of object type

Generally speaking, we only use containers to store one type of formation. One of the main purposes of generics is to specify what type of objects the container should hold, and the compiler will ensure the correctness of the type:

 {
 h3 =
(

That is, tell the compiler what type you want to use, and then the compiler handles all the details for you.

2.1. A one tuple class library

In order to return multiple objects in a method call, the concept of tuple can be used: a group of objects are directly packaged and stored in a single object. This class container allows the elements to be read, but does not allow the storage of new objects (also known as data transfer objects, or messengers).

Tuples can have any length, and objects in tuples can be of any different types. The following program is a two-dimensional tuple that can hold two objects:

 {
元组隐含的保持了其中元素的次序
<span class="javadoc">/**

  • 使用继承机制实现长度更长的元组
    */
    <span class="class"><span class="keyword">class <span class="title">ThreeTuple<<span class="title">A,<span class="title">B,<span class="title">C> <span class="keyword">extends <span class="title">TwoTuple<<span class="title">A,<span class="title">B> {
    <span class="indent"> <span class="keyword">public <span class="keyword">final C third;
    <span class="indent"> <span class="keyword">public ThreeTuple(A a,B b,C c) {
    <span class="indent"> <span class="indent"> <span class="keyword">super(a,b);
    <span class="indent"> <span class="indent"> third = c;
    <span class="indent"> }
    <span class="indent"> <span class="keyword">public String toString() {
    <span class="indent"> <span class="indent"> <span class="keyword">return <span class="string">"(" + first + <span class="string">"," + second + <span class="string">"," + third +<span class="string">")";
    <span class="indent"> }
    }

<span class="class"><span class="keyword">class <span class="title">FourTuple<<span class="title">A,<span class="title">C,<span class="title">D> <span class="keyword">extends <span class="title">ThreeTuple<<span class="title">A,<span class="title">C> {
<span class="indent"> <span class="keyword">public <span class="keyword">final D fourth;
<span class="indent"> <span class="keyword">public FourTuple(A a,C c,D d) {
<span class="indent"> <span class="keyword">super(a,b,c);
<span class="indent"> fourth = d;
<span class="indent"> }
<span class="indent"> <span class="keyword">public String toString() {
<span class="indent"> <span class="keyword">return <span class="string">"(" + first + <span class="string">"," +
<span class="indent"> <span class="indent"> third + <span class="string">"," + fourth + <span class="string">")";
<span class="indent"> }
}

In order to use tuples, you only need to define tuples of appropriate length as the return value of the method

 f() {
        ( g() {
        (
                <span class="keyword"&gt;static FourTuple<Circle,Square,Integer> h() { <span class="keyword"&gt;return <span class="keyword"&gt;new FourTuple<Circle,Integer>( <span class="keyword"&gt;new Circle(),<span class="keyword"&gt;new Square(),<span class="number"&gt;47); } <span class="keyword"&gt;static FiveTuple<Circle,Integer,Double> k() { <span class="keyword"&gt;return <span class="keyword"&gt;new FiveTuple<Circle,Double>( <span class="keyword"&gt;new Circle(),<span class="number"&gt;47,<span class="number"&gt;11.1); } <span class="keyword"&gt;public <span class="keyword"&gt;static <span class="keyword"&gt;void <a href="https://www.jb51.cc/tag/test/" target="_blank" class="keywords">test()</a> { TwoTuple<String,Integer> ttsi = f(); FourTuple<Circle,Integer> ts = h(); Sy<a href="https://www.jb51.cc/tag/stem/" target="_blank" class="keywords">stem</a>.out.println(ttsi); <span class="comment"&gt;// ttsi.first = "there"; // Compile error: final }

}

class FiveTuple<A,D,E> extends FourTuple<A, D> { public final E fifth; public FiveTuple(A a,D d,E e) { super(a,c,d); fifth = e; } < span class="keyword">public String toString() { return "(" + first + "," + third + "," + fourth + "," + fifth + ")"; } }

public class Chapter15_ 2_ 1 { public static void main(String args){ TupleTest.test(); } }

 {
 {
 next;
 next) {
 top = (); (item,top);  lss = (); 

Hold a list of objects of a specific type. Each time you call the select () method on it, you can randomly take an element:

 {
 storage = ();
 rs = ();

Generic interfaces can also be applied to interfaces, such as generators

It is an application of factory mode, but when using the generator to create a new object, it does not need any parameters, while factory methods generally need parameters.

Now I'll create a generator to show the usage scenario of generics in the interface

 { T next(); } <span class="comment">// 现在我们编写一个类,实现Generator
  
  
  
   
   
   接口,能够
   随机
   生成不同类型的Coffee对象
   
   
   
<span class="comment">// 实现了Iterable接口,所以可以再循环语句中使用
<span class="class"><span class="keyword">class <span class="title">ShapeGenerator <span class="keyword">implements <span class="title">Generator<<span class="title">Shape>,<span class="title">Iterable<<span class="title">Shape> {
<span class="indent"> <span class="keyword">private Class[] types = { Circle.class,Square.class,<span class="indent"> <span class="indent"> <span class="indent"> Triangle.class};
<span class="indent"> <span class="keyword">private <span class="keyword">static Random rand = <span class="keyword">new Random(<span class="number">47);
<span class="indent"> <span class="keyword">public ShapeGenerator() {}
<span class="indent"> <span class="comment">// For iteration:
<span class="indent"> <span class="keyword">private <span class="keyword">int size = <span class="number">0;
<span class="indent"> <span class="keyword">public ShapeGenerator(<span class="keyword">int sz) { size = sz; }
<span class="indent"> <span class="keyword">public Shape next() {
<span class="indent"> <span class="indent"> <span class="keyword">try {
<span class="indent"> <span class="indent"> <span class="indent"> <span class="keyword">return (Shape)
<span class="indent"> <span class="indent"> <span class="indent"> <span class="indent"> <span class="indent"> types[rand.nextInt(types.length)].newInstance();
<span class="indent"> <span class="indent"> <span class="comment">// Report programmer errors at run time:
<span class="indent"> <span class="indent"> } <span class="keyword">catch(Exception e) {
<span class="indent"> <span class="indent"> <span class="indent"> <span class="keyword">throw <span class="keyword">new RuntimeException(e);
<span class="indent"> <span class="indent"> }
<span class="indent"> }
<span class="indent"> <span class="class"><span class="keyword">class <span class="title">ShapeIterator <span class="keyword">implements <span class="title">Iterator<<span class="title">Shape> {
<span class="indent"> <span class="indent"> <span class="keyword">int count = size;
<span class="indent"> <span class="indent"> <span class="keyword">public <span class="keyword">boolean hasNext() { <span class="keyword">return count > <span class="number">0; }
<span class="indent"> <span class="indent"> <span class="keyword">public Shape next() {
<span class="indent"> <span class="indent"> <span class="indent"> count--;
<span class="indent"> <span class="indent"> <span class="indent"> <span class="keyword">return ShapeGenerator.<span class="keyword">this.next();
<span class="indent"> <span class="indent"> }
<span class="indent"> <span class="indent"> <span class="keyword">public <span class="keyword">void remove() { <span class="comment">// Not implemented
<span class="indent"> <span class="indent"> <span class="indent"> <span class="keyword">throw <span class="keyword">new UnsupportedOperationException();
<span class="indent"> <span class="indent"> }
<span class="indent"> };

<span class="indent"> <span class="comment">// 迭代方法
<span class="indent"> <span class="annotation">@Override
<span class="indent"> <span class="keyword">public Iterator iterator() {
<span class="indent"> <span class="indent"> <span class="keyword">return <span class="keyword">new ShapeIterator();
<span class="indent"> }

<span class="indent"> <span class="keyword">public <span class="keyword">static <span class="keyword">void test() {
<span class="indent"> <span class="indent"> ShapeGenerator gen = <span class="keyword">new ShapeGenerator();
<span class="indent"> <span class="indent"> <span class="keyword">for(<span class="keyword">int i = <span class="number">0; i < <span class="number">5; i++)
<span class="indent"> <span class="indent"> <span class="indent"> System.out.println(gen.next());
<span class="indent"> <span class="indent"> <span class="keyword">for(Shape c : <span class="keyword">new ShapeGenerator(<span class="number">5))
<span class="indent"> <span class="indent"> <span class="indent"> System.out.println(c);
<span class="indent"> }
}

The following class is another implementation of the generator interface, which is responsible for generating Fibonacci sequence:

 {

Next, write a Fibonacci Generator that implements Iterable to create an adapter class through inheritance:

 {
  <span class="annotation">@Override
<span class="keyword">public Iterator iterator() {
<span class="keyword">return <span class="keyword">new Iterator () {
<span class="keyword">public <span class="keyword">boolean hasNext() { <span class="keyword">return n > <span class="number">0; }
<span class="keyword">public Integer next() {
n--;
<span class="keyword">return IterableFibonacci.<span class="keyword">this.next();
}
<span class="keyword">public <span class="keyword">void remove() { <span class="comment">// Not implemented
<span class="keyword">throw <span class="keyword">new UnsupportedOperationException();
}
};
}
<span class="keyword">public <span class="keyword">static <span class="keyword">void test(String[] args) {
<span class="keyword">for(<span class="keyword">int i : <span class="keyword">new IterableFibonacci(<span class="number">18))
Sy stem.out.print(i + <span class="string">" ");
}
} <span class="comment">/ Output:
1 1 2 3 5 8 13 21 34 55 89 144 233 377 610 987 1597 2584
/<span class="comment">//:~

4.1 inference of lever utilization type parameters

The first is a static method:

 Map map(){
();
<span class="indent">  // 然后可以这样创建一个Map:
<span class="indent"> public static void test(String[] args){
<span class="indent"> <span class="indent"> Map<span class="tag"><<span class="title">String,<span class="attribute">List<<span class="attribute">Cat>> catMap = New.map();
<span class="indent"> }
}

It can be found that the one on the right is no longer written in the previous way:

The type of the declaration part on the left provides an inference for the right, so that the compiler can directly create specific classes. However, there is no declaration in this scenario, and new. Net is used directly Map () fails the compilation because there is no basis to infer like the one on the left here. As shown below, adding f () is a method that needs to pass in a map. The following writing method fails the compilation:

If you really want to use it as above, you can consider using the display type description. Insert angle brackets directly into the operator and method name to indicate the type. The code is as follows:

However, this method is rarely used. In other words, such a description is required only when writing non assignment statements, instead of using lever type inference.

For convenience, we can create other containers in the same way. Unfortunately, the JDK itself does not provide such a class:

 Map map() {
      return new HashMap();
    }
    public static  List list() {
      return new ArrayList();
    }
    public static  LinkedList lList() { return new LinkedList(); } public static  Set set() { return new HashSet(); } public static  Queue queue() { return new LinkedList(); } // Examples: public static void test(String[] args) { Map> sls = New.map(); List ls = New.list(); LinkedList lls = New.lList(); Set ss = New.set(); Queue qs = New.queue(); } }

4.2 variable parameters and generic methods

Variable parameters can also be declared using generic types:

<span class="indent">  public static <span class="tag"><<span class="title">T> List<span class="tag"><<span class="title">T> makeList(T... args){
<span class="indent"> <span class="indent"> List<span class="tag"><<span class="title">T> result = new ArrayList<span class="tag"><<span class="title">T>();
<span class="indent"> <span class="indent"> for(T item : args){
<span class="indent"> <span class="indent"> <span class="indent"> result.add(item);
<span class="indent"> <span class="indent"> }
<span class="indent"> <span class="indent"> return result;
<span class="indent"> }
<span class="indent"> public static void test(String[] args){
<span class="indent"> <span class="indent"> List<span class="tag"><<span class="title">String> ls = makeList("Jay","Mike");
<span class="indent"> }
}

4.3 generic method for generator

By using generic methods, encapsulate more abstract methods, such as the following fill (), and then pass in the specific objects to be used when using them:

<span class="indent">  <span class="keyword">public <span class="keyword">static 
  
  
   Collection
  
  
  
   
   
    fill(
   
   
   
<span class="indent"> <span class="indent"> <span class="indent"> Collection coll,Generator gen,<span class="keyword">int n){
<span class="indent"> <span class="indent"> <span class="keyword">for(<span class="keyword">int i=<span class="number">0; i<n; i++){
<span class="indent"> <span class="indent"> <span class="indent"> coll.add(gen.next());
<span class="indent"> <span class="indent"> }
<span class="indent"> <span class="indent"> <span class="keyword">return coll;
<span class="indent"> }
}

<span class="keyword">public <span class="class"><span class="keyword">class <span class="title">Chapter15_4_3 {
<span class="indent"> <span class="keyword">public <span class="keyword">static <span class="keyword">void main(String[] args){
<span class="indent"> <span class="indent"> Collection shapes = GenericGenerator.fill(<span class="keyword">new ArrayList (),<span class="keyword">new ShapeGenerator(),<span class="number">2);
<span class="indent"> <span class="indent"> <span class="keyword">for(Shape a : shapes){
<span class="indent"> <span class="indent"> <span class="indent"> Sy stem.out.println(a);
<span class="indent"> <span class="indent"> }
<span class="indent"> }
}

4.4. A general generator

By using generic classes, we create a more generic generator.

  {

<span class="indent"> <span class="keyword">private Class type;
<span class="indent"> <span class="keyword">public BasicGenerator(Class type){
<span class="indent"> <span class="indent"> <span class="keyword">this.type = type;
<span class="indent"> }

<span class="indent"> <span class="annotation">@Override
<span class="indent"> <span class="keyword">public T next() {
<span class="indent"> <span class="indent"> <span class="keyword">try {
<span class="indent"> <span class="indent"> <span class="indent"> <span class="keyword">return type.newInstance();
<span class="indent"> <span class="indent"> } <span class="keyword">catch (Exception e) {
<span class="indent"> <span class="indent"> <span class="indent"> <span class="keyword">throw <span class="keyword">new RuntimeException(e);
<span class="indent"> <span class="indent"> }
<span class="indent"> }
<span class="indent"> <span class="keyword">public <span class="keyword">static Generator create(Class type){
<span class="indent"> <span class="indent"> <span class="keyword">return <span class="keyword">new BasicGenerator (type);
<span class="indent"> }
}

Because the newinstance () method is used, the class produced here must provide a default parameterless constructor.

Next, try creating an object. In order to mark it as a newly created object, save a static counter in the class, and add 1 for each object created:

<span class="indent">  <span class="keyword">private <span class="keyword">static <span class="keyword">long counter = <span class="number">0;
<span class="indent"> <span class="keyword">private <span class="keyword">final <span class="keyword">long id = counter++;
<span class="indent"> <span class="keyword">public <span class="keyword">long id(){
<span class="indent"> <span class="indent"> <span class="keyword">return id;
<span class="indent"> }
<span class="indent"> <span class="keyword">public String toString(){
<span class="indent"> <span class="indent"> <span class="keyword">return <span class="string">"countObject" + id;
<span class="indent"> }
<span class="indent"> <span class="keyword">public <span class="keyword">static <span class="keyword">void test(String[] args){
<span class="indent"> <span class="indent"> Generator gen = BasicGenerator.create(CountObject.class);
<span class="indent"> <span class="indent"> <span class="keyword">for(<span class="keyword">int i=<span class="number">0; i<<span class="number">5; i++){
<span class="indent"> <span class="indent"> <span class="indent"> Sy stem.out.println(gen.next());
<span class="indent"> <span class="indent"> }
<span class="indent"> }
}
<span class="comment">/
test 输入结果如下:
countObject0
countObject1
countObject2
countObject3
countObject4
/

4.5. Simplify the use of tuples

We can find that the tuples created before all pass in a long list of specific types when they are used. By leveraging the type inference parameters, we can directly omit the long list of specific types and add a static method to make this method a more general class library method:

<span class="indent">  <span class="keyword">public <span class="keyword">static<A,B,C> ThreeTuple<A,C> tuple(A a,C c){
<span class="indent"> <span class="indent"> <span class="keyword">return <span class="keyword">new ThreeTuple<A,C>(a,c);
<span class="indent"> }

}
<span class="keyword">public <span class="class"><span class="keyword">class <span class="title">Chapter15_4_5 {
<span class="indent"> <span class="keyword">public <span class="keyword">static <span class="keyword">void main(String[] args){
<span class="indent"> <span class="indent"> <span class="comment">// 根据左边的类型自动判断右边的类型,无需手动创建时指明类型了
<span class="indent"> <span class="indent"> ThreeTuple<Cat,String> tt = TupleTest2.tuple(<span class="keyword">new Cat(),<span class="number">1,<span class="string">"Jason");
<span class="indent"> <span class="indent"> System.out.println(tt);
<span class="indent"> }
}

4.6. A set utility

<span class="keyword">class WatercolorSets {
<span class="keyword">public <span class="keyword">static <span class="keyword">void main(String[] args) {
<span class="indent"> Set set1 =
<span class="indent"> <span class="indent"> EnumSet.range(Watercolors.BRILLIANT_RED,Watercolors.VIRIDIAN_HUE);
<span class="indent"> Set set2 =
<span class="indent"> <span class="indent"> EnumSet.range(Watercolors.CERULEAN_BLUE_HUE,Watercolors.BURNT_UMBER);
<span class="indent"> Sy stem.<span class="keyword">out.println(<span class="string">"set1: " + set1);
<span class="indent"> Sy stem.<span class="keyword">out.println(<span class="string">"set2: " + set2);
<span class="indent"> Sy stem.<span class="keyword">out.println(<span class="string">"union(set1,set2): " + union(set1,set2));
<span class="indent"> Set subset = intersection(set1,set2);
<span class="indent"> Sy stem.<span class="keyword">out.println(<span class="string">"intersection(set1,set2): " + subset);
<span class="indent"> Sy stem.<span class="keyword">out.println(<span class="string">"difference(set1,subset): " +
<span class="indent"> <span class="indent"> difference(set1,subset));
<span class="indent"> Sy stem.<span class="keyword">out.println(<span class="string">"difference(set2,subset): " +
<span class="indent"> <span class="indent"> difference(set2,subset));
<span class="indent"> Sy stem.<span class="keyword">out.println(<span class="string">"complement(set1,set2): " +
<span class="indent"> <span class="indent"> complement(set1,set2));
}
} <span class="comment">/ Output: (Sample)
set1: [BRILLIANT_RED,VIRIDIAN_HUE]
set2: [CERULEAN_BLUE_HUE,BURNT_UMBER]
union(set1,set2): [SAP_GREEN,VIRIDIAN_HUE]
intersection(set1,set2): [ULTRAMARINE,VIRIDIAN_HUE]
difference(set1,subset): [ROSE_MADDER,BRILLIANT_RED]
difference(set2,subset): [RAW_UMBER,BURNT_UMBER]
complement(set1,MAGENTA]
/<span class="comment">//:~

The following example uses sets Difference () prints out Java Method differences between various collection classes and map classes in util package:

 methodSet(Class type) {
      Set
  
  
   result = 
  
  
  ();
       type) {
      System. result = ();  c : type.getInterfaces()) result.add(c.getSimpleName()); System.  superset,Class subset) { System. comp = Sets.difference( methodSet(superset),methodSet(subset)); comp.removeAll(
 
 
 

Generic methods can also be applied to inner classes and anonymous inner classes. The following is an example of using anonymous inner classes to implement the generator interface:

 generator() {
        () {
            <span class="class"><span class="keyword">class <span class="title">Teller {
<span class="keyword">private <span class="keyword">static <span class="keyword">long counter = <span class="number">1;
<span class="keyword">private <span class="keyword">final <span class="keyword">long id = counter++;
<span class="keyword">private Teller() {}
<span class="keyword">public String toString() { <span class="keyword">return <span class="string">"Teller " + id; }
<span class="comment">// A single Generator object:
<span class="keyword">public <span class="keyword">static Generator generator =
<span class="keyword">new Generator () {
<span class="keyword">public Teller next() { <span class="keyword">return <span class="keyword">new Teller(); }
};
}

<span class="class"><span class="keyword">class <span class="title">BankTeller {
<span class="keyword">public <span class="keyword">static <span class="keyword">void serve(Teller t,Customer c) {
System.out.println(t + <span class="string">" serves " + c);
}
<span class="keyword">public <span class="keyword">static <span class="keyword">void main(String[] args) {
Random rand = <span class="keyword">new Random(<span class="number">47);
Queue line = <span class="keyword">new LinkedList ();
Generators.fill(line,Customer.generator(),<span class="number">15);
List tellers = <span class="keyword">new ArrayList ();
Generators.fill(tellers,Teller.generator,<span class="number">4);
<span class="keyword">for(Customer c : line)
serve(tellers.get(rand.nextInt(tellers.size())),c);
}
} <span class="comment">/ Output:
Teller 3 serves Customer 1
Teller 2 serves Customer 2
Teller 3 serves Customer 3
Teller 1 serves Customer 4
Teller 1 serves Customer 5
Teller 3 serves Customer 6
Teller 1 serves Customer 7
Teller 2 serves Customer 8
Teller 3 serves Customer 9
Teller 3 serves Customer 10
Teller 2 serves Customer 11
Teller 4 serves Customer 12
Teller 2 serves Customer 13
Teller 1 serves Customer 14
Teller 1 serves Customer 15
/<span class="comment">//:~

An important advantage of generics is that it can easily and safely create complex models, such as list tuples:

> {
 tl =
();
 i: tl)

The following example shows how easy it is to build a complex model using generic types

 generator =
      () {
        <span class="class"><span class="keyword">class <span class="title">Shelf <span class="keyword">extends <span class="title">ArrayList<<span class="title">Product> {
<span class="keyword">public Shelf(<span class="keyword">int nProducts) {
Generators.fill(<span class="keyword">this,Product.generator,nProducts);
}
}

<span class="class"><span class="keyword">class <span class="title">Aisle <span class="keyword">extends <span class="title">ArrayList<<span class="title">Shelf> {
<span class="keyword">public Aisle(<span class="keyword">int nShelves,<span class="keyword">int nProducts) {
<span class="keyword">for(<span class="keyword">int i = <span class="number">0; i < nShelves; i++)
add(<span class="keyword">new Shelf(nProducts));
}
}

<span class="class"><span class="keyword">class <span class="title">CheckoutStand {}
<span class="class"><span class="keyword">class <span class="title">Office {}

<span class="keyword">public <span class="class"><span class="keyword">class <span class="title">Store <span class="keyword">extends <span class="title">ArrayList<<span class="title">Aisle> {
<span class="keyword">private ArrayList checkouts =
<span class="keyword">new ArrayList ();
<span class="keyword">private Office office = <span class="keyword">new Office();
<span class="keyword">public Store(<span class="keyword">int nAisles,<span class="keyword">int nShelves,<span class="keyword">int nProducts) {
<span class="keyword">for(<span class="keyword">int i = <span class="number">0; i < nAisles; i++)
add(<span class="keyword">new Aisle(nShelves,nProducts));
}
<span class="keyword">public String toString() {
StringBuilder result = <span class="keyword">new StringBuilder();
<span class="keyword">for(Aisle a : <span class="keyword">this)
<span class="keyword">for(Shelf s : a)
<span class="keyword">for(Product p : s) {
result.append(p);
result.append(<span class="string">"\n");
}
<span class="keyword">return result.toString();
}
<span class="keyword">public <span class="keyword">static <span class="keyword">void main(String[] args) {
Sy stem.out.println(<span class="keyword">new Store(<span class="number">14,<span class="number">5,<span class="number">10));
}
} <span class="comment">/ Output:
258: Test,price: $400.99
861: Test,price: $160.99
868: Test,price: $417.99
207: Test,price: $268.99
551: Test,price: $114.99
278: Test,price: $804.99
520: Test,price: $554.99
140: Test,price: $530.99
...
/<span class="comment">//:~

<span class="keyword">public <span class="class"><span class="keyword">class <span class="title">Chapter15_6 {
<span class="keyword">public <span class="keyword">static <span class="keyword">void main(String[] args){
TupleList.main(args);
}
}

7. The mystery of erasure

Look at a strange question and consider the following output:

The output turned out to be true.

Let's use class The gettypeparameters () method returns an array of TypeVariable objects to see what happened:

We found that the output result is:

This is just a placeholder for parameters, so you can't get any information about generic parameter types inside generic code. You can know information such as type parameter identifiers and generic type boundaries, but you can't know the actual type parameters used to create a particular instance. Generics in Java are implemented by erasure, so when using generics, any specific type information is erased, and only an object is currently used. That's why equality occurs above.

Check out the following generic code for C + +:

<span class="keyword">template<<span class="keyword">class T> <span class="keyword">class Manipulator {
T obj;
<span class="keyword">public:
Manipulator(T x) { obj = x; }
<span class="keyword">void manipulate() { obj.f(); }
};

<span class="keyword">class HasF {
<span class="keyword">public:
<span class="keyword">void f() { <span class="built_in">cout << <span class="string">"HasF::f()" << endl; }
};

<span class="keyword">int main() {
HasF hf;
Manipulator manipulator(hf);
manipulator.manipulate();
} <span class="comment">/* Output:
HasF::f()

For a generic object written in C + +, when the template is instantiated, the template code knows the type of its template parameters, and the C + + compiler will check. If the generic object calls a method that does not exist in the current instantiated object, a compilation time error will be reported. For example, obj. Is called in the above manipulate F (), because this method exists in the instantiated HASF, no error will be reported.

Java implements generics by erasure. Without specifying boundaries, you cannot directly call methods of generic objects in generic classes, as shown in the following example:

 {

<span class="indent"> <span class="keyword">private T obj;
<span class="indent"> <span class="keyword">public Manipulator(T x){
<span class="indent"> <span class="indent"> obj = x;
<span class="indent"> }
<span class="indent"> <span class="keyword">public <span class="keyword">void doSomething(){
<span class="indent"> <span class="indent"> obj.f(); <span class="comment">// 编译错误
<span class="indent"> }
}

A compilation error occurred by calling f() through obj without boundary. Specify the boundary below and let it pass the compilation:

 {

<span class="indent"> <span class="keyword">private T obj;
<span class="indent"> <span class="keyword">public Manipulator(T x){
<span class="indent"> <span class="indent"> obj = x;
<span class="indent"> }
<span class="indent"> <span class="keyword">public <span class="keyword">void doSomething(){
<span class="indent"> <span class="indent"> obj.f(); <span class="comment">// 编译错误
<span class="indent"> }
}
<span class="class"><span class="keyword">class <span class="title">HasF{
<span class="indent"> <span class="keyword">public <span class="keyword">void f(){
<span class="indent"> <span class="indent"> System.out.println(<span class="string">"HasF.f();");
<span class="indent"> }
}

In the above example, the generic type parameter is erased to HASF, just like replacing T with HASF in the class declaration.

The generic type is jdk1 5, so in order to be compatible, it is realized by erasing. Generic types only appear during static type checking, after which all generic types in the program are erased and replaced with their non Generic upper bound. For example, list will be erased as list, while ordinary type variables will be erased as object without specifying boundaries.

Erasure enables existing non generic client code to continue to be used without change until the client is ready to rewrite the code with generics.

However, the cost of erasure is also significant. Generics cannot be used in operations that explicitly reference runtime types, such as transformation, instanceof and new operators, because all type information about parameters is lost. Whenever you write generic code, you must always remind yourself that you just seem to have type information about parameters. In fact, it is just an object.

When you want to use @ suppresswarnings ("unchecked") to turn off warnings, you'd better "focus" as much as possible, so that you won't accidentally shield the real problems by turning off warnings too broadly.

The following derived3 error means that the compiler expects a native base class. When you want to treat parameter types not just as objects, you need to make extra efforts to manage boundaries.

 {
<span class="class"><span class="keyword">class <span class="title">Derived1<<span class="title">T> <span class="keyword">extends <span class="title">GenericBase<<span class="title">T> {}

<span class="class"><span class="keyword">class <span class="title">Derived2 <span class="keyword">extends <span class="title">GenericBase {} <span class="comment">// No warning

<span class="comment">// class Derived3 extends GenericBase<?> {}
<span class="comment">// Strange error:
<span class="comment">// unexpected type found : ?
<span class="comment">// required: class or interface without bounds

<span class="class"><span class="keyword">class <span class="title">ErasureAndInheritance {
<span class="indent"> <span class="annotation">@SuppressWarnings(<span class="string">"unchecked")
<span class="indent"> <span class="keyword">public <span class="keyword">static <span class="keyword">void main(String[] args) {
<span class="indent"> <span class="indent"> Derived2 d2 = <span class="keyword">new Derived2();
<span class="indent"> <span class="indent"> Object obj = d2.get();
<span class="indent"> <span class="indent"> d2.set(obj); <span class="comment">// Warning here!
<span class="indent"> }
} <span class="comment">///:~

7.4 actions at boundary

 {
 holder =
();

The set () method of the above code will be checked during compilation, and the string type is directly taken out during get (). In fact, the transformation will be carried out here, but it is automatically inserted by the compiler, which is equivalent to inserting such code: (string) holder Get(), the detailed transformation processing can be compiled into bytecode for viewing.

Because the type information is erased, the code related to the type cannot work, as follows:

 {

The instanceof method above cannot be used. In order to judge the type in the generic class, you can introduce the type tag:

 {

<span class="indent"> Class<span class="tag"><<span class="title">T> kind;
<span class="indent"> public ClassTypeCapture(Class<span class="tag"><<span class="title">T> kind){
<span class="indent"> <span class="indent"> this.kind = kind;
<span class="indent"> }
<span class="indent"> public boolean f(Object arg){
<span class="indent"> <span class="indent"> return kind.isinstance(arg);
<span class="indent"> }
<span class="indent"> public static void main(String[] args){
<span class="indent"> <span class="indent"> ClassTypeCapture<span class="tag"><<span class="title">String> ctc = new ClassTypeCapture<span class="tag"><<span class="title">String>(String.class);
<span class="indent"> <span class="indent"> System.out.println(ctc.f("art")); // true
<span class="indent"> <span class="indent"> System.out.println(ctc.f(1)); // false
<span class="indent"> }
}

8.1. Create type instance

How can we create generic objects in a generic class? The methods directly created above also fail to compile? We can use the generic factory approach. You can save a type tag using class Newinstance() to create generic objects, but in this case, the class corresponding to the passed in type label must have a constructor, so it is not recommended. Let's talk about the method of the displayed factory (limit its type so that only classes that implement the factory can be accepted):

First, create a factory interface:

 {
    T create();
}

Next, create an object that contains a generic object that needs to be created using the factory:

 {
    private T x;
    public > Foo(F factory){
        x = factory.create();
    }
}

Next, create the displayed factory:

{
{

In this way, we can create generic objects in generic classes by passing in the above display factory:

((    <span class="comment"&gt;// TODO 模板<a href="https://www.jb51.cc/tag/fangfa/" target="_blank" class="keywords">方法</a>设计模式
}

}

As can be seen from the example of erased above, generic arrays cannot be created directly. Generally, ArrayList is used instead.

 {
 ();
<span class="class"><span class="keyword">class <span class="title">Generic<<span class="title">T> {}

But you can define a reference the way the compiler likes, but you can never create an array of this exact type.

[] gia;
}

Cannot create an array of this exact type

[] gia;
    @SuppressWarnings("unchecked")
    public static void main(String[] args) {
      gia = (Generic[])new Object[SIZE];  // 编译通过,运行报ClassCastException错误,因为数组将跟踪它们的实际类型,而这个类型是在数组被创建时确定的。
      // Runtime type is the raw (erased) type:
      gia = new Generic[SIZE];  // 不能这样创建,Cannot create a generic array of Generic
      gia = (Generic[])new Generic[SIZE];  // 成功创建泛型数组的唯一方法就是创建一个被擦除类型的新数组,然后对其转型。
      System.out.println(gia.getClass().getSimpleName());  // Generic[]
      gia[0] = new Generic();
      gia[1] = new Object();  // 错误:cannot convert from Object to Generic gia[2] = new Generic(); // 错误:cannot convert from Generic to Generic } }

Here is a generic array wrapper

 {
 gai =
(

Because of erasure, the runtime type of the array can only be object []. If we immediately convert it to t [], the actual type of the array will be lost during compilation, and the compiler may miss some potential error checking. Because of this, it is best to use object [] inside the collection. When using array elements, add a type conversion to t

 {
 gai =
(

You can pass a type tag so that the rep () method works:

 {
 type, gai =
(

Methods called using unbounded generics can only be methods that object can call. If the parameter type can be limited to a subset of types, you can use these subsets of types to call methods.

Use the extends keyword to add boundaries to generic declarations:

{
 {
<span class="keyword">public <span class="class"><span class="keyword">class <span class="title">Chapter15_9 {
<span class="indent"> <span class="keyword">public <span class="keyword">static <span class="keyword">void main(String[] args){
<span class="indent"> <span class="indent"> GoldenFish fish = <span class="keyword">new GoldenFish();
<span class="indent"> <span class="indent"> <span class="comment">// 创建泛型类,super关键字对应的类继承结构
<span class="indent"> <span class="indent"> Item1 item1 = <span class="keyword">new Item1 (fish);
<span class="indent"> <span class="indent"> item1.doSomething();
<span class="indent"> }
}

Question marks in generic parameter expressions.

First, let's take a look at an example. You can assign an array reference of base type to an array of export type Apple:

<span class="class"><span class="keyword">class <span class="title">CovariantArrays {
<span class="keyword">public <span class="keyword">static <span class="keyword">void main(String[] args) {
Fruit[] fruit = <span class="keyword">new Apple[<span class="number">10];
fruit[<span class="number">0] = <span class="keyword">new Apple(); <span class="comment">// OK
fruit[<span class="number">1] = <span class="keyword">new Jonathan(); <span class="comment">// OK
<span class="comment">// Runtime type is Apple[],not Fruit[] or Orange[]:
<span class="keyword">try {
<span class="comment">// Compiler allows you to add Fruit:
<span class="comment">// 运行时抛出异常,此时的数组机制知道它处理的是Apple[]
fruit[<span class="number">0] = <span class="keyword">new Fruit(); <span class="comment">// ArrayStoreException
} <span class="keyword">catch(Exception e) { System.out.println(e); }
<span class="keyword">try {
<span class="comment">// Compiler allows you to add Oranges:
fruit[<span class="number">0] = <span class="keyword">new Orange(); <span class="comment">// ArrayStoreException
} <span class="keyword">catch(Exception e) { System.out.println(e); }
}
} <span class="comment">/ Output:
java.lang.ArrayStoreException: Fruit
java.lang.ArrayStoreException: Orange
/<span class="comment">//:~

We use generics to replace arrays so that errors can be detected at recompile time:

 flist = new ArrayList();
}

Generics do not automatically transform upward. You cannot assign a generic involving apple to a generic involving fruit.

Sometimes you want to establish some kind of upward transformation relationship between two types, which is allowed by wildcards:

:具有任何从Fruit继承的类型的列表,但是为了向上转型为flist,这个类型是什么并没有人关心
 flist = ();
(); 也不可以成功添加

10.1. How smart is the compiler

Used? The generic method parameters of extends fruit cannot be passed in any specific parameters.

 ,编译器不能了解这里需要Fruit的哪个具体子类型,因此不会接受任何类型的Fruit,
 flist =

In order to prohibit such calls of contains when wildcards are used in the type, we need to use the type parameter in the parameter list

 {
 Apple = (不能进行向上转型赋值为Holder
    
    
    

     
     
      Fruit = Apple; // Cannot upcast
  fruit = Apple; 
    
    
    

Super type wildcard: you can declare that the wildcard is defined by the Rene accumulation of a specific class, or you can use type parameters, which enables you to safely pass a type object to a generic type. Therefore, with super type wildcard, you can write to the collection:

 apples) {
        apples.add(new Apple());
        apples.add(new Jonathan());
      // apples.add(new Fruit()); // Error
    }
}

Think about subtype and supertype boundaries based on how you can "write" (pass to a method) to a generic type and how you can "read" (return from a method) from a generic type?

The supertype boundary relaxes the restrictions on the parameters that can be passed to the method

 void writeExact(List list,T item) {
 apples = new ArrayList();
 fruit = new ArrayList();
 void writeWithWildcard(List list,T item) { 

Let's continue with an example of covariance and wildcards

 T readExact(  apples = Arrays.asList( fruit = Arrays.asList( {   fruitReader = (); ) cannot be ).  {   fruitReader = (); 

10.3. Borderless wildcard

Unbounded wildcards seem to mean "anything", so using unbounded wildcards seems to be equivalent to using native types.

The compiler seems to support this judgment at first:

 list2;
     list3;
    是不同的
      
    }
      required: List assign1(()); assign2(()); assign3(()); :  wildList = (); assign1(wildList); assign2(wildList); assign3(wildList); } }

In these cases, it can be regarded as a decoration, but it is still very valuable. It declares that "I want to write this code with Java generics. I don't want to use native types here, but in this case, generic parameters can hold any type."

The following shows an important application of unbounded wildcards: when dealing with multiple generic parameters, sometimes one parameter can be of any type, and the ability to determine a specific type for other parameters is very important:

 map2;
 map3;
 map) { map2 = map; }
 map) { map3 = map; }
required: Map ()); ()); ()); 

List

When will the compiler focus on the difference between native types and types involving unbounded wildcards?

The following is an example:

<span class="indent">  <span class="comment">// Can't do this; don't have any 'T':
<span class="indent"> <span class="comment">// T t = holder.get();

<span class="indent"> <span class="comment">// OK,but type information has been lost:
<span class="indent"> Object obj = holder.<span class="keyword">get();
}
<span class="comment">// Similar to rawArgs(),but errors instead of warnings:
<span class="comment">// 这里演示了<?>和原生类型是不同的:
<span class="keyword">static <span class="keyword">void unboundedArg(Holder<?> holder,Object arg) {
<span class="indent"> <span class="comment">// 原生Holder将持有任何类型的组合,而Holder<?>将持有具有某种具体类型的同构集合,因此不能只是向其中传递Object
<span class="indent"> holder.<span class="keyword">set(arg); <span class="comment">// Error:
<span class="indent"> <span class="comment">// set(capture of ?) in Holder<capture of ?>
<span class="indent"> <span class="comment">// cannot be applied to (Object)
<span class="indent"> <span class="comment">// holder.set(new Wildcards()); // Same error

<span class="indent"> <span class="comment">// Can't do this; don't have any 'T':
<span class="indent"> <span class="comment">// T t = holder.get();

<span class="indent"> <span class="comment">// OK,but type information has been lost:
<span class="indent"> Object obj = holder.<span class="keyword">get();
}
<span class="keyword">static T exact1(Holder holder) {
<span class="indent"> T t = holder.<span class="keyword">get();
<span class="indent"> <span class="keyword">return t;
}
<span class="keyword">static T exact2(Holder holder,T arg) {
<span class="indent"> holder.<span class="keyword">set(arg);
<span class="indent"> T t = holder.<span class="keyword">get();
<span class="indent"> <span class="keyword">return t;
}
<span class="comment">// 在Holder类型上的限制被放松为 包括持有任何扩展自T的对象的Holder,
<span class="comment">// 传入了Holder 之后,为了防止将Orange放置到Holder ,<span class="comment">// 对set的 调用都是不允许的,但是你仍旧知道任何来自Holder<? extends Fruit的对象至少是Fruit,因此get()是允许的
<span class="keyword">static T wildSubtype(Holder<? extends T> holder,T arg) {
<span class="indent"> <span class="comment">// holder.set(arg); // Error:
<span class="indent"> <span class="comment">// set(capture of ? extends T) in
<span class="indent"> <span class="comment">// Holder<capture of ? extends T>
<span class="indent"> <span class="comment">// cannot be applied to (T)
<span class="indent"> T t = holder.<span class="keyword">get();
<span class="indent"> <span class="keyword">return t;
}
<span class="comment">// 展示超类型 通配
<span class="keyword">static <span class="keyword">void wildSupertype(Holder<? super T> holder,T arg) {
<span class="indent"> <span class="comment">// holder可以是持有任何T的基类型的容器,因此,set()可以接受T,因为任何可以工作于基类的对象都可以多态地作用于导出类(这里就是T)
<span class="indent"> holder.<span class="keyword">set(arg);
<span class="indent"> <span class="comment">// T t = holder.get(); // Error: 由holder持有的类型可以是任何超类型,因此唯一安全的类型就是Object
<span class="indent"> <span class="comment">// Incompatible types: found Object, required T

<span class="indent"> <span class="comment">// OK,but type information has been lost:
<span class="indent"> Object obj = holder.<span class="keyword">get();
}
<span class="keyword">public <span class="keyword">static <span class="keyword">void main(String[] args) {
<span class="indent"> Holder raw = <span class="keyword">new Holder ();
<span class="indent"> <span class="comment">// Or:
<span class="indent"> raw = <span class="keyword">new Holder();
<span class="indent"> Holder qualified = <span class="keyword">new Holder ();
<span class="indent"> Holder<?> unbounded = <span class="keyword">new Holder ();
<span class="indent"> Holder@H_ 301_2802@ bounded = <span class="keyword">new Holder ();
<span class="indent"> Long lng = <span class="number">1L;

<span class="indent"> rawArgs(raw,lng);
<span class="indent"> rawArgs(qualified,lng);
<span class="indent"> rawArgs(unbounded,lng);
<span class="indent"> rawArgs(bounded,lng);

<span class="indent"> unboundedArg(raw,lng);
<span class="indent"> unboundedArg(qualified,lng);
<span class="indent"> unboundedArg(unbounded,lng);
<span class="indent"> unboundedArg(bounded,lng);

<span class="indent"> <span class="comment">// Object r1 = exact1(raw); // Warnings:
<span class="indent"> <span class="comment">// Unchecked conversion from Holder to Holder
<span class="indent"> <span class="comment">// Unchecked method invocation: exact1(Holder )
<span class="indent"> <span class="comment">// is applied to (Holder)
<span class="indent"> Long r2 = exact1(qualified);
<span class="indent"> Object r3 = exact1(unbounded); <span class="comment">// Must return Object
<span class="indent"> Long r4 = exact1(bounded);

<span class="indent"> <span class="comment">// Long r5 = exact2(raw,lng); // Warnings:
<span class="indent"> <span class="comment">// Unchecked conversion from Holder to Holder
<span class="indent"> <span class="comment">// Unchecked method invocation: exact2(Holder ,T)
<span class="indent"> <span class="comment">// is applied to (Holder,Long)
<span class="indent"> Long r6 = exact2(qualified,lng);
<span class="indent"> <span class="comment">// Long r7 = exact2(unbounded,lng); // Error:
<span class="indent"> <span class="comment">// exact2(Holder ,T) cannot be applied to
<span class="indent"> <span class="comment">// (Holder<capture of ?>,Long)
<span class="indent"> <span class="comment">// Long r8 = exact2(bounded,T) cannot be applied
<span class="indent"> <span class="comment">// to (Holder<capture of ? extends Long>,Long)

<span class="indent"> <span class="comment">// Long r9 = wildSubtype(raw,lng); // Warnings:
<span class="indent"> <span class="comment">// Unchecked conversion from Holder
<span class="indent"> <span class="comment">// to Holder@H_301_2802@
<span class="indent"> <span class="comment">// Unchecked method invocation:
<span class="indent"> <span class="comment">// wildSubtype(Holder<? extends T>,T) is
<span class="indent"> <span class="comment">// applied to (Holder,Long)
<span class="indent"> Long r10 = wildSubtype(qualified,lng);
<span class="indent"> <span class="comment">// OK,but can only return Object:
<span class="indent"> Object r11 = wildSubtype(unbounded,lng);
<span class="indent"> Long r12 = wildSubtype(bounded,lng);

<span class="indent"> <span class="comment">// wildSupertype(raw,lng); // Warnings:
<span class="indent"> <span class="comment">// Unchecked conversion from Holder
<span class="indent"> <span class="comment">// to Holder<? super Long>
<span class="indent"> <span class="comment">// Unchecked method invocation:
<span class="indent"> <span class="comment">// wildSupertype(Holder<? super T>,Long)
<span class="indent"> wildSupertype(qualified,lng);
<span class="indent"> <span class="comment">// wildSupertype(unbounded,lng); // Error:
<span class="indent"> <span class="comment">// wildSupertype(Holder<? super T>,T) cannot be
<span class="indent"> <span class="comment">// applied to (Holder<capture of ?>,Long)
<span class="indent"> <span class="comment">// wildSupertype(bounded,T) cannot be
<span class="indent"> <span class="comment">// applied to (Holder<capture of ? extends Long>,Long)
}
}

Exact2 () has the most limitations because it wants to get exactly a holder and a parameter of type T, which is why it will generate an error or warning unless an exact parameter is provided. That's good again, but if it's too limited, you can use wildcards, depending on whether you want to return a typed return value from the generic parameter (wildsubtype()) or you want to pass a typed parameter to the generic parameter (wildsupertype())

The advantage of using exact types instead of wildcards is that you can do more with generic parameters, but using wildcards makes you have to accept a wider range of parameterized types as parameters. Therefore, we must weigh the pros and cons on a case by case basis and find a method more suitable for your needs.

Here's a demonstration of capture transformation

  holder) {
 holder) { (,still figures it out:  wildcarded = (

Capture conversion is very interesting, but very limited: capture conversion works only in this case, that is, when the exact type needs to be used inside the method, note that t cannot be returned from F2 (), because t is unknown to F2 ().

11.1. Any basic type cannot be used as a type parameter

You can use wrapper classes of basic types. When using containers, the automatic wrapper mechanism will convert the basic types into wrapper classes, but remember: automatic wrapper cannot be used for arrays, so generic arrays cannot be passed into arrays of basic types.

<span class="indent">  <span class="comment">// 使用 t 填充数组
<span class="indent"> <span class="keyword">public <span class="keyword">static T[] fill(T[] a,T t){
<span class="indent"> <span class="indent"> <span class="keyword">for(<span class="keyword">int i=<span class="number">0; i<a.length; i++){
<span class="indent"> <span class="indent"> <span class="indent"> a[i] = t;
<span class="indent"> <span class="indent"> }
<span class="indent"> <span class="indent"> <span class="keyword">return a;
<span class="indent"> }

<span class="indent"> <span class="keyword">public <span class="keyword">static <span class="keyword">void main(String[] args){
<span class="indent"> <span class="indent"> fill(<span class="keyword">new Integer[<span class="number">10],<span class="number">3);
<span class="indent"> <span class="indent"> <span class="comment">// fill(new int[10],3); //编译失败,因为自动包装机制不能应用于数组,因此这无法工作。
<span class="indent"> }
}

11.2. Realize parametric interface

A class cannot implement two variants of the same generic interface. Due to erasure, the two variants will become the same interface.

{}

<span class="class"><span class="keyword">class <span class="title">Employee <span class="keyword">implements <span class="title">Payable<<span class="title">Employee>{}

<span class="javadoc">/**

  • 下面不能编译通过,因为擦除将会将 Payable 和 Payable 简化为相同的类Payable。
  • 去掉泛型,却可以通过编译。
  • */
    <span class="class"><span class="keyword">class <span class="title">Hourly <span class="keyword">extends <span class="title">Employee <span class="keyword">implements <span class="title">Payable<<span class="title">Hourly>{}

11.3 transformation and warning

Using a transformation or indtanceof with generic type parameters has no effect

 {


<span class="keyword">public <span class="class"><span class="keyword">class <span class="title">Chapter15_11_3 {
<span class="indent"> <span class="keyword">public <span class="keyword">static <span class="keyword">final <span class="keyword">int SIZE = <span class="number">10;
<span class="indent"> <span class="keyword">public <span class="keyword">static <span class="keyword">void main(String[] args) {
<span class="indent"> <span class="indent"> FixedSizeStack strings =
<span class="indent"> <span class="indent"> <span class="indent"> <span class="keyword">new FixedSizeStack (SIZE);
<span class="indent"> <span class="indent"> <span class="keyword">for(String s : <span class="string">"A B C D E F G H I J".split(<span class="string">" "))
<span class="indent"> <span class="indent"> <span class="indent"> strings.push(s);
<span class="indent"> <span class="indent"> <span class="keyword">for(<span class="keyword">int i = <span class="number">0; i < SIZE; i++) {
<span class="indent"> <span class="indent"> <span class="indent"> String s = strings.pop();
<span class="indent"> <span class="indent"> <span class="indent"> Sy stem.out.print(s + <span class="string">" ");
<span class="indent"> <span class="indent"> }
<span class="indent"> }

<span class="indent"> <span class="annotation">@SuppressWarnings(<span class="string">"unchecked")
<span class="indent"> <span class="keyword">public <span class="keyword">void f(String filepath) <span class="keyword">throws Exception{
<span class="indent"> <span class="indent"> <span class="comment">// 下面演示由readObject()方法读取转型
<span class="indent"> <span class="indent"> ObjectInputStream in = <span class="keyword">new ObjectInputStream(<span class="keyword">new FileInputStream(filepath));
<span class="indent"> <span class="indent"> <span class="comment">// 如果没有压制的注解,则会阐释警告 Unchecked cast from Object to List
<span class="indent"> <span class="indent"> <span class="comment">// List circles = (List )in.readObject();

<span class="indent"> <span class="indent"> <span class="comment">// 如果想继续使用泛型的情况下不产生警告,则可以使用Java EE5中的使用泛型类来转型
<span class="indent"> <span class="indent"> List circles = List.class.cast(in.readObject());

<span class="indent"> <span class="indent"> <span class="comment">// 但是你继续添加如下转型是仍会得到一个警告
<span class="indent"> <span class="indent"> <span class="comment">// Type safety: Unchecked cast from List to List
<span class="indent"> <span class="indent"> circles = (List )List.class.cast(in.readObject());

<span class="indent"> }
}

Overloaded methods will produce the same type signature due to erasure

 {
    // 错误:Method f(List) has the same erasure f(List) as another method in type UseList
    void f(List v) {}
    void f(List v) {}
}

11.5. The base class hijacks the interface

 {
 and Comparable
  
  
  

   
   
   {
 and 
     
     
     

      
      
      <span class="javadoc">/**

  • 下面演示实现ComparablePet中的相同接口的可行性:
  • 这只是与覆盖基类中的方法相同
    */
    <span class="class"><span class="keyword">class <span class="title">Hamster <span class="keyword">extends <span class="title">ComparablePet <span class="keyword">implements <span class="title">Comparable<<span class="title">ComparablePet> {
    <span class="indent"> <span class="keyword">public <span class="keyword">int compareTo(ComparablePet arg) { <span class="keyword">return <span class="number">0; }
    }
    <span class="comment">// Or just:
    <span class="class"><span class="keyword">class <span class="title">Gecko <span class="keyword">extends <span class="title">ComparablePet {
    <span class="indent"> <span class="keyword">public <span class="keyword">int compareTo(ComparablePet arg) { <span class="keyword">return <span class="number">0; }
    }

12 self defined type

12.1. Weird loop generics

Here is an example of a loop generic

{}
 {}

Let's demonstrate the role of circular generics

First create a generic class

 {

Implement the circular generic class. Function: the base class basickolder uses the derived class subtype to replace the parameters passed between its methods.

 {}

use

First, let's look at an example without self qualification. Basickolder can use any type as its generic parameter:

<span class="class"><span class="keyword">class <span class="title">BasicOther <span class="keyword">extends <span class="title">BasicHolder<<span class="title">Other> {}

<span class="class"><span class="keyword">class <span class="title">Unconstrained {
<span class="keyword">public <span class="keyword">static <span class="keyword">void main(String[] args) {
BasicOther b = <span class="keyword">new BasicOther(),b2 = <span class="keyword">new BasicOther();
b.set(<span class="keyword">new Other());
Other other = b.get();
b.f();
}
}

In fact, we use self qualified types to require that this class be used in inheritance relationships as follows

This forces the subclass being defined to be passed as a parameter to the base class

Let's look at an example of a self qualified type

> {
 set(T arg) {
<span class="class"><span class="keyword">class <span class="title">A <span class="keyword">extends <span class="title">SelfBounded<<span class="title">A> {}
<span class="class"><span class="keyword">class <span class="title">B <span class="keyword">extends <span class="title">SelfBounded<<span class="title">A> {} <span class="comment">// Also OK

<span class="class"><span class="keyword">class <span class="title">C <span class="keyword">extends <span class="title">SelfBounded<<span class="title">C> {
<span class="indent"> C setAndGet(C arg) { set(arg); <span class="keyword">return get(); }
}

<span class="class"><span class="keyword">class <span class="title">D {}
<span class="comment">// Can't do this:
<span class="comment">// class E extends SelfBounded {}
<span class="comment">// Compile error: Type parameter D is not within its bound

<span class="comment">// Alas,you can do this,so you can't force the idiom:
<span class="class"><span class="keyword">class <span class="title">F <span class="keyword">extends <span class="title">SelfBounded {}

<span class="keyword">public <span class="class"><span class="keyword">class <span class="title">Chapter15_12_2 {
<span class="indent"> <span class="keyword">public <span class="keyword">static <span class="keyword">void main(String[] args) {
<span class="indent"> <span class="indent"> A a = <span class="keyword">new A();

<span class="indent"> <span class="indent"> <span class="comment">// 直接使用SelfBounded,传入类似A这样的子类
<span class="indent"> <span class="indent"> SelfBounded bounded = <span class="keyword">new SelfBounded();

<span class="indent"> <span class="indent"> a.set(<span class="keyword">new A());
<span class="indent"> <span class="indent"> a = a.set(<span class="keyword">new A()).get();
<span class="indent"> <span class="indent"> a = a.get();
<span class="indent"> <span class="indent"> C c = <span class="keyword">new C();
<span class="indent"> <span class="indent"> c = c.setAndGet(<span class="keyword">new C());
<span class="indent"> }
}

Self qualification can also be used for generic methods

The content of this article comes from the network collection of netizens. It is used as a learning reference. The copyright belongs to the original author.
THE END
分享
二维码
< <上一篇
下一篇>>