我的编程空间,编程开发者的网络收藏夹
学习永远不晚

Java调用第三方接口封装实现

短信预约 -IT技能 免费直播动态提醒
省份

北京

  • 北京
  • 上海
  • 天津
  • 重庆
  • 河北
  • 山东
  • 辽宁
  • 黑龙江
  • 吉林
  • 甘肃
  • 青海
  • 河南
  • 江苏
  • 湖北
  • 湖南
  • 江西
  • 浙江
  • 广东
  • 云南
  • 福建
  • 海南
  • 山西
  • 四川
  • 陕西
  • 贵州
  • 安徽
  • 广西
  • 内蒙
  • 西藏
  • 新疆
  • 宁夏
  • 兵团
手机号立即预约

请填写图片验证码后获取短信验证码

看不清楚,换张图片

免费获取短信验证码

Java调用第三方接口封装实现

介绍

在Java项目中,会遇到很多调用第三方接口的地方,比如接入微信,其他公司的系统,需要传token或者签名。由于接入调用接口很多,每个接口内部都需要手动设置token或者其他数据,这就显得很麻烦。而且发送http请求还需要自己创建request对象。下面介绍2中封装方式,

一、利用feign功能封装请求,所有接口和服务之间调用是一样的,只需要执行后面的url,参数类,请求方式等。内部需要传输的token信息,在自定的拦截器中设置,自定义的拦截器需要实现RequestInterceptor接口。在这里面设置公共的请求参数。比较推荐的。

二、自己封装一个通用的请求类,里面自己创建Request对象,发送完http请求之后拿到返回的json对象在封装返回类,借助于ObjectMapper类。

一、借助feign实现调用

写一个feign的接口调用类,因为调用服务和接收服务不在一个注册中心,所以需要指定url,并实现拦截器

自定义的feign接口

import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
 
@FeignClient(
    url = "${e-sign.apiHost}",        // 这个值在配置文件中配置好
    value = "authFeign"               // 这个是自定义的服务名称,没有用
)
@RequestMapping(
    headers = {"X-Tsign-Open-Auth-Mode=Signature"}    // 设置请求的header
)
public interface EAuthFeign {
    
// 写封装的参数和请求路径
    @PostMapping({"/v3/oauth2/index"})
    EResponse<String> applyAuth(@RequestBody EApplyAuthDTO params);
}

配置文件内容

e-sign:
  projectId: 111111
  projectSecret: fasdfads
  apiHost: https://ss.sign.cn
  callbackHost: https://call.baidu.com
  redirectHost: https://web.baidu.com

自定义拦截器,这个是feign的拦截器,只需要标记被扫描到就行,会自动加载。写了这个类后,这个类所在的项目所有的feign都会被这个拦截器控制

import common.exception.E;
import esign.config.ESignConfig;
import feign.RequestInterceptor;
import feign.RequestTemplate;
import java.net.URLDecoder;
import java.nio.charset.StandardCharsets;
import java.security.InvalidKeyException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Collection;
import java.util.Map;
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import sun.misc.BASE64Encoder;
 
@Component
public class EAuthFeignRequestInterceptor implements RequestInterceptor {
    private static final Logger log = LoggerFactory.getLogger(EAuthFeignRequestInterceptor.class);
    @Autowired
    private ESignConfig eSignConfig;
    private static final BASE64Encoder encodeBase64 = new BASE64Encoder();
 
    public EAuthFeignRequestInterceptor() {
    }
 
