String StringBuffer StringBuilder
- 运行速度快慢为:StringBuilder > StringBuffer > String
- 操作数量较少的字符串用String,不可修改的字符串;
在单线程且操作大量字符串用StringBuilder,速度快,但线程不安全,可修改;
在多线程且操作大量字符串用StringBuffer,线程安全,可修改。 - for循环中追加字符串 IDEA会提示使用StringBuilder
- 扩容机制:StringBuffer/StringBuilder在没有传参的情况下默认初始容量是16;有参数的情况下,初始容量是16+字符串的长度,并且是用append()方法追加的字符。ensureCapacityInternal()int newCapacity = (value.length << 1) + 2;增加为自身长度的一倍然后再加2;这个时候如果还是放不下,那就直接扩容到它需要的长度 newCapacity = minCapacity;
包装类 基本数据类型、 拆箱装箱、常量池缓存机制
- 包装类是对象,有自己的方法,默认值为null
- 存储位置不同,基本数据类型直接将值保存在值栈中,而包装类型是把对象放在堆中,然后通过对象的引用来调用
- 装箱就是将基本数据类型包装成包装类型,拆箱就是反过来将包装类型拆成基本数据类型。
- 装箱过程是通过调用包装类的valueOf方法实现的,而拆箱过程是通过调用包装器的 xxxValue方法实现的。(其中xxx代表对应的基本数据类型)
- 常量池的缓存机制:Double 和 Float 无 ;Boolean类型的比较类似单纯地比较他们的值是否相等。
如何理解java中只有值传递
- 基本类型传递的是值的副本,引用类型传递的是引用的副本。
- java中不管是值对象还是引用对象都是值传递,在其他方法里面改变引用类型的值肯定是通过引用改变的,当传递引用对象的时候传递的是复制过的对象句柄(引用),注意这个引用是复制过的,也就是说又在内存中复制了一份句柄,这时候有两个句柄是指向同一个对象的,所以你改变这个句柄对应空间的数据会影响外部的变量的,虽然是复制的但是引用指向的是同一个地址,当你把这个句柄指向其他对象的引用时并不会改变原对象,因为你拿到的句柄是复制过的引用。
总结java中的句柄(引用)是复制过的,所以说java只有值传递。
十进制的数在内存中是怎么存的
基于补码
java8新特性
- Lambda 表达式 − Lambda 允许把函数作为一个方法的参数(函数作为参数传递到方法中)。 .sort()等
- Stream API −新添加的Stream API(java.util.stream) 把真正的函数式编程风格引入到Java中。 例子:list.stream().filter().collect(Collectors.toList());
- LocalDate和LocalTime类
==和equals之间的区别
- 种类不同 ==:运算符 equals:是Object类里面的一个方法
- 作用不同 ==:既可以比较基本数据类型(比较数值) 又可以比较引用数据类型(比较地址) equals:只能比较引用数据类型,表示如何制定一个类型的比较规则,可以按照自己的意愿修改比较规则 比如:String类型比较字符串的内容
为什么重写euqals 方法 必须重写 hashCode()
- 两个对象 hashCode() 所得hash值相等 , 但equals()方法不一定返回true
- 两个对象 equals() 返回true,那么对象调用hashCode()返回的hash值一定相等
- 如果 仅重写 equals(),而不重写hashcode(),则存在 equals方法会返回true,而hashcode()方法返回的hash值不相等
- 为了保证同一个对象,保证在equals相同的情况下hashcode值必定相同,如果重写了equals而未重写hashcode方法,可能就会出现两个没有关系的对象equals相同的
- lombok插件 @Data 自动重写 hashCode() equals() toString()方法
面向对象 特征、六原则一法则
- 面向对象的特征:封装 继承 多态 。封装:隐藏对象的属性和实现细节,仅对外提供公共访问方式,将变化隔离,便于使用,提高复用性和安全性。继承:提高代码复用性;继承是多态的前提。多态:父类或接口定义的引用变量可以指向子类或具体实现类的实例对象。提高了程序的拓展性。
- 单一职责原则:一个类只做它该做的事情。”高内聚”
- 开闭原则:软件实体应当对扩展开放,对修改关闭。
- 依赖倒转原则:面向接口编程。(该原则说得直白和具体一些就是声明方法的参数类型、方法的返回类型、变量的引用类型时,尽可能使用抽象类型而不用具体类型,因为抽象类型可以被它的任何一个子类型所替代,请参考下面的里氏替换原则。)
- 里氏替换原则:任何时候都可以用子类型替换掉父类型。简单的说就是能用父类型的地方就一定能使用子类型。
- 接口隔离原则:接口要小而专,绝不能大而全。
- 聚合复用原则:优先使用聚合关系复用代码。
- 迪米特法则:迪米特法则又叫最少知识原则,一个对象应当对其他对象有尽可能少的了解。(迪米特法则简单的说就是如何做到”低耦合”,门面模式和调停者模式就是对迪米特法则的践行。)
Java泛型所给予的编译期检查
Java泛型所给予的编译期检查,是根据该泛型对象的引用类型来定的,如果泛型类对象的引用类型的< >里有具体类型,那么就会执行相应的编译期检查。
在编译之后程序会采取去泛型化的措施。也就是说Java中的泛型,只在编译阶段有效。在编译过程中,正确检验泛型结果后,会将泛型的相关信息擦出,并且在对象进入和离开方法的边界处添加类型检查和类型转换的方法。也就是说,泛型信息不会进入到运行时阶段。
java是解释型语言还是编译型语言?
有人说Java是编译型的。因为所有的Java代码都是要编译的,.java不经过编译就无法执行。
也有人说Java是解释型的。因为java代码编译后不能直接运行,它是解释运行在JVM上的,所以它是解释型的。
对于C和C++,它们经过一次编译之后,可以由操作系统直接执行,所以它们是编译型语言。而Java不一样,它首先由编译器编译成.class(字节码)文件,然后在通过JVM从.class文件中读一行解释执行一行,所以它是解释型的语言。也正是由于java对于多种不同的操作系统有不同的JVM,所以实现了真正意义上的跨平台。
finalize方法是Object提供的的实例方法,使用规则如下
- 当对象不再被任何对象引用时,GC会调用该对象的finalize()方法
- finalize()是Object的方法,子类可以覆盖这个方法来做一些系统资源的释放或者数据的清理
- 可以在finalize()让这个对象再次被引用,避免被GC回收;但是最常用的目的还是做cleanup
- Java不保证这个finalize()一定被执行;但是保证调用finalize的线程没有持有任何user-visible同步锁。
- 在finalize里面抛出的异常会被忽略,同时方法终止。
- 当finalize被调用之后,JVM会再一次检测这个对象是否能被存活的线程访问得到,如果不是,则清除该对象。也就是finalize只能被调用一次;也就是说,覆盖了finalize方法的对象需要经过两个GC周期才能被清除。
深拷贝和浅拷贝有什么区别
- 浅拷贝:复制基本类型的属性;引用类型的属性复制,复制栈中的变量 和 变量指向堆内存中的对象的指针,不复制堆内存中的对象。
- 深拷贝:复制基本类型的属性;引用类型的属性复制,复制栈中的变量 和 变量指向堆内存中的对象的指针和堆内存中的对象。
- 可以说一下BeanUtils.copyProperties() Arrays.copyOf() clone()等
Class类的作用
- Class类是一个比较特殊的类。特殊在这是一个在类加载过程中由虚拟机生成的,由于表示被加载类的类型信息的对象。简单地说,我们创建一个int变量,那么这个int变量是个整数类型,那么我们怎么知道这个类型是整数类型呢?就是通过这个Class类来知道的。java是面向对象编程的,java中几乎所有的数据都是对象,那么是对象,就必须知道自己到底是哪一种类型的对象。于是Class类便顺势而生了。
- Class类的作用,本质上讲,就是前面所说的,它代表着一个类的类型信息。正是因为这个特殊作用的存在,Class类能够实现它所代表的这个类的所有功能,包括创建这个类的实例,获得所有的构造函数,方法,字段值等等,可以说无所不能。
什么是反射机制,有什么作用
- 在Java环境中,反射机制允许程序在执行时获取某个类自身的定义信息,也可以实现动态创建类的对象、变更属性的内容或执行特定的方法的功能。从而使Java具有动态语言的特性,增强了程序的灵活性和可移植性。
- Java反射机制主要用于实现以下功能。1.在运行时判断任意一个对象所属的类型。2.在运行时构造任意一个类的对象。3.在运行时判断任意一个类所具有的成员变量和方法。4.在运行时调用任意一个对象的方法,甚至可以调用private方法。
- 实现Java反射机制的API在Java.lang.reflect包下,具有以下几点。1. Class类:代表一个类。2. Filed类:代表类的成员变量。3.Method类:代表类的方法。4.Constructor类:代表类的构造方法。5.Array类:提供了动态创建数组及访问数组元素的静态方法。该类中的所有方法都是静态的。
- Spring通过反射创建对象,并将对象放到spring ioc容器中;Spring的拦截器也是基于反射实现的;
Synchronized lock volatile
synchronized修饰静态方法以及同步代码块 synchronized (类.class)用法锁的是类,线程想要执行对应同步代码,需要获得类锁。
synchronized修饰成员方法,线程获取的是当前调用该方法的对象实例的对象锁。
synchronized关键字和volatile关键字比较
volatile关键字是线程同步的轻量级实现,所以volatile性能肯定比synchronized关键字要好。
但是volatile关键字只能用于变量,而synchronized关键字可以修饰方法以及代码块。
synchronized关键字在JavaSE 1.6之后进行了主要包括为了减少获得锁和释放锁带来的性能消耗而引入的偏向锁和轻量级锁以及其它各种优化之后执行效率有了显著提升,实际开发中使用 synchronized 关键字的场景还是更多一些。
多线程访问volatile关键字不会发生阻塞,而synchronized关键字可能会发生阻塞。
volatile关键字能保证数据的可见性,但不能保证数据的原子性。synchronized关键字两者都能保证。
volatile关键字主要用于解决变量在多个线程之间的可见性,而 synchronized关键字解决的是多个线程之间访问资源的同步性。
既然有了字节流,为什么还要有字符流
字符流是由JVM将字节转换得到的,所以这个过程还是非常耗时的,字节流在处理时是逐个字节读取,在读取汉字时会出现乱码问题。
图片和音频这些文件用字节流比较好,涉及到字符的使用字符流比较好。