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 }
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;
}
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 }
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 <T 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 }
2
3 //泛型方法
4 public <T 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)
边界不匹配:类型 Test 的通用方法 printClass(T)不适用于参数(Test.Gen)。推断类型 Test.Gen 并不是有界参数 <T 到 Test> 的有效替代项。
at Test.main(Test.java:17)
上面的 <T extends Test> ,要求这个泛型参数必须是继承于Test或者实现了Test接口,把class gen改写为 class gen extends Test即可以编译通过运行。
再复杂一点,
1 public class Test {
2
3 //泛型方法,要求参数必须是继承了泛型类Gen的对象,而泛型类Gen的泛型可以定义为任意
4 public <T 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 }
2
3 //泛型方法,要求参数必须是继承了泛型类Gen的对象,而泛型类Gen的泛型可以定义为任意
4 public <T 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
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 }
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
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 }
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
这是一坨
狗吃了一坨
这是Bull
这是Grass
Bull吃了Grass
将泛型用到这样的接口中看来还是有很多好处的。