泛型指的就是在类定义的时候并不会设置类中的属性或方法中的参数的具体类型,而是在类使用时再进行定义。
基本语法:
class MyClass<T> {
T value1;
}
尖括号 <> 中的 T 被称作是类型参数,用于指代任何类型。实际上这个T你可以任意写,但出于规范的目的,Java 还是建议我们用单个大写字母来代表类型参数。常见的如:
T 代表一般的任何类。
E 代表 Element 的意思,或者 Exception 异常的意思。
K 代表 Key 的意思
V 代表 Value 的意思,通常与 K 一起配合使用。
S 代表 Subtype 的意思,文章后面部分会讲解示意。
注意:泛型只能接受类,所有的基本数据类型必须使用包装类!
1.泛型类
如果一个类被<T>
的形式定义,那么它就被称为是泛型类
2.泛型方法
泛型方法与泛型类稍有不同的地方是,类型参数也就是尖括号那一部分是写在返回值前面的。 <T>
中的 T 被称为 类型参数,而方法中的 T 被称为参数化类型,它不是运行时真正的参数。
class point<T>{
private T x;
private T y;
public T getX() {
return x;
}
public void setX(T x) {
this.x = x;
}
public T getY() {
return y;
}
public void setY(T y) {
this.y = y;
}
}
public class text {
public static void main(String[] args) {
point <String>p = new point<String>();
p.setX("西经180°");
p.setY("南纬20°");
String x = p.getX();
String y = p.getY();
System.out.println("X = "+x+",Y = " +y);
}
}
3.通配符
“?“,可以接收所有的泛型类型,但是又不能够让用户随意修改。
注意: 使用通配符"?"描述的是它可以接收任意类型,但是由于不确定类型,所以无法修改
class Message<T>{
private T massage;
public void setMassage(T massage) {
this.massage = massage;
}
public T getMassage() {
return massage;
}
}
public class project_0411{
public static void main(String[] args) {
Message<Integer> message = new Message();
message.setMassage(55);
fun(message);
}
public static void fun(Message<?> temp){
//temp.setMassage(100); 此时使用通配符"?"描述的是它可以接收任意类型,
//但是由于不确定类型,所以无法修改
System.out.println(temp.getMassage());
}
}
(1)泛型上限
?extends 类 设置上限
(2)泛型下限
?super 类 设置下限
//?extends 类 设置上限
//?super 类 设置下限
class Message<T extends Number >{//设置上限
private T massage;
public void setMassage(T massage) {
this.massage = massage;
}
public T getMassage() {
return massage;
}
}
public class project_PM{
public static void main(String[] args) {
Message<Integer> message = new Message();
Letter<String > letter = new Letter<>();
letter.setLetter("hello world");
message.setMassage(55);
fun(message);
fan(letter);
}
public static void fun(Message<? extends Number> temp){
//temp.setMassage(100);此时仍不能修改
System.out.println(temp.getMassage());
}
public static void fan(Letter<? super String> temp){//设置下限
temp.setLetter("success");//可以修改!
System.out.println(temp.getLetter());
}
}
class Letter<T>{
private T letter;
public T getLetter() {
return letter;
}
public void setLetter(T letter) {
this.letter = letter;
}
}
注意:上限可以用在声明,不能修改;而下限只能用在方法参数,可以修改内容!
4.泛型接口
泛型除了可以定义在类中,也可以定义在接口里面,这种情况我们称之为泛型接口。
interface IMessage<T> { // 在接口上定义了泛型
public void print(T t) ;
}
对于这个接口的实现子类有两种做法
(1):在子类定义时继续使用泛型
(2):在子类实现接口的时候明确给出具体类型
5.类型擦除
泛型信息只存在于代码编译阶段,在进入 JVM 之前,与泛型相关的信息会被擦除掉,专业术语叫做类型擦除。
通俗地讲,泛型类和普通类在 java 虚拟机内是没有什么特别的地方。
在泛型类被类型擦除的时候,之前泛型类中的类型参数部分如果没有指定上限,如 则会被转译成普通的 Object 类型,如果指定了上限如 则类型参数就被替换成类型上限。