自增变量
- 给爷整懵逼了
public static void main(String[] args) {
int i = 1; // i = 1
i = i++; // i = 1
int j = i++; // j = 1 , i = 2
int k = i + ++i * i++; // i = 4, j = 1, k = 11
System.out.println("i=" + i);
System.out.println("j=" + j);
System.out.println("k=" + k);
}
单例模式
- 饿汉式:在类初始化时直接创建实例对象,不管你是否需要这个对象,都会创建。 没有线程安全问题
实现步骤:
- 私有化构造器
- 自行创建,并且用静态变量保存
- 向外提供这个实例
- 强调这是一个单例,我们可以用final修饰
public class Singleton {
//私有化构造器
private Singleton() {};
public static final Singleton INSTANCE = new Singleton();
}
public enum Singleton2 {
INSTANCE;
}
/**
* 使用静态代码块 实现复杂逻辑构造器的饿汉式单例模式
*/
public class Singleton3 {
//私有化有参构造器
private Singleton3(String info){
this.info = info;
}
private String info;
public static final Singleton3 INSTANCE;
//在静态代码块中进行初始化实例对象
static {
Properties props = new Properties();
try {
props.load(Singleton3.class.getClassLoader().getResourceAsStream("application.properties"));
} catch (IOException e) {
e.printStackTrace();
}
String info = props.getProperty("info");
INSTANCE = new Singleton3(info);
}
}
- 懒汉式:延迟创建这个实例对象 (什么时候调用get方法 什么时候创建对象)
实现步骤:
- 私有化构造器
- 用一个静态变量保存这个唯一的实例
- 提供一个静态方法,获取这个实例对象
线程不安全:适用于单线程
public class Singleton4 {
//私有化构造器
private Singleton4() {
}
//私有化静态变量
private static Singleton4 INSTANCE;
/**
* 有线程安全问题(需要增加双端验证,我忘了咋写了,待会百度一下)
*/
public static Singleton4 getInstance() {
//TODO 线程不安全
if (INSTANCE == null) {
INSTANCE = new Singleton4();
}
return INSTANCE;
}
}
线程安全:适用于多线程
public class Singleton5 {
private Singleton5(){}
private static Singleton5 instance;
public static Singleton5 getInstance(){
//提高效率
if(instance == null){
//增加同步锁
synchronized (Singleton5.class){
//双端验证
if(instance == null){
instance = new Singleton5();
}
}
}
return instance;
}
}
线程安全:使用静态内部类实现的 线程安全
静态内部类不会自动随着外部类的加载和初始化而初始化,(他虽然在类的内部)但他还是需要单独去加载和初始化的
因为是在内部类加载和初始化时创建的,因此是线程安全的
public class Singleton6 {
private Singleton6(){}
public static Singleton6 getInstance(){
return Inner.instance;
}
//静态内部类
private static class Inner{
private static final Singleton6 instance = new Singleton6();
}
}
-
总结:
什么时候使用饿汉式 / 懒汉式,取决于需要什么时机来创建对象。 -
关于线程安全问题:
只要是饿汉式,都没有线程安全问题。
懒汉式,有可能存在线程安全问题,但是可以通过同步锁或静态内部类解决。
类的加载过程
-
类初始化过程
-
一个类要创建实例需要先加载并初始化该类
◆main
方法所在的类需要先加载和初始化 -
一个子类要初始化需要先初始化父类
super()
-
一个类初始化就是执行
<init>()
方法
◆<clinit>()
方法由静态类变量显示赋值代码和静态代码块组成
◆类变量显示赋值代码和静态代码块代码从上到下顺序执行
◆<clinit>()
方法只执行一次 -
总结
-
由父及子,先静后动,同级则从上到下,最后触发构造器
-
super()
写与不写,一直存在 -
父类静态代码块/静态属性的显式赋值 =》 子类静态代码块/静态属性的显式赋值 =》 父类非静态代码块/非静态属性的显式赋值 =》 父类构造器 =》 子类非静态代码块/非静态属性的显式赋值 =》 子类构造器
-
父类的
static
方法不能被重写 -
static
修饰的静态代码块和显示赋值只有在类第一次
加载初始化时才会执行 -
非静态
的代码块和显示赋值在每次
实例化对象时 都会执行 -
实例初始化过程
- 实例初始化就是执行方法
<init>()
方法可能重载有多个,有几个构造器就有几个<init>()
方法<init>()
方法由非静态实例变量显示赋值代码和非静态代码块、对应构造器代码组成- 非静态实例变黃显示赋值代码和非静态代码块代码从上到下顺序执行,而对应构造器的代码最后执行
- 每次创建实例对象,调用对应构造器,执行的就是对应的
<init>()
方法 <init>()
方法的首行是super()
或super(实参列表)
,即对应父类的<init>()
方法
-
方法的重写 Override
-
哪些方法不可以被重写
final
方法- 静态方法
- private等子类中不可见方法
-
对象的多态性
- 子类如果重写了父类的方法,通过子类对象调用的一定是子类重写过的代码
- 非静态方法默认的调用对象是this
- this对象在构造器或者说方法中就是正在创建的对象