获取父类泛型应用

在搭建项目的时候,我们经常会用到如下代码,用于抽取出通用的方法放在父类中。

public abstract class BaseDaoImpl implements BaseDao {
    ....
    protected Class getActualType(){
        Type theType = this.getClass().getGenericSuperClass();//获得泛型父类
        if (theType instanceof ParameterizedType) {
            return (Class)((ParameterizedType)theType).getActualTypeArguments()[0];
        } else {
            return Object.class;
        }
    }
    protected T findById(Integer id) {
       return (T)this.getSession().get(getActualType(),id);
       //这样这个方法就可以被通用
    } 
}

然后再BaseDaoImpl的子类中,比如UserDaoImpl,就直接拥有了findById的方法

public class UserDaoImpl extends BaseDaoImpl implements UserDao {
    ........
}
在BaseDaoImpl的实现类中,我们无法拿到T的具体类型,因为它是个泛型,不可能通过T.class取得我们想要的结果。所以,我们可以在UserDaoImpl调用findById方法的时候,获得泛型父类(BaseDaoImpl),再拿到泛型参数,即可得到User.class。

这里的实现最关键的方法是Type getGenericSuperClass(),如果当前class的父类使用了泛型编程,即是泛型,则返回父类,否则返回Object.class.

我们写一些简单的方法对如上的代码作些解析。

javaGrammar.java是泛型的。

public class JavaGrammar {
    public static void mian(String args[]) {
        Type type1 = JavaGrammar.class.getGenericSuperclass();
        Type type2 = SubJavaGrammar.class.getGenericSuperclass();
        System.out.println(type1);//输出class java.lang.Object
        System.out.println(type2);//输出com.xiao.client.JavaGrammar
        if (type1 instanceof ParameterizedType) {
            System.out.println(((ParameterizedType)type1).getActualTypeArguments()[0]);//没有输出
        }
        if (type2 instanceof ParameterizedType) {
            //如果SubJavaGrammar的父类JavaGrammar是泛型的,我们就可以得到父类中泛型的实际类
            System.out.println(((ParameterizedType)type2).getActualTypeArguments()[0]);//class com.xiao.client.Counter
            System.out.println(((ParameterizedType)type2).getRawType());//class com.xiao.client.JavaGrammar
            System.out.println(((ParameterizedType)type2).getOwnerType());//null
        }
    }

}

它有一个子类SubJavaGrammar.java

public class SubJavaGrammar extends JavaGrammar {

}

Couter.类只是用来明确指定一个Type,即T的类型。

public class Counter {
    //This is a empty class
}

当然,子类要使用父类的泛型特征,才能得到我们想要的结果。

我们再来看如下代码:

public class SubJavaGrammar extends JavaGrammar {
}
如果SubJavaGrammar是如上情况的话,
System.out.println(type2);//输出class com.xiao.client.JavaGrammar
也就是说:实际泛型参数是在执行的时候传过去的。如果在实际执行的时候,并没有将实际类型传过去,那么即便JavaGrammar中写成了

public class JavaGrammar {
    ....
}

我们也是没法拿到Counter类的。这时,type1和type2都不是 ParameterizedType的实例。


附注:

如果要满足抽取通用方法的需求,我们也可以在不使用泛型的情况下实现。思路是采用模板方法,让子类返回实际类。

public abstract class JavaGrammar {
    protected abstract Class getClazz();//获取实体类型的工作交给子类去做
    ....
    public Object findById(Integer id) {
       return this.getSession().get(getClazz(),id);
    }
}

在JavaGrammar的子类SubJavaGrammar

public class SubJavaGrammar extends JavaGrammar {
    public Class getClazz() {
        return User.class;
    }
   ......
}

这样SubJavaGrammar也能直接调用父类的getById方法。只不过还需要自己将Object对象转换为User。















你可能感兴趣的:(java)