文章目录

  • 1、泛型
    • 1.1、需求引出
    • 1.2、使用传统方法的问题分析
    • 1.3、用泛型来解决前面的问题
    • 1.4、泛型的好处
    • 1.5、泛型介绍
    • 1.6、泛型的语法
      • 1.6.1、泛型的声明
      • 1.6.2、泛型的实例化
      • 1.6.3、泛型使用举例
      • 1.6.4、泛型使用的注意事项和细节
      • 1.6.5、泛型小练习

1、泛型

1.1、需求引出

package generic;import java.util.ArrayList;@SuppressWarnings({"all"})
public class Generic01 {public static void main(String[] args) {// 使用传统的方法来解决ArrayList arrayList = new ArrayList();arrayList.add(new Dog("旺财", 10));arrayList.add(new Dog("发财", 1));arrayList.add(new Dog("小黄", 5));// 假如我们不小心, 添加了一只猫arrayList.add(new Cat("招财猫", 8));// 遍历for (Object o : arrayList) {// 向下转型 Object -> DogDog dog = (Dog) o;System.out.println(dog.getName() + " - " + dog.getAge());/*** 旺财 - 10* 发财 - 1* 小黄 - 5* Exception in thread "main" java.lang.ClassCastException: generic.Cat cannot be cast to generic.Dog*    at generic.Generic01.main(Generic01.java:20)*   由于里面混入了猫类, 在向下转型的时候报错了*/}}
}/*** 请编写程序, 在 ArrayList 中, 添加 3 个 Dog 对象* Dog 对象含有 name 和 age, 并输出 name 和 age (要求使用 getXxx())*/
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;}
}

1.2、使用传统方法的问题分析

  1. 不能对加入到集合 ArrayList中的数据类型进行约束(不安全)
  2. 遍历的时候,需要进行类型转换,如果集合中的数据量较大,对效率有影响

1.3、用泛型来解决前面的问题

ArrayList arrayList = new ArrayList();

package generic;import java.util.ArrayList;@SuppressWarnings({"all"})
public class Generic01 {public static void main(String[] args) {// 1. 当我们 ArrayList<Dog> 表示存放到 ArrayList 集合中的元素是 Dog 类型// 2. 如果编译器发现添加的类型, 不满足要求, 就会报错// 3. 在遍历的时候, 可以直接取出 Dog 类型而不是 Object// 4. public class ArrayList<E> {} E 称为泛型, 那么 Dog->EArrayList<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));  // 使用了泛型以后, 该行报错// 遍历for (Dog dog : arrayList) {  // 使用泛型以后, 这里不需要向下转型System.out.println(dog.getName() + " - " + dog.getAge());/*** 旺财 - 10* 发财 - 1* 小黄 - 5*/}}
}/*** 请编写程序, 在 ArrayList 中, 添加 3 个 Dog 对象* Dog 对象含有 name 和 age, 并输出 name 和 age (要求使用 getXxx())*/
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;}
}

1.4、泛型的好处

1.5、泛型介绍


package generic;public class Generic03 {public static void main(String[] args) {// 注意, 特别强调: E 具体的数据类型在定义 Person 对象的时候指定, 即在编译期间, 就确定 E 是什么类型Person<String> person = new Person<String>("hello");person.show();  // class java.lang.String/*** 可以这样理解上面的 Person 类* class Person {*     String s;  // E 表示 s 的数据类型, 该数据类型在定义 Person 对象的时候指定, 即在编译期间, 就确定 E 是什么类型**     public Person(String s) {  // E 也可以是参数类型*         this.s = s;*     }**     public String f() {  // 返回类型使用*         return s;*     }**     public void show() {*         System.out.println(s.getClass());  // 显示 s 的运行类型*     }* }*/Person<Integer> person2 = new Person<>(100);person2.show();  // class java.lang.Integer/*** class Person {*     Integer s;  // E 表示 s 的数据类型, 该数据类型在定义 Person 对象的时候指定, 即在编译期间, 就确定 E 是什么类型**     public Person(Integer s) {  // E 也可以是参数类型*         this.s = s;*     }**     public Integer f() {  // 返回类型使用*         return s;*     }**     public void show() {*         System.out.println(s.getClass());  // 显示 s 的运行类型*     }* }*/}
}// 泛型的作用是: 可以在类声明时通过一个标识表示类中某个属性的类型
// 或者是某个方法的返回值的类型, 或者是参数类型
class Person<E> {E s;  // E 表示 s 的数据类型, 该数据类型在定义 Person 对象的时候指定, 即在编译期间, 就确定 E 是什么类型public Person(E s) {  // E 也可以是参数类型this.s = s;}public E f() {  // 返回类型使用return s;}public void show() {System.out.println(s.getClass());  // 显示 s 的运行类型}
}

1.6、泛型的语法

1.6.1、泛型的声明

1.6.2、泛型的实例化

1.6.3、泛型使用举例

package generic;import java.util.*;public class GenericExercise {public static void main(String[] args) {// 使用泛型方式给 HashSet 放入 3 个学生对象HashSet<Student> students = new HashSet<Student>();students.add(new Student("jack", 18));students.add(new Student("tom", 28));students.add(new Student("mary", 19));// 遍历for (Student student : students) {System.out.println(student);/*** Student{name='mary', age=19}* Student{name='tom', age=28}* Student{name='jack', age=18}*/}// 使用泛型方式给 HashMap 放入 3 个学生对象// K -> String V -> StudentHashMap<String, Student> hm = new HashMap<String, Student>();/*public class HashMap<K,V> {}*/hm.put("milan", new Student("milan", 38));hm.put("smith", new Student("smith", 48));hm.put("jack", new Student("jack", 15));// 迭代器 EntrySet/*public Set<Map.Entry<K,V>> entrySet() {Set<Map.Entry<K,V>> es;return (es = entrySet) == null ? (entrySet = new EntrySet()) : es;}*/Set<Map.Entry<String, Student>> entries = hm.entrySet();/*public final Iterator<Map.Entry<K,V>> iterator() {return new EntryIterator();}*/Iterator<Map.Entry<String, Student>> iterator = entries.iterator();System.out.println("==============================");while (iterator.hasNext()) {Map.Entry<String, Student> next = iterator.next();System.out.println(next.getKey() + "-" + next.getValue());}/*** ==============================* smith-Student{name='smith', age=48}* milan-Student{name='milan', age=38}* jack-Student{name='jack', age=15}*/}
}/*** 创建 3 个学生对象* 放入到 HashSet 中学生对象, 使用* 放入到 HashMap 中, 要求 Key 是 String name, Value 就是 学生对象* 使用两种方式遍历*/
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;}@Overridepublic String toString() {return "Student{" +"name='" + name + '\'' +", age=" + age +'}';}
}
1.6.4、泛型使用的注意事项和细节

