java泛型学习篇(一)
1 学习泛型前的传统思路
1.1 遍历集合中元素的方法
1.1.1 思路
①用foreach进行遍历
②把每个Object对象强转成所需类型
③打印其值
1.1.2 示例代码
import java.util.ArrayList;
public class Generic01 {
public static void main(String[] args) {
long startTime=System.currentTimeMillis();
ArrayList arr= new ArrayList<>();
for (int i = 0; i <100000; i++) {
arr.add(Integer.valueOf(i));
}
for (Object o : arr) {
//你想要使用Integer类型的方法必须强转,每一个数据都得这样,很麻烦
Integer temp= (Integer) o;
System.out.println(temp.intValue());
}
long endTime=System.currentTimeMillis();
System.out.println("执行时长为(单位:毫秒): "+(endTime-startTime));
}
}
1.1.3 运行截图
1.2 集合中若存放了非同类型的数据,并不会出现错误,出现的是运行时异常
1.2.1 示例代码
import java.util.ArrayList;
public class Generic02 {
public static void main(String[] args) {
long startTime=System.currentTimeMillis();
ArrayList arr= new ArrayList<>();
for (int i = 0; i <100000; i++) {
arr.add(Integer.valueOf(i));
}
arr.add("123");
for (Object o : arr) {
//你想要使用Integer类型的方法必须强转,每一个数据都得这样,很麻烦
Integer temp= (Integer) o;
System.out.println(temp.intValue());
}
long endTime=System.currentTimeMillis();
System.out.println("执行时长为(单位:毫秒): "+(endTime-startTime));
}
}
1.2.2 运行截图
2 学习泛型后的思路
2.1 遍历集合中元素的方法
2.1.1 思路
①在集合定义的时候加上泛型约束
②使用foreach循环打印值
2.1.2 示例代码
import java.util.ArrayList;
public class Generic03 {
public static void main(String[] args) {
long startTime=System.currentTimeMillis();
ArrayList<Integer> arr= new ArrayList<>();
for (int i = 0; i <100000; i++) {
arr.add(Integer.valueOf(i));
}
for (Integer o : arr) {
//你想要使用Integer类型的方法必须强转,每一个数据都得这样,很麻烦
System.out.println(o.intValue());
}
long endTime=System.currentTimeMillis();
System.out.println("执行时长为(单位:毫秒): "+(endTime-startTime));
}
}
2.1.3 运行截图
2.2 集合中若存放了非同类型的数据,会出现错误,提示使用者必须改(不改必报错)
2.2.1 示例代码
import java.util.ArrayList;
public class Generic04 {
public static void main(String[] args) {
long startTime=System.currentTimeMillis();
ArrayList<Integer> arr= new ArrayList<>();
for (int i = 0; i <100000; i++) {
arr.add(Integer.valueOf(i));
}
arr.add("123");
for (Integer o : arr) {
System.out.println(o.intValue());
}
long endTime=System.currentTimeMillis();
System.out.println("执行时长为(单位:毫秒): "+(endTime-startTime));
}
}
2.2.2 运行截图
a idea给出的错误提示
b 点击运行后
3 使用泛型好处
3.1 编译时,自动检查添加元素的类型,提高安全性,不是指定的类型是加不进去的
3.2 减少了类型转换次数和花费判断是否是一个类的实例的时间,有效提高了效率
4 泛型的理解
泛型是一种广泛的类型,是一种数据类型的数据类型,可以是Integer、String等
泛型又称之为参数化类型,是JDK5.0后出现的新特性(解决了数据类型的安全性问题)
泛型可以保证在编译时没有报错,运行时一定不会出现ClassCastException异常
泛型的作用:在类声明时通过一个标识符来表示类中某个属性的类型OR 方法返回值的类型 OR 参数类型
5 泛型的语法以及练习
5.1 语法
interface 接口<T>{}和 class类<k,v>{}
//T、K、V并不代表值,而是代表类型
//其实任意字母都可以,常用T表示,是Type的缩写
5.2 练习题目
5.2.1 题目内容
①创建5个教师对象
②把教师对象放入到HashSet中,要求约束为教师对象
③把教师对象放入到HashMap中,要求key为String类型,value为教师对象类型
④对②③这两种情况进行遍历,输出对应的结果即可
5.2.2 Teacher类代码
class Teacher{
private String name;
private int age;
public Teacher(String name, int age) {
this.name = name;
this.age = age;
}
@Override
public String toString() {
return "Teacher{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
5.2.3 示例代码
import org.apache.poi.ss.formula.functions.T;
import java.util.*;
public class GenericPractice {
public static void main(String[] args) {
//A.使用HashSet
HashSet<Teacher> set = new HashSet<Teacher>();
set.add(new Teacher("小明", 27));
set.add(new Teacher("小洪", 32));
set.add(new Teacher("小亮", 22));
//使用增强for循环进行打印
for (Teacher o :set) {
System.out.println(o);
}
System.out.println("=========使用hashMap的方式===============");
//B 使用HashMap
HashMap<String, Teacher> h = new HashMap<>();
h.put("xiaoming", new Teacher("小明", 27));
h.put("xiaohong", new Teacher("小洪", 32));
h.put("xiaoliang", new Teacher("小亮", 22));
Set<Map.Entry<String, Teacher>> entries = h.entrySet();
Iterator<Map.Entry<String, Teacher>> iterator = entries.iterator();
while(iterator.hasNext()){
Map.Entry<String, Teacher> next = iterator.next();
System.out.println(next.getKey()+"-"+next.getValue());
}
}
}
class Teacher{
private String name;
private int age;
public Teacher(String name, int age) {
this.name = name;
this.age = age;
}
@Override
public String toString() {
return "Teacher{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
5.2.4 运行截图
6 泛型的注意事项
6.1 泛型一定是引用数据类型,不能是基本数据类型
ArrayList<Integer> arr= new ArrayList<>(); ✔
ArrayList<int> arr= new ArrayList<>(); ❌
6.2 在给泛型指定具体类型后,可以传入该类型或者其子类类型
import java.util.ArrayList;
public class Generic05 {
public static void main(String[] args) {
Pig<A> aPig = new Pig<A>(new A());
//泛型是A类型,实参传过去的是A类型的子类型对象也是可以的
Pig<A> bPig = new Pig<A>(new B());
}
}
class A{}
class B extends A{}
class Pig<E>{
E s;//E表示s的数据类型.该数据类型在定义A对象的时候指定,即在编译期间,就确定了
public Pig(E s) {
this.s = s;
}
}
6.3 泛型的两种写法(推荐使用第二种)
6.3.1 左右两边全写
ArrayList<Integer> arr= new ArrayList<Integer>();
6.3.2 只写左边,不写右边
//实际开发中,往往采用这种
//编译器会进行类型推断,会默认把右边<>的类型和左边<>的类型保持一致
ArrayList<Integer> arr= new ArrayList<>();
6.4 如果没有给泛型指定数据类型,那么默认就是Object类型
ArrayList arr= new ArrayList();
//本质上等价于下面这种写法
ArrayList<Object> arr= new ArrayList<Object>();
7 泛型的经典习题
7.1 题目内容
定义Employee类
①该类中包含 private成员变量name,sal,birthday 其中birthday的类型为MyDate对象类型
③为每个属性定义get和set方法
③重写toString方法输出name,sal,birthday
④定义有参构造
定义MyDate方法
①private成员变量month,day,year
②为每个属性定义get和set方法
③重写toString方法输出month,day,year
题目要求
创建Employee类的三个对象,并放入ArrayList集合中(泛型定义),对集合元素进行排序并输出
排序要求: 调用ArrayList的sort方法,传入Comparator对象
先按照name排序,如果name相同,就按照生日日期的先后进行排序
7.2 示例代码
7.2.1 Employee类
public class Employee{
private String name;
private double sal;
private MyDate birthday;
public Employee() {
}
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 +
'}';
}
}
7.2.2 MyDate类
public class MyDate{
private int month;
private int day;
private int year;
public MyDate() {
}
public MyDate(int month, int day, int year) {
this.month = month;
this.day = day;
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;
}
public int getYear() {
return year;
}
public void setYear(int year) {
this.year = year;
}
@Override
public String toString() {
return "MyDate{" +
"month=" + month +
", day=" + day +
", year=" + year +
'}';
}
}
7.2.3 GenericTest类
import java.util.ArrayList;
import java.util.Comparator;
public class GenericTest {
public static void main(String[] args) {
ArrayList<Employee> arr = new ArrayList<Employee>();
arr.add(new Employee("张三",2000,new MyDate(2,12,1999)));
arr.add(new Employee("李四",4000,new MyDate(3,6,2005)));
arr.add(new Employee("张三",8000,new MyDate(1,15,1970)));
arr.sort(new Comparator<Employee>() {
//先按照name排序,如果nam值相同,按照日期的先后顺序排序
@Override
public int compare(Employee o1, Employee o2) {
if(!(o1 instanceof Employee && o2 instanceof Employee)){
System.out.println("类型不正确");
return 0;
}
//比较name
int i = o1.getName().compareTo(o2.getName());
if(i!=0){
return i;
}
//如果name相同,比较的就是year
int yearMinus = o1.getBirthday().getYear() - o2.getBirthday().getYear();
if(yearMinus!=0){
return yearMinus;
}
//如果year相同,就比较month
int monthMinus = o1.getBirthday().getMonth() - o2.getBirthday().getMonth();
if(monthMinus!=0){
return monthMinus;
}
//如果month相同,就比较day
return o1.getBirthday().getDay()-o2.getBirthday().getDay();
}
});
System.out.println("排序后的数组"+arr);
}
}