1.为什么要使用泛型
泛型意为广泛的类型。
在实际应用中,人们对数据的一致性要求比较看重!如数组之类,每次数据类型都是预先设定好的,但其容量有限,且修改起来较为麻烦。集合则可以存储不同类型数据,存储容量可自动扩容,但每次取值都需要强转。使用集合,同时借助于泛型则可以统一集合中存储数据的类型,且存储容量可自动扩容。
代码示例1:
import java.util.ArrayList;
public class Demo2 {
public static void main(String[] args) {
//声明一个集合
//可以看作一个容器
ArrayList list = new ArrayList();
//向集合中添加元素
//可以添加不同类型的元素(多态,形参为object),且数量没有限制
list.add("念奴");
list.add('娇');
list.add(true);
System.out.println(list); //[念奴, 娇, true]
//取值,借助于get(int index)方法
//需要强转
String str = (String)list.get(0);
System.out.println(str); //念奴
//借助泛型,可以对存储数据的类型进行约束
//告知编译器,只能存储String类型的数据
ArrayList<String> list1 = new ArrayList<>();
list1.add("如花");
list1.add("似玉");
System.out.println(list1); //[如花, 似玉]
//取值
String str1 = list1.get(0);
System.out.println(str1); //如花
}
}
2.带有泛型的方法
语法格式:
public <无意义的占位符> 返回值类型 方法名字(参数列表) {
}
//无意义的占位符:可以是T E ?等。
//静态方法要在public后加static。
代码示例2:
public class Demo3 {
public static void main(String[] args) {
test3("如花");
test3('似');
System.out.println(test4(81.88));
System.out.println(test4(true));
//传入不同类型的数据均不会报错
//T仅作为一个占位,体现了泛型的广泛性和普适性
}
//使用泛型的静态方法
//无参无返回值 (使用泛型并无意义)
public static <T> void test1() {
System.out.println("呵呵");
}
//无参有返回值 (使用泛型并无意义)
public static <T> T test2() {
return null; //返回值为T时,只能返回null
}
//有参无返回值
public static <T> void test3(T t) {
System.out.println(t);
}
//有参有返回值
public static <T> T test4(T t) {
return t;
}
// //有参有返回值,参数为多个
// //因为不能保证传入的参数类型一致,所以会编译出错
// public static <T> T test5(T t1, T t2) {
// return t1 + t2;
// }
}
代码示例3:
class Dog {
//使用泛型的成员方法
public <T> void test (T t) {
System.out.println(t);
}
}
public class Demo3 {
public static void main(String[] args) {
Dog dog = new Dog();
//传入不同类型的数据均不会报错
dog.test("goudan");
dog.test(89);
dog.test(90.8);
}
}
总结:
1.并不是所有方法都适合用泛型来写。一定是带有参数的泛型方法才有意义。
2.泛型方法的返回值要与参数类型保持一致。
3.带有泛型的类
语法格式:
class 类名<无意义的占位符> {
}
代码示例4:
class Person<T> {
// T name;
// T age;
// T sex;
//属性统一用一种数据类型并不合理,因此一般成员变量不用泛型
//带有泛型的成员方法(有参)
//如果成员方法中加了<T>,那么参数中的T类型与声明处的T类型无关
public <T> void test (T t) {
System.out.println(t);
}
//想要一个方法中的泛型和类保持一致,一定不要在方法中加<T>
public void test1 (T t) {
System.out.println(t);
}
//静态的方法在创建对象之前,因此静态方法中的E和类声明处的T无关的
public static <E> void test2 (E e) {
System.out.println(e);
}
}
public class Demo4 {
public static void main(String[] args) {
//在声明对象的时候,指定好T是什么数据类型,那么成员变量T name中的T就是那种数据类型
Person<String> stringPerson = new Person<>();
// stringPerson.name = "goudan";
// stringPerson 泛型 是String 就意味着test(T t)
//创建对象时规定的T的类型不影响test(T t)中参数的类型
stringPerson.test(89);
//但会影响test1(T t)中参数的类型
stringPerson.test1("wuw");
Person<Integer> person1 = new Person<>();
//person1.name = 98;
person1.test1(56);
//调用静态方法
Person.test2("hjsj");
}
}
总结:
1.在一个带有泛型的类中,对于成员方法就不要再加了,如此成员方法中的T与类声明处的的类型才是一致的。
2.在一个带有泛型的类中,如果要写带有泛型的静态成员方法,需要加无意义的占位符,此处E的类型与类声明处的T的类型无关。
4.带有泛型的抽象类
语法格式:
abstract class 类名<无意义的占位符> {
}
代码示例5:
abstract class A<T> {
abstract void testA (T t);
}
class TestA<T> extends A<T> {
@Override
void testA(T t) {
System.out.println(t);
}
}
public class Demo1 {
public static void main(String[] args) {
//Integer是int的包装类 就是代表的是int类型的数据
TestA<Integer> testA = new TestA<>();
testA.testA(89);
}
}
5.带有泛型的接口
语法格式:
interface 接口名字<无意义的占位符> {
}
代码示例6:
interface B<T> {
//成员方法
void eat(T t);
}
class TestB<T> implements B<T> {
@Override
public void eat(T t) {
System.out.println(t);
}
}
public class Demo2 {
public static void main(String[] args) {
TestB<Character> testB = new TestB<>();
testB.eat('g');
}
}