java面试题(持续更新)

简介

是笔者面试时所被问到的问题,面试碰到回答不了的技术问题将分享在这,都是鄙人自己收集的答案,可能答案不正确,欢迎指正,内容不定期更新

1.where 和 having的区别

答:
1where在结果返回前时执行,having是在得到结果后执行
2where不能使用聚合函数,having能使用聚合函数 ps:聚合函数=max sum count avg等

2.简述数据库第一范式第二范式第三范式

1.第一范式:存在非主属性对码的部分依赖关系 R(A,B,C) AB是码 C是非主属性 B–>C B决定C C部分依赖于B。如果关系R 中所有属性的值域都是单纯域,那么关系模式R是第一范式的。

那么符合第一模式的特点就有:有主关键字、主键不能为空、主键不能重复,、字段不可以再分。例如:

StudyNo | Name | Sex | Contact

20040901 john Male Email:kkkk@ee.net,phone:222456

20040901 mary famale email:kkk@fff.net phone:123455

以上的表就不符合,第一范式:主键重复(实际中数据库不允许重复的),而且Contact字段可以再分

所以变更为正确的是:

StudyNo | Name | Sex | Email | Phone

20040901 john Male kkkk@ee.net 222456

20040902 mary famale kkk@fff.net 123455

第二范式:存在非主属性对码的传递性依赖 R(A,B,C) A是码 A -->B ,B–>C。如果关系模式R是第一范式的,而且关系中每一个非主属性不部分依赖于主键,称R是第二范式的。所以第二范式的主要任务就是:满足第一范式的前提下,消除部分函数依赖。

StudyNo | Name | Sex | Email | Phone | ClassNo | ClassAddress

01 john Male kkkk@ee.net 222456 200401 A楼2

01 mary famale kkk@fff.net 123455 200402 A楼3

