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
將泛型用到這樣的接口中看來還是有很多好處的。
浙公網安備 33010602011771號