我们最精彩用java泛型是在集合类中。比如List<String> list = new ArrayList<String>();
1.不使用泛型时一个很严重的问题是会有可能出现java.lang.ClassCastException的异常。看下面一段代码:
List list = new ArrayList();
list.add("123");
list.add(344);
for(int i = 0 ;i < list.size();i++){
String tmp = (String)list.get(i);
System.out.println(tmp);
}
</pre>运行时会抛出类型转换异常,不使用泛型时:List list = new Array();声明的list装入的集合对象是Object,当我们把int型强转为String会抛出异常。<p></p><p>而泛型的出现就很好的解决了这个问题。</p><p></p><pre name="code" class="java">List<String> list2 = new ArrayList<String>();
list2.add("aaa");
list2.add(123);
<span style="white-space:pre"> for(String tmp : list2){
<span style="white-space:pre"> </span>System.out.println(tmp);
<span style="white-space:pre"> </span>}</span>
我们在list2.add(123);时,在编译阶段就会报错。因为我们采用泛型声明了list2。在这个集合中仅允许我们在集合中放入String类型的对象,如果我们放入其他类型就会报错。这样就避免了在出现运行时抛出的java.lang.ClassCastException的异常。
2.自定义泛型类
我们自定义一个泛型类,来看看泛型是怎么回事。
public class test1 {
public static void main(String[] args) {
/**
* 使用自定义泛型类Box<T>声明两个对象box,box2.
* 并分别指定,T的类型,其实box,box2还是一个Box对象
* 我们可以把T看做一个类型参数,在Box类中T被赋予什么类型,
* setT()就只能接收什么类型的参数
* 在获取赋值的对象时,返回的就是T类型的一个对象,也就无需进行类型转换
*/
Box<String> box = new Box<String>();
box.setT("小明");
System.out.println(box.getT());
Box<Integer> box2 = new Box<Integer>();
box2.setT(123);
System.out.println(box2.getT());
}
}
/**
*
* 自定义泛型类:
* 我们可以将<T>看做一个类型参数,对于这个T我们可以在声明的时候传入任何一种类型。
*
* @param <T>
*/
class Box<T> {
//t是类型为T的一个对象,T的类型是在使用这个类的时候赋予的,比如String,Interger等各种类型都可以
private T t;
/**
* 返回数据类型为T的一个对象t,比如如果类型是String,则返回一个字符串
* @return
*/
public T getT() {
return t;
}
/**
* 将一个类型为T的对象赋给t,比如如果类型是String,则返回一个字符串
* @return
*/
public void setT(T t) {
this.t = t;
}
}
3.泛型接口
package com.lql.demo;
/**
* 定义泛型接口
* @author Administrator
*
*/
public interface MyCompare<Anytype> {
public boolean compareTo(Anytype t);
}
package com.lql.demo;
//未使用泛型的接口
public interface MyCompare2 {
public boolean compareTo2(Object o);
}
package com.lql.demo;
/**
* 定义泛型接口的好处:我们在使用这个接口时,更加灵活安全
* 在使用这个泛型接口时,我们只需要将这个泛型的类型给指定了
* 在使用时就很方便安全
* @author Administrator
*
* Message方法实现了两个接口,一个是泛型接口MyCompare
* 另一个是普通接口MyCompare2
*
*/
public class Message implements MyCompare<Message>,MyCompare2{
//Message类中没有使用泛型,那我就把类中可以赋值的字段写死了
//只能保存String类型的字段
private String msg;
public String getMsg() {
return msg;
}
public void setMsg(String msg) {
this.msg = msg;
}
/**
* 非泛型接口方法
* 我们必须要进行强制类型转换,更重要的是这时很危险的
* 如果传递过来的Object参数不是Message类型,就会
* 抛出类型转换异常,不安全
*/
@Override
public boolean compareTo2(Object o) {
// TODO Auto-generated method stub
Message message = (Message) o;
if(msg!=null&&msg!=""&&msg.equals(message.msg)){
return true;
}
return false;
}
/**
* 泛型接口的方法
* 不用进行类型转换
* 如果compareTo的参数不是Message类型,在编译阶段就不会通过
* 更加安全
*/
@Override
public boolean compareTo(Message t) {
// TODO Auto-generated method stub
if(msg!=null&&msg!=""&&msg.equals(t.msg)){
return true;
}
return false;
}
}
4.通配符?在泛型中的使用
定义一个Shape类,一个Square类,和一个Circle类,Shape是Square和Circle的父类。
package com.lql.demo;
public class Shape {
public double area(){
return 0;
}
}
package com.lql.demo;
public class Square extends Shape {
private int width;
private int height;
public int getWidth() {
return width;
}
public void setWidth(int width) {
this.width = width;
}
public int getHeight() {
return height;
}
public void setHeight(int height) {
this.height = height;
}
@Override
public double area() {
return height * width;
}
}
package com.lql.demo;
public class Circle extends Shape {
private final static float PI = 3.14f;
private float r;
public float getR() {
return r;
}
public void setR(float r) {
this.r = r;
}
@Override
public double area() {
// TODO Auto-generated method stub
return PI * r * r;
}
}
有一个计算面积的工具类
package com.lql.demo;
import java.util.Collection;
public class Area {
public static double totleArea(Collection<Shape> list){
double area = 0;
for(Shape s : list){
area += s.area();
}
return area;
}
//通配符可以使Shape子类的集合对象的引用赋值给Collection<? extends Shape>的一个引用,
<span style="white-space:pre"> </span>//使用通配符意思是指,如果集合是一个Shape子类的集合,也可以作为参数进行传递
public static double totleArea2(Collection<? extends Shape> list){
double area = 0;
for(Shape s : list){
area += s.area();
}
return area;
}
}
建一个单元测试进行测试
public void mtest3(){
Collection<Shape> list = new ArrayList<Shape>();
for(int i = 0 ; i < 3 ; i++){
Shape shape = new Shape();
list.add(shape);
}
Square square = new Square();
square.setHeight(2);
square.setWidth(3);
list.add(square);
Circle circle = new Circle();
circle.setR(2);
list.add(circle);
double area = Area.totleArea(list);
System.out.println(area);
Collection<Square> squares = new ArrayList<Square>();
squares.add(square);
//如果将squares作为totleArea的参数,编译时就会报错
//Square是Shape的子类,但Collection<Square>不是Collection<Shape>的子类,
//直接将Collection<Square>的一个引用赋给Collection<Shape>的引用是不合法的
Area.totleArea(squares);//这句是无法通过编译的
Area.totleArea2(squares);//这个可以通过编译,totleArea2使用了通配符
}