JDK1.5之后追加到Java中,主要目的是为了解决ClassCaseException问题。在进行对象的向下转型时永远可能存在安全隐患,java希望通过泛型慢慢解决掉此类问题。
class PointP{
private Object x;
private Object y;
public void setX(Object x){
this.x = x;
}
public void setY(Object y){
this.y = y;
}
public Object getX(){
return x;
}
public Object getY(){
return y;
}
}
class Untitled {
public static void main(String[] args) {
PointP p = new PointP();
p.setX(10);
p.setY(20);
int x = (int)p.getX();
int y = (int)p.getY();
System.out.println( x + "" + y );
}
}
如上述代码,未使用泛型的时候,必须强制转换成int。一旦转换失败,编译的时候不会报错,运行的时候会报错。
泛型的基本定义:
想要避免“ClassCastException”,最好的方法是回避对象的下转型。泛型技术的本质是,类中的属性或方法的参数与返回值的类型可以由对象实例化的时候动态决定。
不设置泛型类型时,会自动设置为Object类型。
class PointP <T>{
private T x;
private T y;
public void setX(T x){
this.x = x;
}
public void setY(T y){
this.y = y;
}
public T getX(){
return x;
}
public T getY(){
return y;
}
}
class Untitled {
public static void main(String[] args) {
PointP <Integer> p = new PointP <Integer>();
p.setX(10);
p.setY(20);
Integer x = p.getX();
Integer y = p.getY();
System.out.println( x + "" + y );
}
}
由于泛型类型设置为Integer,编译的时候如果发现设置的内容有错误会自动的进行错误提示,同时避免了对象的向下转型处理。
使用注意:
1.泛型之中只能设置引用类型,如果操作基本类型必须使用包装类。
2.JDK1.7之后操作可以简略成 : PointP
JDK1.5之前:PointP
使用泛型可以解决大部分的类对象向下转型问题,比使用Object更加合理。
泛型通配符
泛型虽然解决了向下转型带来的安全隐患,但是同时带来了引用传递处理问题。
class PointP <T>{
private T x;
private T y;
public void setX(T x){
this.x = x;
}
public void setY(T y){
this.y = y;
}
public T getX(){
return x;
}
public T getY(){
return y;
}
}
class Untitled {
public static void main(String[] args) {
PointP <Integer> p = new PointP <Integer>();
p.setX(10);
p.setY(20);
func(p);//正确输出30
PointP <String> p2 = new PointP <String>();
p2.setX("11");p2.setY("222");
func(p2);//报错。因为函数参数被固定成Integer
}
public static void func(PointP<Integer> tmp){
System.out.println( tmp.getX() + tmp.getY());
}
}
如果不能引用传递,泛型就丧失了意义。如上代码,正常应该可以接受任意类型的PointP对象,但是代码中设置为只能接受PointP
修改方法:通配符
public static void func(PointP<?> tmp){
System.out.println( tmp.getX() + tmp.getY());
}
注意:
- ? extends 类:设置泛型的上限。
例如:定义 ?extends Number 表示泛型只允许设置为Number及其子类、
- ?super 类:设置泛型的下限。
例如:定义 ?super String 表示泛型只允许使用String或其父类。
上限:
class PointP <T extends Number>{
private T x;
private T y;
public void setX(T x){
this.x = x;
}
public void setY(T y){
this.y = y;
}
public T getX(){
return x;
}
public T getY(){
return y;
}
}
class Untitled {
public static void main(String[] args) {
PointP <Integer> p = new PointP <Integer>();
p.setX(10);
p.setY(20);
func(p);
PointP <String> p2 = new PointP <String>();//报错。String无法转换成Integer。
// p2.setX("11");p2.setY("222");
// func(p2);
}
public static void func(PointP<? extends Number> tmp){
System.out.println(tmp.getX() + " " + tmp.getY());
}
}
下限:
class PointP <T>{
private T x;
private T y;
public void setX(T x){
this.x = x;
}
public void setY(T y){
this.y = y;
}
public T getX(){
return x;
}
public T getY(){
return y;
}
}
class Untitled {
public static void main(String[] args) {
PointP <Integer> p = new PointP <Integer>();
p.setX(10);
p.setY(20);
func(p);//报错,Integer无法转换成String
PointP <String> p2 = new PointP <String>();
// p2.setX("11");p2.setY("222");
// func(p2);
}
public static void func(PointP<? super String > tmp){
System.out.println(tmp.getX() + " " + tmp.getY());
}
}
泛型接口
实现泛型接口的两种方式:
1.子类继续用泛型。
2.子类确定泛型的类型。
interface IMessage<T>{
public String echo(T t);
}
class MessageImpl1<s> implements IMessage<s>{//方式一
public String echo(s t){
return "Echo" + t;
}
}
class MessageImpl2 implements IMessage<String>{//方式二
public String echo(String t){
return "Echo" + t;
}
}
class Untitled {
public static void main(String[] args) {
IMessage <String> msg = new MessageImpl1 <String> ();
System.out.println(msg.echo("111"));
msg = new MessageImpl2();
System.out.println(msg.echo("222"));
}
}
泛型方法
如果一个类上没有定义泛型,依然可以使用泛型方法。
class Untitled {
public static void main(String[] args) {
Integer num [] = fun(1,2,3);
for (int temp:num) {
System.out.println(temp+" ");
}
}
public static <T> T[] fun(T ... args){
return args;
}
}