ssm框架面试题

1. 请简述Java中抽象类和接口有什么区别?

抽象类是被abstract修饰的类, 具备普通类的一切特性,是类的一种增强。
抽象类的作用是在抽象类中提取公共的方法提供子类使用,这些方法可以是抽象的(强制约束),也可以是普通的(扩展),所以抽象就是作为父类使用的。

接口是使用interface修饰的特殊的类型,接口不是类。其特点是不能被实例化,可以被实现,是类的一种弱化。其作用本意是想单纯制定标准使用。在Jdk1.8之前 接口中只有常量和抽象方法, JDK1.8之后增加了default类型、static类型 和java9新增private类型的方法。

区别:
抽象类作为父类可以被子类继承(extends),并且只能是单继承(子类只能有一个父类),可以多重继承(可以有一个继承体系,父类也可以有父类)
接口可以被实现类实现(implements) ,一个接口可以有多个实现类,但是一个实现类可以有多个接口(多个爹),并且接口与接口之间可以使用继承关系且可以支持多继承。

从使用的角度来说:抽象类一般都是设计之初提供公共方法使用,一旦设计完成之后在更改修改就比较麻烦了,这时候我们可以使用接口辅助做增强,同样的抽象方法的都是做标准,抽象类中的标准可以理解就是定死的,接口中的标准可以灵活调度。

抽象类示例

public abstract class Animal {
    int i = 100;

    //构造方法
    public Animal() {
    }
    public abstract void run();
	//普通方法
    public void show(){
        System.out.println("一只尤猪蓬蓬在草原上跳舞");
    }
}

接口

public interface Person extends A,B{
    //public static final 默认省略
    public static final  int i = 100;

    //抽象方法
    public void eat();

    //Java8 default - 和普通方法一样没区别
    public default void study(){
       System.out.println("Person.study");
    }

    //Java8 static类型的方式使用时可以直接Person.ss() 作用:可以作为工具方法使用,和常量一样
    public static void ss(){

    }
    //Java9 新增 private: 私有方法本身只能是自己使用
    //实际这个就是为default类型和static类型抽取方法时使用的。
    private void xx(){}
}
2. Java基本数据类型有哪些?

整型4个: byte 字节(-127 ~ 128) 、short 短整型、 int 整型(默认) 、 long 长整型
浮点2个: float 单精度浮点、 double 双精度浮点 (默认)
特殊2个: char 字符(0~65535) 、 boolean 布尔

3. String、StringBuffer、StringBuild有什么区别?

String字符串常量、是final修饰的类,底层实现是char数据、一旦定义值不可变,使用“”引起来。
StringBuffer 是JDK1.0出现的可变的字符序列,因为方法都添加Synchronized所以线程安全,但效率慢。
StringBuilder 是JDK1.5出现的可变的字符序列,线程不安全,但是效率高。

StringBuffer类原理

public StringBuffer() {
        super(16);
}
public StringBuffer(String str) {
        super(str.length() + 16);
        append(str);
}

从这两个方法中可以看到new StringBuffer()默认char数组的初始化长度为16;
如果new StringBuffer("你好"),默认初始化长度为 16 + 2

public AbstractStringBuilder append(String str) {
        if (str == null)
            return appendNull();
        int len = str.length();
        //方法中判断当前数据是否可以进行追加值
        ensureCapacityInternal(count + len);
        //追加数据
        str.getChars(0, len, value, count);
        count += len;
        return this;
}

扩容的方法为: 规则:原来长度翻倍然后+2

private void ensureCapacityInternal(int minimumCapacity) {
        // 如果数组长度不够 value字符数组 ,copyOf进行扩容
        if (minimumCapacity - value.length > 0) {
            value = Arrays.copyOf(value,
                    newCapacity(minimumCapacity));
        }
}

Stringbuilder的原理和StringBuffer扩容原理是一样的。

关于线程安全问题
StringBuffer

@Override
    public synchronized StringBuffer append(String str) {
        toStringCache = null;
        super.append(str);
        return this;
}

Stringbuilder

@Override
    public StringBuilder append(String str) {
        super.append(str);
        return this;
}

由此可以看出,SpringBuffer添加了线程同步锁,所以在多线程的情况下不会出现线程安全问题,但是这样效率大大降低了,而Stringbuilder就是考虑了效率问题,去掉了synchronized 这样效率高了但是多线程会出问题,实际编程需要程序员根据实际需要考虑哪个。

练习:
手动写一个StringCachePool类,完成字符串缓冲池效果,可以不考虑线程安全问题

/**
 * <p>
 *  StringCachePool 自定义的字符串缓冲类
 * </p>
 */
public final class StringCachePool {

    //字符数组
    private char[] value;

    public StringCachePool(String str) {
        this.value = new char[16 + str.length()];
        append(str);
    }

    public StringCachePool() {
        this("");
    }

    //全局变量记录当前值索引位置
    int count = 0;

    //定义字符串追加的方法
    public void append(String appendStr){
        //判断长度是否够增加的
        if(value.length - count < appendStr.length()){
            //扩容
            value = Arrays.copyOf(value,(value.length << 1) + 2);
        }

        //得到的字符添加到char[]中
        for (int i = 0; i < appendStr.length(); i++) {
          value[count] = appendStr.charAt(i);
          count++;
        }
    }

    public String toString(){
        System.out.println("数组的长度为:"+ value.length);
        return new String(value);
    }

    public static void main(String[] args) {
        StringCachePool sc = new StringCachePool("嘿嘿");
        sc.append("哈哈1");
        sc.append("哈哈2");
        sc.append("哈哈3");
        System.out.println("sc.toString() = " + sc.toString());
    }
}
4.Spring框架中用到了哪些设计模式?
  1. 工厂模式:BeanFactory、ApplicationContext
  2. 单例模式:Spring中的Bean
  3. 代理模式:Spring AOP
  4. 模板方法模式:Spring中以Template结尾的类
  5. 观察者模式:Spring事件驱动模型
  6. 适配器模式: Spring AOP中的AdvisorAdapter Spring MVC中的HandlerAdapter
  7. 装饰器模式:Spring中含有Wrapper和含有Decorator的类
  8. 策略模式:资源访问Resource接口
5. 创建线程有几种方式,分别描述一下
  1. 写一个类继承Thread,覆盖重写run方法
  2. 创建一个Runnable类型的对象,实现run()方法,传入Thread的构造方法中
  3. 实现Callable接口,实现call()方法;
  4. 通过Executor的工具类创建线程池,通过线程池获取线程
6. 事务的四个隔离级别分别是什么?每一个隔离级别会有什么对应的问题?
数据库事务的隔离级别有4种,由低到高分别为Read uncommitted(读未提交) 、Read committed (读已提交)、Repeatable read (重复读)、Serializable (序列化)。读现象是在多个事务并发执行时,在读取数据方面可能碰到的问题。包括脏读、不可重复读、幻读。

脏读:读到了脏数据,即无效数据。

不可重复读:是指在数据库访问中,一个事务内的多次相同查询却返回了不同数据。

幻读:指同一个事务内多次查询返回的结果集不一样,比如增加了行记录。

备注:不可重复读对应的是修改,即update操作。幻读对应的是插入操作。幻读是不可重复读的一种特殊场景。

要想解决脏读、不可重复读、幻读等读现象,那么就需要提高事务的隔离级别。但是随之带来的,
隔离级别越高,并发能力越低。所以,需要根据业务去进行衡量,具体场景应该使用哪种隔离级别。
7.如何设计一个一对一、一对多、多对多数据表请描述一下
  1. 一对多设计: 1的一方的主键在多的一方做外键即可。
  2. 多对多设计:设计中间表,两表的主键分别在中间表做外键。
  3. 一对一设计方案1:
    主表的主键指向到从表的外键上,且声明外键唯一约束,这种方式比较麻烦不推荐
#用户表(主表)
CREATE TABLE `user`  (
  `id` int(0) NOT NULL AUTO_INCREMENT,
  `name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL,
  `sex` int(0) NULL DEFAULT NULL,
  `age` int(0) NULL DEFAULT NULL,
  `id_card` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL,
  `phone` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL,
  `register_time` datetime(0) NULL DEFAULT NULL,
  PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci ROW_FORMAT = Dynamic;

#用户详情表(附表)
DROP TABLE IF EXISTS `user_detail`;
CREATE TABLE `user_detail`  (
  `detail_id` int(0) NOT NULL AUTO_INCREMENT,
  `addr` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL,
  `school` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL,
  `graduate_time` datetime(0) NULL DEFAULT NULL,
  ` school_record` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL,
  `user_id` int(0) NULL DEFAULT NULL,
  PRIMARY KEY (`detail_id`) USING BTREE,
  UNIQUE INDEX `user_id`(`user_id`) USING BTREE,
  CONSTRAINT `user_detail_ibfk_1` FOREIGN KEY (`user_id`) REFERENCES `user` (`id`) ON DELETE RESTRICT ON UPDATE RESTRICT
) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci ROW_FORMAT = Dynamic;


  1. 一对一设计方案2(推荐):主表的主键指向到从表的主键上做外键(从表外键不能自增)。
CREATE TABLE `user_detail`  (
  `detail_id` int(0) NOT NULL,
  `addr` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL,
  `school` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL,
  `graduate_time` datetime(0) NULL DEFAULT NULL,
  ` school_record` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL,
  PRIMARY KEY (`detail_id`) USING BTREE,
  CONSTRAINT `user_detail_ibfk_1` FOREIGN KEY (`detail_id`) REFERENCES `user` (`id`) ON DELETE RESTRICT ON UPDATE RESTRICT
) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci ROW_FORMAT = Dynamic;
8. mybatis #{}和${}有什么区别
  1. #{}为参数占位符,即sql预编译,${}为字符串替换
  2. #{} 预处理时,可以防止sql注入,在sql中的#{}替换为?通过调用PreparedStatement的set方法来赋值, ${}不能防止sql注入,并且是直接替换成变量的值。
  3. #{} 的变量替换是在DBMS(数据库管理系统)中 ${}的变量替换是在DBMS外
  4. ${}方式一般用于传入数据库对象,例如列表和表名。
9. @AutoWired和@Resource的区别
  1. 来源不同:@autowired是Spring定义的注解,@resource是Java定义的规范 。
  2. 依赖查找的顺序不一样:@autowired先会按照type查找,@Resource则会先按照名称查找 。
  3. 支持的参数不一样,@Resource支持多个参数,@autowired只支持一个参数 。
  4. 支持的依赖注入的方式不一样,@autowired属性注入,构造方法注入,
    setter注入都支持,而@Resource不支持构造方法注入 。
  5. 使用idea时提示不一样,当注入的对象是Mapper时,使用@Autowired注解会报错但是不会影响程序的正确运行,使用@Resource注解不会报错。
10. 请简述什么是IOC,并说明在编程时在哪里有IOC的应用?
IOC为控制反转,是Spring框架的核心容器,其主要思想是将对象的控制权移交给SpringIOC容器统一管理。

以Servlet为例,以前控制层调用业务层方法一般都是这样写:

UserService userService = new UserService();

这种方法如果是多并发执行就会出现特别多的对象造成内存压力。

而如果使用SpringIOC容器方式,对象的创建是单例的,不会造成内存压力,我们只需要这样处理即可

@Controller
public class UserController(){
	@AutoWired
	private UserService userService ;
}
11. 简述SpringMVC工作原理

在这里插入图片描述

12. SpringMVC和Spring的常用注解有哪些并说明作用

SpringMVC:

  1. @Controller 在SpringMVC中,controller主要负责处理前端控制器(DispatcherServlet )发过来的请求,经过业务逻辑层处理之后封装层一个model,并将其返回给view进行展示。@controller注解通常用于类上,如果结合Thymeleaf模板使用的话,会返回一个页面。

  2. @RestController,表明返回的是json格式数据。

  3. @RequestMapping 是一个用来处理请求地址映射的注解,它可以用于类上,也可以用于方法上。用于类上的注解会将一个特定请求或者请求模式映射到一个控制器之上,表示类中的所有响应请求的方法都是以该地址作为父路径;方法的级别上注解表示进一步指定到处理方法的映射关系。

  4. @PathVariable @PathVariable 注解主要用来获取 URL 参数,Spring Boot 支持 Restfull 风格的 URL,比如一个 GET 请求携带一个参数 id,我们将 id 作为参数接收,可以使用 @PathVariable 注解。

  5. @RequestParam 注解顾名思义,也是获取请求参数的

  6. @RequestBody RequestBody 注解用于接收前端传来的实体,接收参数也是对应的实体,比如前端通过 JSON 提交传来两个参数 username 和 password,此时我们需要在后端封装一个实体来接收。在传递的参数比较多的情况下,使用 @RequestBody 接收会非常方便。

Spring常用注解:

  1. 声明bean的注解
    @Component:泛指各种组件
    @Controller、@Service、@Repository都可以称为@Component
    @Controller:控制层
    @Service:业务层
    @Repository:数据访问层

  2. 注入bean的注解
    @Autowired:由Spring提供
    @Resource:由JSR-250提供

  3. Java配置类相关注解
    @Configuration:声明当前类为配置类
    @Bean:注解在方法上,声明当前方法的返回值为一个bean,替代xml中的方式
    @ComponentScan:用于对Component进行扫描

  4. 切面(AOP)相关注解,Spring支持AspectJ的注解式切面编程
    @Aspect:声明一个切面
    @After:在方法执行之后执行(方法上)
    @Before:在方法执行之前执行(方法上)
    @Around:在方法执行之前与之后执行(方法上)
    @PointCut:声明切点
    @EnableAspectJAutoProxy:开启Spring对AspectJ代理的支持

  5. @Value注解 获取配置文件属性值

13. mybatis 中ResultMap有哪些属性?并说明作用
id:给当前ResultMap设定唯一名称
type: 设定当前ResultMap类型
autoMapping:自动映射封装信息
extends:继承 父类有的那一部分属性标签(id、result标签)就不用自己写了
14. short s = 5; s = s + 1; 代码是否有错? short s = 5; s += 1; 代码是否有错?
 short s = 5; s = s + 1;  有错误,int 转化short 会发生强制类型转换。
 short s = 5; s += 1;  没有错误,+= 会默认转型。
15. SpringMVC方法中如何实现转发和重定向,请书写一下代码。
public String show(){
	return "redirect:/地址"; //重定向
	return "forward:/地址"; //转发
}
16. 如何使用SpringMVC实现上传功能,请罗列一下具体实现步骤。
  1. 导入依赖:
<dependency>
    <groupId>commons-fileupload</groupId>
    <artifactId>commons-fileupload</artifactId>
    <version>1.3.2</version>
</dependency>
  1. 声明表单属性 enctype="multipart/form-data" 且表单必须post提交
  2. 配置SpringMVC上传控制器
<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
       <!-- <property name="maxUploadSize" value="100000000"></property>-->
    </bean>
  1. 控制层使用MultipartFile xxMultipartFile[] xx 接收

  2. 使用 xx.transferTo(new File(path,newFilename)); 上传

17. SpringMVC有几种返回数据的方式? 请罗列一下。
ModelAndView
Model
Map
@ResponseBody
18. 相比jsp+servlet+jdbc你觉得ssm框架的优势有哪些?
  1. 成本低:Spring框架是企业型开发使用的成熟的开源框架,节省成本。

  2. 节省开发时间,典型的三层结构MVC(模型,视图模型,视图和控制),允许开发人员降低重新开发的复杂的问题,及时更改解决方案。对于敏捷开发的新需求,减少开发时间和成本。

  3. 良好的扩展性:SSM主流技术有强大的用户社区来支持它,所以这个框架是非常具有扩展性的,可根据特殊应用具有良好的可插入性,避免大多数因为技术问题无法实现的功能的困扰。

  4. 以进行修改,以最低的需求。对于流行的新技术或系统的老化,系统可能需要进行重构问题,SSM框架重构的成功率比其他框架要高得多。

  5. 技术比servlet更先进,运行效率也高

19. 请简述Java中== 和 equals 的区别

能比较基本数据类型和引用数据类型,如果是基本数据类型的比较,直接比较值是否相等,如果是引用数据类型,则比较内存地址是否相同。
equals() 方法是Object类中的方法,默认是引用数据类型的比较,方法中默认也是使用==进行内存地址比较的,但是一般我们都使用重写后的方法,以String为例:String重写后默认也是先使用==进行比较,如果内存地址相等返回true,如果不相等,再判断长度之后再转化为char数组进行挨个比较。

使用时,基本数据类型使用 == 引用类型使用.equals()方法。

public boolean equals(Object anObject) {
        if (this == anObject) {
            return true;
        }
        if (anObject instanceof String) {
            String anotherString = (String)anObject;
            int n = value.length;
            if (n == anotherString.value.length) {
                char v1[] = value;
                char v2[] = anotherString.value;
                int i = 0;
                while (n-- != 0) {
                    if (v1[i] != v2[i])
                        return false;
                    i++;
                }
                return true;
            }
        }
        return false;
}
20. 常见运行时异常有哪些,并说明出现的原因(至少写5个)

NullPointerException - 空指针引用异常
ClassCastException - 类型强制转换异常。
IllegalArgumentException - 传递非法参数异常。
ArithmeticException - 算术运算异常
ArrayStoreException - 向数组中存放与声明类型不兼容对象异常
IndexOutOfBoundsException - 下标越界异常
NegativeArraySizeException - 创建一个大小为负数的数组错误异常
NumberFormatException - 数字格式异常
SecurityException - 安全异常
UnsupportedOperationException - 不支持的操作异常

  • 6
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

未系上弦月

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值