泛型
从JDK1.5以后引入了三大常用新特性:
- 泛型
- 枚举(enum)
- 注解(Annotation)
其中在JDK1.5中泛型是一件非常重要的实现技术,它可以帮助我们解决程序的参数转换问题。通常我们遇到参数类型冲突的时候一般需要转换参数类型来解决问题,而有了泛型就不需要了.
泛型,顾名思义就是广泛的类型,也就是可以接受各种参数类型
一.泛型问题的引出
首先我们来想想,不了解泛型之前我们是怎么解决参数类型冲突这个问题的
**假设需要你定义一个描述坐标的程序类Point,需要提供两个属性x、y。对于这两个属性的内容可能有如下选择:
**
.1. x = 10、y = 20;
.2.x = 10.1、y = 20.1;
.3. x = 东经80度、y = 北纬20度;
那么现在首先要解决的问题就是Point类中的x、y的属性类型问题,此时需要保存的有int、double、String,所以在java中只有一种类型可以保存所有类型:Object型
(1)定义Point类
class Point {
private Object x ;
private Object y ;
public Object getX() {
return x;
}
public void setX(Object x) {
this.x = x;
}
public Object getY() {
return y;
}
public void setY(Object y) {
this.y = y;
}
}
(2)设置整型坐标
// 设置数据
Point p = new Point() ;
p.setX(10); // 自动装箱并且向上转型为Object
p.setY(20);
// 取出数据
int x = (Integer) p.getX() ; // 强制向下转型为Integer并且自动拆箱
int y = (Integer) p.getY() ;
System.out.println("x = " +x+",y = "+y);
(3)设置字符串
// 设置数据
Point p = new Point() ;
p.setX("东经80度");
p.setY("北纬20度");
// 取出数据
String x = (String) p.getX() ;
String y = (String) p.getY() ;
System.out.println("x = " +x+",y = "+y);
以上代码看起来已经解决问题,但是现在解决问题的关键在于Object,于是问题也就出现在Object上。
(4)观察程序问题
// 设置数据
Point p = new Point() ;
p.setX(10.2);
p.setY("北纬20度");
// 取出数据
String x = (String) p.getX() ;
String y = (String) p.getY() ;
System.out.println("x = " +x+",y = "+y);
这个时候由于设置方的错误,将坐标内容设置成了double与String,但是接收方不知道,于是在执行时就会出现ClassCastException ,ClassCastException 指的是两个没有关系的对象进行强转出现的异常。这个时候语法不会对其做任何限制,但执行的时候出现了程序错误,所以得出结论:向下转型是不安全的操作,会带来隐患。
所以引入了泛型,泛型就不会出现如上问题
二.泛型的基本使用
(1)泛型的定义:泛型指的是就是在类定义的时候并不会设置类中的属性或者方法中的参数的具体类型,而是在类使用的时候再定义.
(2)泛型类的基本语法
class MyClass<T> {
T value1;
}
尖括号 <> 中的 T 被称作是类型参数,用于指代任何类型。实际上这个T你可以任意写,但出于规范的目的,Java
还是建议我们用单个大写字母来代表类型参数。常见的如:
- T 代表一般的任何类。
- E 代表 Element 的意思,或者 Exception 异常的意思
- K 代表 Key 的意思
- V 代表 Value 的意思,通常与 K 一起配合使用
- S 代表 Subtype 的意思
如果一个类被 的形式定义,那么它就被称为是泛型类
(3)使用泛型类
MyClass<String> myClass1 = new MyClass<String>();
MyClass<Integer> myClass2 = new MyClass<Integer>();
`注意:泛型只能接受类,所有的基本数据类型必须使用包装类!
(4)泛型类引入多个类型参数以及使用
class MyClass<T,E> {
T value1;
E value2;
}
public class Test {
public static void main(String[] args) {
MyClass<String,Integer> myClass1 = new MyClass<String,Integer>();
}
}
(5)使用泛型定义Point类
class Point <T> { // T表示参数,是一个占位的标记;如果有多个泛型就继续在后面追加
private T x ;
private T y ;
public T getX() {
return x;
}
public void setX(T x) {
this.x = x;
}
public T getY() {
return y;
}
public void setY(T y) {
this.y = y;
}
}
public class TestDemo {
public static void main(String[] args) {
// 设置数据
Point<String> p = new Point<String>() ; // JDK1.5的语法
p.setX("东经80度");
p.setY("北纬20度");
// 取出数据
String x = p.getX() ; // 避免了向下转型
String y = p.getY() ;
System.out.println("x = " +x+",y = "+y);
}
}
泛型的出现彻底改变了向下转型的需求。引入泛型后,如果明确设置了类型,则为设置类型;如果没有设置类型,则默认为Object类型。
三.泛型方法
泛型不仅可以用于定义类,还可以单独来定义方法
(1)泛型方法定义
class MyClass{
public <T> void testMethod(T t) {
System.out.println(t);
}
}
泛型方法与泛型类稍有不同的地方是,类型参数也就是尖括号那一部分是写在返回值前面的。 中的 T 被称为类型参数,而方法中的 T 被称为参数化类型,它不是运行时真正的参数。当然,声明的类型参数,其实也是可以当作返回值的类型的。
(2)使用类型参数做返回值的泛型方法
class MyClass{
public <T> T testMethod(T t) {
return t;
}
}
(3)泛型方法与泛型类可以共存
泛型方法与泛型类共存
class MyClass<T>{
public void testMethod1(T t) {
System.out.println(t);
}
public <T> T testMethod2(T t) {
return t;
}
}
public class Test {
public static void main(String[] args) {
MyClass<String> myClass = new MyClass<>();
myClass.testMethod1("hello 泛型类");
Integer i = myClass.testMethod2(100);
System.out.println(i);
}
}
上面代码中,MyClass 是泛型类,testMethod1 是泛型类中的普通方法,而 testMethod2 是一个泛型方法。而泛型类中的类型参数与泛型方法中的类型参数是没有相应的联系的,泛型方法始终以自己定义的类型参数为准
泛型类的实际类型参数是 String,而传递给泛型方法的类型参数是 Integer,两者不相干。但是,为了避免混淆,如果在一个泛型类中存在泛型方法,那么两者的类型参数最好不要同名。比如,MyClass 代码可以更改为这样
class MyClass<T>{
public void testMethod1(T t) {
System.out.println(t);
}
public <E> E testMethod2(E e) {
return e;
}
}