FunTester 泛型类的正确用法

FunTester · 2020年10月21日 · 435 次阅读

在准备下次直播Java基础的内容中,偶然看到Java泛型这个知识点,突然有了点想法,之前一直纠结的一个问题有了解答的思路。

问题:我在多线程任务基类中定义了一个泛型T的对象t,但是一直没有找到一个特别合适的发光点,感觉跟重新写一个内部类差别不大,偶尔在匿名类中使用,非但没有更加灵活,反而衍生出一些其他多线程锁的问题。

具体代码如下:

完整的代码地址:https://github.com/JunManYuanLong/FunTester


public abstract class ThreadBase<T> extends SourceCode implements Runnable {

····省略代码···
    /**
     * 用于设置访问资源,用于闭包中无法访问包外实例对象的情况
     * @since 2020年10月19日,统一用来设置HTTPrequestbase对象.同样可以用于执行SQL和redis查询语句或者对象,暂未使用dubbo尝试
     */
    public T t;

这个t对象在之前唯一用到的地方就是在标记执行任务的时候用到,把生成的标记(通常是String类型)赋值到t中,然后在接下来的过程中访问。但是也仅仅是多了一个存储的地方,实际上标记对象的方法会把标记返回。

突然想到的解决之道是,在除去几种基本类型的多线程任务类(多位abstract类)属性意外,针对需要引入新的属性的实践任务类,例如RequestThreadTimeUpdateSqlThread等多线程任务类中,额外的属性对象就可以用这个泛型T代替。

突觉自己以前走了很多弯路,对泛型的掌握和应用太浅薄,说干就干了,马上对现有的性能测试框架中的abstract类和实现类都改一遍。

这里取RequestThreadTimes为例分享一下代码,有兴趣的同学可以在GitHub上看到我的提交记录,对比一下前后的修改。

package com.fun.frame.thead;

import com.fun.base.constaint.ThreadLimitTimesCount;
import com.fun.base.interfaces.MarkThread;
import com.fun.frame.httpclient.FanLibrary;
import com.fun.frame.httpclient.FunRequest;
import com.fun.frame.httpclient.GCThread;
import org.apache.http.client.methods.HttpRequestBase;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * http请求多线程类
 */
public class RequestThreadTimes<T extends HttpRequestBase> extends ThreadLimitTimesCount<HttpRequestBase> {

    static Logger logger = LoggerFactory.getLogger(RequestThreadTimes.class);

    /**
     * 单请求多线程多次任务构造方法
     *
     * @param request 被执行的请求
     * @param times   每个线程运行的次数
     */
    public RequestThreadTimes(HttpRequestBase request, int times) {
        super(request, times, null);
    }

    /**
     * 应对对每个请求进行标记的情况
     *
     * @param request
     * @param times
     * @param mark
     */
    public RequestThreadTimes(HttpRequestBase request, int times, MarkThread mark) {
        super(request, times, mark);
    }

    protected RequestThreadTimes() {
        super();
    }

    @Override
    public void before() {
        super.before();
        GCThread.starts();
    }

    /**
     * @throws Exception
     */
    @Override
    protected void doing() throws Exception {
        FanLibrary.executeSimlple(t);
    }

    @Override
    public RequestThreadTimes clone() {
        RequestThreadTimes threadTimes = new RequestThreadTimes();
        threadTimes.times = this.times;
        threadTimes.t = FunRequest.cloneRequest(t);
        threadTimes.mark = mark == null ? null : mark.clone();
        return threadTimes;
    }


}

关于类名那一行,我尝试了很多中办法,包括public class RequestThreadTimes<T extends HttpRequestBase> extends ThreadLimitTimesCount<HttpRequestBase> {public class RequestThreadTimes<T> extends ThreadLimitTimesCount<HttpRequestBase> {public class RequestThreadTimes extends ThreadLimitTimesCount<HttpRequestBase> {public class RequestThreadTimes<HttpRequestBase> extends ThreadLimitTimesCount<HttpRequestBase> {,然后报出了各种错误,最终我选择了第一种写法,据我粗浅的尝试,被继承的父类中T可以声明成为HttpRequestBase类,然后在代码中关于父类的操作,如super(request, times, mark);中是可以成立的,然后在本类名后面的泛型不能声明对象,只能用<T extends HttpRequestBase>限制创建对象是声明泛型的上限。

这里还涉及到一个标记方法中类型转化的修改,如下:

@Override
public String mark(ThreadBase threadBase) {
    if (threadBase instanceof RequestThreadTime) {
        RequestThreadTime<HttpRequestBase> req = (RequestThreadTime<HttpRequestBase>) threadBase;
        return mark(req.t);
    } else if (threadBase instanceof RequestThreadTimes) {
        RequestThreadTimes<HttpRequestBase> req = (RequestThreadTimes<HttpRequestBase>) threadBase;
        return mark(req.t);
    } else {
        ParamException.fail(threadBase.getClass().toString());
    }
    return EMPTY;
}

公众号FunTester首发,原创分享爱好者,腾讯云、开源中国和掘金社区首页推荐,知乎八级强者,欢迎关注、交流,禁止第三方擅自转载。

FunTester 热文精选

如果觉得我的文章对您有用,请随意打赏。您的支持将鼓励我继续创作!
暂无回复。
需要 登录 后方可回复, 如果你还没有账号请点击这里 注册