什么是泛型?
泛型是对 Java 语言的类型系统的一种扩展,以支持创建可以按类型进行参数化的类。
泛型的引入可以消除强制类型的转换,使得代码更加可读,并且减少了出错机会。
泛型让程序员在保存在集合中的元素上指定类型约束。
package com.cjw.b_fanxing;
import java.util.ArrayList;
public class Demo1 {
public static void main(String[] args) {
//声明一个int类型数组
int[] arr = {1, 2, 3, 4};
char[] chs = {'a', 'b', 'c'};
//在数组的容量中 所存储数据的数据类型都是一致的
//数组中的存储的数据是一致的,但是开发不用!!!为啥?
//因为数组的容量先定好的,而且数组添加数据删除数据,太麻烦了
//实际开发中咱们需要后面即将学的集合
//集合就是用来存储的数据的!!!
ArrayList list = new ArrayList();//就把他当成一个容器即可
list.add("小狗");
list.add(250);
list.add('a');
list.add(false);
//任何类型的数据都可以存进来的
System.out.println(list);
//以上存储的数据好不好? 不好!!!
//对数据类型一致性要求是比较高的!!!
//取值,每次都需要强转
String str = (String)list.get(0);
System.out.println(str);
//可以使用泛型 进行约束
ArrayList<String> list1 = new ArrayList<>();
//告知编译器 这个集合只能存String类型的数据
list1.add("小狗");
list1.add("小猫");
list1.add("小鸡");
System.out.println(list1);
//取值
String s = list1.get(0);
System.out.println(s);
// ArrayList人家底层是封装了好了泛型,人家已经做好的
//学习自己如何自己写带有泛型的类 泛型的方法 等
}
}
在定义泛型类或声明泛型类的变量时,使用尖括号来指定形式类型参数。形式类型参数与实际类型参数之间的关系类似于形式方法参数与实际方法参数之间的关系,只是类型参数表示类型,而不是表示值。
java 中泛型标记符:
- E - Element (在集合中使用,因为集合中存放的是元素)
- T - Type(Java 类)
- K - Key(键)
- V - Value(值)
- N - Number(数值类型)
- ? - 表示不确定的 java 类型
带有泛型的方法:
语法格式:
权限修饰符 <无意义的占位符> 返回值类型 方法的名字(参数列表){
}
package com.cjw.b_fanxing;
public class Demo2 {
public static void main(String[] args) {
test(34);
test("狗");
test('猫');
test1();
test3("老王");
test3(77.6);
}
// public static void test (int a) {
// System.out.println(a);
// }
// public static void test (String a) {
// System.out.println(a);
// }
// public static void test (char a) {
// System.out.println(a);
// }
//使用泛型的写法
//这个T只是一个占位而已,如果你传了字符串 那么这个T就是String
//如果你传了一个整数 那么T 就是Integer
//具有广泛性和普适性
//其实方法的重载的升级版本
//无返回值有参数的
public static <T> void test (T t) {
System.out.println(t);
}
//无返回值 无参的方法,没有必要使用泛型 没有意义
public static <T> void test1 () {
T t = null;
//你这个结果和泛型有有啥关联?没有任何意义
System.out.println("吃饭");
}
//无参 有返回值的方法,有咩有必要使用泛型? 没有
public static <T> T test2() {
return null;
}
//有参 有返回值的方法,这个使用泛型有没有意义? 有!!!
public static <T> T test3 (T t) {
return t;
}
// public static <T> T test4 (T t, T t1) {
// return t + ":" + t1;
// }
//总结:
/**
* 泛型的方法一定是带有参数的才有意义!!!
* 无参的都是无意义的,而且一定要注意带有返回值的
* 这个返回值是和参数的T 数据类型要保持一致的
*/
}
结论:
- 带有泛型的方法要有参数才有意义
- 返回值类型要和T(无意义的占位符)的类型保持一致
带有泛型的类:
语法格式:
(public)class 类名 <无意义的占位符>{
}
package com.cjw.b_fanxing;
class Person<T> {
// T name;//所以成员变量最好不用
// T age;
// T sex;
//主要看成员方法
//带有泛型的方法,最起码得有参数
//注意: 如果再一个带有泛型的类,成员方法不要加<T> 了
public <T> void test (T t) {
System.out.println(t);
}
//想要一个方法中的泛型和类保持一致,一定在方法不要加<T>
public void test1 (T t) {
System.out.println(t);
}
//如果是静态方法呢?
//对象创建的时候才 确定E数据类型,静态的方法在创建对象之前
//这个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 也应该是String
stringPerson.test(89);
stringPerson.test1("wuw");
Person<Integer> person1 = new Person<>();
//person1.name = 98;
person1.test1(56);
//调用静态方法
Person.test2("hjsj");
}
}
总结:
在一个带有泛型的类中,成员方法不要加<T> ,要不然没有意义,这样才能保证带有泛型的类和方法中的泛型保持一致
练习:
package com.cjw.b_fanxing;
class Animal<T> {
public void play (T t) {
System.out.println(t);
}
}
class Panda<T> extends Animal<T> {
@Override
public void play(T t) {
System.out.println(t);
}
}
public class Demo6 {
public static void main(String[] args) {
Panda<String> panda = new Panda<>();
panda.play("玩竹子");
}
}
带有泛型的抽象类:
语法格式:
abstract class 类名 <无意义的占位符> {
}
package com.cjw.c_fanxing;
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) {
//是int的包装类 就是代表的是int类型的数据
TestA<Integer> testA = new TestA<>();
testA.testA(89);
}
}
总结:
继承了带有泛型的抽象类,那么继承类也需要有泛型
带有泛型的接口:
语法格式:
interface 接口名字 <无意义的占位符> {
}
package com.cjw.c_fanxing;
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('');
}
}