泛 型

泛型简介

概念

  1. 泛型的本质就是数据类型的参数化,处理的数据类型不是固定的,而是可以作为参数传入。
  2. 我们可以把“泛型”理解为数据类型的一个占位符(类似:形式参数),即告诉编
    译器,在调用泛型时必须传入实际类型。
  3. 这种参数类型可以用在类、接口和方法中,分别被称为泛型类、泛型接口、泛型方法。

好处

  1. 可以让编译器帮助我们识别强制类型转换时可能引起的错误,自动转换增加安全性和可读性

类型擦除

编码时采用泛型写的类型参数,编译器会在编译时去掉,这称之为“类型擦除”。

泛型主要用于编译阶段,编译后生成的字节码 class 文件不包含泛型中的类型信息,涉及类型转换仍然是普通的强制类型转换。 类型参数在编译后会被替换成 Object,运行时虚拟机并不知道泛型。

泛型使用

定义泛型

在这里插入图片描述
在这里插入图片描述

泛型类

  1. 泛型类就是把泛型定义在类上,用户使用该类的时候,才把类型明确下来
多个标识符用逗号隔开
public class 类名<泛型标识符,泛型标识符>{
}
  • 定义一个泛型类
package generic;

public class Generic <T>{
	
	private T flag;
	
	public void setFlag(T flag) {
		this.flag = flag;
	}
	public T getFlag() {
		return flag;
	}
	
	
}

  • 测试泛型类
package generic;

public class testGeneric {

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		Generic<String> generic = new Generic<>();
		generic.setFlag("admin");
		String flag = generic.getFlag();
		System.out.println(flag);
		
		Generic<Integer> generic2 = new Generic<>();
		generic2.setFlag(123);
		Integer flag1 = generic2.getFlag();
		System.out.println(flag1);
		System.out.println(flag1.TYPE);
	}	

}
admin
123
int

泛型接口

  1. 泛型接口和泛型类的声明方式一致。泛型接口的具体类型需要在实现类中进行声明。
多个标识符用逗号隔开
public interface 接口名<泛型标识符,泛型标识符>{
}
  • 定义一个泛型接口
public interface Igeneric<T> {
	T getName(T name);
}
  • 定义一个泛型接口实现类
public class IgenericImpl implements Igeneric<String>{
	@Override
	public String getName(String name) {
		// TODO Auto-generated method stub
		return name;
	}
}

  • 测试类
  1. 通过接口实现类创建对象时,按照实现类的参数类型确定
  2. 直接通过接口修饰时需要确定参数类型,不指定之前时Object类型
package generic;

import Study.Salary;

public class testGeneric {

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		IgenericImpl igenericImpl = new IgenericImpl();
		String name = igenericImpl.getName("ssc");
		System.out.println(name);
	}	

}

泛型方法

  1. 泛型方法是指将方法的参数类型定义成泛型,以便在调用时接收不同类型的参数。类型参数可以有多个,用逗号隔开,如:<K,V>。定义时,类型参数一般放到返回值前面。
  2. 调用泛型方法时,不需要像泛型类那样告诉编译器是什么类型,编译器可以自动推断出类型来。

非静态方法

只要定义了泛型方法,方法的参数和内部都可以使用该泛型

public <泛型表示符号> void getName(泛型表示符号 name){
}
public <泛型表示符号> 泛型表示符号 getName(泛型表示符号 name){
}
package generic;

public class MethodGeneric {

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		MethodGeneric methodGeneric = new MethodGeneric();
		//不需要写出参数类型
		methodGeneric.setName("ssc");
		methodGeneric.setName(123);
		
		System.out.println(methodGeneric.getName(456));
		System.out.println(methodGeneric.getName("ssc1"));
	}
	
	//定义了一个泛型方法
	public <T> void setName(T name) {
		System.out.println(name);
	}
	public <T> T getName(T name){
		return name;
		
	}
}
ssc
123
456
ssc1

静态方法

  1. 静态方法无法访问类上定义的泛型;如果静态方法操作的引用数据类型不确定的时候,必须要将泛型定义在方法上。
