泛型的理解和好处
泛型的好处
- 编译时,检查添加元素的类型,提高了安全性
- 减少了类型转换的次数,提高效率
不使用泛型
Dog-加入->Object-取出->Dog(向下转型) Dog放入到ArrayList 会先转成Object,在转出时,还需要转换成Dog
使用泛型
Dog->Dog->Dog 放入和取出时,不需要类型转换,提高效率 - 不再提示编译警告
泛型的介绍
泛型:广泛类型
- 泛型又称参数化类型,是JDK5.0 出现的新特性,解决数据类型的安全性问题
- 在类声明或实例化时(在定义对象时,即编译期间),只要指定好需要的具体类型即可
- Java 泛型可以保证如果程序在编译时,没有发出警告,运行时就不会产生,ClassCastException异常。同时,代码更加简洁
- 泛型的作用:可以在类声明时通过一个标识表示类中某个属性的类型,或者某个方法的返回值类型,或者是参数类型
public class Generic01 {
public static void main(String[] args) {
//注意:E 具体的数据类型在定义Person对象时指定(即在编译期间),就确定E是什么类型
Person<Integer> integerPerson = new Person<>(1);//E的数据类型是Integer
integerPerson.show();
}
}
//泛型的作用:可以在类声明时通过一个标识表示类中某个属性的类型、某个方法的返回值类型 或 参数类型
class Person<E>{
E S;//E表示s的数据类型,该数据类型在定义Person对象的时候指定,即在编译期间,就确定E是什么类型
public Person(E s) {//E也可以是参数类型
S = s;
}
public E f(){//E也可以是返回类型
return S;
}
public void show(){
System.out.println("S的运行类型="+S.getClass());
}
}
结果
泛型的语法
泛型的声明
- interface 接口{} 和 class类<K,V>{}
1,其中 T K V 不代表值,而是表示类型
2,任意字母都可以,常用T表示,是Type的缩写
泛型的实例化
要在类名后面指定类型参数的值(类型)。如:
- 1,List strList = new ArrayList();
- 2,Iterator iterator = customers.iterator();
泛型使用实例
public class GenericExercise {
public static void main(String[] args) {
//使用泛型方式给HashSet放入三个学生对象,遍历时可以直接调用Student1中的方法
Set<Student1> objects = new HashSet<Student1>();
objects.add(new Student1("jack"));//当调用add方法时,显示调用Student1 对象
objects.add(new Student1("tom"));
objects.add(new Student1("smith"));
// 遍历
for(Student1 o:objects){
System.out.println(o.getName());
}
//使用泛型方式给 HashMap 放入 3 个学生对象
//K -> String V->Student
//一旦添加了泛型,编译器就会规范调用类型
Map<String, Student1> map = new HashMap<String, Student1>();
//public class HashMap<K,V> {}
Student1 student1 = new Student1("jack");
Student1 student2 = new Student1("tom");
Student1 student3 = new Student1("smith");
map.put("jack",student1);
map.put("tom",student2);
map.put("smith",student3);
//遍历
//迭代器 EntrySet
/*
public Set<Map.Entry<K,V>> entrySet() {
Set<Map.Entry<K,V>> es;
return (es = entrySet) == null ? (entrySet = new EntrySet()) : es;
}
*/
//1,map.entrySet();
Set<Map.Entry<String, Student1>> entries = map.entrySet();
/*
public final Iterator<Map.Entry<K,V>> iterator() {
return new EntryIterator();
}
*/
//2,调迭代器 entries.iterator()
Iterator<Map.Entry<String, Student1>> iterator = entries.iterator();
//3,先判断hasNext 下一个是否还有
while (iterator.hasNext()) {
Map.Entry<String, Student1> next = iterator.next();
System.out.println(next.getKey()+"-"+next.getValue());
}
}
}
class Student1{
private String name;
public Student1(String name) {
this.name = name;
}
public String getName() {
return name;
}
@Override
public String toString() {
return "Student1{" +
"name='" + name + '\'' +
'}';
}
}
结果
泛型的注意事项
- 1,interface List{} public class HashSet{}
说明:T E 只能是引用类型 - 2,在给泛型指定具体类型后,可以传入该类型或其子类类型
- 3,泛型使用形式
List list1 = new ArrayList ();
List list1 = new ArrayList <>();
如果我们这样写List list1 = new ArrayList (); 默认他的泛型是 E 就是Object
public class GenericDetail {
public static void main(String[] args) {
//1,泛型指向的数据类型是引用类型Integer,不能是基本数据类型int
List<Integer> list = new ArrayList<Integer>();
//List<int> list = new ArrayList<int>(); 错误
//2,E指定了A类型,构造器传入 new A()
// 在给泛型指定具体类型后,可以传入该类型或者子类类型
Pig<A> aPig = new Pig<A>(new A());
aPig.f();
Pig<A> aPig1 = new Pig<A>(new B());
aPig1.f();
//3,泛型的使用形式
List<Integer> list1 = new ArrayList <Integer>();
//实际开发中往往简写为:
List<Integer> list2 = new ArrayList <>();
//4,如果我们这样写List list1 = new ArrayList (); 默认他的泛型是 <E> E 就是Object
List list3 = new ArrayList ();//等价 ArrayList<Object> arrayList = new ArrayList<Object>();
}
}
class A{
}
class B extends A{}
class Pig<E>{
E e;
public Pig(E e) {
this.e = e;
}
public void f(){
System.out.println("Pig类中的f方法");
}
}