泛型的概念
1.为什么要使用泛型?
不使用泛型的案例:
List list1 = new ArrayList();
list.add("张三");
list.add(20);
list.add(100.00);
......
//获取元素
//获取第一个元素
String name = (String)list.get(0);
//获取第二个元素
int age = (Integer)list.get(1);
//获取第三个元素
double score = (Double)list.get(2);
......
代码分析
:
集合与数组不同.数组只能存储单一的数据类型,而集合中可以存储任意的数据类型,可以是字符串,可以是整型,也可以是浮点型,这造成了两个问题
1.每使用一个元素就要进行向下转型,导致代码冗余
2.容易发生类型转换异常,安全性不高
所以泛型时为了解决这些问题的
2.泛型的概念:
ArrayList<String> arrList1 = new ArrayList<String>();
ArrayList<Integer> arrList2 = new ArrayList<Integer>();
//getClass();方法:获取字节码文件名
Class c1 = arrList1.getClass();
Class c2 = arrList2.getClass();
//判断c1,c2的字节码文件是否相同
System.out.println(c1 == c2);//结果为true
代码分析
:无论是对于ArrayList<String>
还是 ArrayList<Integer>
,他们的Class类型是一致的,都是ArrayList.class。
那么他们明明有指定类型的差异,这个差异到底体现在哪里呢?
答案是体现在类编译的时候,当JVM进行类编译的时候会进行泛型检查,如果说一个List被声明为String类型,那么他往该集合存取数据的时候就会对数据进行判断,从而就避免了存入或取出错误的数据。
这也就是说,泛型只存在于编译阶段,而不存在于运行阶段
。
泛型的知识点
1.迭代器的使用和增强for循环
迭代器(Iterator):
作用:对集合进行遍历
常用方法:
1.boolean hasNext( ):如果仍有元素可以迭代,则返回true
2.E next( );返回迭代的下一个元素,去除集合中的下一个元素
hasNext()和next()方法的原理:
迭代器的使用步骤
:
1.先使用集合中Collection的方法iterator( )获取迭代器实现类对象,使用Iterator接口接收(多态)
2.使用Iterator接口中的方法hasNext( )判断还有没有下一个元素
3.使用Iterator的next方法取出下一个元素
Iterator是一个接口,无法直接访问,需要用Iterator的实现类进行访问,
获取实现类的方式比较特殊:Collection接口中有一个方法叫做"iteractor()"
这个方法的返回值就是迭代器的实现对象
Iterator iterator( ) //返回在此Collection的集合元素上进行迭代的迭代器
代码实现:
public class IteratorDemo {
public static void main(String[] args) {
Collection<String> coll = new ArrayList<>();//多态
//向集合里添加元素
coll.add("张三");
coll.add("李四");
coll.add("王五");
coll.add("赵六");
//1.先使用集合中Collection的方法iterator( )获取迭代器实现类对象,使用Iterator接口接收(多态)
//注意:
//Iterator是有泛型的,泛型的实际类型是根据Collection集合的泛型进行定义
//Iterator接口<泛型> 对象名 = 实现类对象 -----多态
Iterator<String> it = coll.iterator();//多态
// 2.使用Iterator接口中的方法hasNext( )判断还有没有下一个元素
boolean isNext = it.hasNext();
System.out.println(isNext);
// 3.使用Iterator的next方法取出下一个元素
// String s = it.next();
// System.out.println(s);
// s = it.next();
// System.out.println(s);
// s = it.next();
// System.out.println(s);
// s = it.next();
// System.out.println(s);
//
//循环取出集合中的元素
while(it.hasNext( )) {
String s1 = it.next();
System.out.println(s1);
}
增强for循环
:
增强for循环的本质是迭代器,只适用于取出数组和集合的元素
代码实现:
//增强for循环的使用:
//增强for循环的底层实现是迭代器,使用for循环格式简化了迭代器的复杂性
//只能在集合或者数组中使用
//格式
//for(集合/数组的数据类型 变量名 : 集合名/数组名){
//输出元素;
// }
//遍历数组:
int[] arr = {1,2,3,4,5,6,7,8,9,10};
for (int i : arr) {
System.out.println(i);
}
//遍历集合
for(String s : coll) {
System.out.println(s);
}
2.泛型类
代码实现:
public class GenericClass <T> {
//T 代表类型参数
//泛型:是指类型参数化,处理的数据类型不是固定的,而是可以作为参数传入
T first;
T second;
public GenericClass(T first,T second) {
this.first = first;
this.second = second;
}
/**
* @return first
*/
public T getFirst() {
return first;
}
/**
* @return second
*/
public T getSecond() {
return second;
}
}
//多个类型参数泛型类
class GenericClass2 <U,V>{
U first;
V second;
public GenericClass2(U first, V second {
this.first = first;
this.second = second;
}
/**
* @return first
*/
public U getFirst() {
return first;
}
/**
* @return second
*/
public V getSecond() {
return second;
}
}
//以普通类作为泛型类
class GenericClass3{
Object first;
Object second;
public GenericClass3(Object first, Object second) {
this.first = first;
this.second = second;
}
/**
* @return first
*/
public Object getFirst() {
return first;
}
/**
* @return second
*/
public Object getSecond() {
return second;
}
}
测试:
public class GenericClassDemo {
public static void main(String[] args) {
//使用泛型类
//Integer 是实际的类型参数
GenericClass<Integer> minmax = new GenericClass<Integer>(1,100);
Integer min = minmax.getFirst();
Integer max = minmax.getSecond();
System.out.println(min);
System.out.println(max);
//实际类型参数是可以改变的
//String 是实际类型参数
GenericClass<String> name = new GenericClass<String>("张三","李四");
String name1 = name.getFirst();
String name2 = name.getSecond();
System.out.println(name1);
System.out.println(name2);
//多个类型参数泛型类
GenericClass2<String,Integer> name_age = new GenericClass2<String,Integer>("张三",20);
String name3 = name_age.getFirst();
int age = name_age.getSecond();
System.out.println(name3);
System.out.println(age);
//以Object类作为泛型类
GenericClass3 objMinMax = new GenericClass3(1,100);
Integer min1 = (Integer)objMinMax.getFirst();
Integer max1 = (Integer)objMinMax.getSecond();
System.out.println(min1 + " " + max);
}
}
3.泛型方法
代码:
public class Generic {
public static void main(String[] args) {
// 创建泛型类对象
GenericClass<String,Integer,String> coll = new GenericClass<String,Integer,String>("张三",19,"男");
System.out.println(coll.getName());
System.out.println(coll.getAge());
System.out.println(coll.getSex());
// 调用含有泛型的方法
GenericMethod.method("李四");
GenericMethod.method(19);
GenericMethod.method(true);
GenericMethod.method(100.0);
GenericMethod.method2("hello", "world");
}
class GenericMethod{
// 定义含有泛型的方法
//在调用含有泛型的方法时,确定方法的数据类型,传递给这个方法的参数是什么类型的,这个泛型就是什么类型的
public static <T> void method(T t) {
System.out.println(t);
}
// 含有多个泛型的方法
public static <T,V> void method2(T t , V v) {
System.out.printf("%s%s",t,v);
}
}
4.泛型接口
//泛型接口
public interface GenericInterface<T> {
public abstract void method(T t);
}
//接口的实现类
//实现接口,并且指定接口的泛型
class GenericInterfaceImplementsClass implements GenericInterface<String>{
@Override
public void method(String t) {
// TODO 自动生成的方法存根
System.out.println(t);
}
}
//创建含有泛型的接口实现类
class GenericInterfaceImplementsClass2<T> implements GenericInterface<T>{
@Override
public void method(T t) {
// TODO 自动生成的方法存根
System.out.println(t);
}
}
测试:
public class GenericInterfaceDemo {
public static void main(String[] args) {
GenericInterfaceImplementsClass test = new GenericInterfaceImplementsClass();
test.method("泛型接口");
System.out.println("==============================");
GenericInterfaceImplementsClass2<String> test2 = new GenericInterfaceImplementsClass2<>();
test.method("含有泛型的接口实现类");
}
}
总结:
泛型就是在定义的时候不知道是什么类型,创建含有泛型的对象或者调用含有泛型的方法时再指定数据类型,然后把数据类型传给用字母代替的泛型,最后编译器会根据传递过去的数据类型执行相应的代码.