Java 基础查漏补缺

优先级

++ 作为后缀时的优先级比 * 高,因此 *p++ 是先 p++, 而后*(p++) 的。

++ 作为后缀时优先级和 () 一样高,结合律从左到右。因此(*p)++ 是先取值,然后 ++

++ 作为前缀时的优先级和 * 一样高, 结合律从右到左, 所以 ++*p == ++(*p) 的。

基本的数据结构

img

从框架图中了解继承关系以及重要的数据结构(包括其继承情况、底层原理等)

集合常考点:

img

Collection中存放的是一组各自独立的对象,Map中存放的是“键-值”对象。

List和Set都是Collection的子接口,List是一个有序可重复列表,Set是一个无序重复集。

而Array是数组,并不继承Collection接口。

String、StringBuilder、StringBuffer

String StringBuffer StringBuilder
String的值是不可变的,这就导致每次对String的操作都会生成新的String对象,不仅效率低下,而且浪费大量优先的内存空间 StringBuffer是可变类,和线程安全的字符串操作类,任何对它指向的字符串的操作都不会产生新的对象。每个StringBuffer对象都有一定的缓冲区容量,当字符串大小没有超过容量时,不会分配新的容量,当字符串大小超过容量时,会自动增加容量 可变类,速度更快
不可变 可变 可变
线程安全 线程不安全
多线程操作字符串 单线程操作字符串

对String对象的任何改变都不影响到原对象,相关的任何change操作都会生成新的对象

和 String 类不同的是,StringBuffer 和 StringBuilder 类的对象能够被多次的修改,并且不产生新的未使用对象

由于 StringBuilder 相较于 StringBuffer 有速度优势,所以多数情况下建议使用 StringBuilder 类。然而在应用程序要求线程安全的情况下,则必须使用 StringBuffer 类。

小结:

(1)如果要操作少量的数据用 String;

(2)多线程操作字符串缓冲区下操作大量数据 StringBuffer;

(3)单线程操作字符串缓冲区下操作大量数据 StringBuilder。

hashMap、linkedHashMap、hashTable、concurrentHashMap

Hashmap中的value可以之null,get(key)==null有两种情况,一是key不存在,二是该key中存的是null,所以应该使用map.containskey(key)返回的true/false来判断是否存在这个key。

hashMap在单线程中使用大大提高效率,在多线程的情况下使用hashTable来确保安全。hashTable中使用synchronized关键字来实现安全机制,但是synchronized是对整张hash表进行锁定即让线程独享整张hash表,在安全同时造成了浪费。concurrentHashMap采用分段加锁的机制来确保安全

Vector、List

Vector相当于一个线程安全的List

HashMap是非线程安全的,其对应的线程安全类是HashTable

Arraylist是非线程安全的,其对应的线程安全类是Vector

StringBuffer是线程安全的,相当于一个线程安全的StringBuilder

Properties 继承了Hashtable,因为Hashtable是线程安全的,所以Properties是线程安全的

关键字

instanceof

访问权限

img

默认访问权限是整个package,而protected访问权限不仅包含package还包含其子类就可以了

二进制相关

异常处理

一旦在finally块中使用了return或throw语句,将会导致try块,catch块中的return,throw语句失效

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public boolean returnTest()
{
try
{
return true;
}
catch (Exception e)
{

}
finally
{
return false;
}
}

返回 false

根据官方的JVM规范:
如果try语句里有return,返回的是try语句块中变量值。
详细执行过程如下:

  1. 如果有返回值,就把返回值保存到局部变量中;
  2. 执行jsr指令跳到finally语句里执行;
  3. 执行完finally语句后,返回之前保存在局部变量表里的值。

如果try,finally语句里均有return,忽略try的return,而使用finally的return.

