泛型的学习
泛型类:
先看下面这个例子:
先写一个不是泛型的(定义构造方法和一个方法,来进行引用)。
package com.FanXing.Contrast;
public class Ordinary {
private int number;//这里的number定义类型为:int
public Ordinary(int number) throws Exception {
this.number = number;
}
public int getnumber() {
return number;
}
}
测试类:
class TestSimple {
public static void main(String[] args) {
Ordinary Ord1 = new Ordinary(1111);
try {
Ordinary Ord2 = new Ordinary("整型类型的number");//这个是编译都通过不了吗?
// 所以这里的try catch都直接不能输出。
}catch (Exception e) {
e.printStackTrace();
}finally {
System.out.println(Ord1.getnumber());
}
}
}
输出为:
这里明显就能看出来错误,Ord2 里面输入"整型类型的number"
是String类型的怎么可以转换成int嘛。改为int类型(或者这里直接把他删掉,就是对的了。)
class TestSimple {
public static void main(String[] args) {
Ordinary Ord1 = new Ordinary(1111);
System.out.println(Ord1.getnumber());
}
}
输出为:
1111
然后是一个为泛型类型的类。
package com.FanXing.Contrast;
public class GenericsTest1_1<T> {
private T number;//这次把这里的number改为泛型了。
public GenericsTest1_1(T number) {
this.number = number;
}
public T getnumber() {
return number;
}
}
泛型测试类:
class show {
public static void main(String[] args) {
GenericsTest1_1 t1 = new GenericsTest1_1(1111);
GenericsTest1_1 t2 = new GenericsTest1_1("1111");
System.out.println(t1.getnumber());
System.out.println(t2.getnumber());
}
}
输出为:
1111
1111
这里的String
类型的为泛型,所以int
和String
都可以。
但是对于int
和T
(泛型)类型直接转换会报错。(如下方将参数的T
改为int
类型)
private T number;
public GenericsTest1_1(int number) {
this.number = number;
}
//下面左边的number与上面的 private T number对应。
//下面右边的number与形参的 int number 对应。
//也就是左边的T 不能转换成右边的 int
会报错。(这里用强转也是可以。不过下面测试类中的使用,又可以即用int又可以用String,但是为什么T这个泛型却不能直接转换成int
或是String
?)
对于泛型经常看到的肯定不只有用T的,常见的还有EKV。这几个符号都是用来表示泛型的。而且不仅仅只有这几中类型。用其他的大写字母,小写字母,字符串(AD ,a1),甚至是中文都行。但是以数字为开头却不行。
(那这里是不是得规避那些已经定义好了的数据结构类型,才能算作泛型。比如我定义String 肯定就不是泛型了对吧。)
尝试了一下,发现并不是,尝试的几个封装类型Integer,Boolean,Double的都可以。基本数据类型像 int double反而不行。
这里给出一个改为String
类型的例子。(发现是可以的,所以上面的说法是错的。String
可以作为泛型类型来。)
package com.FanXing.Contrast;
public class GenericsTest1_1<String> {
private String number;//以String来作为泛型字段。
public GenericsTest1_1(String number) {
this.number = number;
}
public String getnumber() {
return number;
}
}
对于常用的 ?
意思是 :不确定的类型。
T
:表示具体的一个类型。
K V
:键和值的类型。
E
: 元素(element)类型。
不仅是一个参数适用于泛型,对于多个参数也是可以用泛型来定义类型的,这样还省去了后续可能出现的类型转换问题。(比如map。) (那这么看来Object,也是泛型的一种咯。之前还对Object类型的参数不太了解。)
泛型接口。
定义接口:
package com.FanXing.interfaceTKEV;
public interface interfaceGenerics<T> {
public T getShow(T t);//其中包括一个getShow()的方法。
}
测试类:(感觉这个泛型有包含的关系,跟String啊这些数据类型。)
package com.FanXing.interfaceTKEV;
public class interfaceGenericsTest<T> implements interfaceGenerics<String> {
private String t;
@Override
public String getShow(String t) {
this.t = t;
return t;
}
public void show() {
getShow("pz");
System.out.println(t);
}
public static void main(String[] args) {
interfaceGenericsTest<String> test = new interfaceGenericsTest<>();
test.show();
}
}
输出为:
pz
上面这个测试类,有多次不直接使用T
来充当泛型,在尝试过程中容易报错。(就像下面这样。)
public static void main(String[] args) {
interfaceGenericsTest<T> test = new interfaceGenericsTest<T>();
}
如果把语句的泛型改为T。就会报错。(那是不同的方法没有static修饰,但是由于接口的方法是没用static修饰的,所以改起来要改的地方较多。)
如果就是要把其中的String
全改为T
呢。//(接口还是不变。)
package com.FanXing.interfaceTKEV;
public class interfaceGenericsTest<T> implements interfaceGenerics<T> {
private T t;//因为this赋不上值了。类型不同,不强转的话。
@Override
public T getShow(T t) {//这个是用泛型来当作返回类型。
return t;
}
public void show() {
getShow((T) "pz");//这里需要强转,不然会报错。
System.out.println(t);
}
public static void main(String[] args) {
interfaceGenericsTest<String> test = new interfaceGenericsTest<>();
test.show();
}
}
输出为:
null
这输出为null
是因为下面定义的类型中使String
吗?(不过了解到在编译后会去泛型化,泛型不会进入运行时阶段。)所以就是上面因为不能定义 this.t = t
。所以传的pz
是没有赋值上的。
所以,在class interfaceGenericsTest<T>
这个类中的private T t;
属性t是没有被赋值上。所以是默认的初始值:null
。
那我要想输出,就直接把输出语句放getShow()
里面就行了。
public T getShow(T t) {
System.out.println(t);
return t;
}
//其他不变。
输出为:
pz
null
所以上面的猜测是正确的。
泛型通配符是什么?
还有Object ? 的区别。
泛型方法(可变参数,数组类型的泛型,静态的泛型类型)。
泛型方法。
粗略的说,也就是在返回值前有一个<T>
修饰的方法,称为泛型方法。(一个非常简单的例子)
package com.FanXing.Gmethod;
public class GmethodTest1_1 {
public static <T> void show() {// <-----这就是泛型方法。
System.out.println("普通的show泛型方法");
}
public static void main(String[] args) {
show();
}
}
输出为:
普通的show泛型方法
是不是乍一看跟普通的方法没有什么区别。(至少这个例子看起来完全显示不出来区别(哭笑)主要是没有参数不好体现吧)。
package com.FanXing.Gmethod;
public class GmethodTest1_1 {//定义的泛型方法,带一个泛型参数。
public static <T> String show(String name, T t) {
System.out.println("稍微不普通的show泛型方法");
String str = name + " " + t;
return str;
}
public static void main(String[] args) {
GmethodTest1_1 method = new GmethodTest1_1();
method.show("002", "200");//这个后面的类型是String
System.out.println("----------------");
System.out.println(method.show("002", "200"));
String str1 = method.show("001", 100);//这个后面的类型是int或是Integer
System.out.println(str1);
}
}
输出为:
稍微不普通的show泛型方法
----------------
稍微不普通的show泛型方法
002 200
稍微不普通的show泛型方法
001 100
这样还是能体现一下泛型方法的特点了。但是这是不是容易跟只是有一个参数为泛型的,而本身却不是泛型方法的弄混。(所以这里我还把<T>
去掉了来看看。会报错。)
通过上面的测试,需要清楚的是,泛型 所在的位置:
1.类后面,2.是返回值类型(这就单是T
连尖括号都没有。),3.参数类型,4.返回值前。
可以看出,如果类不是泛型类,而且返回值前没有泛型的话,本身也不是返回值类型,再使用T
作为参数类型的话,会报错的。
public void showTest1_2(T t) {
}
就是上面这个形式。
(以下为对泛型作为参数时的小测试。)
package com.FanXing.Gmethod;
public class GmethodT<T> {
}
测试类:
package com.FanXing.Gmethod;
public class GmethodTest1_2 {
public void showTest1_2(GmethodT<T> t) {
}
public static void main(String[] args) {
}
private class T {
}
}
但是写成这个样子不会报错。(而且如果把GmethodT<T>
的T
换成Number或是别的。连下面那个T
的class都不需要定义。)