object
Declaration of singleton object:
object Model{
var temp = "1"
val temp2 = "2"
const val temp3 = "3"
}
Questions are raised: object
What type of singleton pattern is used for the modified class?
Here we first review java
the six singleton patterns
1. Hungry Chinese style
public class HungryMan {
private HungryMan(){
}
private static HungryMan hungryMan = new HungryMan();
public static HungryMan getInstance(){
return hungryMan;
}
}
Advantages: simple and convenient, thread safe
Disadvantages: Whether it is used or not, it will be instantiated, and it will be instantiated when the class is loaded
2. Lazy style
public class LazyMan {
private static LazyMan lazyMan = null;
private LazyMan() {
}
public static LazyMan getInstatce() {
if (lazyMan == null) {
lazyMan = new LazyMan();
}
return lazyMan;
}
}
Advantages: Objects are only generated when they are used, which can reduce memory overhead
Disadvantages: Thread is not safe and can only be used in a single thread. When multiple threads access, multiple objects will be generated.
3. Lazy sync lock
public class LazyMan {
private static volatile LazyMan lazyMan = null;
private LazyMan() {
}
public static LazyMan getInstatce() {
synchronized (LazyMan.class){
if (lazyMan == null) {
lazyMan = new LazyMan();
}
}
return lazyMan;
}
}
Pros: supports multithreading
Disadvantages: There will be a lock and release operation every time, which is inefficient and can destroy the singleton mode through reflection.
4. DCL
Double detection lock
public class LazyMan {
private static volatile LazyMan lazyMan = null;
private LazyMan() {
}
public static LazyMan getInstatce() {
if(lazyMan == null){
synchronized (LazyMan.class){
if (lazyMan == null) {
lazyMan = new LazyMan();
}
}
}
return lazyMan;
}
}
Here is an introduction to explain DCL
the double detection lock mechanism:
DCL
Double detection lock mechanism: DCL
Why use double detection lock mechanism to valoatile
modify, because lazyMan=new LazyMan()
it is not an atomic operation. In fact, JVM
I probably did 3 things in .
1. To lazyMan
allocate memory,
2. Call the constructor to initialize member variables
3. Point lazyMan
the object to the allocated memory space. However JVM
, there is an optimization of instruction reordering in the real-time compiler, that is to say, the order of the second and third steps above is uncertain. Once 2, 3, the order is messed up. This is because a thread calls the method. It is non-null, but it is not initialized, so an error is reported directly.
Advantages: high efficiency, thread safety
Disadvantages: the code is complicated, and the singleton can be destroyed by reflection
5. Static inner class
public class Singleton {
private Singleton() {
}
private static class SingletonInstance {
//私有静态内部类
private static final Singleton INSTANCE = new Singleton();
}
public static Singleton getInstance() {
return SingletonInstance.INSTANCE;
}
}
Advantages: The static properties of the class are only initialized when the class is loaded for the first time, so thread safety
Disadvantages: the code becomes complicated and
apk
the file size increases
6. Enumerate singletons
public enum SingleTon {
SINGLE_TON;
private String field;
public String getField() {
return field;
}
public void setField(String field) {
this.field = field;
}
}
Advantages: thread safety, no need to worry about reflection breaking singleton mode
Disadvantage: enumeration class takes up a lot of memory
Analysis: What type of singleton is the object singleton class
Here we directly convert kotlin
the code to Java code for viewing.
kotlin
code show as below
Java
after turning
We can see Model
that Java
after the class is converted into code, it is a hungry singleton. So object
the class used is a hungry Chinese singleton.
companion object
What type of singleton is the singleton that appears in the companion object
kotlin
code show as below
class Model{
companion object{
val text = ApiWrapper("11")
}
}
class ApiWrapper (val api : String){
fun s() {
}
}
java
code show as below
public final class Model {
@NotNull
private static final ApiWrapper text = new ApiWrapper("11");
@NotNull
public static final Model.Companion Companion = new Model.Companion((DefaultConstructorMarker)null);
public static final class Companion {
@NotNull
public final ApiWrapper getText() {
return Model.text;
}
private Companion() {
}
public Companion(DefaultConstructorMarker $constructor_marker) {
this();
}
}
}
It can be seen that if you assign text
a value directly, it is equivalent to a hungry Chinese style loading
But what if we text
do lazy assignment onby lazy
public final class Model {
@NotNull
private static final Lazy text$delegate;
@NotNull
public static final Model.Companion Companion = new Model.Companion((DefaultConstructorMarker)null);
static {
text$delegate = LazyKt.lazy((Function0)null.INSTANCE);
}
public static final class Companion {
@NotNull
public final ApiWrapper getText() {
Lazy var1 = Model.text$delegate;
Model.Companion var2 = Model.Companion;
Object var3 = null;
return (ApiWrapper)var1.getValue();
}
private Companion() {
}
public Companion(DefaultConstructorMarker $constructor_marker) {
this();
}
}
}
It can be seen that this time becomes 懒汉式同步单例
,
As for why it is a synchronous singleton, here you need to look at LazyKt.lazy()
the method