相关文章:
1、《夯实JAVA基本之一 —— 泛型详解(1):基本使用》
2、《夯实JAVA基本之一——泛型详解(2):高级进阶》
3、《夯实JAVA基本之二 —— 反射(1):基本类周边信息获取》
4、《夯实JAVA基本之二 —— 反射(2):泛型相关周边信息获取》
5、《夯实JAVA基本之二 —— 反射(3):类内部信息获取》
-
class Point<T> {
-
private T x;
// 表示X坐标
-
private T y;
// 表示Y坐标
-
-
public void setX(T x) {
-
this.x = x;
-
}
-
-
public void setY(T y) {
-
this.y = y;
-
}
-
-
public T getX() {
-
return
this.x;
-
}
-
-
public T getY() {
-
return
this.y;
-
}
-
}
-
-
//使用
-
Point
p1 =
new Point();
-
p1.setX(
new Integer(
100));
-
System.out.println(p1.getX());
首先,我们要知道一点,任何的泛型变量(比如这里的T)都是派生自Object,所以我们在填充泛型变量时,只能使用派生自Object的类,比如String,Integer,Double,等而不能使用原始的变量类型,比如int,double,float等。
private T x;
当然只能调用Object所具有的函数,因为编译器根本不知道T具体是什么类型,只有在运行时,用户给什么类型,他才知道是什么类型。编译器唯一能确定的是,无论什么类型,都是派生自Object的,所以T肯定是Object的子类,所以T是可以调用Object的方法的。
-
public
interface Comparable<T>{
-
public boolean compareTo(T i);
-
}
但如果我们直接利用T的实例来调用compareTo()函数的话,会报错,编译器截图如下:
这是因为,编译器根本无法得知T是继承自Comparable接口的函数。那怎么样才能让编译器知道,T是继承了Comparable接口的类型呢?
这就是类型绑定的作用了。
此定义表示T应该是BoundingType的子类型(subtype)。T和BoundingType可以是类,也可以是接口。另外注意的是,此处的”extends“表示的子类型,不等同于继承。
-
public
interface Comparable<T> {
-
public boolean compareTo(T i);
-
}
-
//添加上extends Comparable之后,就可以Comparable里的函数了
-
public
static
T min(T...a){
-
T smallest = a[
0];
-
for(T item:a){
-
if (smallest.compareTo(item)){
-
smallest = item;
-
}
-
}
-
return smallest;
-
}
这段代码的意思就是根据传进去的T类型数组a,然后调用其中item的compareTo()函数,跟每一项做对比,最终找到最小值。
-
public
class StringCompare implements Comparable<StringCompare> {
-
private String mStr;
-
-
public StringCompare(String string){
-
this.mStr = string;
-
}
-
-
@Override
-
public boolean compareTo(StringCompare str) {
-
if (mStr.length() > str.mStr.length()){
-
return
true;
-
}
-
return
false;
-
}
-
}
在这段代码,大家可能会疑惑为什么把T也填充为StringCompare类型,记得我们上面说的吗:smallest.compareTo(item),smallest和item是同一类型!!所以compareTo的参数必须是与调用者自身是同一类型,所以要把T填充为StringCompare;
-
StringCompare result = min(
new StringCompare(
"123"),
new StringCompare(
"234"),
new StringCompare(
"59897"));
-
Log.d(TAG,
"min:"+result.mStr);
结果如下:
这里有extends接口,我们开篇说过,extends表示绑定,后面的BindingType即可以是接口,也可以是类,下面我们就再举个绑定类的例子。
(3)、实例:绑定类
我们假设,我们有很多种类的水果,需要写一个函数,打印出填充进去水果的名字:
为此,我们先建一个基类来设置和提取名字:
-
class Fruit {
-
private String name;
-
-
public String getName() {
-
return name;
-
}
-
public void setName(String name) {
-
this.name = name;
-
}
-
}
然后写个泛型函数来提取名字:
-
public
static
String getFruitName(T t){
-
return t.getName();
-
}
这里泛型函数的用法就出来了,由于我们已知水果都会继承Fruit基类,所以我们利用
-
class Banana extends Fruit{
-
public Banana(){
-
setName(
"bababa");
-
}
-
}
-
class Apple extends Fruit{
-
public Apple(){
-
setName(
"apple");
-
}
-
}
最后调用:
-
String name_1 = getFruitName(
new Banana());
-
String name_2 = getFruitName(
new Apple());
-
Log.d(TAG,name_1);
-
Log.d(TAG,name_2);
结果如下:
-
public
static
String getFruitName(T t){
-
return t.getName();
-
}
再加深下难度,如果我们有多个泛型,每个泛型都带绑定,那应该是什么样子的呢:
-
public
static
T foo(T a, U b){
-
…………
-
}
大家应该看得懂,稍微讲一下:这里有两个泛型变量T和U,将T与Comparable & Serializable绑定,将U与Runnable绑定。
-
class Point<T> {
-
private T x;
-
private T y;
-
-
public Point(){
-
-
}
-
public Point(T x,T y){
-
this.x = x;
-
this.y = y;
-
}
-
-
public void setX(T x) {
-
this.x = x;
-
}
-
-
public void setY(T y) {
-
this.y = y;
-
}
-
-
public T getX() {
-
return
this.x;
-
}
-
-
public T getY() {
-
return
this.y;
-
}
-
}
这段代码很简单,引入了一个泛型变量T,然后是有两个构造函数,最后分别是利用set和get方法来设置和获取x,y的值。这段代码没什么难度,不再细讲。
-
Point
integerPoint =
new Point(
3,
3);
-
…………
-
Point
floatPoint =
new Point(
4.3f,
4.3f);
-
…………
-
Point
doublePoint =
new Point(
4.3d,
4.90d);
-
…………
-
Point
longPoint =
new Point(
12l,
23l);
-
…………
在这段代码中,我们使用Point
-
Point> point;
-
-
point =
new Point
(
3,
3);
-
point =
new Point
(
4.3f,
4.3f);
-
point =
new Point
(
4.3d,
4.90d);
-
point =
new Point
(
12l,
23l);
在这里,我们首先,利用下面的代码生成一个point实例,注意到,在填充泛型时,用的是?
Point> point;
然后,各种类型的Point实例,都可以赋值给point了:
-
point =
new Point
(
3,
3);
-
point =
new Point
(
4.3f,
4.3f);
-
point =
new Point
(
4.3d,
4.90d);
-
point =
new Point
(
12l,
23l);
这里的?就是无边界通配符。通配符的意义就是它是一个未知的符号,可以是代表任意的类。