泛型和方法

[size=medium][color=darkred]如何在java类中一些通用方法, 特别是一些静态的工具方法?

比如,数组Arrays的sort、search等?[/color][/size]
[b][size=medium]1. 整数数组的顺序收缩[/size][/b]

public static int seqSearch(int[] arr, int first, int last, int target) {
for (int i = first; i < last; i++)
if (arr[i] == target)
return i;

return -1;
}

1.1对上面的方法进行抽象,最先让我们想到就是,使用java的Object的引用,来实现通用方法

public static int seqSearch(Object[] arr, int first, int last, Object target) {
for (int i = first; i < last; i++)
if (arr[i].equals(target))
return i;

return -1;
}

[b][size=medium]2.使用泛型来改进通用方法[/size][/b]
2.1这样看来好像Object的引用好像非常方便,而且第二个顺序搜索可以使用到float,double,String等等。如果我们要进一步研究就会出现问题

public static void selectionSort(int[] arr) {
int n = arr.length, smallIndex = 0;
for (int i = 0; i < n; i++) { // 遍历array数组
smallIndex = i;
for (int j = i + 1; j < n; j++)
if (arr[smallIndex] > arr[j]) // 选择最小的索引j
smallIndex = j;
// if (smallIndex != i) {
exchange(arr, i, smallIndex);// 交换array[i]与 min(array[i+1,..,n])
// }
}
}

2.2上面的代码是一个顺序排序的算法,若果我们要写一个通用方法,就必须把object类型强制装换为一个实现Comparable接口的方法。[quote]JVM在处理类型强制装换的时候就会,抛出一个警告: uncheck cast[/quote]

@SuppressWarnings("unchecked")
public static void selectionSort(Object[] arr) {

int n = arr.length, smallIndex = 0;
for (int i = 0; i < n; i++) { // 遍历array数组
smallIndex = i;
for (int j = i + 1; j < n; j++)
if (((Comparable<Object>)arr[smallIndex]).compareTo(((Comparable<Object>)arr[j])) > 0) // 选择最小的索引j
smallIndex = j;
// if (smallIndex != i) {
exchange(arr, i, smallIndex);// 交换array[i]与 min(array[i+1,..,n])
// }
}
}


有此可以看出使用Object引用来处理通用问题,当使用实参如果没有实现Comparable接口,编译器会抛出一个castClassException的运行时异常。这样的程序是不安全的。
[b][size=medium]3比较Object引用和泛型[/size][/b]
3.1使用Object引用来泛化一个算法(如顺序搜索)。通过使用数组的Object引用和目标值, 只要数据类型实现了equals方法,算法中要比较大小的数据类必须实现Comparable接口, 现在我们来用java泛型来解决这个问题

public static <T extends Comparable<? super T>> void selectionSort(T[] arr){
int n = arr.length;
int smallIndex;
for (int i = 0; i < n-1; i++) {
smallIndex=i;
for (int j = i+1; j < n; j++)
if (arr[j].compareTo(arr[smallIndex])<0)
smallIndex=j;
exchange(arr, smallIndex, i);
}
}


[quote]在Arrays类中的静态方法 selectionSort(),这个方法处理的是整数类型,现在我们要用泛型范本版本来实现这个算法, 由于要泛型类型数组T[]中的两个元素要进行比较,所以传递实参的对象类型或其超类必须实现Comparable借口
[/quote]
泛型的使用javac知道了需要检查输入实参或实参对象的超类必须实现Comparable接口,才能正确调用
[b][size=medium]4.下面来介绍Java泛型的使用和思想[/size][/b]
[b]4.1泛型集合[/b]
考虑到基于Object的集合局限性,我们需要寻求一种新的解决方案来解决创建通用结构的为您提。 首先,我们希望通用结构是类型安全的(type safe), 简单说来就是指编译器应该标识出对象类型的任何错误使用,从而能够避免在运行时发现这样的错误。 通过这种方式,软件在发布之前会表示对象的错误使用问题, 而且能够避免来自客户端的讨厌的和令人为难的应用。此外,我们还希望通过减少对类型强制转换的要求来显著地简化应用程序中集合的使用。 Java泛型(java generic)提供了这样的解决方案。 在创建就集合对象时指定了类型(该类型规定了集合中存储元素的种类)。编译器不允许使用具有无效类型时的元素来更新集合, 并且还在可以识别在集合中的任意元素的类型
[quote]
泛型类允许编译器类型检查类型,并且避免使用类型强制转换。
[/quote]
[b]4.2泛型类:[/b]

