一、泛型
1.案例引入
要求:
请编写程序,在 ArrayList 中,添加 3 个 Dog 对象 Dog 对象含有 name 和 age, 并输出 name 和 age (要求使用 getXxx())
import java.util.ArrayList;
class test1{
@SuppressWarnings({"all"})
public static void main(String[] args){
ArrayList list = new ArrayList();
list.add(new Dog("小黄",2));
list.add(new Dog("小白",1));
list.add(new Dog("小黑",5));
//假如不小心,添加了一直猫
list.add(new Cat("小花",2));
//遍历
for (Object o: list) {
Dog dog = (Dog) o;
System.out.println(dog.getName()+" "+dog.getAge());
}
}
}
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{
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;
}
}
以上代码就会出现ClassCastException: com.test.Cat cannot be cast to com.test.Dog
使用传统方法缺点
- 不能对加入到集合ArrayList中的数据类型进行约束(不安全)
- 遍历的时候,需要进行类型转换,如果集合中的数据量较大,对效率有影响
2.泛型引入
使用泛型解决上面的问题
import java.util.ArrayList;
class test1{
@SuppressWarnings({"all"})
public static void main(String[] args){
ArrayList<Dog> list = new ArrayList<Dog>();
list.add(new Dog("小黄",2));
list.add(new Dog("小白",1));
list.add(new Dog("小黑",5));
//假如不小心,添加了一直猫,代码会提示Required type 必须是Dog类型的数据,但是你给它一个Cat数据类型
// list.add(new Cat("小花",2));
//遍历
for (Object o: list) {
Dog dog = (Dog) o;
System.out.println(dog.getName()+" "+dog.getAge());
}
}
}
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{
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;
}
}
泛型的好处
- 编译时,检查添加元素的类型,提高了安全性
- 减少了类型转换的次数,提高效率
不适用泛型:Dog放入到ArrayList会先转成Object,在取出时,还需要转换成Dog
使用泛型:Dog放入ArrayList时和取出时,不需要类型转换,提高效率
二、泛型介绍
1.基本介绍
泛型其实就是一种表示数据类型的数据类型
- 泛型又称参数化类型,是jdk5出现的新特性,解决了数据类型的安全性问题
- 在类声明或实例化时,只要指定好需要的具体类型即可
- java泛型可以保证如果程序在编译时没有发出警告,进行时就不会产生异常。同时代码更加简洁、健壮
- 泛型的作用:可以在类声明时通过一个标识表示类中某个属性的类型,或者是某个方法的返回值的类型,或者是参数类型
加深泛型的理解
class test1{
@SuppressWarnings({"all"})
public static void main(String[] args){
//E 具体的数据类型在定义 Person 对象的时候指定,即在编译期间,就确定 E 是什么类型
test<String> stringtest = new test<String>("String类型");
System.out.println(stringtest.demo());
stringtest.getClass1();
test<Integer> integertest = new test<Integer>(1000);
System.out.println(integertest.demo());
integertest.getClass1();
}
}
/*
泛型的作用:
可以在类声明时通过一个标识表示类中某个属性的类型,
或者是某个方法的返回值的类型,或者是参数类型。
*/
//泛型类
class test<E>{
E unknown; //不确定是什么类型
//E可以是方法参数类型
public test(E unknown) {
this.unknown = unknown;
}
//E可以是方法返回类型
public E demo(){
return unknown;
}
//获取它的运行类型
public void getClass1(){
System.out.println(unknown.getClass());
}
}
2.基本语法
泛型声明
接口:interface 接口{ }
类:class 类<K,V>{ }
其中T、K、V不代表值,而是表示类型,任意字母都可以,常用T表示,是Type的缩写
泛型实例化
要在类的后面指定类型参数
比如:
List<String>stringtest = new ArrayList<String>();
案例练习
要求:
1.创建3个学生对象
2.放入到HashSet中学生对象使用
3.放入到HashMap中,要求Key是String name,Value就是 学生的对象
4.使用两种遍历方式
import java.util.*;
class test1{
@SuppressWarnings({"all"})
public static void main(String[] args){
//HashSet
HashSet<Student> students = new HashSet<>();
students.add(new Student("张三",18));
students.add(new Student("李四",20));
students.add(new Student("小明",17));
//HashMap
HashMap<String, Student> hashMap = new HashMap<>();
hashMap.put("张三",new Student("张三",18));
hashMap.put("李四",new Student("李四",20));
hashMap.put("小明",new Student("小明",17));
//增强for遍历HashSet
for (Object o : students) {
Student student = (Student) o;
System.out.println(student.getName()+" "+student.getAge());
}
System.out.println("=======");
//迭代器遍历HashMap
Set<String> keySet = hashMap.keySet();
Iterator<String> iterator = keySet.iterator();
while (iterator.hasNext()){
String key = iterator.next();
System.out.println(key+" "+hashMap.get(key).getAge());
}
System.out.println("=======");
//EntrySet方式遍历HashMap
Set<Map.Entry<String, Student>> entries = hashMap.entrySet();
Iterator<Map.Entry<String, Student>> iterator1 = entries.iterator();
while (iterator1.hasNext()){
Map.Entry<String, Student> entry = iterator1.next();
System.out.println(entry.getKey()+" "+entry.getValue().getAge());
}
}
}
class Student{
private String name;
private int age;
public Student(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;
}
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
3.泛型使用细节
- interface 接口{ } 或 class 类<K,V>{ },其中T、K、V必须是引用数据类型
- 泛型指定具体类型后,可以传入该类型或者其子类类型
- 泛型使用形式
①List< String > list1 = new ArrayList< String >();
②List< String > list1 = new ArrayList<>(); 简写形式,比较推荐 - 如果我们这样写 List list = new ArrayList(); 默认给它的泛型是[< E > E就是 Object ]
import java.util.ArrayList;
class test1{
@SuppressWarnings({"all"})
public static void main(String[] args){
//细节一
ArrayList<String> strings = new ArrayList<>();
// ArrayList<int> ints = new ArrayList<int>(); //错误的
//细节二
C<A> A = new C<A>(new A());
C<A> A1 = new C<A>(new B());
//细节三
ArrayList<String> strings1 = new ArrayList<>(); //这里编译器会自动推断
ArrayList<String> strings2 = new ArrayList<String>();
//细节四
ArrayList list = new ArrayList();
ArrayList<Object> list1 = new ArrayList<Object>(); //跟上面等价
}
}
class A{}
class B extends A{}
class C<E>{
E s;
public C(E s) {
this.s = s;
}
}
细节四
Object e其实就是ArrayList默认的泛型
综合案例练习
要求:
- 定义 Employee 类,该类包含:private 成员变量 name,sal,birthday,其中 birthday 为 MyDate 类的对象
- 为每一个属性定义 getter, setter 方法
- 重写 toString 方法输出 name, sal, birthday
- MyDate 类包含: private 成员变量 month,day,year;并为每一个属性定义 getter, setter 方法;
- 创建该类的 3 个对象,并把这些对象放入 ArrayList 集合中(ArrayList 需使用泛型来定义),对集合中的元素进 行排序,并遍历
- 调用 ArrayList 的 sort 方法 排序, 传入Comparator 对象[使用泛型],先按照 name 排序,如果 name 相同,则按生日日期的先后排序
import java.util.ArrayList;
import java.util.Comparator;
class test1{
@SuppressWarnings({"all"})
public static void main(String[] args){
ArrayList<Employee> employees = new ArrayList<>();
employees.add(new Employee("tom",5000,new MyDate(2022,8,15)));
employees.add(new Employee("juck",6000,new MyDate(2022,2,19)));
employees.add(new Employee("juck",10000,new MyDate(2022,4,20)));
employees.sort(new Comparator<Employee>(){
@Override
public int compare(Employee o1, Employee o2) {
//判断是否为Employee类型的数据;如果不是就不进行比较
if (!(o1 instanceof Employee && o2 instanceof Employee)){
return 0;
}
//判断name是否相同,compareTo字符串的比较
int i = o1.getName().compareTo(o2.getName());
if (i != 0 ){
return i;
}
//如果name相同,判断year
int i1 = o1.getBirthday().getYear() - o2.getBirthday().getYear();
if (i1 != 0){
return i1;
}
//如果name相同,判断month
int i2 = o1.getBirthday().getMonth() - o2.getBirthday().getMonth();
if (i2 != 0){
return i2;
}
//如果name相同,判断day
int i3 = o1.getBirthday().getDay() - o2.getBirthday().getDay();
if (i3 != 0){
return i3;
}
return 0;
}
});
for (Object o: employees) {
System.out.println(o);
}
}
}
class Employee {
private String name;
private int sal;
private MyDate birthday;
public Employee(String name, int 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 int getSal() {
return sal;
}
public void setSal(int sal) {
this.sal = sal;
}
public MyDate getBirthday() {
return birthday;
}
public void setBirthday(MyDate birthday) {
this.birthday = birthday;
}
@Override
public String toString() {
return "Employee{" +
"name='" + name + '\'' +
", sal=" + sal +
", birthday=" + birthday.getYear() +
", birthday=" + birthday.getMonth() +
", birthday=" + birthday.getDay() +
'}';
}
}
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;
}
}