泛型概述和好处
泛型:JDK5中引入的特性,它提供了编译时类型安全检测机制,该机制允许在编译时检测到非法的类型 泛型的本质是参数化类型,将来在使用或调用时才传入具体的类型 参数化类型,也就是说所操作的数据类型被指定为一个参数。就是一种不确定的数据类型
什么是参数化类型:就是将类型由原来的具体的类型参数化,然后在使用或调用时传入具体的类型 这种参数类型可以用在类、方法和接口中,分别被称为泛型类、泛型方法、泛型接口
泛型的好处: 1、省略了强转的代码。 2、可以把运行时的问题提前到编译时期,提高Java程序的类型安全 3、编写的代码可以被不同类型的对象所重用,可以编写重用性更好的代码
泛型定义的几种格式: 1、<类型>:指定一种类型的格式。这里的类型可以看成是形参 2、<类型1,类型2,,…>:指定多种类型的格式,多种类型之间用逗号隔开。这里的类型可以看成是形参
将来具体调用的时候给定的类型可以看成是实参,并且实参的类型只能是引用类型,或叫引用数据类型
泛型概述和好处的练习
xxxxxxxxxx
package ch16;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
public class a_1_1测试 {
public static void main(String[] args) {
//创建Collection集合的对象
Collection c = new ArrayList(); //不指定集合中的元素类型
//添加元素
c.add("hello"); //当不指定集合中的元素类型时,会默认是Object类型,Object代表所有引用类型
c.add("world");
c.add("java"); //原理是将字符串赋值给Object,这也叫向上转型
//遍历集合
Iterator it = c.iterator();
while (it.hasNext()){
Object obj = it.next(); //注意因为上面添加元素的时候是Object类型,所以这行获取的时候也要Object类型
System.out.println(obj);
}
System.out.println("-------------------");
//-------------------------------------------------------------------------------------------------------------
//上面的问题:我们存进去的元素是String类型,在遍历的时候我们不想当作Object类型时候,我们需要向下转型变成String类型,而不是向上转型
//如下
//遍历集合
Iterator it2 = c.iterator();
while (it2.hasNext()){
String s2 = (String)it2.next(); //把Object类型变回String类型
System.out.println(s2);
}
System.out.println("-------------------");
//------------------------------------------------------------------------------------------------------------
//当我们添加一个int类型的元素 。
//c.add(100); //这个int类型100,可以自动向上转型为Integer类型。这行会报错,先注释了,需要自行解开
//遍历集合
Iterator it3 = c.iterator();
while (it3.hasNext()){
String s3 = (String)it3.next(); //就会出问题,报错Integer类型不能转为String类型
System.out.println(s3);
}
System.out.println("-------------------");
//出现问题的原因:我们在创建集合对象的时候没有指定只能放String类型,所以我们在添加元素的时候,可以添加任意类型,在遍历的时候,我们
//在46行那里进行了强转为String类型,但是就会报错Integer类型不能转为String类型
//----------------------------------------------------------------------------------------------------------------
//上面出现的诸多问题,如何解决呢,很简单,使用我们现在学的泛型就可以解决,如下
//创建Collection集合的对象
Collection<String> st = new ArrayList<String>(); //指定集合里只能存储String类型的数据
//添加元素
st.add("hello2");
st.add("world2");
st.add("java2");
//st.add(100);//在编译期间就会出现报错,因为我们指定了只能存储String类型。避免了运行期间出现报错。即泛型的第一个好处,把问题提前
//遍历集合
Iterator<String> it4 = st.iterator();
while (it4.hasNext()){
String s = it4.next(); //泛型的第二个好处,不需要再进行强制转换
System.out.println(s);
}
}
}
泛型类
泛型类的定义格式如下
xxxxxxxxxx
修饰符 class 类名 <类型>{}
格式范例如下
public class Generic<T>{}
注意上面那行的T可以随便写为任意标识,常见的如T、E、K、V等形式的参数常用于表示泛型。提示:T是type、E是element、K是key、V是value
泛型类的练习
xxxxxxxxxx
package ch16;
public class a_2_1Student {
//成员变量
private String name;
//成员变量对应的get、set方法
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
package ch16;
public class a_2_2Teacher {
//成员变量
private Integer age;
//成员变量的get和set方法
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
}
xxxxxxxxxx
package ch16;
public class a_2_3测试 {
public static void main(String[] args) {
//当不使用泛型的话,需要两个类才能完成输出姓名和年龄。前提是姓名和年龄是不同类型的
a_2_1Student s = new a_2_1Student();
s.setName("张三");
System.out.println(s.getName());
a_2_2Teacher t = new a_2_2Teacher();
t.setAge(18);//需要的是integer类型,我们写int类型时会自动向上转型为integer类型
//如果上面那行传的参数是字符串类型的18就会报错。那如果我们只想在学生类或老师类里面用一个方法,该方法的参数去接收任何类型
//解决方法就是使用泛型类来解决
System.out.println(t.getAge());
System.out.println("----------------------");
//--------------------------------------------------------------------------------------------------------------
//当使用泛型的时候,只需要一个类就能完成输出姓名和年龄。前提是姓名和年龄是不同类型的
a_2_4泛型Generic<String> g1 = new a_2_4泛型Generic<String>();
g1.setT("李四");//String类型
System.out.println(g1.getT());
a_2_4泛型Generic<Integer> g2 = new a_2_4泛型Generic<Integer>();
g2.setT(19);//Integer类型
System.out.println(g2.getT());
//还可以继续给其他类型
a_2_4泛型Generic<Boolean> g3 = new a_2_4泛型Generic<Boolean>();
g3.setT(true);//Boolean类型
System.out.println(g3.getT());
}
}
xxxxxxxxxx
package ch16;
public class a_2_4泛型Generic<T> {
//定义成员变量t,该变量的类型是T类型
private T t;
//get和set方法
public T getT() {
return t;
}
public void setT(T t) {
this.t = t;
}
}
泛型方法
泛型方法的定义格式如下 修饰符 <类型> 返回值类型 方法名(类型 变量名){}
泛型方法定义格式的范例如下
publicc <T> void show(T t){}
注意上面那行的T可以随便写为任意标识,常见的如T、E、K、V等形式的参数常用于表示泛型。提示:T是type、E是element、K是key、V是value
泛型方法的练习
xxxxxxxxxx
package ch16;
/*
public class a_3_1泛型Generic {
public void show(String s){ System.out.println(s);}
public void show(Integer i){ System.out.println(i);}
public void show(Boolean b){ System.out.println(b);}
}
*/
//-------------------------------------------------------------------------------------------------------------
//泛型类改进。这里只用1个方法就完成了上面3个方法做的事情
//public class a_3_1泛型Generic<T> {
//
// public void show(T t){ System.out.println(t);}
//
//}
//---------------------------------------------------------------------------------------------------------------
//使用泛型方法进行最终的改进,如下
public class a_3_1泛型Generic {
public <T> void show(T t){ //传参数的时候,传什么类型就是什么类型,在调用show方法时才明确类型
System.out.println(t);
}
}
xxxxxxxxxx
package ch16;
public class a_3_2测试 {
public static void main(String[] args) {
a_3_1泛型Generic g = new a_3_1泛型Generic();
g.show("张三");//String类型
g.show(18);//Integer类型
g.show(true);//Boolean类型
//g.show(5.20);//这行报错,因为我们没有在泛型类里面提供对应方法。我们把泛型类进行改进一下
//----------------------------------------------------------------------------------------------------------------
/*//泛型类改进
System.out.println("-------------------");
//测试一下我们改进的泛型类
a_3_1泛型Generic<String> g1 = new a_3_1泛型Generic<String>();
g1.show("李四");
a_3_1泛型Generic<Integer> g2 = new a_3_1泛型Generic<Integer>();
g2.show(19);
a_3_1泛型Generic<Boolean> g3 = new a_3_1泛型Generic<Boolean>();
g3.show(true);*/
//但是还是有一个问题:我们每次创建对象的时候都要明确一次类型。如何在创建对象的时候不明确类型,将来调方法的时候再明确类型。
//需要用到这节课学的泛型方法,如下
//-----------------------------------------------------------------------------------------------------------------
//使用泛型方法进行最终的改进
System.out.println("-------------------");
a_3_1泛型Generic g2 = new a_3_1泛型Generic();
g2.show("王五");
g2.show(20);
g2.show(true);
g2.show(5.20);
//虽然调的是同一个方法,但我们在'a_3_1泛型Generic'里面已经做了泛型方法的最终改进
}
}
泛型接口
泛型接口的定义格式,如下
修饰符 interface 接口名<类型>{}
泛型接口定义格式的范例,如下
public interface Generic<T>{}
泛型接口的练习
xxxxxxxxxx
package ch16;
public interface a_4_1泛型接口Generic<T> { //这里要自己添加<T>
//因为上面那行的接口无法直接实例化,所以在测试类里面还不能直接使用
//解决:需要给一个'a_4_1泛型接口Generic<T>'的实现类。即新建一个‘a_4_3GenericImpl’类
void show(T t);
}
xxxxxxxxxx
package ch16;
public class a_4_2测试 {
public static void main(String[] args) {
a_4_1泛型接口Generic<String> g1 = new a_4_3GenericImpl<String>();
g1.show("张三");
a_4_1泛型接口Generic<Integer> g2 = new a_4_3GenericImpl<Integer>();
g2.show(18);
}
}
xxxxxxxxxx
package ch16;
//该类是'a_4_1泛型接口Generic<T>'的实现类
public class a_4_3GenericImpl<T> implements a_4_1泛型接口Generic<T> {
//重写接口的show方法
public void show(T t) {
System.out.println(t);
}
}