improve改善
public 公共的
personal===private 私人的
cast 投
exception 异常
integer 整形
泛型
使用传统方法的问题分析
1.不能对加入到集合 ArrayList 中的数据类型进行约束(不安全)
2.遍历的时候,需要进行类型转换,如果集合中的数据量较大,对效率有影响
-
泛型快速体验 - 用泛型来解决前面的问题
不使用泛型:
-
Dog -> 加入 -> Object -> 取出 -> Dog // 放入到ArrayList时会先转换成Object,在取出时,还需要转换成Dog。
使用泛型:
-
Dog -> Dog -> Dog // 放入时,和取出时,不需要类型转换,提高效率。
不再提示编译警告。
解释:
-
不使用泛型:在Java早期版本中,集合类如
ArrayList
是不带泛型的,这意味着你可以向ArrayList
中添加任何类型的对象,因为它们都被视为Object
类型。当你从集合中取出对象时,需要显式地将Object
类型转换为实际的对象类型(如Dog
)。这种做法不仅繁琐,而且容易出错,因为如果集合中包含了非Dog
类型的对象,运行时就会抛出ClassCastException
。 -
使用泛型:泛型(Generics)是Java 5引入的一个特性,它允许在编译时检查类型安全。通过使用泛型,你可以指定集合中可以存储的对象类型,这样在编译时就能确保类型安全,避免了类型转换的需要。例如,你可以声明一个
ArrayList<Dog>
,这样就只能向其中添加Dog
类型的对象,取出时也直接是Dog
类型,无需进行类型转换。这不仅提高了代码的可读性和安全性,也提升了运行效率。 -
不再提示编译警告:使用泛型后,由于类型安全在编译时就已经得到保证,因此不会再出现因为类型转换而产生的编译警告。
-
package com.improve; import java.util.ArrayList; public class Generic02 { public static void main(String[] args) { ArrayList<dog> arrayList = new ArrayList<dog>(); // 当我们ArrayList<dog>,表示我们存放在ArrayList集合的元素是dog类型 // 如果编译器发现添加的类型不满足要求会报错 arrayList.add(new dog("ss",12)); // 遍历的时候可以直接取出dog类型而不是object for(dog o : arrayList) { System.out.println(o.getName()+ - + o.getAge()); } } } 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; } @Override public String toString() { return "Cat{" + "name='" + name + '\'' + ", age=" + age + '}'; } } 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; } }
泛型的说明
泛型的理解:泛型(泛型类型)指的是像Integer
、String
、Dog
这样的具体类型。
-
泛型,也称为参数化类型,是Java 5.0引入的一个新特性,它解决了数据类型安全性问题。
-
使用泛型时,在类声明或实例化时指定具体的类型即可。
-
Java泛型确保如果程序在编译时没有发出警告,那么运行时就不会产生
ClassCastException
异常。同时,使用泛型可以使代码更加简洁和健壮。 -
泛型的作用包括:在类声明时通过一个标识符表示类中某个属性的类型、方法的返回值类型或参数类型。
泛型是Java语言中用于处理集合和其他数据结构时提供类型安全的一种机制。它允许你在编译时期就检查类型错误,避免了在运行时进行类型转换的需要,从而提高了代码的可读性和稳定性。
泛型的具体数据类型在编译时,确定
泛型的语法
泛型的声明
-
interface 接口<T>{ } 和 class 类<K,V>{ }
-
//比如:List,ArrayList
-
说明:
1.其中,T,K,V不代表值,而是表示类型。
2.任意字母都可以。常用T表示,是Type的缩写
-
泛型的实例化:
-
要在类名后面指定类型参数的值(类型)。如:
1.List<String> strList = new ArrayList<String>(); [举例说明]
2.Iterator<Customer> iterator = customers.iterator();
-
这段内容解释了泛型声明和泛型实例化的概念:
-
泛型的声明:泛型可以用于接口和类中,通过在接口或类名后面添加尖括号
<>
并放入类型参数(如T
、K
、V
)来声明。这些类型参数代表了泛型类型,可以在接口或类的定义中使用。T
、K
、V
是类型参数的常用标识,T
是Type的缩写,但可以使用任何字母来表示。 -
泛型的实例化:在创建泛型类的实例时,需要指定具体的类型参数值(类型),这称为泛型实例化。例如,创建一个
List
集合,存储String
类型的元素,可以声明为List<String>
,并实例化为new ArrayList<String>()
。同样,如果有一个customers
集合,其元素类型为Customer
,可以使用customers.iterator()
来获取一个Iterator<Customer>
类型的迭代器。
练习:
1.创建 3 个学生对象
2.放入到 HashMap 中,要求 Key 是 String name, Value 就是 学生对象
3.使用两种方式遍历
package com.improve; import java.util.*; public class GenericExercise { public static void main(String[] args) { // 使用泛型,给hashmap放入三个学生对象 HashSet<Student> student = new HashSet<Student>(); student.add(new Student("nihao",14)); student.add(new Student("nhao",15)); student.add(new Student("niho",16)); // 1.增强for循环遍历 for(Student s : student){ System.out.println(s); } HashMap<String,Student> hashMap = new HashMap<String,Student>(); hashMap.put("nihao",new Student("nihao",14)); hashMap.put("nhao",new Student("nhao",15)); hashMap.put("niho",new Student("niho",16)); Set<Map.Entry<String, Student>> entries = hashMap.entrySet(); Iterator<Map.Entry<String, Student>> iterator = entries.iterator(); while (iterator.hasNext()) { Map.Entry<String, Student> next = iterator.next(); System.out.println(next.getKey()); } } } class Student { private String name; private int age; public Student(String name, int age) { this.name = name; this.age = age; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } public String getName() { return name; } public void setName(String name) { this.name = name; } @Override public String toString() { return "Student{" + "name='" + name + '\'' + ", age=" + age + '}'; } }
泛型使用的注意事项和细节
interface List<T> ,public class HashSet<E>{}..
等等说明:TE只能是引用类型看看下面语句是否正确?:
List<Integer> list = new ArrayList<Integer>(); //OK List<int>list2 = new ArrayList<int>();//错误
2在给泛型指定具体类型后,可以传入该类型或者其子类类型3.泛型使用形式
List<Integer> list1 = new AfrayList<Integer>(); List<Integer> list2 = new ArrayList<>();
3.如果我们这样写 List list3 = new ArrayList();默认给它的 泛型是[<E>E就是 Object ]
泛型课堂练习题
-
定义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 方法,传入 Comparer对象(使用泛型),先按照name排序,如果name相同,则按生日日期的先后排序。【即:定制排序】
-
自定义泛型
自定义泛型3类(难度)
基本语法
class 类名<T,R...>{} 成员
注意细节
-
1.普通成员可以使用泛型(属性、方法)
-
2.使用泛型的数组,不能初始化
-
3.静态方法中不能使用类的泛型
-
4.泛型类的类型,是在创建对象时确定的(因为创建对象时,需要指定确定类型)
-
5.如果在创建对象时,没有指定类型,默认为Object
自定义泛型接口
基本语法
interface 接口名<T, R...> { }
注意细节
-
1.接口中,静态成员也不能使用泛型(这个和泛型类定义一样)
-
2.泛型接口的类型,在继承接口或者实现接口时确定
-
3.没有指定类型,默认为Object
自定义泛型方法
-
基本语法
修饰符<T,R> 返回类型 方法名(参数列表) { }
-
注意细节
-
1.泛型方法,可以定义在普通类中,也可以定义在泛型类中
-
2.当泛型方法被调用时,类型会确定
-
3.
public void eat(E e) { }
,修饰符后没有<T,R>
eat方法不是泛型方法,而是使用了泛型
-
泛型的继承和通配符
1)泛型不具备继承性List<Object> list = new ArrayList<String>(); // 对吗?
2)<?>:支持任意泛型类型 3)<?extends A>:支持A类以及A类的子类,规定了泛型的上限 4)<?super A>: 支持A类以及A类的父类,不限于直接父类,规定了泛型的下限