局部变量、成员变量、static、初始值:

  1. 成员变量是独立于方法外的变量,局部变量是类的方法中的变量
    1. 成员变量:包括实例变量和类变量,用 static 修饰的是类变量,不用 static 修饰的是实例变量,所有类的成员变量可以通过 this 来引用。
    2. 局部变量:包括形参,方法局部变量,代码块局部变量,存在于方法的参数列表和方法定义中以及代码块中。
  2. 成员变量可以被public,protect,private,static等修饰符修饰,而局部变量不能被控制修饰符及 static修饰;两者都可以定义成final型。
  3. 成员变量存储在堆,局部变量存储在栈。局部变量的作用域仅限于定义它的方法,在该方法的外部无法访问它。成员变量的作用域在整个类内部都是可见的,所有成员方法都可以使用它。如果访问权限允许,还可以在类的外部使用成员变量。
  4. 局部变量的生存周期与方法的执行期相同。当方法执行到定义局部变量的语句时,局部变量被创建;执行到它所在的作用域的最后一条语句时,局部变量被销毁。类的成员变量,如果是实例成员变量,它和对象的生存期相同。而静态成员变量的生存期是整个程序运行期。
  5. 成员变量在类加载或实例被创建时,系统自动分配内存空间,并在分配空间后自动为成员变量指定初始化值,初始化值为默认值,基本类型的默认值为0,复合类型的默认值为null。(被final修饰且没有static的必须显式赋值),局部变量在定义后必须经过显式初始化后才能使用,系统不会为局部变量执行初始化。
  6. 局部变量可以和成员变量 同名,且在使用时,局部变量具有更高的优先级,直接使用同名访问,访问的是局部变量,如需要访问成员变量可以用this.变量名访问
    1. 成员变量赋值的规律:接班数据类型byte、short、char、int、long默认赋值0,float、double默认赋值0.0,String等引用数据类型默认赋值null
    2. 类变量在不设置初始值时,会进行默认值赋值,而局部方法中声明的变量则必须进行初始化,他不会进行默认值赋值。
    3. 静态变量会默认赋初值,局部变量和final声明的变量必须手动赋初值

static 相关

声明位置 初始值 生命周期 修饰的内容

抽象类

abstract修饰的类是抽象类,是可以继承的,而final修饰的类表示不能再被继承,故两者不能共同使用

父类、子类、继承、super

  1. 子类构造函数调用父类构造函数用super,且super语句必须是子类构造方法的第一句

  2. 子类重写父类方法后,若想调用父类中被重写的方法,用super。未被重写的方法可以直接调用。

  3. 关于文件

    1. File类是对文件整体或者文件属性操作的类,例如创建文件、删除文件、查看文件是否存在等功能,不能操作文件内容;文件内容是用IO流操作的。

Java 三大注解

  1. Java三大注解分别是@Override @Deprecated @Suppresswarnings
  2. @Override 注解表名子类中覆盖了超类中的某个方法,如果写错了覆盖形式,编译器会报错
  3. @Deprecated 表明不希望别人在以后使用这个类,方法,变量等等
  4. @Suppresswarnings 达到抑制编译器产生警告的目的,但是不建议使用,因为后期编码人员看不懂编译器提示的警告,不能更好的选择更好的类去完成任务

文件处理

文件操作的类及其用法:文本文件 二进制文件

内存使用问题

各个变量的存储位置,JVM的内存模型等

多线程、同步等问题

volatile关键字是一种轻量级的同步机制,只保证数据的可见性,而不保证数据的原子性。

volatile关键字有两个作用:

1.并发环境可见性:volatile修饰后的变量能够保证该变量在线程间的可见性,线程进行数据的读写操作时将绕开工作内存(CPU缓存)而直接跟主内存进行数据交互,即线程进行读操作时直接从主内存中读取,写操作时直接将修改后端变量刷新到主内存中,这样就能保证其他线程访问到的数据是最新数据

2.并发环境有序性:通过对volatile变量采取内存屏障(Memory barrier)的方式来防止编译重排序和CPU指令重排序,具体方式是通过在操作volatile变量的指令前后加入内存屏障,来实现happens-before关系,保证在多线程环境下的数据交互不会出现紊乱。

一旦一个共享变量(类的成员变量、类的静态成员变量)被volatile修饰之后,那么就具备了两层语义:

1)保证了不同线程对这个变量进行操作时的可见性,即一个线程修改了某个变量的值,这新值对其他线程来说是立即可见的。

2)禁止进行指令重排序。

volatile只提供了保证访问该变量时,每次都是从内存中读取最新值,并不会使用寄存器缓存该值——每次都会从内存中读取。

而对该变量的修改,volatile并不提供原子性的保证。

由于及时更新,很可能导致另一线程访问最新变量值,无法跳出循环的情况

多线程下计数器必须使用锁保护。

volatile本质是在告诉jvm当前变量在寄存器中的值是不确定的,需要从主存中读取,对volatile变量的操作不会造成阻塞。synchronized则是锁定当前变量,只有当前线程可以访问该变量,其他线程被阻塞住。

Synchronized用于线程间的数据共享,而ThreadLocal则用于线程间的数据隔离。

坚持原创技术分享,感谢您的支持和鼓励!