优先级
++
作为后缀时的优先级比*
高,因此*p++
是先 p++, 而后*(p++)
的。
++
作为后缀时优先级和()
一样高,结合律从左到右。因此(*p)++
是先取值,然后++
。
++
作为前缀时的优先级和*
一样高, 结合律从右到左, 所以++*p == ++(*p)
的。
基本的数据结构
从框架图中了解继承关系以及重要的数据结构(包括其继承情况、底层原理等)
集合常考点:
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
访问权限
默认访问权限是整个package,而protected访问权限不仅包含package还包含其子类就可以了
二进制相关
异常处理
一旦在finally块中使用了return或throw语句,将会导致try块,catch块中的return,throw语句失效
1 | public boolean returnTest() |
返回 false
根据官方的JVM规范:
如果try语句里有return,返回的是try语句块中变量值。
详细执行过程如下:
- 如果有返回值,就把返回值保存到局部变量中;
- 执行jsr指令跳到finally语句里执行;
- 执行完finally语句后,返回之前保存在局部变量表里的值。
如果try,finally语句里均有return,忽略try的return,而使用finally的return.
局部变量、成员变量、static、初始值:
- 成员变量是独立于方法外的变量,局部变量是类的方法中的变量
- 成员变量:包括实例变量和类变量,用 static 修饰的是类变量,不用 static 修饰的是实例变量,所有类的成员变量可以通过 this 来引用。
- 局部变量:包括形参,方法局部变量,代码块局部变量,存在于方法的参数列表和方法定义中以及代码块中。
- 成员变量可以被public,protect,private,static等修饰符修饰,而局部变量不能被控制修饰符及 static修饰;两者都可以定义成final型。
- 成员变量存储在堆,局部变量存储在栈。局部变量的作用域仅限于定义它的方法,在该方法的外部无法访问它。成员变量的作用域在整个类内部都是可见的,所有成员方法都可以使用它。如果访问权限允许,还可以在类的外部使用成员变量。
- 局部变量的生存周期与方法的执行期相同。当方法执行到定义局部变量的语句时,局部变量被创建;执行到它所在的作用域的最后一条语句时,局部变量被销毁。类的成员变量,如果是实例成员变量,它和对象的生存期相同。而静态成员变量的生存期是整个程序运行期。
- 成员变量在类加载或实例被创建时,系统自动分配内存空间,并在分配空间后自动为成员变量指定初始化值,初始化值为默认值,基本类型的默认值为0,复合类型的默认值为null。(被final修饰且没有static的必须显式赋值),局部变量在定义后必须经过显式初始化后才能使用,系统不会为局部变量执行初始化。
- 局部变量可以和成员变量 同名,且在使用时,局部变量具有更高的优先级,直接使用同名访问,访问的是局部变量,如需要访问成员变量可以用this.变量名访问
- 成员变量赋值的规律:接班数据类型byte、short、char、int、long默认赋值0,float、double默认赋值0.0,String等引用数据类型默认赋值null
- 类变量在不设置初始值时,会进行默认值赋值,而局部方法中声明的变量则必须进行初始化,他不会进行默认值赋值。
- 静态变量会默认赋初值,局部变量和final声明的变量必须手动赋初值
static 相关
声明位置 初始值 生命周期 修饰的内容
抽象类
abstract修饰的类是抽象类,是可以继承的,而final修饰的类表示不能再被继承,故两者不能共同使用
父类、子类、继承、super
子类构造函数调用父类构造函数用super,且super语句必须是子类构造方法的第一句
子类重写父类方法后,若想调用父类中被重写的方法,用super。未被重写的方法可以直接调用。
关于文件
- File类是对文件整体或者文件属性操作的类,例如创建文件、删除文件、查看文件是否存在等功能,不能操作文件内容;文件内容是用IO流操作的。
Java 三大注解
- Java三大注解分别是@Override @Deprecated @Suppresswarnings
- @Override 注解表名子类中覆盖了超类中的某个方法,如果写错了覆盖形式,编译器会报错
- @Deprecated 表明不希望别人在以后使用这个类,方法,变量等等
- @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则用于线程间的数据隔离。