这个表完全满足于第一范式,主键由StudyNo和ClassNo组成,这样才能定位到指定行。但是,ClassAddress部分依赖于关键字(ClassNo-〉ClassAddress,所以要变为两个表:

表一

StudyNo | Name | Sex | Email | Phone | ClassNo

01 john Male kkkk@ee.net 222456 200401

01 mary famale kkk@fff.net 123455 200402

表二

ClassNo | ClassAddress

200401 A楼2

200402 A楼3

3.第三范式

不存在非主属性对码的传递性依赖以及部分性依赖 ,

StudyNo | Name | Sex | Email | bounsLevel | bouns

20040901 john Male kkkk@ee.net 优秀 $1000

20040902 mary famale kkk@fff.net 良 $600

这个完全满足了第二范式,但是bounsLevel和bouns存在传递依赖,更改为:

StudyNo | Name | Sex | Email | bouunsNo

20040901 john Male kkkk@ee.net 1

20040902 mary famale kkk@fff.net 2

bounsNo | bounsLevel | bouns

1 优秀 $1000

2 良 $600

这里可以用bounsNo作为主键,基于两个原因

(1)不要用字符作为主键。可能有人说:如果我的等级一开始就用数值就代替呢?

(2)但是如果等级名称更改了,不叫 1,2 ,3或优、良,这样就可以方便更改,所以一般优先使用与业务无关的字段作为关键字。

一般满足前三个范式就可以避免数据冗余。

3.@autowired和@resource的区别

@resource
来自JSR-250规范定义,默认通过byname去自动装配,其中有name和type两个值
(1)如果同时指定了name和type,则从Spring上下文中找到唯一匹配的bean进行装配,找不到则抛出异常

(2)如果指定了name,则从Spring上下文中查找名称(id)匹配的bean进行装配,找不到则抛出异常

(3)如果指定了type,则从Spring上下文中找到类型匹配的唯一bean进行装配,找不到或找到多个,都抛出异常

(4)如果既没指定name,也没指定type,则自动按照byName方式进行装配。如果没有匹配,则回退为一个原始类型进行匹配,如果匹配则自动装配。
默认按照名称进行装配,名称可以通过name属性进行指定,如果没有指定name属性,当注解写在字段上时,默认取字段名进行名称查找。如果注解写在setter方法上默认取属性名进行装配。当找不到与名称匹配的bean时才按照类型进行装配。但是需要注意的是,如果name属性一旦指定,就只会按照名称进行装配。
@autowired
来自spring的注解,通过bytype的形式去自动装配
默认按类型装配,默认情况下必须要求依赖对象存在,如果要允许null值,可以设置它的required属性为false。如果想使用名称装配可以结合@Qualifier注解进行使用

4.计算机网络的7层按顺序

应用层 应用程序的通信服务 例子:TELNET,HTTP,FTP,NFS,SMTP
表示层 定义数据格式及加密 例子:加密,ASCII等
会话层 如何开始、控制和结束一个会话 例子:RPC,SQL
传输层 选择差错恢复协议还是无差错恢复协议 示例:TCP,UDP,SPX。
网络层 端到端的包传输 IP,IPX
数据链路层 在单个链路上如何传输数据 ATM,FDDI
物理层 是有关传输介质的特性 连接头、帧、帧的使用、电流、编码及光调制等都属于各种物理层规范中的内容

5.怎么重写一个注解

1.添加依赖

<dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-aop</artifactId>
</dependency>

2.新建一个annotation类,annotation类添加如下注解
target注解用来解释注解能用的地方,如下是能用在参数和方法上,想知道更多请自行百度
retention是表明注解所有效的地方,有三种,一般用的是runtime
documented注解表明加入javadoc,我不太了解,应该有和没有都无所谓,加上总没错

public @interface ValidateToken {
}
@Documented
@Target({ElementType.PARAMETER, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)

3.编写一个切面类

package com.dzq.springbootTest.aspect;

import com.dzq.springbootTest.service.TokenService;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

/**
 * @ClassName: TokenAspect
 * @Package: com.dzq.springbootTest.aspect
 * @author: 越
 * @date: 2021/3/31 20:58
 * @Description: Token切面类
 */
@Aspect
@Component
@Slf4j
public class TokenAspect {

//    public static final Logger logger = LoggerFactory.getLogger(TokenAspect.class);
    @Autowired
    public void setTokenService(TokenService tokenService) {
        this.tokenService = tokenService;
    }
    private TokenService tokenService;


    public static final String TOKEN_KEY = "token";

    /**
     * checkUrl,keyUrl,tokenScope是通过Spring的@Value注解来获取配置文件中的配置项
     * @Value 等同于Spring原先的配置模式中的value
     * <bean id="" class="">
     *        <property name="" value="">
     * </bean>
     */
    @Value(value = "${jwt.checkUrl}")
    String checkUrl;

    @Value(value = "${jwt.keyUrl}")
    String keyUrl;

    @Value(value = "${jwt.clientId}")
    String tokenScope;
    //切点表达式 aop横切的是 com.dzq.springbootTest.controller 包下的 任意类 任意方法 任意参数
    @Pointcut("execution(* com.dzq.springbootTest.controller.*.*(..)) &&@annotation(com.dzq.springbootTest.annotation.ValidateToken)")
    public void annotationPointcut() {

    }

    @Before("annotationPointcut()")
    public void beforePointcut(JoinPoint joinPoint) {
        System.out.println("Before");
        // 此处进入到方法前  可以实现一些业务逻辑
    }

    @Around("annotationPointcut()")
    public Object doAround(ProceedingJoinPoint joinPoint) throws Throwable {
        System.out.println("Around");
        MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();
        String[] params = methodSignature.getParameterNames();// 获取参数名称
        Object[] args = joinPoint.getArgs();// 获取参数值
        if (null == params || params.length == 0){
            String mes = "Using Token annotation, the token parameter is not passed, and the parameter is not valid.";
            log.info(mes);
            throw new Exception(mes);
        }
        boolean hasToken = false;
        int index = 0;
        for (int i = 0; i < params.length; i++) {
            if (TOKEN_KEY.equals(params[i])) {
                hasToken = true;
                index = i;
                break;
            }
        }
        if (!hasToken){
            String mes = "The token parameter is not included in the requested parameter, the parameter is not valid.";
            log.info(mes);
            throw new Exception(mes);
        }
        this.checkToken(String.valueOf(args[index]));
        return joinPoint.proceed();
    }

    /**
     * 在切入点return内容之后切入内容(可以用来对处理返回值做一些加工处理)
     * @param joinPoint 切点
     */
    @AfterReturning("annotationPointcut()")
    public void doAfterReturning(JoinPoint joinPoint) {
        System.out.println("AfterReturning");
    }

    private void checkToken(String token) {
//        Decrypt decrypt = new Decrypt();// 这个类是自己的业务类,主要进行token验证(JWT)
        try {
            tokenService.checkToken(token, checkUrl, keyUrl, tokenScope);
        } catch (Exception e) {
            log.info(e.getMessage());
            throw new RuntimeException(e.getMessage());
        }
    }

}

5.使用注解

/**
 * @ApiIgnore 该注解表示,swagger2在生成文档的时候,忽略该方法或类。
 */
@ApiIgnore
@ValidateToken
@RequestMapping("getmessage")
public Response<User> getmessage(){
    return Response.success("获取信息成功");
}

6.字节流和字符流的区别

1.字节流操作的基本单元为字节;字符流操作的基本单元为Unicode码元。
2.字节流默认不使用缓冲区;字符流使用缓冲区,并且使用flush()方法将缓冲区内容写到硬盘。
3.字节流通常用于处理二进制数据,实际上它可以处理任意类型的数据,但它不支持直接写入或读取Unicode码元;字符流通常处理文本数据,它支持写入及读取Unicode码元。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值