一、泛型的目的
- 泛型解决的是:向下转型时存在的安全隐患;
- 泛型的核心是:在定义类或接口的时候,不需要显示地声明参数或属性的类型。
二、类中使用泛型
- 注:在类、接口或方法中,泛型可以定义多个,泛型的名称自定义;
- 注:使用泛型中,在显示指定具体类型时,只能是引用类型,不能是基本数据类型;
- 注:使用泛型中,如果没有显示指定具体类型,则系统默认使用Object作为具体类型;
package com.study.Type;
/**
* 在声明类的时候,定义了两个泛型:T、A
* @param <T>
* @param <A>
*/
class Fruit<T, A>{
private T name;
private A size;
public Fruit(T name, A size) {
this.name = name; this.size = size; } public void getInfo(){ System.out.println("name: "+this.name+" , size: "+this.size); } public T getName() { return name; } public void setName(T name) { this.name = name; } public A getSize() { return size; } public void setSize(A size) { this.size = size; } } public class Test { public static void main(String[] args) { Fruit<String,Integer> f1 = new Fruit<>("苹果",10); f1.getInfo(); // name: 苹果 , size: 10 String name2 = f1.getName(); int size2 = f1.getSize(); System.out.println(name2); // "苹果" System.out.println(size2); // 10 Fruit<String,String> f2 = new Fruit<>("苹果","直径10公分"); f2.getInfo(); // name: 苹果 , size: 直径10公分 } }
三、接口中使用泛型
package com.study.Type;
/**
* 接口使用泛型:T
*/
interface IFruit<T>{
public void print(T t);
}
/**
* 实现类继续使用泛型:T
*/
class Apple<T> implements IFruit<T>{
@Override
public void print(T t) {
System.out.println(t+" , "+t.getClass()); } } /** * 实现类不使用泛型,指定接口的泛型参数类型 */ class Orange implements IFruit<String>{ @Override public void print(String s) { System.out.println(s+" , "+s.getClass()); } } public class Test { public static void main(String[] args) { IFruit<String> a1 = new Apple<String>(); a1.print("苹果"); // 苹果 , class java.lang.String IFruit<Integer> a2 = new Apple<Integer>(); a2.print(100); // 100 , class java.lang.Integer IFruit<String> orange = new Orange(); orange.print("橘子"); // 橘子 , class java.lang.String //orange.print(100); //语法错误:Error:(43, 22) java: 不兼容的类型: int无法转换为java.lang.String } }
四、方法中使用泛型
class Test {
public static void main(String[] args) {
String str = print("苹果");
System.out.println(str); // 苹果
int num = print(123);
System.out.println(num); // 123
}
/**
*
* @param t : 入参
* @param <T> : 声明一个泛型
* @return
*/
public static <T> T print(T t){
return t;
}
}
五、通配符"?"的使用
- 注:使用通配符,只能取出数据,不能设置数据
package com.study.Type;
import java.util.Date;
class Message<T> {
private T msg;
public Message(T msg) {
this.msg = msg;
}
public T getMsg() {
return msg;
}
}
public class Test {
public static void main(String[] args) {
Message<String> f1 = new Message<>("苹果");
print(f1); // 苹果 , class java.lang.String
Message<Integer> f2 = new Message<>(100);
print(f2); // 100 , class java.lang.Integer
Message<Date> f3 = new Message<>(new Date());
print(f3); // Fri Mar 08 15:26:25 CST 2019 , class java.util.Date
}
/**
* 使用通配符"?",来接受泛型
* @param message
*/
public static void print(Message<?> message){
System.out.println(message.getMsg()+" , "+message.getMsg().getClass());
}
}
六、通配符的引申用法
1、"? extends 类" : 设置泛型上限。可以在声明上和方法参数上使用。
- 如:"? extends Number":意味着只可以设置Number或Number的子类(如:Integer、Long、Double、......)
2、"? super 类":设置泛型下限。可以在方法参数上使用。
- 如:"? super Number":意味着只可以设置Number和Number的父类(Object)
七、分析:泛型
1、Java泛型只存在于编辑期(.java文件中),在编译成字节码文件(.class文件)时,会把泛型擦除掉,替换为具体的类型
在JAVA的虚拟机中并不存在泛型,泛型只是为了完善java体系,增加程序员编程的便捷性以及安全性而创建的一种机制,在JAVA虚拟机中对应泛型的都是确定的类型,在编写泛型代码后,java编译过程中会把这些泛型参数类型都擦除,用相应的确定类型来代替,代替的这一动作叫做类型擦除,而用于替代的类型称为原始类型,在类型擦除过程中,一般使用第一个限定的类型来替换,若无限定,则使用Object。
2、泛型类的静态变量是共享的,于具体实例化的基本类型无关。
class GT<T>{
/**
* 泛型类的静态变量是共享的
*/
public static int var = 0;
public void nothing(T x){}
}
class StaticTest{
public static void main(String[] args){
GT<Integer> g1 = new GT<Integer>();
g1.var = 1;
System.out.println(g1.var); // 1
GT<String> g2 = new GT<String>();
g2.var = 2;
System.out.println(g1.var); // 2
System.out.println(g2.var); // 2
GT<Date> g3 = new GT<>();
System.out.println(g1.var); // 2
System.out.println(g2.var); // 2
System.out.println(g3.var); // 2
}
}