1.泛型的简介
1.1 什么是泛型
泛型是一种特殊的数据类型。 它是Java 的一个高级特性。在 Mybatis、Hibernate 这种持久化框架,泛型更是无处不在。
在这之前,不管我们在定义成员变量时,还是方法的形参时,都要规定他们的具体类型。所以提出猜想,有没有一种可能,一次声明,就可以给各种各样的值呢?所以,泛型这个概念就出来了。
泛型的定义:
我们在定义一个语法结构时,不用指明具体类型,而是先定义一个类型变量,在真正使用的时候再确定该变量的具体类型。
总结: 类型参数化
两个参数化:
数据参数化: 就是使用形参接收具体数据(实际参数)
类型参数化: 就是使用形参接收具体类型。
1.2 泛型的定义
泛型,定义在一对尖括号中,也是一个标识符,遵循大驼峰命名法。通常都是用一个大写字母。
public class Test1<T> {
}
class Person<T,M>{
}
class Calculate<T>{
public T calculate(T a, T b){
return a;
}
}
2.泛型的应用
2.1 泛型类的应用
当我们将泛型用在类上时,这个类就叫做泛型类。
泛型类: 泛型应用在类上。一般在类名后,使用尖括号括起来。用大写字母作为泛型参数。
演示代码:
import java.util.Date;
public class Person<T> {
private T idCard;
public Person(){
}
public Person(T idCard){
this.idCard = idCard;
}
public static void main(String[] args) {
//创建一个Person对象。需要给泛型参数赋值具体类型
Person p = new Person<String>("cds123");
Person<String> p2 = new Person<>("cds122");
// 泛型参数,只能赋值引用类型,不能赋值八大基本数据类型
Person<Long> p3 = new Person<>(3215466L);
Date date = new Date();
//小贴士: 实例化过程中,泛型只在一边给泛型参数赋值,但是两遍的尖括号都不能省略。
Person<Date> p4 = new Person<>(date);
}
}
/*
当一个子类继承带有泛型的父类时,一般情况下要给泛型参数赋值具体类名
*/
class Student extends Person<Integer>{
public Student(Integer idCard){
super(idCard);
}
}
/*
子类的泛型参数可以给父类的泛型参数赋值。
下面的例子就是E赋值给了T。
*/
class Teacher<E> extends Person<E>{
public Teacher(E idCard){
super(idCard);
}
}
/*
如果子类在定义期间,没有给泛型父类的泛型参数赋值,那么默认就是Object类型
*/
class Persident extends Person{
public Persident(Object idCard){
super(idCard);
}
}
总结:
在实例化时,要给泛型参数赋具体值。实例化时两边的类名都可以赋值,也可以一边赋值,但是两边的尖括号不能去掉。在继承时也要赋值,如果没有赋值,那就默认object类型。也可以将子类的泛型赋值给父类。
2.2 泛型接口的应用
将泛型用在接口上时,这个接口就叫做泛型接口。 泛型定义在接口名后。 用法和泛型类,一模一样。
测试代码:
import java.util.Arrays;
import java.util.Comparator;
/**
* 泛型接口,泛型用在接口上,就叫泛型接口。
* @param <T>
*/
public interface MyComparable<T,M> {
/**
* 两种类型进行比较
* @param o1
* @param o2
* @return
*/
public int mycompare(T o1, M o2);
public static void main(String[] args) {
Employee[] employees = new Employee[3];
employees[0] = new Employee("佐伊",18);
employees[1] = new Employee("建模",19);
employees[2] = new Employee("ez",17);
//使用比较器接口,来重新定义比较规则: 从泛型的角度来说,在实例化接口时,要给泛型参数传具体类型。
Comparator c = new Comparator<Employee>(){
//重写比较器里面的compare方法
public int compare(Employee o1, Employee o2) {
//调用了自定义的员工类里的比较方法。
return o1.name.compareTo(o2.name);
}
};
Arrays.sort(employees);
System.out.println(Arrays.toString(employees));
}
}
//子类实现接口 : 通常子类要给泛型接口的泛型参数赋值具体类型名。
//下面案例,就是给T和M都赋值了Employee这个类型。
class Employee implements MyComparable<Employee,Employee>, Comparator<Employee> {
String name;
int age;
public Employee(String name, int age) {
this.name = name;
this.age = age;
}
public String toString(){
return "["+name+","+age+"]";
}
// 在我们自己定义的方法中来实现比较规则。
public int mycompare(Employee o1, Employee o2) {
return o1.age - o2.age;
}
@Override
public int compare(Employee o1, Employee o2) {
return mycompare(o1,o2);
}
}
2.3 泛型方法的应用
泛型不仅能用在类和接口上,还可以用在方法上。 需要把泛型定义在返回值类型前面。
测试代码:
import java.util.Objects;
public class MyUtil {
public static <T> boolean equals(T t1,T t2){
return t1.equals(t2);
}
public static void main(String[] args) {
Cat cat = new Cat("咪咪");
Cat cat1 = new Cat("咪咪");
//泛型方法在调用期间,不需要指定具体类型,只需要传入具体对象
//泛型方法调用期间,并没有给泛型参数赋值。下面的案例是c1给t1,c2给t2赋值,没有给T赋值。
boolean a = MyUtil.equals(cat, cat1);
System.out.println("equals"+a);
}
}
class Cat{
String name;
public Cat(){
}
public Cat(String name){
this.name = name;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Cat cat = (Cat) o;
return Objects.equals(name, cat.name);
}
@Override
public int hashCode() {
return Objects.hashCode(name);
}
}
注意:
在方法调用期间,不需要给泛型具体赋值,只需要传入变量即可。
3.泛型通配符
3.1 简介
泛型通配符用 ?
表示,代表不确定的类型,是泛型的一个重要组成。 在调用时,表示我不关心具体类型。也可以使用通配符规定调用时,传入的类型的范围,即上边界,和下边界。
3.2 简单应用
import java.util.ArrayList;
import java.util.List;
/*
泛型通配符: ? 用于表明不关心调用时的具体类型。
*/
public class MyUtil {
/**
* 将集合元素打印到控制台上
*/
public static void print(List<?> lists){
for(int i = 0; i<lists.size();i++){
System.out.println(lists.get(i));
}
}
/**
* 上边界的定义: <? extends Number>
* 具体使用的时候,可以是上边界的任何子类型或者是本类型。
* @param list
*/
public static void print2(List<? extends Number> list){
}
/**
* 下边界的定义: <? super 具体类名>
* 具体使用的时候,可以是下边界的任何父类型或者本类型。
* @param list
*/
public static void print3(List<? super Integer> list){
for(int i = 0; i<list.size();i++){
System.out.println(list.get(i));
}
}
public static void main(String[] args) {
List<Long> ns = new ArrayList<Long>();
ns.add(1L);
ns.add(2L);//注意 L 是Long类型不是long。
ns.add(3L);
MyUtil.print(ns);
print2(new ArrayList<Long>());
print2(new ArrayList<Number>());
// print2(new ArrayList<Object>());最高到达Number类型
//下边界的测试
print3(new ArrayList<Number>());
print3(new ArrayList<Object>());
print3(new ArrayList<Integer>());
// print3(new ArrayList<Long>());//Long和Integer没有关系。
}
}
3.3 总结
标签:Person,类型,泛型,new,java9,public,赋值 From: https://blog.csdn.net/zhaogodzero/article/details/140934942泛型是一种特殊的类型,你可以把泛型用在类、接口、方法上,从而实现一些通用算法。
此外,使用泛型有三个步骤:定义类型变量、使用类型变量、确定类型变量。
在确定类型变量这一步中,你可以用泛型通配符来限制泛型的范围,从而实现一些特殊算法。(方法 <? extends 类名>上边界、 <? super 类名>下边界(都包括类名))。