package 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();  // class generic.APig<A> aPig2 = new Pig<A>(new B());aPig2.f();  // class generic.B// 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.如果是这样写 泛型默认是 ObjectArrayList 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();/*** 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());  // 运行类型}
}
1.6.5、泛型小练习

package generic;import java.util.ArrayList;
import java.util.Comparator;@SuppressWarnings({"all"})
public class GenericExercise02 {public static void main(String[] args) {ArrayList<Employee> employees = new ArrayList<>();employees.add(new Employee("jack", 12000.95, new MyDate(1993, 10, 10)));employees.add(new Employee("tom", 25000.40, new MyDate(1981, 11, 11)));employees.add(new Employee("lucy", 5500.50, new MyDate(2004, 9, 12)));// 循环遍历for (Employee employee : employees) {System.out.println(employee);/*** Employee{name='jack', sal=12000.95, birthday=MyDate{year=1993, month=10, day=10}}* Employee{name='tom', sal=25000.4, birthday=MyDate{year=1981, month=11, day=11}}* Employee{name='lucy', sal=5500.5, birthday=MyDate{year=2004, month=9, day=12}}*/}// 排序// 传入 Comparator 对象[使用泛型], 先按照 name 排序, 如果 name 相同, 则按生日日期的先后排序 【即: 定制排序】employees.sort(new Comparator<Employee>() {@Overridepublic int compare(Employee employee1, Employee employee2) {// 先对传入的参数进行验证if (!(employee1 instanceof Employee && employee2 instanceof Employee)) {System.out.println("类型不正确..");return 0;}int i = employee1.getName().compareTo(employee2.getName());if (i != 0) {return i;}// 下面是对 birthday 的比较, 因此, 我们最好把这个比较, 放在 MyDate 类完成// 封装后, 将来可维护性和复用性, 就大大增强return employee1.getBirthday().compareTo(employee2.getBirthday());}});// 排序后System.out.println("=== 排序后 ===");for (int j = 0; j < employees.size(); j++) {System.out.println(employees.get(j));/*** === 排序后 ===* Employee{name='jack', sal=12000.95, birthday=MyDate{year=1993, month=10, day=10}}* Employee{name='lucy', sal=5500.5, birthday=MyDate{year=2004, month=9, day=12}}* Employee{name='tom', sal=25000.4, birthday=MyDate{year=1981, month=11, day=11}}*/}}
}/*** 定义 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 相同, 则按生日日期的先后排序 【即: 定制排序】*/// Employee 类
class Employee {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;}@Overridepublic String toString() {return "Employee{" +"name='" + name + '\'' +", sal=" + sal +", birthday=" + birthday +'}';}
}// MyDate 类
class MyDate implements Comparable<MyDate> {private Integer year;private Integer month;private Integer day;public MyDate(Integer year, Integer month, Integer day) {this.year = year;this.month = month;this.day = day;}public Integer getYear() {return year;}public void setYear(Integer year) {this.year = year;}public Integer getMonth() {return month;}public void setMonth(Integer month) {this.month = month;}public Integer getDay() {return day;}public void setDay(Integer day) {this.day = day;}@Overridepublic String toString() {return "MyDate{" +"year=" + year +", month=" + month +", day=" + day +'}';}@Overridepublic int compareTo(MyDate o) {  // 把对year-month-day比较放在这里int yearMinus = year - o.getYear();if (yearMinus != 0) {return yearMinus;}// 如果year相同, 就比较monthint monthMinus = month - o.getMonth();if (monthMinus != 0) {return monthMinus;}// 如果year 和 month 相同直接返回day的比较结果return day - o.getDay();}
}

Java面向对象之泛型基本使用相关推荐