public static <泛型表示符号> void setName(泛型表示符号 name){
}
public static <泛型表示符号> 泛型表示符号 getName(泛型表示符号 name){
}
//静态方法中测试泛型
	//有返回值
	public static <T> void getFlag(T flag) {
		System.out.println(flag);
	}
	//无返回值
	public static <T> T setFlag1(T flag) {
		return flag;
	}
package generic;

import Study.Salary;

public class testGeneric {

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		//静态方法测试
		Igeneric<String> igenericImpl2 = new IgenericImpl();
		String name1 = igenericImpl2.getName("sdasdad");
		System.out.println(name1);
		
		MethodGeneric.getFlag(132);
		Integer flag12 = MethodGeneric.setFlag1(234);
		System.out.println(flag12);
	}	
}

132
123456

泛型方法和可变参数

public <泛型表示符号> void showMsg(泛型表示符号... agrs){
}
//泛型方法可变参数
	public <T> void method(T...args) {
		for(T t:args) {
			System.out.println(t);
		}
	}
public class testGeneric {

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		//可变参数类型遍历数组
		MethodGeneric methodGeneric2 = new MethodGeneric();
		String[] arr = new String[] {"a","b","c"};
		Integer[] a = new Integer[] {1,2,3};
		methodGeneric2.method(arr);
		methodGeneric2.method(a);
	}	

}
a
b
c
1
2
3

通配符的使用

  1. “?”表示类型通配符,用于代替具体的类型。它只能在“<>”中使用。可以解决当具体类型不确定的问题。
public void showFlag(Generic<?> generic){
}
package generic;

public class Wildcard {
	public static void main(String[] args) {
		ShowMsg uMsg = new ShowMsg();
		
		Generic<Integer> generic = new Generic<>();
		generic.setFlag(20);
		uMsg.showFlag(generic);
		
		Generic<Number> generic1 = new Generic<>();
		generic1.setFlag(30);
		uMsg.showFlag(generic1);
	}

}
class ShowMsg{
	//?通配符
	public void showFlag(Generic<?> generic) {
		System.out.println(generic.getFlag());
	}
//	public void showFlag(Generic<Integer> generic) {
//		System.out.println(generic.getFlag());
//	}
}
20
30
通配符的上限限定
  1. 上限限定表示通配符的类型是 T 类以及 T 类的子类或者 T 接口以及 T 接口的子接口。该方式同样适用于与泛型的上限限定
public void showFlag(Generic<? extends Number> generic){
}
public class Wildcard {
	public static void main(String[] args) {
		ShowMsg uMsg = new ShowMsg();

		//被限定在Number的子类
//		Generic<String> generic2 = new Generic<>();
//		generic2.setFlag(40);
//		uMsg.showFlag(generic2);
	}

}
class ShowMsg{
	//?通配符
	public void showFlag(Generic<? extends Number> generic) {
		System.out.println(generic.getFlag());
	}
}
Exception in thread "main" java.lang.Error: Unresolved compilation problems: 
通配符的下限限定
  1. 下限限定表示通配符的类型是 T 类以及 T 类的父类或者 T 接口以及 T 接口的父接口。
    注意:该方法不适用泛型类
public void showFlag(Generic<? super Number> generic){
}
public class Wildcard {
	public static void main(String[] args) {
		ShowMsg uMsg = new ShowMsg();

		//被限定在Integer的父类
//		Generic<String> generic2 = new Generic<>();
//		generic2.setFlag(40);
//		uMsg.showFlag1(generic2);

}
class ShowMsg{
	//?通配符下限
	public void showFlag1(Generic<? super Integer> generic) {
		System.out.println(generic.getFlag());
	}
}
Exception in thread "main" java.lang.Error: Unresolved compilation problems: 

总结

  1. 泛型最大的作用就是在编译时类型安全的问题,仅在编译阶段有效,结束后会自动转为Object类
  2. 使用泛型时,如下几种情况是错误的:
    1. 不能创建基本类型
      Test t; 这样写法是错误,我们可以使用对应的包装类;Test t ;
    2. 不能通过类型参数创建对象
      T elm = new T(); 运行时类型参数 T 会被替换成 Object,无法创建 T 类型的对 象,容易引起误解,所以在 Java 中不支持这种写法
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值