    public void apply(RequestTemplate template) {
        String host = this.eSignConfig.getApiHost();
        String url = template.url();
        String target = template.feignTarget().url();
        boolean b = target.equals(host);
// 这个判断就是为了防止所有的feign都走这个拦截器,限制只有第三方接口才能进入下面的逻辑
        if (b) {
            template.header("X-Tsign-Open-App-Id", new String[]{this.eSignConfig.getProjectId()});
            Map<String, Collection<String>> headers = template.headers();
            Collection<String> authMode = (Collection)headers.get("X-Tsign-Open-Auth-Mode");
            boolean isSign = authMode != null && authMode.contains("Signature");
            if (isSign) {
                template.header("X-Tsign-Open-Ca-Timestamp", new String[]{String.valueOf(System.currentTimeMillis())});
                template.header("Accept", new String[]{"**", contentMD5, "application/json;charset=UTF-8", "", "", url);
        log.info("接口,url:{}, 签名字符串:{}", url, message);
        String reqSignature = doSignatureBase64(message, this.eSignConfig.getProjectSecret());
        template.header("Content-MD5", new String[]{contentMD5});
        template.header("X-Tsign-Open-Ca-Signature", new String[]{reqSignature});
    }
 
    private static String doContentMD5(byte[] body) {
        if (body == null) {
            return "";
        } else {
            byte[] md5Bytes = null;
            MessageDigest md5 = null;
            String contentMD5 = null;
 
            try {
                md5 = MessageDigest.getInstance("MD5");
                md5.update(body);
                byte[] md5Bytes = md5.digest();
                contentMD5 = encodeBase64.encode(md5Bytes);
                return contentMD5;
            } catch (NoSuchAlgorithmException var5) {
                log.error("不支持此算法", var5);
                throw new E("不支持此算法");
            }
        }
    }
 
    private static String doSignatureBase64(String message, String secret) {
        String algorithm = "HmacSHA256";
        String digestBase64 = null;
 
        try {
            Mac hmacSha256 = Mac.getInstance(algorithm);
            byte[] keyBytes = secret.getBytes(StandardCharsets.UTF_8);
            byte[] messageBytes = message.getBytes(StandardCharsets.UTF_8);
            hmacSha256.init(new SecretKeySpec(keyBytes, 0, keyBytes.length, algorithm));
            byte[] digestBytes = hmacSha256.doFinal(messageBytes);
            digestBase64 = encodeBase64.encode(digestBytes);
            return digestBase64;
        } catch (NoSuchAlgorithmException var8) {
            log.error("不支持此算法", var8);
            throw new E("不支持此算法");
        } catch (InvalidKeyException var9) {
            log.error("无效的密钥规范", var9);
            throw new E("无效的密钥规范");
        }
    }
 
    private static String appendSignDataString(String method, String accept, String contentMD5, String contentType, String date, String headers, String url) {
        StringBuilder sb = new StringBuilder();
        sb.append(method).append("\n").append(accept).append("\n").append(contentMD5).append("\n").append(contentType).append("\n").append(date).append("\n");
        if ("".equals(headers)) {
            sb.append(headers).append(url);
        } else {
            sb.append(headers).append("\n").append(url);
        }
 
        return new String(sb);
    }
}

配置类

@Configuration
@ConfigurationProperties(
    prefix = "e-sign"
)
public class ESignConfig {
    private static final Logger log = LoggerFactory.getLogger(ESignConfig.class);
    private String projectId;
    private String projectSecret;
    private String apiHost;
    private String callbackHost;
    private String redirectHost;
}

上边几个类就可以封装对外请求了。自己服务根据要求可以另外处理

二、自己封装请求类

通用请求返回结果类

package com.service;
 
import com.alibaba.fastjson.JSONObject;
import com.common.dto.coop.HttpDTO;
import com.common.vo.coop.ThirdResultVO;
import com.cooperation.generator.ThirdTokenGenerator;
import com.cooperation.template.TokenTemplate;
import lombok.extern.slf4j.Slf4j;
import okhttp3.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.Assert;
 
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.Objects;
import java.util.concurrent.TimeUnit;
 

@Slf4j
@Service
public class HttpService2 {
 
    @Autowired
    private TokenTemplate tokenTemplate;
 
    
    public ThirdResultVO getInterfaceResult(HttpDTO param) {
 
        // 参数转换成json
        JSONObject json = Objects.isNull(param.getObj()) ? new JSONObject()
                : JSONObject.parseObject(JSONObject.toJSONString(param.getObj()));
 
        // 如果需要token,将token放在参数中
        if (param.getNeedToken()) {
 
            String token = tokenTemplate.getToken(new ThirdTokenGenerator());
 
            json.put("token", token);
        }
 
        // 发起请求,获得响应
        Response response = doRequest(param.getUrl(), json);
 
        // 处理返回值
        ThirdResultVO ThirdResult = handleReturn(response);
 
        // 如果为null,响应有问题,不能转成返回值类型
        Assert.notNull(ThirdResult, "接口调用异常");
 
        return ThirdResult;
    }
 
    
    private ThirdResultVO handleReturn(Response response) {
        // 如果响应为空,返回null
        if (Objects.isNull(response)) {
            return null;
        }
 
        try {
            // 如果响应体为空,返回null
            if (Objects.isNull(response.body())) {
                return null;
            }
 
            // 响应体的字节数组
            byte[] bytes = response.body().bytes();
            log.info("调用接口返回数据--:{}", new String(bytes));
            // 转换成返回值类型
            return JSONObject.parseObject(bytes, ThirdResultVO.class);
 
        } catch (Exception e) {
            log.info("处理返回值失败:{}", e.getMessage(), e);
        }
 
        return null;
    }
 
    
    private Response doRequest(String url, JSONObject jsonObject) {
 
        // 获得表单请求对象
        Request formRequest = getFormRequest(url, jsonObject);
 
        // 调用接口 请求入参
        log.info("调用接口请求入参--:url:{} , jsonObject :{}",url, JSONObject.toJSONString(jsonObject));
 
        // 获得okhttp请求工具
        OkHttpClient requestClient = getRequestClient();
 
        // 获得请求调用对象
        Call call = requestClient.newCall(formRequest);
 
        // 发起请求,获得响应
        Response execute = null;
        try {
            execute = call.execute();
        } catch (IOException e) {
            log.info("调用接口失败:{}", e.getMessage(), e);
        }
 
        return execute;
    }
 
    
    private Request getFormRequest(String url, JSONObject jsonObject) {
 
        // 获得请求构造器
        Request.Builder requestBuilder = new Request.Builder();
 
        // 设置表单请求的请求头
        try {
            requestBuilder.addHeader("content-type", "application/x-www-form-urlencoded").post(getFormBody(jsonObject)).url(new URL(url));
        } catch (MalformedURLException e) {
            log.info("url转换失败:{}", e.getMessage(), e);
        }
 
        // 返回请求对象
        return requestBuilder.build();
    }
 
    
    private OkHttpClient getRequestClient() {
        return new OkHttpClient.Builder()
                .readTimeout(2L, TimeUnit.MINUTES)
                .build();
    }
 
    
    private FormBody getFormBody(JSONObject jsonObject) {
 
        // 获取表单请求构造器
        FormBody.Builder fb = new FormBody.Builder();
 
        // 设置请求参数
        jsonObject.keySet().forEach(item -> fb.addEncoded(item, jsonObject.getString(item)));
 
        // 返回body
        return fb.build();
    }
}

通用请求参数类

@Data
@Accessors(chain = true)
@EqualsAndHashCode(callSuper = false)
public class HttpDTO implements Serializable {
 
    private static final long serialVersionUID = 1L;
 
    @NotNull(message = "请求路径不能为空")
    @NotBlank(message = "请求路径不能为空")
    @ApiModelProperty(value = "请求路径url")
    private String url;
 
    @ApiModelProperty(value = "参数")
    private Object obj;
 
    @NotNull(message = "是否需要token 不能为空")
    @ApiModelProperty(value = "是否需要token:true是,false否")
    private Boolean needToken;
}

请求调用示例

public List<String> getSkuCode(String classifyCode) {
 
        ResultVO interfaceResult = httpService.getInterfaceResult(new HttpDTO()
                .setUrl(Constant.HOST.concat(Constant.GOODS_GET_SKUS_BY_CLASSID_URI))
                .setNeedToken(true)
                .setObj(new DeLiGetSkusByClassId3DTO().setCode(classifyCode3).setIsAll(1)));
 
        log.info(interfaceResult.getResultMessage());
 
        return JSONArray.parseArray(interfaceResult.getResult(), String.class);
    }

上边的请求返回,从结果里取出result字符串,再转一下list,这可以放在后面的请求方法中,传一个返回的类class。使用objectMapper转一下。

private ObjectMapper mapper = new ObjectMapper();
 
public <T, RR> Response<RR> api(ApiDTO<T> jsonParams, Class<RR> responseResult) {
        String json = JSONObject.toJSONString(jsonParams);
        log.info("三方api.do, requestParams:{}", json);
        String responseStr = this.thirdFileAgentFeign.api(json);
        // 构建返回类型
        JavaType javaType1 = this.mapper.getTypeFactory().constructParametricType(YZResponse.class, new Class[]{responseResult});
 
        try {
            // 这个代码块就看这里返回带泛型的类
            return (Response)this.mapper.readValue(responseStr, javaType1);
        } catch (JsonProcessingException e) {
            log.error("反序列化返回值异常, responseStr:{}, errInfo:{}", new Object[]{responseStr, var7.getMessage(), e});
            throw new E("反序列化返回值异常");
        }
    }

第二种返回类型

import com.fasterxml.jackson.core.type.TypeReference;
 
public static <T> T toObj(String json, Class<T> type) {
        try {
            return MAPPER.readValue(json, type);
        } catch (IOException e) {
            log.error("toObj error", e);
            throw E.of(BaseExceptionEnum.FORMAT_ERROR);
        }
    }
 
public static <T> T toObj(String json, TypeReference<T> typeReference) {
        try {
            return mapper.readValue(json, typeReference);
        } catch (IOException e) {
            log.error("toObj error", e);
            throw E.of(BaseExceptionEnum.FORMAT_ERROR);
        }
    }

泛型返回处理可以参考RestTemplate里面的postForObject()

Class<?> deserializationView = ((MappingJacksonInputMessage)inputMessage).getDeserializationView();
                if (deserializationView != null) {
                    // 部分代码,构建一个reader
                    ObjectReader objectReader = this.objectMapper.readerWithView(deserializationView).forType(javaType);
                    if (isUnicode) {
                    // 返回class类型的对象
                        return objectReader.readValue(inputMessage.getBody());
                    }
 
                    Reader reader = new InputStreamReader(inputMessage.getBody(), charset);
                    return objectReader.readValue(reader);
                }

具体可以学习一下ObjectMapper的用法

请求接口返回结果类

@Accessors(chain = true)
@EqualsAndHashCode(callSuper = false)
public class ResultVO implements Serializable {
 
    private static final long serialVersionUID = 1L;
 
    @ApiModelProperty(value = "接口返回成功与否")
    private Boolean success;
 
    @ApiModelProperty(value = "返回数据描述")
    private String resultMessage;
 
    @ApiModelProperty(value = "平台业务代码标记")
    private String resultCode;
 
// 返回的json结果,再处理成返回对象
    @ApiModelProperty(value = "业务数据")
    private String result;
}

三、调用第三方生成token,可以使用策略类实现

策略接口类

public interface TokenGeneratorStrategy {
    
    String getToken();
 
    
    String getTokenCacheKey();
 
    
    Duration getTokenExpireTime();
 
}

获取token的实现类

package com.generator;
 
import com.alibaba.fastjson.JSONObject;
import com.common.constant.ThirdConstant;
import com.common.constant.MallCacheKeyConstant;
import com.common.constant.MallCommonConstant;
import com.common.dto.coop.HttpDTO;
import com.common.vo.coop.ThirdResultVO;
import com.common.vo.coop.ThirdTokenVO;
import com.cooperation.dto.ThirdTokenDTO;
import com.cooperation.service.HttpService;
import com.cooperation.strategy.TokenGeneratorStrategy;
import com.common.exception.E;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.DigestUtils;
 
import java.nio.charset.StandardCharsets;
import java.time.Duration;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.format.DateTimeFormatter;
import java.util.Objects;
 

@Slf4j
@Service
public class ThirdTokenGenerator implements TokenGeneratorStrategy {
 
    @Autowired
    private HttpService httpService;
 
    @Override
    public String getToken() {
 
        // 获取当前时间,转换成yyyy/MM/dd格式
        DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
        String format = LocalDateTime.now().format(dateTimeFormatter);
 
        // 签名规则:client_secret+timestamp+client_id+username+password+scope+client_secret将上面字符串MD5 加密后转为小写。
        String sign = ThirdConstant.CLIENT_SECRET
                .concat(format)
                .concat(ThirdConstant.CLIENT_ID)
                .concat(ThirdConstant.USERNAME)
                .concat(ThirdConstant.PASSWORD)
                .concat(ThirdConstant.CLIENT_SECRET);
 
        // md5 加密
        String signMd5 = DigestUtils.md5DigestAsHex(sign.getBytes(StandardCharsets.UTF_8)).toLowerCase();
 
        ThirdTokenDTO ThirdTokenDto = new ThirdTokenDTO().setClient_id(ThirdConstant.CLIENT_ID).setClient_secret(ThirdConstant.CLIENT_SECRET)
                .setUsername(ThirdConstant.USERNAME).setPassword(ThirdConstant.PASSWORD)
                .setTimestamp(format).setSign(signMd5);
 
        // 接口调用
        ThirdResultVO interfaceResult = httpService.getInterfaceResult(
                new HttpDTO()
                        .setUrl(ThirdConstant.HOST.concat(ThirdConstant.TOKEN_URI))
                        .setObj(ThirdTokenDto)
                        .setNeedToken(false));
 
 
        ThirdTokenVO ThirdToken = new ThirdTokenVO();
        try {
            ThirdToken = JSONObject.parseObject(interfaceResult.getResult(), ThirdTokenVO.class);
        } catch (Exception e) {
            log.info("token 返回值处理异常:{}", e.getMessage(), e);
        }
        if (Objects.isNull(ThirdToken)) {
            log.error("获取三方token为空----{}", interfaceResult);
            throw new E("获取三方token异常信息--" + interfaceResult.getResultMessage());
        }
 
        return ThirdToken.getAccess_token();
    }
 
    @Override
    public String getTokenCacheKey() {
        return MallCacheKeyConstant.COOP_Third_TOKEN + MallCommonConstant.DEFAULT_KEY;
    }
 
    
    @Override
    public Duration getTokenExpireTime() {
 
        // 当前时间到12点的时间
        Duration nowTo12 = Duration.between(LocalDateTime.now(), LocalDateTime.of(LocalDate.now(), LocalTime.MAX));
 
        // 50分钟
        Duration fiftyMin = Duration.ofSeconds(50 * 60L);
 
        // 如果当前时间到12点的时间超过50分钟,返回50分钟
        if (nowTo12.compareTo(fiftyMin) > 0) {
            return fiftyMin;
        }
 
        // 否则返回当前时间到12点的时间
        return nowTo12;
    }
}

总结

到此这篇关于Java调用第三方接口封装实现的文章就介绍到这了,更多相关Java调用第三方接口封装内容请搜索编程网以前的文章或继续浏览下面的相关文章希望大家以后多多支持编程网!

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

Java调用第三方接口封装实现

下载Word文档到电脑,方便收藏和打印~

下载Word文档

猜你喜欢

Java调用第三方接口封装实现

本文主要介绍了Java调用第三方接口封装实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
2023-02-16

Java 中如何实现异步调用第三方接口?(java异步调用第三方接口怎么实现)

在Java开发中,异步调用第三方接口是一个常见的需求,它可以提高系统的性能和响应速度。以下是实现Java异步调用第三方接口的步骤:一、选择异步编程模型Java提供了多种异步编程模型,其中最常用的是线程和异步框架。线程是
Java 中如何实现异步调用第三方接口?(java异步调用第三方接口怎么实现)
Java2024-12-17

java异步调用第三方接口怎么实现

在Java中,可以使用多线程或使用异步框架来实现异步调用第三方接口。1. 使用多线程:可以创建一个新的线程来执行第三方接口的调用操作,这样可以让主线程继续执行其他任务而不需要等待第三方接口的返回结果。可以使用Java的Thread类或者Ex
2023-10-09

Java如何调用第三方接口

这篇“Java如何调用第三方接口”文章的知识点大部分人都不太理解,所以小编给大家总结了以下内容,内容详细,步骤清晰,具有一定的借鉴价值,希望大家阅读完这篇文章能有所收获,下面我们一起来看看这篇“Java如何调用第三方接口”文章吧。一、 通过
2023-07-02

java怎么调用第三方接口

在Java中调用第三方接口通常可以通过使用网络请求的方式来实现。以下是一种基本的方法:使用Java的内置网络请求类,比如HttpURLConnection或者HttpClient来发送HTTP请求到第三方接口的URL。根据第三方接口的要求
java怎么调用第三方接口
2024-03-05

Java怎么调用第三方http接口

Java可以通过以下几种方式调用第三方HTTP接口:1. 使用Java内置的HttpURLConnection类:```javaimport java.io.BufferedReader;import java.io.InputStream
2023-08-17

如何在 JavaWeb 中调用第三方接口?(javaweb怎么调用第三方接口)

在JavaWeb开发中,调用第三方接口是一个常见的需求。通过调用第三方接口,我们可以获取外部服务提供的数据或功能,扩展我们的应用程序。以下是在JavaWeb中调用第三方接口的步骤:一、选择合适的第三方接口在开始调用第三方
如何在 JavaWeb 中调用第三方接口?(javaweb怎么调用第三方接口)
javaweb2024-12-16

javaweb怎么调用第三方接口

调用第三方接口的方法在JavaWeb中与其他Java应用程序相同,可以使用Java的网络编程库来发送HTTP请求并处理响应。以下是一个简单的示例代码,演示如何使用JavaWeb调用第三方接口:```javaimport java.io.Bu
2023-08-23

php如何调用第三方api接口

要调用第三方API接口,可以使用PHP中的curl函数,示例如下:```php// 第三方API的URL$url = 'http://example.com/api';// 请求参数$data = ['param1' => 'value1'
2023-08-30

Java调用第三方http接口的方式总结(四种)

在实际开发过程中,我们经常需要调用对方提供的接口或测试自己写的接口是否合适。很多项目都会封装规定好本身项目的接口规范,所以大多数需要去调用对方提供的接口或第三方接口(短信、天气等) ①通过JDK网络类Java.net.HttpURLConn
2023-08-16

如何使用Feign调用第三方http接口

本篇内容介绍了“如何使用Feign调用第三方http接口”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!Feign调用第三方http接口我们平
2023-06-29

python开发接口怎么让第三方调用

要让第三方调用Python开发的接口,可以采用以下几种方式:1. 使用HTTP协议:Python开发的接口可以通过HTTP协议暴露出来,第三方可以通过发送HTTP请求来调用接口。可以使用Flask、Django等Web框架来搭建接口,并提供
2023-09-28

Java 中如何通过封装实现接口和实现的分离?(Java中封装如何做到接口和实现分离)

在Java编程中,封装是一种重要的面向对象编程原则,它允许我们将数据和操作数据的方法组合在一起,同时隐藏内部实现细节,对外提供简洁的接口。通过封装,我们可以实现接口和实现的分离,提高代码的可维护性、可扩展性和安全性。一、封装的概念
Java 中如何通过封装实现接口和实现的分离?(Java中封装如何做到接口和实现分离)
Java2024-12-18

编程热搜

  • Python 学习之路 - Python
    一、安装Python34Windows在Python官网(https://www.python.org/downloads/)下载安装包并安装。Python的默认安装路径是:C:\Python34配置环境变量:【右键计算机】--》【属性】-
    Python 学习之路 - Python
  • chatgpt的中文全称是什么
    chatgpt的中文全称是生成型预训练变换模型。ChatGPT是什么ChatGPT是美国人工智能研究实验室OpenAI开发的一种全新聊天机器人模型,它能够通过学习和理解人类的语言来进行对话,还能根据聊天的上下文进行互动,并协助人类完成一系列
    chatgpt的中文全称是什么
  • C/C++中extern函数使用详解
  • C/C++可变参数的使用
    可变参数的使用方法远远不止以下几种,不过在C,C++中使用可变参数时要小心,在使用printf()等函数时传入的参数个数一定不能比前面的格式化字符串中的’%’符号个数少,否则会产生访问越界,运气不好的话还会导致程序崩溃
    C/C++可变参数的使用
  • css样式文件该放在哪里
  • php中数组下标必须是连续的吗
  • Python 3 教程
    Python 3 教程 Python 的 3.0 版本,常被称为 Python 3000,或简称 Py3k。相对于 Python 的早期版本,这是一个较大的升级。为了不带入过多的累赘,Python 3.0 在设计的时候没有考虑向下兼容。 Python
    Python 3 教程
  • Python pip包管理
    一、前言    在Python中, 安装第三方模块是通过 setuptools 这个工具完成的。 Python有两个封装了 setuptools的包管理工具: easy_install  和  pip , 目前官方推荐使用 pip。    
    Python pip包管理
  • ubuntu如何重新编译内核
  • 改善Java代码之慎用java动态编译

目录