  1. Java学习 第四章 java面向对象(二)

    一.封装性 1.封装性产生目的 保护某些属性和方法不被外部所看见. 2.封装性的实现  为属性和方法进行封装是通过关键字private声明的;  实现该属性的set和get方法,为外部所访问:  eg ...

  2. java模型给泛型_java 泛型详解-绝对是对泛型方法讲解最详细的,没有之一

    对java的泛型特性的了解仅限于表面的浅浅一层,直到在学习设计模式时发现有不了解的用法,才想起详细的记录一下. 1. 概述 泛型在java中有很重要的地位,在面向对象编程及各种设计模式中有非常广泛的应 ...

  3. java定义list_我的Java Web之路59 - Java中的泛型

    本系列文章旨在记录和总结自己在Java Web开发之路上的知识点.经验.问题和思考,希望能帮助更多(Java)码农和想成为(Java)码农的人. 目录 介绍 再谈Java中的类型 为什么需要泛型? J ...

  4. Java面向对象编程篇6——注解与反射

    Java面向对象编程篇6--注解与反射 1.注解概述 Java 注解(Annotation)又称 Java 标注,是 JDK5.0 引入的一种注释机制 Java 语言中的类.方法.变量.参数和包等都可 ...

  5. 【JAVA基础】java基础之-泛型详解

    写在前面的话 脑子是个好东西,可惜的是一直没有搞懂脑子的内存删除机制是什么,所以啊,入行多年,零零散散的文章看了无数,却总是学习了很多也忘了很多. 痛定思痛的我决定从今天开始系统的梳理下知识架构,记录 ...

  6. JAVA面向对象的基础知识快速通过---自学笔记(一)

    网上的教学很多,看视频非常浪费时间,看文字快点,快速捡起知识点,我只根据我学到的,集各种教学学习,把精华提取出来,把主要概念通俗的展示出来,基本常识就不介绍了,其他的资料谁看了都能看懂,只是java特 ...

  7. Java面向对象高阶

    继承 继承是java面向对象编程技术的基石,因为它允许创建分等级层次的类 继承就是子类继承父类的特征和行为,使得子类对象具有父类的属性(特征)和方法(行为). 子类实例化内存分析 super不是引用类 ...

  8. Java面向对象知识详解——三大基本特征

    文章目录 前言 什么是面向过程? 什么是面向对象? 三大基本特征 封装 继承 多态 Java中的多态 最后 前言 相信很多程序员在最初接触Java的时候就听过,Java中一切皆对象那么什么是面向对象呢 ...

  9. Java面向对象程序设计笔记 • 【目录】

    持续更新中- 我的大学笔记>>> 章节 内容 实践练习 Java面向对象作业目录(作业笔记) 第1章 Java面向对象笔记 • [第1章 面向对象] 第2章 Java面向对象笔记 • ...

最新文章

  1. token验证失败_ASP.NET CORE WEBAPI JWT 带BEARER的TOKEN
  2. Rust 数据类型介绍
  3. coco数据集大小分类_MicroSoft COCO数据集
  4. DataTable ,XML和JSON相互转化
  5. python笔记: staticmethod classmethod
  6. [剑指offer][JAVA]面试题第[21]题[调整数组顺序使奇数位于偶数面前][双指针]
  7. 死锁的 4 种排查工具 !
  8. 【Win 10 应用开发】分析 URI 中的查询字符串
  9. [学习笔记]舞蹈链(Dancing Links)C++实现(指针版)
  10. 最终幻想13 公布发售日期和主题曲
  11. [转载] python--isalnum()函数
  12. Spring Cloud Sleuth 使用教程
  13. UINavigationController 直接pop到指定controllerView的方法
  14. MyBatis中Mapper映射文件的输入(parameterType)和输出(resultType)映射
  15. MAC 及 Python 快捷键
  16. 良心安利Unity3D U3D游戏源码素材网站
  17. 分区助手合并移动硬盘分区后,无法访问的解决方法
  18. 微信开启指纹支付显示java,微信找不到指纹支付怎么办?微信指纹支付怎么使用?...
  19. 竞价被恶意点击怎么办?该怎么屏蔽?
  20. C#+ArcEgine开发(2)添加shp和lyr文件

热门文章

  1. POI导出EXCEL合并单元格对象嵌套List数据
  2. 利用拼音查询城市小结
  3. 猫爪精油的全球与中国市场2022-2028年:技术、参与者、趋势、市场规模及占有率研究报告
  4. 游戏公司都有什么岗位?主要做什么的?
  5. 配置idea自带的tomcat_Tomcat下载安装并部署到IDEA的教程(附带idea两种热部署设置方法)...
  6. SolidWorks 2021 设置为中文界面
  7. 云计算ACP弹性计算服务(一)
  8. 计算机网络自顶向下方法套接字编程作业
  9. linux脚本同时运行,shell多个脚本同时执行
  10. 【张量分解(二)】CP分解