public class Store<T> {
private T value;// 被保存的变量value引用
public Store(T v) {// 构造器使用泛型类型实参创建一个实例
value = v;
}
public T getValue() {
return value;
}
public void setValue(T value) {
this.value = value;
}
public String toString() {
return "value = " + value;
}

[quote]在类名后面的尖括号中扩入某个泛型类型就能够生成了这个泛型类[/quote]
[b]4.3泛型接口[/b]
接口也可是泛型结构。与泛型类一样, 接口头部中使用一个类型参数, 并且这个类型能够用于方法和返回类型。 例如, 我们定义Accumulator<T>接口, 这个接口具有单个方法add(), 该方法为参数V使用的方形类

public interface Accumulator <T> {
/**
* 形式参数V的类型T,要和接口头部定义的泛型类型一样, 否者编译会出现错误
* @param v
*/
public void add(T v);
}

[quote]接口也可是泛型结构。实现泛型接口时, 需要提供实际的类型[/quote]
实现一:AccumulatorNumber

public class AccumulatorNumber implements Accumulator<Number> {
private double total;

public AccumulatorNumber(){
total=0.0;
}
public double getTotal() {
return total;
}
@Override
public void add(Number v) {
total+=v.doubleValue();
}

}

实现二:

public class AccumulatorTime implements Accumulator<Time24> {
private Time24 total;
public AccumulatorTime(){
total=new Time24();
}
public Time24 getTotal() {
return total;
}
@Override
public void add(Time24 v) {
total.addTime(v.getTime()*60+v.getMinute());
}

}

泛型接口和其实现的测试用例

public class AccumulatorTestCase extends TestCase {
/**
* 测试: AccumulatorTime 实例能否正常实现泛型接口Accumulator<Time24>
*/
public void accumulatorTime(){
AccumulatorTime time=new AccumulatorTime();
time.add(new Time24(8,30));
time.add(new Time24(2,30));
System.out.println(time.getTotal());
}

/**
* 测试: AccumulatorNumber 实例能否正常实现泛型接口Accumulator<Number>
*/
public void accumulatorNumber(){
AccumulatorNumber number=new AccumulatorNumber();
number.add(1.1);
number.add(5);
System.out.println(number.getTotal());
}

}

[b]4.4泛型方法[/b]
我们使用类型参数创建泛型类和接口。使用相同的参数也可以用来创建泛型方法。 我们使用一个简单的示例,求比较两个实参的大小
[quote]方法可以是泛型结构, 这允许你创建用于搜索、排序的范型方法[/quote]
[color=red]4.4.1基本的范型方法[/color]

@SuppressWarnings("unchecked")
public static <T> T max1(T objA, T objB){
if (((Comparable<T>)objA).compareTo(objB)>0)
return objA;
return objB;
}


在泛型方法的java处理中, 类型参数在运行时被传递给方法. 编译器不会验证方法Comparable<T>的类型, 会给出一个警告"uncheck cast". 因此, if语句中需要显示的类型强制转换为Comparable<T>的类型.类型参数在运行时被传递的行为具有其他的影响,即使类型T没有实现T没有实现Comparable接口, 方法max()也可以包含在源代码中. 此时, 编译器会发出一个"classCastException"异常.
* @param <T> 泛型类型T
* @param objA 比较的大小的一个对象
* @param objB 比较的大小的另外一个对象
* @return 最大值
[quote]在max()第一个版本中, 如果类型没有实现Comparable接口,那么会出现一个ClassCastException异常[/quote]
[color=red]4.4.2为泛型类型使用绑定[/color]

public static <T extends Comparable<T>> T max2(T objA,T objB){
if (objA.compareTo(objB)>0)
return objA;
return objB;
}

为泛型类型使用绑定, 为了更好的改进类型检查, 需要编译必须检查类型实参,从而确保这个类型实现Comparable<T>. 通过使用标示符<T extends Comparable<T>>能够完成类型实参的检查. 这个方法min()方式是第二个版本, 类型T必须实现Comparable<T> , 这个借口不能在超类中实现 * @param <T> 泛型类型T
* @param objA 比较的大小的一个对象
* @param objB 比较的大小的另外一个对象
* @return 最大值
[color=darkred]4.4.3泛型和继承一起使用[/color]

public static <T extends Comparable<? super T>> T max3(T objA,T objB){
if (objA.compareTo(objB)>0)
return objA;
return objB;
}

为了处理能够将超类或子类类型作为实参传递给泛型类和方法引入通配符.语法<?>提示类型正在处理的是未知类型

public static <T extends Comparable<? super T>> T fun(T t1,T t2)

[quote] 通配符"?"和绑定"super T" 会指示编译器验证类型T或T的某些超类是否实现了Comparable接口,这个第三个版本,也是最通用的形式.这个方法min()方式是第二个版本, 类型T必须实现Comparable<T> , 这个借口不能在超类中实现[/quote]
4.4.4前面三个方法测试用例:

/**
* 这个第一个版本泛型方法
*/
public void max1() {
int a = 0, b = 1;
System.out.println(GenericUtil.max(a, b));// Output:1(b)

Integer a1 = -5, b2 = 5;
System.out.println(GenericUtil.max(a1, b2));// Output:5(b2)

String s1 = "abc", s2 = "bbc";
System.out.println(GenericUtil.max(s1, s2));// Output:bbc(s2)

String s3 = "abc", s4 = "abb";
System.out.println(GenericUtil.max(s3, s4));// Output:abc(s3)

// Error: java.lang.ClassCastException: ds.demo.Rectange cannot be cast
// to java.lang.Comparable
// 因为Rectange没有Comparable<T>接口给objA强制转换类型时, 抛出异常
System.out.println(GenericUtil.max1(new Rectange(5, 4), new Rectange(5,
4)));
}

/**
* 这个第二个版本泛型方法
*/
public void max2() {
String s1 = "abc", s2 = "bbc";
System.out.println(GenericUtil.min(s1, s2));// Output:abc(s1)


//如果两个实参没有实现Comparable<T>编译器报错:Bound mismatch
System.out.println(GenericUtil.max2(new Employee("liao", "123-45-678"), new Employee("sun",
"123-55-678"))); //Employee= liao \n SSN= 123-45-678
}
/**
* 这个第三个版本泛型方法
*
*测试: GenericUtil#<T> boolean equals(T, T)方法
*
*通配符"?"和绑定"super T" 会指示编译器验证类型T或T的某些超类是否实现了Comparable接口,这个第三个版本,也是最通用的形式.这个方法min()方式是第二个版本,
* 类型T必须实现Comparable<T> , 这个借口不能在超类中实现
*/
public void max3() {
String s1 = "abc", s2 = "bbc";
System.out.println(GenericUtil.equals(s1, s2));// Output:abb(s2)


//如果两个实参没有实现Comparable<T>编译器报错:Bound mismatch
System.out.println(GenericUtil.max3(new Employee("liao", "123-45-678"), new HourlyEmployee("sun",
"123-55-678",7.8,8.2))); //Employee= liao \n SSN= 123-45-678

System.out.println("**************************");
System.out.println(GenericUtil.equals( new HourlyEmployee("sun",
"123-55-678",7.8,8.2),new SalaryEmployee("liao", "123-45-678",3300.3))); //Employee= liao \n SSN= 123-45-678
}

[b][size=medium]5.我们对泛型的使用的扩展实例[/size][/b]
Entry类具有建字段和值字段的不同实例变量。 这个类的方法允许只访问键字段。不允许访问和更新键字段

public class Entry {
private int key;
private int value;
public Entry(int key, int value){
this.key=key;
this.value=value;
}
public int getKey() {
return key;
}
public int getValue() {
return value;
}
public void setValue(int value) {
this.value = value;
}
public String toString(){
return "key= "+key+" value= "+value;
}
}

修改Entry类, 使其成为一个泛型, 并且储存类型K的变量Key以及类型V的变量value。泛型类型K和V可以不同。 例如K=String,V=Integer。为了在一个类中包括两个泛型类,需要在类名之后放置泛型<K,V>。Entry类实现方equals(Object obj)和Comparable接口

public class Entry<K extends Comparable<? super K>, V> implements
Comparable<Entry<K, V>> {
private K key;
private V value;
public Entry(K key, V value) {
this.key = key;
this.value = value;
}
public K getKey() {
return key;
}
public V getValue() {
return value;
}
public void setValue(V value) {
this.value = value;
}
public String toString() {
return "key= " + key + " value= " + value;
}
@Override
public int compareTo(Entry<K, V> o) {
int keyCompareTo = key.compareTo(o.key);

if (keyCompareTo > 0)
return 1;
else if (keyCompareTo < 0)
return -1;
else
return 0;
}
@SuppressWarnings("unchecked")
public boolean equals(Object o){
if(o instanceof Entry)
if(key.compareTo(((Entry<K, V>)o).key)==0)
return true;
return false;
}
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值