本文概述:
- 本文为 Java泛型系列第一篇文章,以 Java泛型的使用为主题,介绍了泛型类、泛型接口的定义与使用;着重探讨了泛型方法,诸如才什么叫泛型方法、怎么使用泛型方法以及泛型类参数对其中方法的影响等
泛型类与泛型接口的定义
为什么需要泛型:泛型的两大好处
-
好处一:简化逻辑相同但参数不同造成的代码冗余(避免创建过多的类)
- 业务需求:实现两数相加
- 冗余代码示意:
package generic; /* * 多种数据类型,执行相同的逻辑*/ public class NoGeneric { public int addInt(int x,int y){ return x + y; } public Float addFloat(Float a,Float b){ return a + b; } public static void main(String[] args) { NoGeneric ma = new NoGeneric(); System.out.println(ma.addInt(1,2)); System.out.println(ma.addFloat(1.1f,2.2f)); } }- 泛型优化后的代码:参数类型参数化(泛型 )
-
好处二:在编译期就检查出错误,避免将其带到运行时
- 业务需求:向容器中添加数据后,逐个取出
- 未指定泛型
package generic; import java.util.ArrayList; import java.util.List; /* * 泛型好处之二,指定容器中应当存储的数据类型, * 让错误在编译期出现,避免将错误带到运行期*/ public class NoGenericList { public static void main(String[] args) { List list = new ArrayList(); list.add("WAsbry"); list.add("Hello"); list.add(100); for (int i = 0;i < list.size();i++){ String string = (String)list.get(i); System.out.println(string + " "); } } }- 运行报错:错误的类型转换
-
有个细节:在取出数据时,不将其强转成String 类型是不会报错的,因为Object 类型实现了toString 方法
- 修改数据取出代码
Object string = list.get(i);- 运行结果
怎么自定义泛型
-
泛型的种类:泛型类、泛型方法、泛型接口
-
泛型类的定义:
-
编写思路:
- 在类后面添加< T >即可,跟普通类没有什么区别
-
编写细节:不一定是T
-
完整代码:
package generic; /* * 自定义泛型类*/ public class GenericClass<T> { private T data; public GenericClass(){ } public GenericClass(T data) { this.data = data; } public T getData() { return data; } public void setData(T data) { this.data = data; } public static void main(String[] args) { GenericClass<String> ma = new GenericClass<>(); ma.setData("Hello"); System.out.println(ma.getData()); } } -
-
泛型接口的定义:
- 泛型接口代码:
package generic; public interface GenericInterface<T> { //泛型接口中的方法 public T next(); }- 泛型接口的实现类:实现类还是一个泛型类
package generic; public class ImplGenericInterface<T> implements GenericInterface<T> { @Override public T next() {//此时重写接口方法的返回值为T (接口泛型) return null; } }- 泛型接口的实现类:实现类中指定了泛型接口的类型
package generic; public class ImplSuperGenericInterface implements GenericInterface<String> { @Override public String next() {//此时重写接口方法的返回值为String (实现类指定的类型) return null; } }
泛型方法:
泛型方法简单使用:
-
与泛型类、泛型接口独立,可单独存在;
-
泛型方法、泛型类、泛型接口的区别
- 泛型类:在实例化时指定泛型的具体类型
- 泛型方法:在调用时告诉编译期泛型的具体类型(可以省略,编译器会自动推断)
-
问题汇总:
- 泛型方法可以在普通、泛型类中使用;
- 泛型方法中,泛型参数可以存在多个
-
泛型方法存在于普通类中
package generic;
public class GenericMethod {
public <T> T genericMethod(T...a){
return a[a.length/2];
}
public void test(int x,int y){
System.out.println(x + y);
}
public static void main(String[] args) {
GenericMethod ma = new GenericMethod();
ma.test(2,3);
System.out.println(ma.<String>genericMethod(
"Hello","world","WAsbry"));
System.out.println(ma.genericMethod(12,34,15));
}
}
- 运行截图:
在泛型方法的使用
-
总结:
- 不是声明在泛型类中的方法就叫泛型方法,关键是看这个方法声明上有无< T >
- 在泛型类中使用泛型方法,需要在方法访问修饰符与返回类型之间,指定泛型类型
-
代码展示:
package generic; public class GenericMethod2 { //自定义泛型类(内部类) public class Generic<T>{ //类属性 private T data; //这个不是泛型方法(泛型方法是一定有<T> 的),只是普通的类的get 方法而已 public T getData(){ return data; } //泛型方法的错误写法(编译出错):在泛型定义时,用的是T (定义域使用是相同的) public E setData(E data){ this.data = data; } // } //这也不是泛型方法:是泛型类作为参数的普通方法 public void show(Generic<String> string){ System.out.println(string); return; } //泛型方法的错误写法二:使用未定义的类型 public <T> T show2(Generic<E> data){ } // 泛型方法的错误写法三:首先次方法是归属于普通类而非泛型内部类,即T 对于此方法是未声明的 public void show3(T data){ } }
泛型方法细节:
-
泛型类参数对其中方法的影响
-
普通方法:参数类型为泛型类指定类型
-
泛型方法:指定其他泛型类型
- 调用时,可以传入其指定类型(跟泛型类指定类型相同)
- 调用是,亦可以传入泛型类指定类型
-
泛型方法:参数类型与泛型类指定类型相同
- 调用时,必须传入其指定类型(跟泛型类指定类型相同)
-
-
泛型类中的泛型方法可以声明与泛型类指定泛型不同的泛型类型
package generic; public class GenericMethod3 { static class Fruit{ @Override public String toString() { return "fruit"; } } static class Apple extends Fruit{ @Override public String toString() { return "apple"; } } static class Person{ @Override public String toString() { return "person"; } } static class GenericMethodTest<T>{ public void show(T t){ System.out.println(t.toString()); } public <E> void show1(E e){ System.out.println(toString()); } public <T> void show2(T t){ System.out.println(t.toString()); } } public static void main(String[] args) { Apple apple = new Apple(); Person person = new Person(); GenericMethodTest<Fruit> ma = new GenericMethodTest<>(); ma.show(apple);//可以的 ma.show(person);//不行,编译报错,泛型类参数类型会影响其中的普通方法 ma.show2(apple);//可以的,已经指定了泛型参数类型 ma.show1(person);//可以的,泛型类参数类型不会影响其中的泛型方法(这个是指定了类型的) ma.show1(apple);//可以的,参数类型不受限 } }