java 之 泛型

 1 public class Test {
 2     
 3     //泛型方法
 4     public <T> void printClass(T a){
 5         System.out.println(a.getClass());
 6     }
 7 
 8     public static void main(String[] args){
 9         
10         Test t=new Test();
11         t.printClass(t);                    
12     }
13 }

输出:

class Test

泛型方法中,<T>在返回值的定义前面,如果有返回值,返回值也可以是<T>,就可以是这样:

//泛型方法,它什么也没干
    public <T> T printClass(T a){
        
return a;
    }

可以这样理解:<>告诉编译器,这里里面的东西到时候给我替换了,于是,调用这个方法时,传入了某个类型a,则这些代码中的T都被临时变为a的类型了。

当然,<>中可以随便写

 1 //<> 里面可以随便写
 2 public <X> void printClass(X a){
 3         System.out.println(a.getClass());
 4     }
 5 
 6 public <a> void printClass(a a){
 7         System.out.println(a.getClass());
 8     }
 9 
10 public <Xa> void printClass(Xa a){
11         System.out.println(a.getClass());
12     }

以上代码都可以编译通过的。

下面复杂一点,泛型边界控制:

 1 public class Test {
 2     
 3     //泛型方法
 4     public <extends Test> void printClass(T a){
 5         System.out.println(a.getClass());
 6     }
 7     
 8     public class Gen {
 9         
10     }
11 
12     public static void main(String[] args){
13         
14         Test t=new Test();
15         Gen g=t.new Gen();
16         t.printClass(g);                    
17     }
18 }

输出:

Exception in thread "main" java.lang.Error: 无法解析的编译问题:
    边界不匹配:类型 Test 的通用方法 printClass(T)不适用于参数(Test.Gen)。推断类型 Test.Gen 并不是有界参数 
<T 到 Test> 的有效替代项。

    at Test.main(Test.java:
17)

上面的 <extends Test>  ,要求这个泛型参数必须是继承于Test或者实现了Test接口,把class gen改写为 class gen extends Test即可以编译通过运行。

再复杂一点,

 1 public class Test {
 2     
 3     //泛型方法,要求参数必须是继承了泛型类Gen的对象,而泛型类Gen的泛型可以定义为任意
 4     public <extends Gen<?>> void printClass(T a){
 5         System.out.println(a.getClass());
 6     }
 7     
 8     public class Gen<T> {
 9         
10     }
11     
12     //继承了泛型类Gen,并定义泛型类的类型参数是String
13     public class Gen1 extends Gen<String>{
14         
15     }
16     //继承了泛型类Gen,并定义泛型类的类型参数是Gen1
17     public class Gen2 extends Gen<Gen1>{
18         
19     }
20     
21     public static void main(String[] args){
22         
23         Test t=new Test();
24         Gen1 g1=t.new Gen1();        
25         t.printClass(g1);    
26         Gen2 g2=t.new Gen2();
27         t.printClass(g2);
28         
29     }
30 }

输出:

class Test$Gen1
class Test$Gen2

到这里为止,所有的泛型都只运用到了方法的传入参数,那么对于方法的返回值怎么泛型呢:

 1 public class Test {
 2     
 3     //泛型方法,传入参数a为任意类型,返回值为传入值的类型
 4     public static <T> T getA(T a){
 5         return a;
 6     }
 7     
 8     //泛型方法,传入参数a为整形,返回值为传入值的类型
 9     @SuppressWarnings("unchecked")
10     public static <T> T getB(String a){
11         return (T)a;
12     }
13 
14     //返回值为String ,参数a的类型为任意
15     public static <T> String getC(T a){
16         return a.toString();
17     }
18     
19     
20     public static void main(String[] args){
21         int a=1;
22         int b=getA(a);
23         System.out.println(b);
24         String s1="test";
25         String s=getA(s1);    
26         System.out.println(s);
27         
28         s=getB(s);
29         System.out.println(s);
30         
31         s=getC(a);
32         System.out.println(s);
33     }
34 }

输出:

1
test
test
1

泛型的使用,很常见的比如容器,看看下面的示例,就知道自己该如何定义泛型了:

 1 public class Test {
 2     
 3     //这是个泛型接口,定义了一个泛型方法
 4     public interface  Eat <T> {
 5         public void doEat(T t);
 6         
 7     }
 8 
 9     
10     //实现了Eat接口,使Eat接口的泛型类型为Shit这个内部类
11     public class Dog implements Eat<Dog.Shit>{
12 
13         public Dog(){
14             System.out.println("这是狗");
15             //这里只是掩饰,Dog自己并不是自产自销的家伙
16             Shit s=new Shit();
17             this.doEat(s);
18         }
19         
20         
21         //内部类
22         public class Shit{
23             public Shit(){
24                 System.out.println("这是一坨");
25             }            
26         
27         }
28 
29 
30         @Override
31         public void doEat(Shit t) {
32             // TODO Auto-generated method stub
33             System.out.println("狗吃了一坨");
34         }
35 
36         
37     }
38     
39     public class Bull implements Eat<Bull.Grass>{
40         
41         public Bull(){
42             System.out.println("这是Bull");
43             Grass g=new Grass();
44             this.doEat(g);
45         }
46 
47         //内部类
48         public class Grass {
49             public Grass(){
50                 System.out.println("这是Grass");
51             }
52         }
53 
54         @Override
55         public void doEat(Grass t) {
56             // TODO Auto-generated method stub
57             System.out.println("Bull吃了Grass");
58             
59         }
60         
61     }
62     
63 
64     public static void main(String[] args){
65         Test t=new Test();
66         Dog d=t.new Dog();
67         Bull b=t.new Bull();
68     }
69 }

输出:

这是狗
这是一坨
狗吃了一坨
这是Bull
这是Grass
Bull吃了Grass

将泛型用到这样的接口中看来还是有很多好处的。

原文地址:https://www.cnblogs.com/hangxin1940/p/2042240.html