1.为什么需要泛型?
//int类型相加
public int addInt(int x,int y){
return x+y;
}
//如果是float相加
public float addFloat(float x,float y){
return x+y;
}
//如果是double呢?...相同一段代码,仅仅是因为传入的参数不同,就重写一遍方法,很是麻烦,这就需要泛型了。
2.泛型的好处:
- 适用于多种数据类型,执行相同的代码
- 规定了数据类型后,在编译期就会发现错误,避免了在使用时运行期的报错
List list = new ArrayList();
list.add("apple");
list.add("100");
list.add(100);
//编译不会报错,因为没有给list规定类型,这会的list是object类型,往里放的时候不会报错,但是取数据的时候会报类型转换异常。
//如果规定list为String类型,那么放入int类型,就会报错
List<String> list = new ArrayList();
list.add("apple");
list.add("100");
list.add(100);
3.泛型的定义
参数化的类型
//泛型类
public class NormalGeneric<T> {
private T data;
public T getData() {
return data;
}
public void setData(T data) {
this.data = data;
}
public static void main(String[] args) {
NormalGeneric<String> normalGeneric = new NormalGeneric<>();
normalGeneric.setData("ok");
System.out.println(normalGeneric.getData());
}
}
//泛型接口
//第一种实现方式,泛型类实现泛型接口
public interface IGenertor<T> {
public T getData();
}
public class ImplGenertor<T> implements IGenertor<T> {
@Override
public T getData() {
return null;
}
}
//第二种实现方式
public class ImplGenertor1 implements IGenertor<String>{
@Override
public String getData() {
return null;
}
}
//泛型方法
//泛型方法是独立的,不用非要在泛型类或者泛型接口里
public class GenertorMethod {
public <T>T ggetGenertor(T...t){
return t[t.length/2];
}
}
public static void main(String[] args) {
GenertorMethod genertorMethod = new GenertorMethod();
System.out.println(genertorMethod.<String>getGenertor("张三","李四"));//使用时指定类型
System.out.println(genertorMethod.getGenertor(1,2,3,4));//也可以不指定,高版本编译器可以自行判断
}
public class NormalFenertor2 {
public class Generic<T>{
private T key;
public Generic(T key) {
this.key = key;
}
//这不是泛型方法,只是一个普通方法。
public T getKey() {
return key;
}
//这也不是泛型类,只是一个普通方法。只是是用了Generic<Number>这个泛型类做行参而已。
public void show(Generic<Number> obj){
}
}
}
public class NormalGeneric3 {
static class Fruit{
@Override
public String toString() {
return "fruit";
}
}
static class Apple extends Fruit{
@Override
public String toString() {
return "apple";
}
}
static class Person{
@Override
public String toString() {
return "person";
}
}
static class GenerateTest<T>{
//普通方法 泛型类中的T只会影响普通方法中的T
public void show(T t){
System.out.println(t.toString());
}
//泛型方法,使用泛型E,这个泛型E可以为任意类型
//可以与T相同,也可以不同
//由于泛型方法在声明的时候会声明泛型<E>,因此即使在泛型类中并未声明泛型,
//编译器也能够正确识别泛型方法中识别的泛型
public <E> void show_2(E e){
System.out.println(e.toString());
}
//在泛型类型中声明了一个泛型方法,使用泛型T
//这个泛型T是一个全新的类型,可以与泛型类中声明的T不是同一个类型
public <T> void show_3(T t){
System.out.println(t.toString());
}
}
public static void main(String[] args) {
Apple apple = new Apple();
Person person = new Person();
GenerateTest<Fruit> generateTest = new GenerateTest<>();
generateTest.show(apple);
// generateTest.show(person);//泛型已经规定了类型,再重新使用类型就报错
generateTest.show_2(apple);
generateTest.show_2(person);
generateTest.show_3(apple);
generateTest.show_3(person);
}
}
4.限定类型变量
public class ArrayAlg {
//要保证a和b有compareTo的方法,就要在泛型上限制,让T extends Compareable,
// 可以继承多个类或接口,但是如果类和接口混用,类要写在继承的第一个,并且只能有一个类,
//因为在java里是单继承,多实现,所以只能继承一个类
public static <T extends Comparable> T min(T a,T b){
if (a.compareTo(b) > 0) return a;else return b;
}
public static <T extends ArrayList & Comparable & Serializable> T min(T a, T b){
if (a.compareTo(b) > 0) return a;else return b;
}
}
5.泛型中的约束和局限性
1.不能实例化类型变量
2.静态域或方法里不能引用类型变量
因为 对象创建的时候才知道泛型的类型,对象创建的时候先执行静态方法,再执行构造方法。虚拟机不知道泛型是什么类型
3.静态方法本身是泛型方法就行
public class Restrict<T> {
private T data;
//正常的构造方法
public Restrict(T data) {
this.data = data;
}
public Restrict() {
}
//这样是错误的
// public Restrict() {
// this.data = new T();
// }
//静态域或方法里不能引用类型变量
//因为 对象创建的时候才知道泛型的类型,对象创建的时候先执行静态方法,再执行构造方法。虚拟机不知道泛型是什么类型
// public static T instance;//这个是错误的,不允许这样
//静态方法本身是泛型就可以
public static <T>T getInstance(){
return null;
}
public static void main(String[] args) {
// Restrict<double> //double是基础类型,所有的基础类型都不能当泛型类型,得要用包装类型Double,因为基础类型不是对象
Restrict<Double> restrict = new Restrict<>();
//泛型不能使用instanceof
// if (restrict instanceof Restrict<Double>)
// if (restrict instanceof Restrict<T>)
Restrict<String> stringRestrict = new Restrict<>();
//返回结果为true,不管什么类型都是返回一个类对象
System.out.println(restrict.getClass() == stringRestrict.getClass());
Restrict<Double>[] restricts;//可以定义泛型数组
Restrict<Double>[] restrictArray = new Restrict[10];
// Restrict<Double>[] restrictArray1 = new Restrict<Double>[10];//不能创建数组
}
}
6.泛型的约束和局限性
public class ExceptionRestrict {
//泛型类不能继承 Exception Throwable
// private class Problem<T> extends Exception{}
//不能捕获泛型类对象
// public <T extends Throwable> void doWork(T t){
// try {
//
// }catch (T t){
//
// }
// }
//可以这样写
public <T extends Throwable> void doWork(T t) throws T{
try {
}catch (Throwable e){
}
}
}
如果A类继承自B类,那么泛型A和泛型B没有任何继承关系
public class Employee {
}
public class Worker extends Employee {
}
public class Pair<T> {
public static void main(String[] args) {
//Pair<Employee> employeePair 和 Pair<Worker> workerPair完全是两个独立的,没有任何继承关系
Pair<Employee> employeePair = new Pair<>();
Pair<Worker> workerPair = new Pair<>();
Employee employee = new Employee();
// Pair<Employee> employeePair2 = new Pair<Worker>();//报错,没有继承关系
Pair<Employee> pair = new ExtendsPair<>();//因为ExtendsPair 继承 Pair
}
//泛型类可以继承或者扩展其他泛型类,比如List和ArrayList
private static class ExtendsPair<T> extends Pair<T>{
}
}
7.通配符
? extends Fruit ,通配符只能使用在方法上,类不能使用 extends一般用于安全的访问数据、读取数据 super可以安全的写入数据
public class Employee extends Person{
}
public class GenericType<T> {
private T data;
public T getData() {
return data;
}
public void setData(T data) {
this.data = data;
}
}
public static void main(String[] args) {
GenericType<Employee> employeeGenericType = new GenericType<>();
printChild(employeeGenericType);
GenericType<Worker> workerGenericType = new GenericType<>();
printChild(workerGenericType);
// print1(new GenericType<Person>());//这是错误的,Person是Employee的父类,超过了界限
GenericType<? extends Employee> childGenericType = employeeGenericType;//这样是没问题的
GenericType<? extends Employee> childGenericType1 = workerGenericType;//这样是没问题的
Employee employee = new Employee();
Worker worker = new Worker();
//三个都报错
// childGenericType.setData(new Person());
// childGenericType.setData(employee);
// childGenericType.setData(worker);
//extends用于安全的读取数据
//set是set的Employee的子类,但是取的时候编译器不知道是哪个子类,
//所以只能返回Employee对象
employee = childGenericType.getData();
//set是set的Employee的子类,但是取的时候编译器不知道是哪个子类,
// 所以不能返回Worker对象,报错,得强转
worker = (Worker) childGenericType.getData();
GenericType<Person> personGenericType = new GenericType<>();
printSuper(employeeGenericType);
printSuper(personGenericType);
// printSuper(workerGenericType);//Worker是Employee的子类,低于Employee不行
//super用于安全的写入数据
GenericType<? super Employee> parentGenericType = new GenericType<>();
parentGenericType.setData(new Worker());
parentGenericType.setData(new Employee());
// parentGenericType.setData(new Person());//不能设置比它大的
Object parentData = parentGenericType.getData();//返回父类object
}
//extends Employee 的Employee代表传入参数的上限,不能超过
public static void printChild(GenericType<? extends Employee> genericType){}
//super Employee 的Employee代表传入参数的下限,不能低于
public static void printSuper(GenericType<? super Employee> genericType){} public static void main(String[] args) {
GenericType<Employee> employeeGenericType = new GenericType<>();
printChild(employeeGenericType);
GenericType<Worker> workerGenericType = new GenericType<>();
printChild(workerGenericType);
// print1(new GenericType<Person>());//这是错误的,Person是Employee的父类,超过了界限
GenericType<? extends Employee> childGenericType = employeeGenericType;//这样是没问题的
GenericType<? extends Employee> childGenericType1 = workerGenericType;//这样是没问题的
Employee employee = new Employee();
Worker worker = new Worker();
//三个都报错
// childGenericType.setData(new Person());
// childGenericType.setData(employee);
// childGenericType.setData(worker);
//extends用于安全的读取数据
employee = childGenericType.getData();//set是set的Employee的子类,但是取的时候编译器不知道是哪个子类,所以只能返回Employee对象
worker = (Worker) childGenericType.getData();//set是set的Employee的子类,但是取的时候编译器不知道是哪个子类,所以不能返回Worker对象,报错,得强转
GenericType<Person> personGenericType = new GenericType<>();
printSuper(employeeGenericType);
printSuper(personGenericType);
// printSuper(workerGenericType);//Worker是Employee的子类,低于Employee不行
//super用于安全的写入数据
GenericType<? super Employee> parentGenericType = new GenericType<>();
parentGenericType.setData(new Worker());
parentGenericType.setData(new Employee());
// parentGenericType.setData(new Person());//不能设置比它大的
Object parentData = parentGenericType.getData();//返回父类object
}
//extends Employee 的Employee代表传入参数的上限,不能超过
public static void printChild(GenericType<? extends Employee> genericType){}
//super Employee 的Employee代表传入参数的下限,不能低于
public static void printSuper(GenericType<? super Employee> genericType){}
在java虚拟机是如何实现泛型的 ?
类型擦除、泛型擦除、强制转型