首页 > 编程语言 >Java基础20问(6-10)

Java基础20问(6-10)

时间:2023-10-25 18:01:35浏览次数:33  
标签:10 Java String List 接口 file 泛型 20 public


6.Java接口和抽象类的区别?

不同点

1.接口在Java8之前不能写方法实现逻辑,Java8及以后的版本,可以用default关键字写方法的实现。

2.接口中方法都是public的,public可以省略,而抽象类没有这个限制。

3.接口用interface关键字,抽象类用abstract class来声明。

相同点

接口和抽象类都不能直接new。

实战总结

接口用于制定规范,而抽象类用于代码的复用,比如模板方法模式。

实际开发中,我们用接口来制定规范,直接参与上层业务(Controller)代码的编写,然后具体的实现放到业务层(ServiceImpl),如果实现类有很多相同的逻辑,就可以考虑封装为一个抽象类。

举一个例子,Excel导入,我们可以封装一个导入接口:

public interface ImportService {

    /**
     * Excel导入
     * @param file 上传的excel文件
     * @return
     */
    Result<ImportResultDto> importData(MultipartFile file);

}

importData 要求输入一个file文件,返回导入的结果。

具体使用是在controller层:

public Result<ImportResultDto> imp(@RequestParam("file") MultipartFile file) {
        return userImportService.importData(file);
    }

userImportService 就是具体的实现类,是ImportService接口的业务实现。

又因为Excel导入通常都需要这么几个步骤:解析文件 -> 校验数据 -> 保存数据 -> 返回导入结果。

因此我们可以再单独封装一个抽象类。

public abstract class AbstractImportService<T> implements ImportService {

    @Override
    @Transactional(rollbackFor = Throwable.class)
    public Result<ImportResultDto> importData(MultipartFile file) {
        checkFileType(file.getOriginalFilename());

        List<T> dataList = parseData(file);
        ImportResultDto resultDTO = checkData(dataList);
        if (resultDTO == null || CollectionUtils.isEmpty(resultDTO.getErrorList())) {
            this.saveData(dataList);
            return Result.success();
        }
        return Result.fail(ResultEnum.SYSTEM_OP_ERROR.getCode(), "导入失败", resultDTO);
    }

    /**
     * 解析文件中的数据
     *
     * @param file 文件
     * @return
     */
    protected abstract List<T> parseData(MultipartFile file);

    /**
     * 校验数据
     *
     * @param dataList 数据
     * @return
     */
    protected abstract ImportResultDto checkData(List<T> dataList);

    /**
     * 处理数据
     *
     * @param dataList 数据
     */
    protected abstract void saveData(List<T> dataList);

    /**
     *  校验文件类型
     */
    private static void checkFileType(String fileName) {
        if (StringUtils.isNotBlank(fileName) && fileName.contains(".")) {
            String suffix = fileName.substring(fileName.lastIndexOf(".")).toLowerCase();
            if (StringUtils.isNotBlank(suffix) && Arrays.asList(".xls", ".xlsx").contains(suffix)) {
                return;
            }
        }
        throw new BusinessInfoException(ResultEnum.SYSTEM_INNER_ERROR, "只支持excel文件导入,请检查!");
    }
}

这就是一个典型的模板方法模式,因为这个抽象类已经实现了接口,所以真正的实现类就不需要重复去实现了,只需要继承这个抽象类即可。

7.Java中有了基本类型为什么还需要包装类?

先说渊源,Java毕竟是面向对象的语言,很多地方都需要用到象,比如集合类中,是无法塞进基本类型的。

Java基础20问(6-10)_java

某杠精:你胡扯,我塞入int类型的压根不报错!

public static void main(String[] args) {
    List<Integer> numbers = new ArrayList<Integer>();
    numbers.add(1);
}

这是因为从JDK5开始,就支持了自动拆装箱系统,所以并不是集合可以装进基本类型,而是系统帮我们自动装箱了。

自动装箱都是通过包装类的 valueof()方法来实现的自动折箱都是通过包装类对象的xxxValue()来实现的。

已int为例:

Integer a = 1;     // 自动装箱
int b = a;         // 自动拆箱

相当于

Integer a = Integer.valueOf(1);     
int b = a.intValue();

避坑指南

1.注意空指针

有的时候,我们会直接用包装类去参与四则运算,这个时候要注意包装类对象不能是null,因为自动拆箱会调用xxxValue()方法,就会有报空指针的风险。

public class Test {
    public static void main(String[] args) {
        Integer a = getCount();
        int b = a + 10;   
    }

    private static Integer getCount() {
        // 因为某种原因,返回了null
        return null;
    }
}

恭喜你,喜提 NullPointerException一份。

Java基础20问(6-10)_List_02

2.Entity中一定要用包装类

java老鸟都知道,Entity中一定不能用基本类型,因为基本类型有默认初始值,比如int类型默认就是0,如果结合Mybatis,会不小心把这个默认值误更新到数据库!而用Integer则没问题,因为对象默认为null,mybatis默认的策略就是不更新Null值,是安全的。

8.接口的返回值一定要用包装类

我们写接口给外部调用,按理说就必须要是一个明确的值,如果你接口返回boolean,默认是false,这个false我们也不知道究竟是计算后得到的,还是基本类型默认的,这就有二义性。

3.为什么用float会有精度丢失的问题?

要解答这个问题,我们得知道,计算机中用32bit来标识一个浮点数,即将一个数字转换为一个32位的二进制数。比如10,就是1010。表达整数没问题,但是并非所有小数都能用二进制表示,我们知道10进制转二进制用的是辗转相除法(除以2),那总有除不尽的时候吧?

