泛型
泛型的引出
例:向下转型的错误示范
package Project.Study.Genericity;
class Point{ //定义坐标类
private Object x; //可以保存任意数据
private Object y; //可以保存任意数据
public Object getX() {
return x;
}
public Object getY() {
return y;
}
public void setX(Object x) {
this.x = x;
}
public void setY(Object y) {
this.y = y;
}
}
public class Test {
public static void main(String args[]){
Point p=new Point(); //实例化Point类数据
p.setX("东经100度"); //设置坐标数据
p.setY(10); //设置坐标数据
System.out.println("x坐标:"+p.getX()+"y坐标"+p.getY());
//根据设置好的坐标取出数据进行操作
String x=(String)p.getX(); //取出坐标数据
String y=(String)p.getY(); //取出坐标数据
System.out.println("x坐标:"+x+"y坐标"+y);
}
}
//结果
//Exception in thread "main" java.lang.ClassCastException: class //java.lang.Integer cannot be cast to class java.lang.String //(java.lang.Integer and java.lang.String are in module java.base of //loader 'bootstrap')
// at Project.Study.Genericity.Test.main(Test.java:30)
//x坐标:东经100度y坐标10
例:使用泛型减少转型操作
package Project.Study.Genericity;
//此时的T在Point类定义上只表示一个标记,在使用时需要为其设置具体的类型
class Point<T>{
private T x; //此属性的类型不知道,由Point类使用时的动态决定
private T y; //此属性的类型不知道,由Point类使用时的动态决定
public T getX() {
return x;
}
public T getY() {
return y;
}
public void setX(T x) {
this.x = x;
}
public void setY(T y) {
this.y = y;
}
}
public class Test {
public static void main(String args[]){
Point<String> p=new Point<String>(); //实例化Point类数据,设置泛型为String
p.setX("东经100度");
p.setY("北纬20度");
System.out.println("x坐标:"+p.getX()+"y坐标"+p.getY());
String x=p.getX(); //取出坐标数据,不再需要强制类型转换
String y=p.getY(); ////取出坐标数据,不再需要强制类型转换
System.out.println("x坐标:"+x+"y坐标"+y);
}
}
//结果
//x坐标:东经100度y坐标10
//x坐标:东经100度y坐标10
提示:一个类中可以定义多个泛型标记。
class Point<P,R>{
public R fun(P p){
return null;
}
}
需要注意的是,如果要想使用泛型,那么它能够采用的类型只能够是类,即不能是基本类型,只能是引用类型。
通配符
例:通配符"?"的使用
package Project.Study.Genericity;
class Message<T>{
private T msg;
public void setMsg(T msg){
this.msg=msg;
}
public T getMsg() {
return msg;
}
}
public class Test1 {
public static void main(String args[]){
Message<Integer>message1=new Message<>();
Message<String>message2=new Message<>();
message1.setMsg(30);
message2.setMsg("Hello World");
fun1(message1); //引用传递
fun2(message2);
}
public static void fun1(Message<?> temp){ //不能设置,但是可以取出
System.out.println(temp.getMsg());
}
public static void fun2(Message temp){ //默认使用Object作为泛型类型,可以在方法中随意修改对象内容(即使类型不符合),这种做法是不严谨的
temp.setMsg(100);
System.out.println(temp.getMsg());
}
}
//结果
//30
//100
由上fun2(),必须使用通配符"?"来制约这种任意修改数据问题的操作。所以"?"设置的泛型类型只表示可以取出,但是不能设置,一旦设置了内容,程序编译就会出现错误提示。
“? extends 类”:设置泛型上限,可以在声明和方法参数上使用;
? extends Number:意味着可以设置Number或者是Number的子类(Integer、Double、…)
例:设置泛型的上限
package Project.Study.Genericity;
class Message<T extends Number>{ //设置泛型上限,只能是Number或Number子类
private T msg;
public void setMsg(T msg){
this.msg=msg;
}
public T getMsg() {
return msg;
}
}
public class Test1 {
public static void main(String args[]){
Message<Integer>message1=new Message<>(); //Integer是Number子类
message1.setMsg(30);
fun1(message1); //引用传递
}
public static void fun1(Message<? extends Number> temp){ //定义泛型上限
System.out.println(temp.getMsg());
}
}
//结果
//30
“? super 类”:设置泛型下限,方法参数上使用;
? super String:意味着只能设置String或它的父类Object。
例:设置泛型的下限
package Project.Study.Genericity;
class Message<T>{ //定义泛型
private T msg;
public void setMsg(T msg){
this.msg=msg;
}
public T getMsg() {
return msg;
}
}
public class Test1 {
public static void main(String args[]){
Message<String>message1=new Message<>();
message1.setMsg("Hello World"); //设置属性内容
fun1(message1); //引用传递
}
public static void fun1(Message<? super String> temp){ //定义泛型下限
System.out.println(temp.getMsg());
}
}
//结果
//Hello World
泛型接口
任何情况下如果要使用接口,就必须定义相应的子类,而对于使用了泛型的接口子类而言,有以下两种实现方式。
实现方式一:在子类继续设置泛型标记
例:
package Project.Study.Genericity;
interface IMessage<T>{ //定义泛型接口
public void print(T t);
}
class MessageImpl<S>implements IMessage<S>{ //在子类继续设置泛型,此泛型也作为接口中的泛型类型
public void print(S t){
System.out.println(t);
}
}
public class Test2 {
public static void main(String[] args){
IMessage<String>msg=new MessageImpl<String>();
msg.print("HelloWorld");
}
}
//结果
//HelloWorld
实现方式二:在子类不设置泛型,而为父类接口明确地定义一个泛型类型。
package Project.Study.Genericity;
interface IMessage1<T>{
public void print(T t);
}
class MessageImpl1 implements IMessage1<String>{
public void print(String t){
System.out.println(t);
}
}
public class Test3 {
public static void main(String [] args){
IMessage1<String>msg=new MessageImpl1();
msg.print("HelloWorld");
}
}
//结果
//HelloWorld
泛型方法
package Project.Study.Genericity;
public class Test4 {
public static void main(String [] args){
String str=fun("HelloWorld");
System.out.println(str.length());
}
/**
* 此方法为泛型方法,T的类型由传入的参数类型决定
* 必须在方法返回值前明确定义泛型标记
* @param t 参数类型,同时也决定了返回值类型
* @param <T>
* @return 直接返回设置进来的内容
*/
public static <T>T fun(T t){
return t;
}
}
//结果
//10