泛型的特点:
- 适用于多种数据类型执行相同的代码
- 泛型中的类型在使用时指定
- 泛型归根到底就是“模版”
使用泛型的优点:使用泛型时,在实际使用之前类型就已经确定了,不需要强制类型转换。
泛型类
创建一个泛型类的示例:
泛型类的注意事项:
- 对象实例化时如果不指定泛型,默认为:Object类型
- 泛型不同的引用不能相互赋值
public class GenericClassTest {
public static void main(String[] args) {
A<String> a1 = new A<String>(); //在new A出来的对象中指定泛型的类型是String
a1.setKey("abc");
System.out.println(a1.getKey());
A a2 = new A(); //在创建泛型类对象时,如果不指定泛型,相当于指定了一个Object类型
a2.setKey(new Object());
Object obj = a2.getKey();
}
}
//此处的泛型T可以任意地取名,一般用大写字母T表示
class A<T>{
private T key;
public void setKey(T key)
{
this.key = key;
}
public T getKey()
{
return this.key;
}
}
泛型接口
创建一个泛型接口的示例:
注意:在声明类的时候,需要将泛型的声明也一起加到类中
定义一个类去实现一个泛型接口,并且同时指定接口的泛型的类型:
示例代码
public class GenericInterfaceTest {
public static void main(String[] args) {
//用B类的引用指向B类自己创建的对象
B<String> b1 = new B<String>();
System.out.println(b1.test("abc"));
//用接口IB的引用指向B类创建的对象
IB<String> ib1 = new B<String>();
System.out.println(ib1.test("abc"));
//用C类的引用指向C类自己创建的对象
C c1 = new C();
System.out.println(c1.test("123"));
//用接口IB的引用指向C类创建的对象
IB<String> ib2 = new C();
System.out.println(ib2.test("123"));
}
}
interface IB<T>{
T test(T t);
}
class B<T> implements IB<T>{
@Override
public T test(T t) {
return t;
}
}
class C implements IB<String>{
@Override
public String test(String t) {
return t;
}
}
运行结果:
泛型方法
注意:在静态方法中,不能使用类定义泛型(泛型类的泛型),如果要使用泛型,只能用静态方法自动定义的泛型。
注意:泛型方法,在调用之前没有固定的数据类型,在调用时传入的参数是什么类型,就会把泛型改成什么类型。
泛型方法的使用示例:
public class GenericMethodTest {
public static void main(String[] args) {
AB a = new AB();
//泛型方法,在调用之前没有固定的数据类型,在调用时传入的参数是什么类型,就会把泛型改成什么类型
System.out.println(a.test1("a"));
System.out.println(a.test1(123)); //传入的参数是Integer类型,泛型就固定成Integer类型
a.test2("abc","12345","hello");
}
}
class AB{
//在静态方法中,不能使用类定义泛型,如果要使用泛型,只能用静态方法自动定义的泛型
public static<T> void test3(T t)
{
System.out.println(t);
}
//无返回值的泛型方法
public<T> void test(T s)
{
T t = s;
}
//有返回值的泛型方法
public<T> T test1(T s)
{
return s;
}
//T...strs为可变参数,strs参数的类型是T,可变参数和数组类似
//形参为可变参数的泛型方法
public<T> void test2(T...strs)
{
for(T s : strs)
{
System.out.println(s);
}
}
}
运行结果: