IDEA插件easycode模板-无代码生成表CURD代码

标题

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档

文章目录

  • 安装
  • 修改生成模板
  • controller
    • 分页查询示例
    • 生成效果
    • 模板
  • dao
    • 生成效果
    • 模板
  • mapper
    • 生成效果
    • 模板
  • pom依赖
  • 开始生成
    • 1.选择数据库,点击生成按钮
    • 选择要生成的内容


安装

点击IDEA插件下载easycode
IDEA插件easycode模板-无代码生成表CURD代码_第1张图片

修改生成模板

CURD可以说是编程最重要也是最繁琐的事情,使用IDEA的EasyCode插件,可以帮助我们不用一行代码,就生成controller、service、dao、mapper文件。但是easycode的默认模板存在很多问题,以下是我完善修改后的模板,解决了默认模板的很多bug,生成代码后可以直接运行。
安装好easycode,在setting里设置模板
IDEA插件easycode模板-无代码生成表CURD代码_第2张图片

controller

分页查询示例

IDEA插件easycode模板-无代码生成表CURD代码_第3张图片

生成效果

package com.mabo.controller;

import com.alibaba.fastjson.JSONObject;
import org.springframework.web.bind.annotation.*;
import com.mabo.entity.User;
import com.mabo.service.UserService;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.http.ResponseEntity;
import javax.annotation.Resource;

/**
 * (User)表控制层
 *
 * @author makejava
 * @since 2023-05-30 01:34:08
 */
@RestController
@RequestMapping("user")
public class UserController {
    /**
     * 服务对象
     */
    @Resource
    private UserService userService;

    /**
     * 分页查询
     *
     *  page      页数0开始
     *  size      分页size
     * @return 查询结果
     */
    @PostMapping("queryByPage")
    public ResponseEntity<Page<User>> queryByPage(@RequestBody JSONObject param) {
        JSONObject json = param.getJSONObject("user");
        User user = json.toJavaObject(User .class);
        Integer size = param.getInteger("size");
        Integer page = param.getInteger("page");
        PageRequest pageRequest= PageRequest.of
                (page, size);
        return ResponseEntity.ok(this.userService.queryByPage(user, pageRequest));
    }

    /**
     * 通过主键查询单条数据
     *
     * @param id 主键
     * @return 单条数据
     */
    @PostMapping("queryById")
    public ResponseEntity<User> queryById(@RequestParam Integer id) {
        return ResponseEntity.ok(this.userService.queryById(id));
    }
    /**
     * 新增数据
     *
     * @param user 实体
     * @return 新增结果
     */
    @PostMapping("add")
    public ResponseEntity<User> add(@RequestBody User user) {
        return ResponseEntity.ok(this.userService.insert(user));
    }

    /**
     * 编辑数据
     *
     * @param user 实体
     * @return 编辑结果
     */
    @PostMapping("edit")
    public ResponseEntity<User> edit(@RequestBody User user) {
        return ResponseEntity.ok(this.userService.update(user));
    }

    /**
     * 删除数据
     *
     * @param id 主键
     * @return 删除是否成功
     */
    @PostMapping("deleteById")
    public ResponseEntity<Boolean> deleteById(@RequestParam Integer id) {
        return ResponseEntity.ok(this.userService.deleteById(id));
    }

}



模板

##定义初始变量
#set($tableName = $tool.append($tableInfo.name, "Controller"))
##设置回调
$!callback.setFileName($tool.append($tableName, ".java"))
$!callback.setSavePath($tool.append($tableInfo.savePath, "/controller"))
##拿到主键
#if(!$tableInfo.pkColumn.isEmpty())
    #set($pk = $tableInfo.pkColumn.get(0))
#end

#if($tableInfo.savePackageName)package $!{tableInfo.savePackageName}.#{end}controller;

import com.alibaba.fastjson.JSONObject;
import org.springframework.web.bind.annotation.*;
import $!{tableInfo.savePackageName}.entity.$!{tableInfo.name};
import $!{tableInfo.savePackageName}.service.$!{tableInfo.name}Service;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.http.ResponseEntity;
import javax.annotation.Resource;

/**
 * $!{tableInfo.comment}($!{tableInfo.name})表控制层
 *
 * @author $!author
 * @since $!time.currTime()
 */
@RestController
@RequestMapping("$!tool.firstLowerCase($tableInfo.name)")
public class $!{tableName} {
    /**
     * 服务对象
     */
    @Resource
    private $!{tableInfo.name}Service $!tool.firstLowerCase($tableInfo.name)Service;

    /**
     * 分页查询
     *
     *  page      页数0开始
     *  size      分页size
     * @return 查询结果
     */
    @PostMapping("queryByPage")
    public ResponseEntity<Page<$tableInfo.name>> queryByPage(@RequestBody JSONObject param) {
        JSONObject json = param.getJSONObject("$!{tool.firstLowerCase($tableInfo.name)}");
        $tableInfo.name $!{tool.firstLowerCase($tableInfo.name)} = json.toJavaObject($tableInfo.name .class);
        Integer size = param.getInteger("size");
        Integer page = param.getInteger("page");
        PageRequest pageRequest= PageRequest.of
                (page, size);
        return ResponseEntity.ok(this.$!{tool.firstLowerCase($tableInfo.name)}Service.queryByPage($!{tool.firstLowerCase($tableInfo.name)}, pageRequest));
    }

    /**
     * 通过主键查询单条数据
     *
     * @param id 主键
     * @return 单条数据
     */
    @PostMapping("queryById")
    public ResponseEntity<$!{tableInfo.name}> queryById(@RequestParam $!pk.shortType id) {
        return ResponseEntity.ok(this.$!{tool.firstLowerCase($tableInfo.name)}Service.queryById(id));
    }
    /**
     * 新增数据
     *
     * @param $!{tool.firstLowerCase($tableInfo.name)} 实体
     * @return 新增结果
     */
    @PostMapping("add")
    public ResponseEntity<$!{tableInfo.name}> add(@RequestBody $!{tableInfo.name} $!{tool.firstLowerCase($tableInfo.name)}) {
        return ResponseEntity.ok(this.$!{tool.firstLowerCase($tableInfo.name)}Service.insert($!{tool.firstLowerCase($tableInfo.name)}));
    }

    /**
     * 编辑数据
     *
     * @param $!{tool.firstLowerCase($tableInfo.name)} 实体
     * @return 编辑结果
     */
    @PostMapping("edit")
    public ResponseEntity<$!{tableInfo.name}> edit(@RequestBody $!{tableInfo.name} $!{tool.firstLowerCase($tableInfo.name)}) {
        return ResponseEntity.ok(this.$!{tool.firstLowerCase($tableInfo.name)}Service.update($!{tool.firstLowerCase($tableInfo.name)}));
    }

    /**
     * 删除数据
     *
     * @param id 主键
     * @return 删除是否成功
     */
    @PostMapping("deleteById")
    public ResponseEntity<Boolean> deleteById(@RequestParam $!pk.shortType id) {
        return ResponseEntity.ok(this.$!{tool.firstLowerCase($tableInfo.name)}Service.deleteById(id));
    }

}


dao

生成效果

package com.mabo.dao;

import com.mabo.entity.User;
import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.Mapper;
import org.springframework.data.domain.Pageable;
import java.util.List;

/**
 * (User)表数据库访问层
 *
 * @author makejava
 * @since 2023-05-30 01:34:08
 */
@Mapper
public interface UserDao {

    /**
     * 通过ID查询单条数据
     *
     * @param id 主键
     * @return 实例对象
     */
    User queryById(Integer id);

    /**
     * 查询指定行数据
     *
     * @param user 查询条件
     * @param pageable         分页对象
     * @return 对象列表
     */
    List<User> queryAllByLimit(@Param("user") User user, @Param("pageable") Pageable pageable);

    /**
     * 统计总行数
     *
     * @param user 查询条件
     * @return 总行数
     */
    long count(User user);

    /**
     * 新增数据
     *
     * @param user 实例对象
     * @return 影响行数
     */
    int insert(User user);

    /**
     * 批量新增数据(MyBatis原生foreach方法)
     *
     * @param entities List 实例对象列表
     * @return 影响行数
     */
    int insertBatch(@Param("entities") List<User> entities);

    /**
     * 批量新增或按主键更新数据(MyBatis原生foreach方法)
     *
     * @param entities List 实例对象列表
     * @return 影响行数
     * @throws org.springframework.jdbc.BadSqlGrammarException 入参是空List的时候会抛SQL语句错误的异常,请自行校验入参
     */
    int insertOrUpdateBatch(@Param("entities") List<User> entities);

    /**
     * 修改数据
     *
     * @param user 实例对象
     * @return 影响行数
     */
    int update(User user);

    /**
     * 通过主键删除数据
     *
     * @param id 主键
     * @return 影响行数
     */
    int deleteById(Integer id);

}



模板

##定义初始变量
#set($tableName = $tool.append($tableInfo.name, "Dao"))
##设置回调
$!callback.setFileName($tool.append($tableName, ".java"))
$!callback.setSavePath($tool.append($tableInfo.savePath, "/dao"))

##拿到主键
#if(!$tableInfo.pkColumn.isEmpty())
    #set($pk = $tableInfo.pkColumn.get(0))
#end

#if($tableInfo.savePackageName)package $!{tableInfo.savePackageName}.#{end}dao;

import $!{tableInfo.savePackageName}.entity.$!{tableInfo.name};
import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.Mapper;
import org.springframework.data.domain.Pageable;
import java.util.List;

/**
 * $!{tableInfo.comment}($!{tableInfo.name})表数据库访问层
 *
 * @author $!author
 * @since $!time.currTime()
 */
@Mapper
public interface $!{tableName} {

    /**
     * 通过ID查询单条数据
     *
     * @param $!pk.name 主键
     * @return 实例对象
     */
    $!{tableInfo.name} queryById($!pk.shortType $!pk.name);

    /**
     * 查询指定行数据
     *
     * @param $!tool.firstLowerCase($!{tableInfo.name}) 查询条件
     * @param pageable         分页对象
     * @return 对象列表
     */
    List<$!{tableInfo.name}> queryAllByLimit(@Param("$!tool.firstLowerCase($!{tableInfo.name})") $!{tableInfo.name} $!tool.firstLowerCase($!{tableInfo.name}), @Param("pageable") Pageable pageable);

    /**
     * 统计总行数
     *
     * @param $!tool.firstLowerCase($!{tableInfo.name}) 查询条件
     * @return 总行数
     */
    long count($!{tableInfo.name} $!tool.firstLowerCase($!{tableInfo.name}));

    /**
     * 新增数据
     *
     * @param $!tool.firstLowerCase($!{tableInfo.name}) 实例对象
     * @return 影响行数
     */
    int insert($!{tableInfo.name} $!tool.firstLowerCase($!{tableInfo.name}));

    /**
     * 批量新增数据(MyBatis原生foreach方法)
     *
     * @param entities List<$!{tableInfo.name}> 实例对象列表
     * @return 影响行数
     */
    int insertBatch(@Param("entities") List<$!{tableInfo.name}> entities);

    /**
     * 批量新增或按主键更新数据(MyBatis原生foreach方法)
     *
     * @param entities List<$!{tableInfo.name}> 实例对象列表
     * @return 影响行数
     * @throws org.springframework.jdbc.BadSqlGrammarException 入参是空List的时候会抛SQL语句错误的异常,请自行校验入参
     */
    int insertOrUpdateBatch(@Param("entities") List<$!{tableInfo.name}> entities);

    /**
     * 修改数据
     *
     * @param $!tool.firstLowerCase($!{tableInfo.name}) 实例对象
     * @return 影响行数
     */
    int update($!{tableInfo.name} $!tool.firstLowerCase($!{tableInfo.name}));

    /**
     * 通过主键删除数据
     *
     * @param $!pk.name 主键
     * @return 影响行数
     */
    int deleteById($!pk.shortType $!pk.name);

}


mapper

生成效果

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.mabo.dao.UserDao">

    <resultMap id="BaseResultMap" type="com.mabo.entity.User">
        <!--@Table user-->
        <result property="id" column="id" jdbcType="INTEGER"/>
        <result property="name" column="name" jdbcType="VARCHAR"/>
        <result property="pwd" column="pwd" jdbcType="VARCHAR"/>
    </resultMap>

    <!--查询单个-->
    <select id="queryById" resultMap="BaseResultMap">
        select
          id, name, pwd
        from user
        where id = #{id}
    </select>

    <!--查询指定行数据-->
    <select id="queryAllByLimit" resultMap="BaseResultMap">
        select
          id, name, pwd
        from user
        <where>
            <if test="user.id != null">
                and id = #{user.id}
            </if>
            <if test="user.name != null and user.name != ''">
                and name = #{user.name}
            </if>
            <if test="user.pwd != null and user.pwd != ''">
                and pwd = #{user.pwd}
            </if>
        </where>
        limit #{pageable.offset}, #{pageable.pageSize}
    </select>
    <!--通过实体作为筛选条件查询-->
    <select id="queryAll" resultMap="BaseResultMap">
        select
          id, name, pwd
        from user
     </select>
    <!--统计总行数-->
    <select id="count" resultType="java.lang.Long">
        select count(1)
        from user
        <where>
            <if test="id != null">
                and id = #{id}
            </if>
            <if test="name != null and name != ''">
                and name = #{name}
            </if>
            <if test="pwd != null and pwd != ''">
                and pwd = #{pwd}
            </if>
        </where>
    </select>

    <!--新增所有列-->
    <insert id="insert" keyProperty="id" useGeneratedKeys="true">
        insert into user(id, name, pwd)
        values (#{id}, #{name}, #{pwd})
    </insert>

    <insert id="insertBatch" keyProperty="id" useGeneratedKeys="true">
        insert into user(id, name, pwd)
        values
        <foreach collection="entities" item="entity" separator=",">
        (#{entity.id}, #{entity.name}, #{entity.pwd})
        </foreach>
    </insert>

    <insert id="insertOrUpdateBatch" keyProperty="id" useGeneratedKeys="true">
        insert into user(id, name, pwd)
        values
        <foreach collection="entities" item="entity" separator=",">
            (#{entity.id}, #{entity.name}, #{entity.pwd})
        </foreach>
        on duplicate key update
        id = values(id),
        name = values(name),
        pwd = values(pwd)
    </insert>

    <!--通过主键修改数据-->
    <update id="update">
        update user
        <set>
            <if test="name != null and name != ''">
                name = #{name},
            </if>
            <if test="pwd != null and pwd != ''">
                pwd = #{pwd},
            </if>
        </set>
        where id = #{id}
    </update>

    <!--通过主键删除-->
    <delete id="deleteById">
        delete from user where id = #{id}
    </delete>

</mapper>




模板

##引入mybatis支持
$!{mybatisSupport.vm}

##设置保存名称与保存位置
$!callback.setFileName($tool.append($!{tableInfo.name}, "Dao.xml"))
$!callback.setSavePath($tool.append($modulePath, "/src/main/resources/mapper"))

##拿到主键
#if(!$tableInfo.pkColumn.isEmpty())
    #set($pk = $tableInfo.pkColumn.get(0))
#end

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="$!{tableInfo.savePackageName}.dao.$!{tableInfo.name}Dao">

    <resultMap id="BaseResultMap" type="$!{tableInfo.savePackageName}.entity.$!{tableInfo.name}">
        <!--@Table $!{tableInfo.obj.name}-->
#foreach($column in $tableInfo.fullColumn)
        <result property="$!column.name" column="$!column.obj.name" jdbcType="$!column.ext.jdbcType"/>
#end
    </resultMap>

    <!--查询单个-->
    <select id="queryById" resultMap="BaseResultMap">
        select
          #allSqlColumn()

        from $!tableInfo.obj.name
        where $!pk.obj.name = #{$!pk.name}
    </select>

    <!--查询指定行数据-->
    <select id="queryAllByLimit" resultMap="BaseResultMap">
        select
          #allSqlColumn()

        from $!tableInfo.obj.name
        <where>
#foreach($column in $tableInfo.fullColumn)
            <if test="$!tool.firstLowerCase($!{tableInfo.name}).$!column.name != null#if($column.type.equals("java.lang.String")) and $!tool.firstLowerCase($!{tableInfo.name}).$!column.name != ''#end">
                and $!column.obj.name = #{$!tool.firstLowerCase($!{tableInfo.name}).$!column.name}
            </if>
#end
        </where>
        limit #{pageable.offset}, #{pageable.pageSize}
    </select>
    <!--通过实体作为筛选条件查询-->
    <select id="queryAll" resultMap="BaseResultMap">
        select
          #allSqlColumn()

        from $!tableInfo.obj.name
     </select>
    <!--统计总行数-->
    <select id="count" resultType="java.lang.Long">
        select count(1)
        from $!tableInfo.obj.name
        <where>
#foreach($column in $tableInfo.fullColumn)
            <if test="$!column.name != null#if($column.type.equals("java.lang.String")) and $!column.name != ''#end">
                and $!column.obj.name = #{$!column.name}
            </if>
#end
        </where>
    </select>

    <!--新增所有列-->
    <insert id="insert" keyProperty="$!pk.name" useGeneratedKeys="true">
        insert into $!{tableInfo.obj.name}(#foreach($column in $tableInfo.fullColumn)$!column.obj.name#if($velocityHasNext), #end#end)
        values (#foreach($column in $tableInfo.fullColumn)#{$!{column.name}}#if($velocityHasNext), #end#end)
    </insert>

    <insert id="insertBatch" keyProperty="$!pk.name" useGeneratedKeys="true">
        insert into $!{tableInfo.obj.name}(#foreach($column in $tableInfo.fullColumn)$!column.obj.name#if($velocityHasNext), #end#end)
        values
        <foreach collection="entities" item="entity" separator=",">
        (#foreach($column in $tableInfo.fullColumn)#{entity.$!{column.name}}#if($velocityHasNext), #end#end)
        </foreach>
    </insert>

    <insert id="insertOrUpdateBatch" keyProperty="$!pk.name" useGeneratedKeys="true">
        insert into $!{tableInfo.obj.name}(#foreach($column in $tableInfo.fullColumn)$!column.obj.name#if($velocityHasNext), #end#end)
        values
        <foreach collection="entities" item="entity" separator=",">
            (#foreach($column in $tableInfo.fullColumn)#{entity.$!{column.name}}#if($velocityHasNext), #end#end)
        </foreach>
        on duplicate key update
        #foreach($column in $tableInfo.fullColumn)$!column.obj.name = values($!column.obj.name)#if($velocityHasNext),
        #end#end

    </insert>

    <!--通过主键修改数据-->
    <update id="update">
        update $!{tableInfo.obj.name}
        <set>
#foreach($column in $tableInfo.otherColumn)
            <if test="$!column.name != null#if($column.type.equals("java.lang.String")) and $!column.name != ''#end">
                $!column.obj.name = #{$!column.name},
            </if>
#end
        </set>
        where $!pk.obj.name = #{$!pk.name}
    </update>

    <!--通过主键删除-->
    <delete id="deleteById">
        delete from $!{tableInfo.obj.name} where $!pk.obj.name = #{$!pk.name}
    </delete>

</mapper>



pom依赖

 		<dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>8.0.17</version>
        </dependency>
        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
            <version>2.2.2</version>
        </dependency>
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
            <version>1.2.83</version>
        </dependency>

开始生成

1.选择数据库,点击生成按钮

IDEA插件easycode模板-无代码生成表CURD代码_第4张图片

选择要生成的内容

设置生成的包路径
生成类型默认选mybatis,生成controller、service、dao、mapper、entity
然后启动boot项目就可以直接请求接口了
IDEA插件easycode模板-无代码生成表CURD代码_第5张图片

JAVA 基础知识点
什么是Java虚拟机?为什么Java被称作是“平台无关的编程语言”?
Java虚拟机是一个可以执行Java字节码的虚拟机进程。Java源文件被编译成能被Java虚拟机执行的字节码文件。
Java被设计成允许应用程序可以运行在任意的平台,而不需要程序员为每一个平台单独重写或者是重新编译。Java虚拟机让这个变成可能,因为它知道底层硬件平台的指令长度和其它特性。

什么是J2EE?JVM?JRE?JDK?
(1)J2EE:是为开发企业环境下的应用程序提供的一套解决方案,该技术体系中包含的技术如Servlet、Jsp等,主要针对Web应用程序开发。
(2)JVM:JVM是java虚拟机(JVM Java Virtual Machine),java程序需要运行在虚拟机上,不同平台有自己的虚拟机,因此java语言可以跨平台。
(3)JRE:包括Java虚拟机(JVM Java Virtual Machine)和Java程序所需的核心类库等如果想要运行一个开发好的Java程序,计算机中只需要安装JRE即可。JRE:JVM+类库。
(4)JDK:JDK是提供给Java开发人员使用的,其中包含了java的开发工具,也包括了JRE。所以安装了JDK,就不用在单独安装JRE了。其中的开发工具:编译工具(javac.exe) 打包工具(jar.exe)等。JDK:JRE+JAVA的开发工具。

static关键字是什么意思?Java中是否可以覆盖(override)一个private或者是static方法?
“static”关键字表明一个成员变量或者是成员方法可以在没有所属的类的实例变量的情况下被访问。

Java中static方法不能被覆盖,因为方法覆盖是基于运行时动态绑定的,而static方法是编译时静态绑定的。static方法跟类的任何实例都不相关,所以概念上不适用。

Java中也不可以覆盖private方法,因为private修饰的变量和方法只能在当前类中使用,如果是其它类继承当前类,是不能访问到private变量或方法的,当然也不能覆盖。

是否可以在static环境中访问非static变量?
static变量在Java中是属于类的,它在所有的实例中的值是一样的,当类被Java虚拟机载入的时候,会对static变量进行初始化。如果你的代码尝试不用实例来访问非static的变量,编译器会报错,因为这些变量还没有被创建出来,还没有跟任何实例关联上。

Java支持的数据类型有哪些?什么是自动拆装箱?
Java语言支持的8种基本数据类型是:

boolean

byte、char

short、int

long、float、double

自动装箱是Java编译器在基本数据类型和对应的对象包装类型之间做的一个转化。比如:把int转化成integer,double转化成Double,等等。反之就是自动拆箱。

面向对象的三大特性(继承、封装、多态)
继承、封装、多态

什么是继承?
①继承是面向对象程序设计能够提高软件开发效率的重要原因之一。
②继承是具有传递性的,就像现实中孙子不仅长得像爸爸而且还像他爷爷。
③继承来的属性和方法是隐式的,也就是在本类里面是看不见的。
④一个类只能有一个父类,也就是类只能是单继承。
⑤一个接口可以有多个父类,也就是接口可以是多继承。
实际项目开发中,一个类继承于另一个类,那么前者就是后者的子类,反则反之。

什么是封装?
对象数据和操作该对象的指令都是对象自身的一部分,能够实现尽可能对外部隐藏数据。
实际项目开发中,使用封装最多的就是实体类,常常和JavaBean(类必须是具体的和公共的,并且具有无参数的构造器)一起使用。
那么,实体类有那些东西呢?
答:私有的成员变量、无参数的构造器、有参数的构造器、setter和getters方法、重写tostring方法、重写hashCode和equals方法。

什么是多态?
①多态就是对象拥有多种形态:引用多态和方法多态。
②引用多态:父类的引用可以指向本类对象、父类的引用可以指向子类的对象。
③方法多态:创建本类对象时,调用的方法为本类的方法;创建子类对象时,调用的方法为子类重写的方法或者继承的方法。
④存在多态的必要条件:继承、重写。
⑤多态的作用是消除类型之间的耦合关系。
在实际项目开发中,A类继承B类,如果在A类中不重写B类的方法的时候,输出的仍旧是B类方法里面的信息(B b=new A());如果在A类中重写B类的方法的时候,输出的是A类方法里面的信息(B b=new A())。

java为什么不支持多继承?
1.若子类继承的父类中拥有相同的成员变量,子类在引用该变量时将无法判别使用哪个父类的成员变量。
2.若一个子类继承的多个父类拥有相同方法,同时子类并未覆盖该方法(若覆盖,则直接使用子类中该方法),那么调用该方法时将无法确定调用哪个父类的方法。

Java 中覆盖和重载是什么意思?
解析:覆盖和重载是比较重要的基础知识点,并且容易混淆,所以面试中常见。
答:覆盖(Overide)是指子类对父类方法的一种重写,只能比父类抛出更少的异常,访问权限不能比父类的小。
被覆盖的方法不能是 private 的,否则只是在子类中重新定义了一个方法;

重载(Overload)表示同一个类中可以有多个名称相同的方法,但这些方法的参数列表各不相同。

面试官: 那么构成重载的条件有哪些?

答:参数类型不同、参数个数不同、参数顺序不同。

面试官: 函数的返回值不同可以构成重载吗?为什么?

答:不可以,因为 Java 中调用函数并不需要强制赋值。举例如下:
如下两个方法:

void f(){}
int f(){ return 1;}
1
2
只要编译器可以根据语境明确判断出语义,比如在 int x = f();中,那么的确可以据此区分重载方法。不过, 有时你并不关心方法的返回值,你想要的是方法调用的其他效果 (这常被称为 “为了副作用而调用”),这时你可能会调用方法而忽略其返回值,所以如果像下面的调用:

fun();

此时 Java 如何才能判断调用的是哪一个 f() 呢?别人如何理解这种代码呢?所以,根据方法返回值来区分重载方法是行不通的。

重定向和转发的区别。
1、重定向是两次请求,转发是一次请求,因此转发的速度要快于重定向
2、重定向之后地址栏上的地址会发生变化,变化成第二次请求的地址,转发之后地址栏上的地址不会变化,还是第一次请求的地址
3、转发是服务器行为,重定向是客户端行为。重定向时浏览器上的网址改变 ,转发是浏览器上的网址不变
4、重定向是两次request,转发只有一次请求
5、重定向时的网址可以是任何网址,转发的网址必须是本站点的网址

抽象类和接口的区别有哪些?
答:
抽象类中可以没有抽象方法;接口中的方法必须是抽象方法;
抽象类中可以有普通的成员变量;接口中的变量必须是 static final 类型的,必须被初始化 , 接口中只有常量,没有变量。
抽象类只能单继承,接口可以继承多个父接口;
Java8 中接口中会有 default 方法,即方法可以被实现。

面试官:抽象类和接口如何选择?
答:
如果要创建不带任何方法定义和成员变量的基类,那么就应该选择接口而不是抽象类。
如果知道某个类应该是基类,那么第一个选择的应该是让它成为一个接口,只有在必须要有方法定义和成员变量的时候,才应该选择抽象类。因为抽象类中允许存在一个或多个被具体实现的方法,只要方法没有被全部实现该类就仍是抽象类。

Java 和 C++ 的区别:
答:都是面向对象的语言,都支持封装、继承和多态;
指针:Java 不提供指针来直接访问内存,程序更加安全;
继承: Java 的类是单继承的,C++ 支持多重继承; Java 通过一个类实现多个接口来实现 C++ 中的多重继承; Java 中类不可以多继承,但是!!!接口可以多继承;
内存: Java 有自动内存管理机制,不需要程序员手动释放无用内存。

&与&&的区别:
&运算符有两种用法:(1)按位与;(2)逻辑与。&&运算符是短路与运算。逻辑与跟短路与的差别是非常巨大的,虽然二者都要求运算符左右两端的布尔值都是true整个表达式的值才是true。&&之所以称为短路运算是因为,如果&&左边的表达式的值是false,右边的表达式会被直接短路掉,不会进行运算。

equals和==
==:比较的是两个字符串内存地址(堆内存)的数值是否相等,属于数值比较;
equals():比较的是两个字符串的内容,属于内容比较。

ArrayList简介
**ArrayList 的底层是数组队列,相当于动态数组。**与 Java 中的数组相比,它的容量能动态增长。在添加大量元素前,应用程序可以使用ensureCapacity操作来增加 ArrayList 实例的容量。这可以减少递增式再分配的数量。

它继承于 AbstractList,实现了 List, RandomAccess, Cloneable, java.io.Serializable 这些接口。

在我们学数据结构的时候就知道了线性表的顺序存储,插入删除元素的时间复杂度为O(n),求表长以及增加元素,取第 i 元素的时间复杂度为O(1)

ArrayList 继承了AbstractList,实现了List。它是一个数组队列,提供了相关的添加、删除、修改、遍历等功能。

和 Vector 不同,ArrayList 中的操作不是线程安全的!所以,建议在单线程中才使用 ArrayList,而在多线程中可以选择 Vector 或者 CopyOnWriteArrayList。
ArrayList的遍历我们有三种方式:for循环,增强for循环 和 迭代器三种方式。

链表的代码实现
#include
#include
using namespace std;

typedef int DataType;

class Node
{
public:
DataType data;
Node *next;
};

class LinkList
{
public:
LinkList();
~LinkList();
int CreateLinkList(int size);
int BYELinkList();
int TravalLinkList();
int InsertLinklList(Node *data, int n);
int DeleteLinklist(int n);

int GetLen();
bool IsEmply();

Node *head;
int size;

};

LinkList::LinkList()
{
head = new Node;
head->data = 0;
head->next = NULL;
size = 0;
}

LinkList::~LinkList()
{
delete head;
}

int LinkList::CreateLinkList(int n)
{
if (n<0) {
printf(“error\n”);
return -1;
}
Node *ptemp = NULL;
Node *pnew = NULL;

this->size = n;
ptemp = this->head;
for(int i =0 ; inext = NULL;
	cout << "输入第" << i+1 << "个节点值" << endl;
	cin >> pnew->data;
	ptemp->next = pnew;
	ptemp = pnew;
}
cout << "创建完成" << endl;
return 0;

}

int LinkList::BYELinkList()
{
Node *ptemp;
if (this->head == NULL) {
cout << “链表原本就为空” << endl;
return -1;
}
while (this->head)
{
ptemp = head->next;
free(head);
head = ptemp;
}
cout << “销毁链表完成” << endl;
return 0;
}

int LinkList::TravalLinkList()
{
Node *ptemp = this->head->next;
if (this->head == NULL) {
cout << “链表为空” << endl;
return -1;
}
while(ptemp)
{
cout << ptemp->data << “->”;
ptemp = ptemp->next;
}
cout <<“NULL”<< endl;
return 0;
}

int LinkList::InsertLinklList(Node *data, int n)
{
Node *ptemp;
if (this->head == NULL) {
cout << “链表为空” << endl;
return -1;
}
if (data == NULL) {
cout << “插入节点为空” << endl;
return -1;
}
//头插
if (n<2) {
Node *pnew = new Node;
pnew->data = data->data;
pnew->next = this->head->next;
this->head->next = pnew;
this->size++;
return 0;
}
//尾插
if (n > this->size) {
ptemp = this->head;
while (ptemp->next != NULL) {
ptemp = ptemp->next;
}
Node *pnew = new Node;
pnew->data = data->data;
pnew->next = NULL;
ptemp->next = pnew;
this->size++;
return 0;
}
//中间插
else {
ptemp = this->head;
for (int i = 1; i < n; i++) {
ptemp = ptemp->next;
}
Node *pnew = new Node;
pnew->data= data->data;
pnew->next = ptemp->next;
ptemp->next = pnew;
this->size++;
return 0;
}
}

int LinkList::DeleteLinklist(int n)
{
Node *ptemp;
Node *ptemp2;
if (n > this->size) {
cout << “n太大” << endl;
return -1;
}
//删头节点
if (n < 2) {
ptemp = this->head->next;
this->head->next = ptemp->next;
free(ptemp);
this->size–;
return 0;
}
//尾部删除
if (n == this->size) {
ptemp = this->head;
for (int i = 1; i < this->size;i++) {
ptemp = ptemp->next;
}
ptemp2 = ptemp->next;
ptemp->next = NULL;
free(ptemp2);
this->size–;
return 0;
}
//中间删除
else
{
ptemp = this->head;
for (int i = 1; i < n; i++) {
ptemp = ptemp->next;
}
ptemp2 = ptemp->next;
ptemp->next = ptemp2->next;
free(ptemp2);
this->size–;
return 0;
}
}

int LinkList::GetLen()
{
return this->size;
}

bool LinkList::IsEmply()
{
if (this->head == NULL) {
return true;
}
else{
return false;
}
}

void main(void)
{
LinkList list;
LinkList *plist = &list;
plist->CreateLinkList(5);
plist->TravalLinkList();
Node temp;
temp.data = 100;
temp.next = NULL;
plist->InsertLinklList(&temp, 0);
plist->TravalLinkList();
plist->InsertLinklList(&temp, plist->GetLen()+1);
plist->TravalLinkList();
plist->InsertLinklList(&temp, 5);

plist->TravalLinkList();
plist->DeleteLinklist(0);
plist->TravalLinkList();
plist->DeleteLinklist(list.GetLen());
plist->TravalLinkList();
plist->DeleteLinklist(2);
plist->TravalLinkList();


plist->BYELinkList();
system("pause");

}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
Java 中常见集合(重点)
集合这方面的考察相当多,这部分是面试中必考的知识点。

1)说说常见的集合有哪些吧?
答:Map 接口和 Collection 接口是所有集合框架的父接口:

Collection 接口的子接口包括:Set 接口和 List 接口;
Map 接口的实现类主要有:HashMap、TreeMap、Hashtable、ConcurrentHashMap 以及 Properties 等;
Set 接口的实现类主要有:HashSet、TreeSet、LinkedHashSet 等;
List 接口的实现类主要有:ArrayList、LinkedList、Stack 以及 Vector 等。

2)HashMap 和 Hashtable 的区别有哪些?(必问)
答:
HashMap 没有考虑同步,是线程不安全的;Hashtable 使用了 synchronized 关键字,是线程安全的;
前者允许 null 作为 Key;后者不允许 null 作为 Key。

3)HashMap 的底层实现你知道吗?
答:在 Java8 之前,其底层实现是数组 + 链表实现,Java8 使用了数组 + 链表 + 红黑树实现。
主要是为了提升在 hash 冲突严重时(链表过长)的查找性能,使用链表的查找性能是 O(n),而使用红黑树是 O(logn)。

4)ConcurrentHashMap 和 Hashtable 的区别?(必问)
答:ConcurrentHashMap 结合了 HashMap 和 HashTable 二者的优势。HashMap 没有考虑同步,hashtable 考虑了同步的问题。但是 hashtable 在每次同步执行时都要锁住整个结构。 ConcurrentHashMap 锁的方式是稍微细粒度的。 ConcurrentHashMap 将 hash 表分为 16 个桶(默认值),诸如 get,put,remove 等常用操作只锁当前需要用到的桶。

面试官:ConcurrentHashMap 的具体实现知道吗?
答:
该类包含两个静态内部类 HashEntry 和 Segment;前者用来封装映射表的键值对,后者用来充当锁的角色;
Segment 是一种可重入的锁 ReentrantLock,每个 Segment 守护一个 HashEntry 数组里得元素,当对 HashEntry 数组的数据进行修改时,必须首先获得对应的 Segment 锁。

5)HashMap 的长度为什么是 2 的幂次方?
答:
通过将 Key 的 hash 值与 length-1 进行 & 运算,实现了当前 Key 的定位,2 的幂次方可以减少冲突(碰撞)的次数,提高 HashMap 查询效率;
如果 length 为 2 的次幂 则 length-1 转化为二进制必定是 11111……的形式,在于 h 的二进制与操作效率会非常的快,而且空间不浪费;
如果 length 不是 2 的次幂,比如 length 为 15,则 length-1 为 14,对应的二进制为 1110,在于 h 与操作,最后一位都为 0,而 0001,0011,0101,1001,1011,0111,1101 这几个位置永远都不能存放元素了,空间浪费相当大。
更糟的是这种情况中,数组可以使用的位置比数组长度小了很多,这意味着进一步增加了碰撞的几率,减慢了查询的效率!这样就会造成空间的浪费。

6)List 和 Set 的区别是啥?
答:List 元素是有序的,可以重复;Set 元素是无序的,不可以重复。

7)List、Set 和 Map 的初始容量和加载因子
答:

List
ArrayList 的初始容量是 10;加载因子为 0.5; 扩容增量:原容量的 0.5 倍 +1;一次扩容后长度为 16。
Vector 初始容量为 10,加载因子是 1。扩容增量:原容量的 1 倍,如 Vector 的容量为 10,一次扩容后是容量为 20。
Set
HashSet,初始容量为 16,加载因子为 0.75; 扩容增量:原容量的 1 倍; 如 HashSet 的容量为 16,一次扩容后容量为 32
Map
HashMap,初始容量 16,加载因子为 0.75; 扩容增量:原容量的 1 倍; 如 HashMap 的容量为 16,一次扩容后容量为 32
8)Comparable 接口和 Comparator 接口有什么区别?
答:
前者简单,但是如果需要重新定义比较类型时,需要修改源代码。
后者不需要修改源代码,自定义一个比较器,实现自定义的比较方法。

9)Java 集合的快速失败机制 “fail-fast”
答:它是 java 集合的一种错误检测机制,当多个线程对集合进行结构上的改变的操作时,有可能会产生 fail-fast 机制。
例如 :假设存在两个线程(线程 1、线程 2),线程 1 通过 Iterator 在遍历集合 A 中的元素,在某个时候线程 2 修改了集合 A 的结构(是结构上面的修改,而不是简单的修改集合元素的内容),那么这个时候程序就会抛出 ConcurrentModificationException 异常,从而产生 fail-fast 机制。

原因: 迭代器在遍历时直接访问集合中的内容,并且在遍历过程中使用一个 modCount 变量。集合在被遍历期间如果内容发生变化,就会改变 modCount 的值。

每当迭代器使用 hashNext()/next() 遍历下一个元素之前,都会检测 modCount 变量是否为 expectedmodCount 值,是的话就返回遍历;否则抛出异常,终止遍历。

解决办法:

在遍历过程中,所有涉及到改变 modCount 值得地方全部加上 synchronized;
使用 CopyOnWriteArrayList 来替换 ArrayList。

高并发编程-JUC 包
在 Java 5.0 提供了 java.util.concurrent(简称 JUC )包,在此包中增加了在并发编程中很常用的实用工具类,用于定义类似于线程的自定义子系统,包括线程池、异步 IO 和轻量级任务框架。

多线程和单线程的区别和联系:
答:
在单核 CPU 中,将 CPU 分为很小的时间片,在每一时刻只能有一个线程在执行,是一种微观上轮流占用 CPU 的机制。
多线程会存在线程上下文切换,会导致程序执行速度变慢,即采用一个拥有两个线程的进程执行所需要的时间比一个线程的进程执行两次所需要的时间要多一些。
结论:即采用多线程不会提高程序的执行速度,反而会降低速度,但是对于用户来说,可以减少用户的响应时间。

如何指定多个线程的执行顺序?
解析:面试官会给你举个例子,如何让 10 个线程按照顺序打印 0123456789?(写代码实现)
答:
设定一个 orderNum,每个线程执行结束之后,更新 orderNum,指明下一个要执行的线程。并且唤醒所有的等待线程。
在每一个线程的开始,要 while 判断 orderNum 是否等于自己的要求值!!不是,则 wait,是则执行本线程。

线程和进程的区别:(必考)
答:
进程是一个 “执行中的程序”,是系统进行资源分配和调度的一个独立单位;
线程是进程的一个实体,一个进程中拥有多个线程,线程之间共享地址空间和其它资源(所以通信和同步等操作线程比进程更加容易);
线程上下文的切换比进程上下文切换要快很多。
(1)进程切换时,涉及到当前进程的 CPU 环境的保存和新被调度运行进程的 CPU 环境的设置。
(2)线程切换仅需要保存和设置少量的寄存器内容,不涉及存储管理方面的操作。

多线程产生死锁的 4 个必要条件?
答:
**互斥条件:**一个资源每次只能被一个线程使用;
**请求与保持条件:**一个线程因请求资源而阻塞时,对已获得的资源保持不放;
**不剥夺条件:**进程已经获得的资源,在未使用完之前,不能强行剥夺;
**循环等待条件:**若干线程之间形成一种头尾相接的循环等待资源关系。
面试官:如何避免死锁?(经常接着问这个问题哦~)
答:指定获取锁的顺序,举例如下:
比如某个线程只有获得 A 锁和 B 锁才能对某资源进行操作,在多线程条件下,如何避免死锁?
获得锁的顺序是一定的,比如规定,只有获得 A 锁的线程才有资格获取 B 锁,按顺序获取锁就可以避免死锁!!!

5)sleep( ) 和 wait( n)、wait( ) 的区别:
答:
sleep 方法:是 Thread 类的静态方法,当前线程将睡眠 n 毫秒,线程进入阻塞状态。当睡眠时间到了,会解除阻塞,进行可运行状态,等待 CPU 的到来。睡眠不释放锁(如果有的话);
wait 方法:是 Object 的方法,必须与 synchronized 关键字一起使用,线程进入阻塞状态,当 notify 或者 notifyall 被调用后,会解除阻塞。但是,只有重新占用互斥锁之后才会进入可运行状态。睡眠时,释放互斥锁。

6)synchronized 关键字:
答:底层实现:
进入时,执行 monitorenter,将计数器 +1,释放锁 monitorexit 时,计数器-1;
当一个线程判断到计数器为 0 时,则当前锁空闲,可以占用;反之,当前线程进入等待状态。
含义:(monitor 机制)
Synchronized 是在加锁,加对象锁。对象锁是一种重量锁(monitor),synchronized 的锁机制会根据线程竞争情况在运行时会有偏向锁(单一线程)、轻量锁(多个线程访问 synchronized 区域)、对象锁(重量锁,多个线程存在竞争的情况)、自旋锁等。
该关键字是一个几种锁的封装。

7)volatile 关键字
答:该关键字可以保证可见性不保证原子性。
功能:
主内存和工作内存,直接与主内存产生交互,进行读写操作,保证可见性;
禁止 JVM 进行的指令重排序。
解析:关于指令重排序的问题,可以查阅 DCL 双检锁失效相关资料。

8)ThreadLocal(线程局部变量)关键字:
答:当使用 ThreadLocal 维护变量时,其为每个使用该变量的线程提供独立的变量副本,所以每一个线程都可以独立的改变自己的副本,而不会影响其他线程对应的副本。

ThreadLocal 内部实现机制:

每个线程内部都会维护一个类似 HashMap 的对象,称为 ThreadLocalMap,里边会包含若干了 Entry(K-V 键值对),相应的线程被称为这些 Entry 的属主线程;
Entry 的 Key 是一个 ThreadLocal 实例,Value 是一个线程特有对象。Entry 的作用即是:为其属主线程建立起一个 ThreadLocal 实例与一个线程特有对象之间的对应关系;
Entry 对 Key 的引用是弱引用;Entry 对 Value 的引用是强引用。

9)Atomic 关键字:
答:可以使基本数据类型以原子的方式实现自增自减等操作。参考我的博客:concurrent.atomic 包下的类 AtomicInteger 的使用。

10)线程池有了解吗?(必考)
答:java.util.concurrent.ThreadPoolExecutor 类就是一个线程池。客户端调用 ThreadPoolExecutor.submit(Runnable task) 提交任务,线程池内部维护的工作者线程的数量就是该线程池的线程池大小,有 3 种形态:

当前线程池大小 :表示线程池中实际工作者线程的数量;
最大线程池大小 (maxinumPoolSize):表示线程池中允许存在的工作者线程的数量上限;
核心线程大小 (corePoolSize ):表示一个不大于最大线程池大小的工作者线程数量上限。
如果运行的线程少于 corePoolSize,则 Executor 始终首选添加新的线程,而不进行排队;
如果运行的线程等于或者多于 corePoolSize,则 Executor 始终首选将请求加入队列,而不是添加新线程;
如果无法将请求加入队列,即队列已经满了,则创建新的线程,除非创建此线程超出 maxinumPoolSize, 在这种情况下,任务将被拒绝。
————————————————
版权声明:本文为CSDN博主「[email protected]」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/weixin_47053123/article/details/117326316

你可能感兴趣的:(intellij-idea,java,spring)