所以,即便float有32bit,也是一个近似值。double也是一样的,只是精度更高了,有64bit。

对于金额的计算,Java提供了BigDecimal来表示和运算。

9.请说说String、StringBuilder和StringBuffer的区别?

可变性: String是不可变的,StringBuilder和StringBuffer是可变的。

为什么String要设计为不可变的呢?

首先String使用太频繁了,JVM单独开辟一块区域用作字符串缓存池,节省内存的开支。又因为String不可变,所以hashCode也不变,方便命中缓存提高效率,我们用HashMap的时候,你敢说自己不用String作为Key吗?一样的道理。

安全性: StringBuffer是线程安全的,而StringBuilder是非线程安全的。

StringBuffer 和 StringBuilder如何取舍?

StringBuilder是非线程安全的,也就意味着效率更高,在方法体里面,本来也不会涉及到线程安全问题,拼接较多的话值得使用。

尽量不要使用 + 来拼接字符串,因为 + 虽然编译时也会转成StringBuilder,但每次都会new一个,反而影响性能。

10.什么是泛型

泛型是JDK5引入的一种新特性,泛型包括泛型类和泛型方法,目的是保证数据类型的安全,常与集合类一起使用。

1.方便:可以提高代码的复用性。

以List接口为例,我们可以将String、Integer等类型放入List中,如不用泛型,存放String类型要写一个List接口,存放Integer要写另外一个List接口,泛型可以很好的解决这个问题。

ArrayList源码:

Java基础20问(6-10)_抽象类_03

2.安全

在泛型出之前,通过Object实现的类型转换需要在运行时检查,如果类型转换出错,程序直接GG,可能会带来毁灭性打击。。而泛型的作用就是在编译时做类型检查这无疑增加程序的安全性。

3.什么是泛型擦除?

泛型擦除是指在编译过程中,泛型会被擦除,最终只会得到同一份字节码。因此,泛型主要的功能就是在编译时确保数据类型的正确性,防止把问题留到运行时。

标签:10,Java,String,List,接口,file,泛型,20,public
From: https://blog.51cto.com/u_10957019/8023641

相关文章

  • java基本语法
    1.注释 2. ......
  • 查看Java class文件元信息
    命令javap-v/com/pany/Hello.class输出:D:\lab>javap-vLibEnvMap.classClassfile/D:/lab/LibEnvMap.classLastmodified2023年10月25日;size1442bytesSHA-256checksum163a912c8adb9511d630c71483f134b2583e87a66ad8e46ace4fa30656e5af7eCompiledfrom&q......
  • Java 方法 01~06
    Java方法01~061.什么方法?方法概念:语句的集合;方法的命名规则:驼峰法则publicstaticintadd(inta,intb){returna+b;}//static类方法标识符//int返回值类型//inta,intb形参2.方法的定义和调用​ 定义要素:修饰符;返回值类型;方法名;参数类型;方法体......
  • 《动手学深度学习 Pytorch版》 10.4 Bahdanau注意力
    10.4.1模型Bahdanau等人提出了一个没有严格单向对齐限制的可微注意力模型。在预测词元时,如果不是所有输入词元都相关,模型将仅对齐(或参与)输入序列中与当前预测相关的部分。这是通过将上下文变量视为注意力集中的输出来实现的。新的基于注意力的模型与9.7节中的模型相同,只不过......
  • 单词接龙(JAVA)
    classSolution{Map<String,Integer>wordId=newHashMap<String,Integer>();//哈希图,用于广度优先搜索List<List<Integer>>edge=newArrayList<List<Integer>>();//哈希图的邻接表,嵌套的两个一维数组组成的二维数组,......
  • WebStorm2023安装prettier并生效
    1.首先去File>Settings>Plugins里下载并install插件Prettier 2.在settings里搜索prettier,按图片所示设置一下Apply 3.在你需要的文件中按下快捷键Ctrl+Alt+Shift+L会弹出提示框,点Run即可 ......
  • CSP 2023 游记
    Day-35初赛,不在状态。看到了一车的小学生,虽然我也是。J78pts,S61pts,不知道S为啥那么高,总之两个都过了。Day-20~-16国庆来到GF集训,面到了@VitrelosTia,看见了非常有实力又有\(6\)级勾又AK了CSP-J的学长lbw。Day-1没干什么。Day0早上考J。有点冷,穿了......
  • Java基础 序列化流和反序列化流的 三个使用细节
    细节一:如果说一个类实现了Serializable接口,表示这个类的对象是可被序列化的,Java底层会根据这个类里面所有的内容进行计算,计算出一个long类型的序列号(或版本号)。假设计算出来的版本号是1,当我创建了一个这个类的对象的时候,在对象里面就包含了版本号1,用序列化流写到本地文......
  • 现代C++语言核心特性解析 谢丙堃​ 2021年pdf电子版
    现代C++语言核心特性解析2021年pdf电子版作者: 谢丙堃出版年: 2021-10ISBN: 9787115564177连接提取码:ckop自从C++11发布,就没有系统学习C++的书,也很久没有看国内作者出的C++书籍了。市面上对于现代C++的书很少,这是一本讲述现代C++11~C++20的书。意外,写得不错,容易理解,难得是除了......
  • windows安装MySQL8.0.20
    一、下载地址(zip版):https://downloads.mysql.com/archives/community/二、安装mysql8.0.201、解压缩至目录D:\software\mysql-8.0.20-winx642、新建my.ini文件在D:\software\mysql-8.0.20-winx64目录下新建my.ini文件注意:需要将配置文件中的basedir和datadir的值改成自己......