目录
1、泛型的引出
定义一个表示坐标的操作类(Point),在这个类里要求保存以下几种坐标:
整形:x=10,y=20
浮点:x=10.2,y=20.3;
字符串:x=东经20度,y=北纬16度
设计的关键在于x与y这两个变量的类型设计上。必须有一种类型可以保存这三类数据。
public class Point<T extends Number> {
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;
}
@Override
public String toString() {
return "Point{" +
"x=" + x +
", y=" + y +
'}';
}
}
2、通配符
public class Message<T> {
private T msg;
public T getMsg() {
return msg;
}
public void setMsg(T msg) {
this.msg = msg;
}
public static void main(String[] args) {
Message<String> m=new Message<String>();
m.setMsg("hello");
fun(m);
}
public static void fun(Message<String> tmp){
System.out.println(tmp.getMsg());
}
}
以上代码设置的String类型的变量,如果换为其他的。比如:Integer
public static void main(String[] args) {
Message<Integer> m=new Message<Integer>();
m.setMsg(1234);
fun(m);
}
public static void fun(Message<String> tmp){
System.out.println(tmp.getMsg());
}
这时fun(m) 会报错。
解决方法一:不设置方法参数的泛型
public static void main(String[] args) {
Message<Integer> m=new Message<Integer>();
m.setMsg(1234);
Message<String> m2=new Message<String>();
m2.setMsg("1234213");
fun(m);
fun(m2);
}
public static void fun(Message tmp){
System.out.println(tmp.getMsg());
}
解决方法二:可以设置可以接收一个类的任意的泛型类型,就可以使用“?”来描述。
public static void main(String[] args) {
Message<Integer> m=new Message<Integer>();
m.setMsg(1234);
Message<String> m2=new Message<String>();
m2.setMsg("1234213");
fun(m);
fun(m2);
}
public static void fun(Message<?> tmp){
System.out.println(tmp.getMsg());
}
在"?"通配符基础上还会有两个字的通配符:
- ?extend类:设置泛型上限,可以在声明上和方法参数上使用;
?extend Number:意味着可以设置Number 或者Number的子类(Integer,Double,Float)
- ?super 类:设置泛型下限
?extend String:意味着只能够设置String或者是它的父类Object
范例:设置泛型的上限
public class Message<T extends Number> {
private T msg;
public T getMsg() {
return msg;
}
public void setMsg(T msg) {
this.msg = msg;
}
public static void main(String[] args) {
Message<Integer> m=new Message<Integer>();
m.setMsg(1234);
fun(m);
//以下代码会报错,编译时会报错
//Message<String> m2=new Message<String>();
//m2.setMsg("1234213");
//fun(m2);
}
public static void fun(Message<? extends Number> tmp){
System.out.println(tmp.getMsg());
}
}
范例:设置下限
public class Message<T> {
private T msg;
public T getMsg() {
return msg;
}
public void setMsg(T msg) {
this.msg = msg;
}
public static void main(String[] args) {
Message<String> m=new Message<String>();
m.setMsg("1234");
fun(m);
}
//设置下限
public static void fun(Message<? super String> tmp){
System.out.println(tmp.getMsg());
}
}
3、泛型接口
泛型在接口上声明,叫泛型接口
- 定义接口在前面字母加I 例如:IMessge
- 定义抽象类 加Abstract 例如:AbstractMessage
- 定义普通类直接编写 例如:Message
public interface IMessage<T> {
public void print(T t );
}
可以设置多个泛型 例如:
public interface IMessage<T,R> {
public void print(T t );
}
定义泛型子类的两种形式
形式一:子类继续是使用泛型、并且父接口使用和子类同样的泛型标记
public class MessageImpl<T> implements IMessage<T> {
public void print(T t) {
System.out.println("-----------" + t +"---------");
}
}
public class TestDemo{
public static void main(String[] args) {
IMessage<String> stringIMessage=new MessageImpl<String>();
stringIMessage.print("string");
}
}
形式二:在子类不设置泛型,而为父接口明确的定义一个泛型类型,在实现接口上明确指定泛型类型 如:String
public class MessageImpl implements IMessage<String> {
public void print(String s) {
}
}
要明白这两种形式
4、泛型方法
泛型方法不一定非要定义在支持泛型的类里面。
public class TestDemo{
public static void main(String[] args) {
String str=fun("Hello");
System.out.println(str.length());
}
//泛型方法
public static <T> T fun(T t){
return t;
}
}
能够看懂泛型方法的标记就可以了。
总结:
- 泛型解决的是向下转型所带来的安全隐患,其核心的组成就在声明类或接口的时候不设置参数或属性的类型。
- “?” 可以接收任意的泛型类型,只能够取出,但是不能够修改。