泛型的理解和好处
首先我们先来看看泛型的好处
1)编译时,检查添加元素的类型,提高了安全性
2)减少了类型转换的次数,提高效率[说明]
不使用泛型 Dog -> Object -> Dog//放入到ArrayList 会先转成Object,在取出时,还需要转换成Dog使用泛型 Dog-> Dog -> Dog//放入时,和取出时,不需要类型转换,提高效率
3)不再提示编译警告
代码演示:
注意:
1.当我们在集合的后面指定了泛型,那么表示存放到集合中的元素的类型是dog类型
2.如果我们加入的类型不是dog那么编译器会直接报错
3.我们在遍历的时候,可以直接取出dog的类型而不是Object
package idea.chapter15.generic.improve;
import java.util.ArrayList;
@SuppressWarnings({"all"})
public class Generic02 {
public static void main(String[] args) {
//使用传统的方法来解决===> 使用泛型
//1. 当我们 ArrayList<Dog> 表示存放到 ArrayList 集合中的元素是Dog类型
//2. 如果编译器发现添加的类型,不满足要求,就会报错
//3. 在遍历的时候,可以直接取出 Dog 类型而不是 Object
//4. public class ArrayList<E> {} E称为泛型,那么 Dog->E
ArrayList<Dog> arrayList = new ArrayList<Dog>();
arrayList.add(new Dog("旺财", 10));
arrayList.add(new Dog("发财", 1));
arrayList.add(new Dog("小黄", 5));
//假如我们,不小心,添加了一只猫,就会直接报错
//arrayList.add(new Cat("招财猫", 8));
System.out.println("===使用泛型====");
for (Dog dog : arrayList) {
System.out.println(dog.getName() + "-" + dog.getAge());
}
}
}
/*
1.请编写程序,在ArrayList 中,添加3个Dog对象
2.Dog对象含有name 和 age, 并输出name 和 age (要求使用getXxx())
3.使用泛型来完成代码
*/
class Dog {
private String name;
private int age;
public Dog(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
class Cat { //Cat类
private String name;
private int age;
public Cat(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
泛型的介绍
理解:泛(广泛)型(类型)=> Integer,String,Dog
1)泛型又称参数化类型,是Jdk5.0出现的新特性,解决数据类型的安全性问题
2)在类声明或实例化时只要指定好需要的具体的类型即可。
3)Java泛型可以保证如果程序在编译时没有发出警告,运行时就不会产ClassCastException异常。同时,代码更加简洁、健壮
4)泛型的作用是:可以在类声明时通过一个标识表示类中某个属性的类型,或者是某个方法的返回值的类型,或者是参数类型。
代码演示:
注意:
泛型的作用是:可以在类声明时通过一个标识表示类中某个属性的类型,
或者是某个方法的返回值的类型,或者是参数类型
class Person <E> 红色标注的这一块就是泛型,在代码中我们可以看到,我们在类的后面加入了<E>就表示该一个类型,后面根据我们传入的不同的对象,比如我们传入的是一个String,那么E就是String类型的,传入的是一个Integer 那么E 就是一个Integer
package idea.chapter15.generic;
public class Generic03 {
public static void main(String[] args) {
//注意,特别强调: E具体的数据类型在定义Person对象的时候指定,即在编译期间,就确定E是什么类型
Person<String> person = new Person<String>("jack");
person.show(); //String
/*
你可以这样理解,上面的Person类
class Person {
String s ;//E表示 s的数据类型, 该数据类型在定义Person对象的时候指定,即在编译期间,就确定E是什么类型
public Person(String s) {//E也可以是参数类型
this.s = s;
}
public String f() {//返回类型使用E
return s;
}
}
*/
Person<Integer> person2 = new Person<Integer>(100);
person2.show();//Integer
/*
class Person {
Integer s ;//E表示 s的数据类型, 该数据类型在定义Person对象的时候指定,即在编译期间,就确定E是什么类型
public Person(Integer s) {//E也可以是参数类型
this.s = s;
}
public Integer f() {//返回类型使用E
return s;
}
}
*/
}
}
//泛型的作用是:可以在类声明时通过一个标识表示类中某个属性的类型,
// 或者是某个方法的返回值的类型,或者是参数类型
class Person<E> {
E s ;//E表示 s的数据类型, 该数据类型在定义Person对象的时候指定,即在编译期间,就确定E是什么类型
public Person(E s) {//E也可以是参数类型
this.s = s;
}
public E f() {//返回类型使用E
return s;
}
public void show() {
System.out.println(s.getClass());//显示s的运行类型
}
}
泛型的语法
泛型的声明
interface接口<T>和class 类<K,V>
//比如:List,ArrayList
说明: 1)其中,T,K,V不代表值,而是表示类型。
2)任意字母都可以。常用T表示,是Type的缩写
泛型的实例化:
要在类名后面指定类型参数的值(类型)
-
List<String> strList =new ArrayList<String>(); [举例说明]
-
Iterator<Customer> iterator = customers.iterator();
泛型课堂练习
代码演示:
package idea.chapter15.generic;
import java.util.*;
/*
练习:
1. 创建3个学生对象
2. 放入到HashMap中,要求Key是String name,Value就是 学生对象
3.使用两种方式遍历
*/
@SuppressWarnings({"all"})
public class GenericExercise {
public static void main(String[] args) {
HashSet<Student> students = new HashSet<>();
students.add(new Student("jack", 12));
students.add(new Student("tom", 10));
students.add(new Student("smith", 1));
// //使用增强for遍历
// System.out.println("使用增强for的方式");
// for (Student student : students) {
// System.out.println(student);
// }
//
// //使用迭代器
// System.out.println("使用迭代器的方式");
// Iterator<Student> iterator = students.iterator();
// while (iterator.hasNext()) {
// Student next = iterator.next();
// System.out.println(next);
// }
//使用HashMap
HashMap<String, Student> hashMap = new HashMap<>();
hashMap.put("jack", new Student("jack", 1));
hashMap.put("tom", new Student("tom", 11));
hashMap.put("mary", new Student("mary", 111));
//使用增强for
Set<String> strings = hashMap.keySet();
for (String string : strings) {
System.out.println(string + "-" + hashMap.get(string));
}
//使用迭代器
System.out.println("\n使用迭代器的方式");
Set<Map.Entry<String, Student>> entries = hashMap.entrySet();
Iterator<Map.Entry<String, Student>> iterator = entries.iterator();
while (iterator.hasNext()) {
//此时的next就是一个Entry
Map.Entry<String, Student> next = iterator.next();
System.out.println(next.getKey() + "-" + next.getValue());
}
}
}
class Student {
private String name;
private int id;
public Student(String name, int id) {
this.name = name;
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", id=" + id +
'}';
}
}
泛型使用的注意事项和细节
1.interface List<T>0,public class HashSet<E>{}..等等,说明:T,E只能是引用类型
2.在给泛型指定具体类型后,可以传入该类型或者其子类类型
3.泛型使用形式
List<Integer> list1=new ArrayList<Integer>{}; List<Integer>list2=new ArrayList<>);
3.如果我们这样写 List list3=new ArrayList0;默认给它的 泛型是[<E> E就是Object]即:
代码演示:
package idea.chapter15.generic;
import java.util.ArrayList;
import java.util.List;
/**
* 讲解泛型的注意事项和使用细节
*/
@SuppressWarnings({"all"})
public class GenericDetail {
public static void main(String[] args) {
//1.给泛型指向数据类型是,要求是引用类型,不能是基本数据类型
List<Integer> list = new ArrayList<Integer>(); //OK
//List<int> list2 = new ArrayList<int>();//错误
//2. 说明
//因为 E 指定了 A 类型, 构造器传入了 new A()
//在给泛型指定具体类型后,可以传入该类型或者其子类类型
Pig<A> aPig = new Pig<A>(new A());
aPig.f();
Pig<A> aPig2 = new Pig<A>(new B());
aPig2.f();
//3. 泛型的使用形式
ArrayList<Integer> list1 = new ArrayList<Integer>();
List<Integer> list2 = new ArrayList<Integer>();
//在实际开发中,我们往往简写
//编译器会进行类型推断, 老师推荐使用下面写法
ArrayList<Integer> list3 = new ArrayList<>();
List<Integer> list4 = new ArrayList<>();
ArrayList<Pig> pigs = new ArrayList<>();
//4. 如果是这样写 泛型默认是 Object
ArrayList arrayList = new ArrayList();//等价 ArrayList<Object> arrayList = new ArrayList<Object>();
/*
public boolean add(Object e) {
ensureCapacityInternal(size + 1); // Increments modCount!!
elementData[size++] = e;
return true;
}
*/
Tiger tiger = new Tiger();
//如果什么都不写,默认是Object,也就是下面的这种方式
/*
class Tiger {//类
Object e;
public Tiger() {}
public Tiger(Object e) {
this.e = e;
}
}
*/
}
}
class Tiger<E> {//类
E e;
public Tiger() {
}
public Tiger(E e) {
this.e = e;
}
}
class A {
}
class B extends A {
}
class Pig<E> {//
E e;
public Pig(E e) {
this.e = e;
}
public void f() {
System.out.println(e.getClass()); //运行类型
}
}
泛型练习2
代码演示:
package idea.chapter15.generic;
import java.util.ArrayList;
import java.util.Comparator;
/*
泛型课堂练习题
定义Employee类
1)该类包含:private成员变量name,sal,birthday,其中birthday为MyDate类的对象;
2)为每一个属性定义getter,setter方法;
3)重写 toString 方法输出 name,sal,birthday
4) MyDate类包含:private成员变量month,day.year;并为每一个属性定义getter setter 方法;
5)创建该类的3个对象,并把这些对象放入ArrayList集合中(ArrayList需使用泛型来定义),对集合中的元素进行排序,并遍历输出:
排序方式:调用ArrayList的sort 方法,传入 Comparator对象[使用泛型],先按照name排序,如果name相同,则按生日日期的先后排序。 【即:定制排序】
有一定难度15min,比较经典 泛型使用案例
*/
@SuppressWarnings({"all"})
public class GenericExercise02 {
public static void main(String[] args) {
ArrayList<Employee> employees = new ArrayList<>();
employees.add(new Employee("jack", 200, new MyDate(2001, 1, 1)));
employees.add(new Employee("tom", 100, new MyDate(2003, 3, 2)));
employees.add(new Employee("tom", 300, new MyDate(2002, 5, 3)));
employees.sort(new Comparator<Employee>() {
@Override
public int compare(Employee o1, Employee o2) {
//根据要求,如果名字相同我们按照出生日期比较,如果名字不相同就按照名字比较
if (o1.getName().equals(o2.getName())) {
return o1.getBirthday().getYear() - o2.getBirthday().getYear();
} else//还可以继续增加逻辑,比如出生年份相同就按照月份比较
return o1.getName().equals(o2.getName()) ? 1 : -1;
}
});
System.out.println(employees);
}
}
class Employee implements Comparator {
private String name;
private double sal;
private MyDate birthday;
public Employee(String name, double sal, MyDate birthday) {
this.name = name;
this.sal = sal;
this.birthday = birthday;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public double getSal() {
return sal;
}
public void setSal(double sal) {
this.sal = sal;
}
public MyDate getBirthday() {
return birthday;
}
public void setBirthday(MyDate birthday) {
this.birthday = birthday;
}
@Override
public String toString() {
return "\nEmployee{" +
"name='" + name + '\'' +
", sal=" + sal +
", birthday=" + birthday +
'}';
}
@Override
public int compare(Object o1, Object o2) {
return 0;
}
}
class MyDate {
private int year;
private int month;
private int day;
public MyDate(int year, int month, int day) {
this.year = year;
this.month = month;
this.day = day;
}
public int getYear() {
return year;
}
public void setYear(int year) {
this.year = year;
}
public int getMonth() {
return month;
}
public void setMonth(int month) {
this.month = month;
}
public int getDay() {
return day;
}
public void setDay(int day) {
this.day = day;
}
@Override
public String toString() {
return "MyDate{" +
"year=" + year +
", month=" + month +
", day=" + day +
'}';
}
}