From 37db34cb8acdd42834e5d9af0df42e61440fd6f5 Mon Sep 17 00:00:00 2001 From: anmoldeep0123 Date: Fri, 9 Jul 2021 14:57:55 +0530 Subject: [PATCH] BAEL-4933 | Differences between static classes and the singleton pattern in Java (#11014) * BAEL-4220 | A Guide to IllegalAccessError and when it happens * BAEL-4220 | A Guide to IllegalAccessError and when it happens | fix tests * BAEL-4220 | A Guide to IllegalAccessError and when it happens | fix tests * BAEL-4220 | A Guide to IllegalAccessError and when it happens | BDD test names * BAEL-4494 | .toArray(new MyClass[0]) or .toArray(new MyClass[myList.size()])? * BAEL-4494 | .toArray(new MyClass[0]) or .toArray(new MyClass[myList.size()])? * BAEL-4933 | Differences between static classes and the singleton pattern in Java Co-authored-by: root --- .../CachingSingleton.java | 30 ++++++++ .../FileSystemSingleton.java | 36 +++++++++ .../staticsingletondifference/MyLock.java | 8 ++ .../SerializableCloneableSingleton.java | 49 ++++++++++++ .../SingletonInterface.java | 10 +++ .../SingletonLock.java | 20 +++++ .../staticsingletondifference/SubUtility.java | 8 ++ .../SuperUtility.java | 8 ++ .../ForSingletonsUnitTest.java | 77 +++++++++++++++++++ 9 files changed, 246 insertions(+) create mode 100644 core-java-modules/core-java-lang-oop-modifiers/src/main/java/com/baeldung/staticsingletondifference/CachingSingleton.java create mode 100644 core-java-modules/core-java-lang-oop-modifiers/src/main/java/com/baeldung/staticsingletondifference/FileSystemSingleton.java create mode 100644 core-java-modules/core-java-lang-oop-modifiers/src/main/java/com/baeldung/staticsingletondifference/MyLock.java create mode 100644 core-java-modules/core-java-lang-oop-modifiers/src/main/java/com/baeldung/staticsingletondifference/SerializableCloneableSingleton.java create mode 100644 core-java-modules/core-java-lang-oop-modifiers/src/main/java/com/baeldung/staticsingletondifference/SingletonInterface.java create mode 100644 core-java-modules/core-java-lang-oop-modifiers/src/main/java/com/baeldung/staticsingletondifference/SingletonLock.java create mode 100644 core-java-modules/core-java-lang-oop-modifiers/src/main/java/com/baeldung/staticsingletondifference/SubUtility.java create mode 100644 core-java-modules/core-java-lang-oop-modifiers/src/main/java/com/baeldung/staticsingletondifference/SuperUtility.java create mode 100644 core-java-modules/core-java-lang-oop-modifiers/src/test/java/com/baeldung/staticsingletondifference/ForSingletonsUnitTest.java diff --git a/core-java-modules/core-java-lang-oop-modifiers/src/main/java/com/baeldung/staticsingletondifference/CachingSingleton.java b/core-java-modules/core-java-lang-oop-modifiers/src/main/java/com/baeldung/staticsingletondifference/CachingSingleton.java new file mode 100644 index 0000000000..d472e386eb --- /dev/null +++ b/core-java-modules/core-java-lang-oop-modifiers/src/main/java/com/baeldung/staticsingletondifference/CachingSingleton.java @@ -0,0 +1,30 @@ +package com.baeldung.staticsingletondifference; + +public class CachingSingleton implements SingletonInterface { + + private CachingSingleton() { + } + + private static class SingletonHolder { + public static final CachingSingleton instance = new CachingSingleton(); + } + + public static CachingSingleton getInstance() { + return SingletonHolder.instance; + } + + @Override + public String describeMe() { + return "Caching Responsibilities"; + } + + @Override + public String passOnLocks(MyLock lock) { + return lock.takeLock(1); + } + + @Override + public void increment() { + throw new UnsupportedOperationException("Not Supported Here"); + } +} diff --git a/core-java-modules/core-java-lang-oop-modifiers/src/main/java/com/baeldung/staticsingletondifference/FileSystemSingleton.java b/core-java-modules/core-java-lang-oop-modifiers/src/main/java/com/baeldung/staticsingletondifference/FileSystemSingleton.java new file mode 100644 index 0000000000..84ea5d4d1a --- /dev/null +++ b/core-java-modules/core-java-lang-oop-modifiers/src/main/java/com/baeldung/staticsingletondifference/FileSystemSingleton.java @@ -0,0 +1,36 @@ +package com.baeldung.staticsingletondifference; + +public class FileSystemSingleton implements SingletonInterface{ + + private int filesWritten; + + private FileSystemSingleton() { + } + + private static class SingletonHolder { + public static final FileSystemSingleton instance = new FileSystemSingleton(); + } + + public static FileSystemSingleton getInstance() { + return SingletonHolder.instance; + } + + @Override + public String describeMe() { + return "File System Responsibilities"; + } + + @Override + public String passOnLocks(MyLock lock) { + return lock.takeLock(2); + } + + @Override + public void increment() { + this.filesWritten++; + } + + public int getFilesWritten() { + return filesWritten; + } +} diff --git a/core-java-modules/core-java-lang-oop-modifiers/src/main/java/com/baeldung/staticsingletondifference/MyLock.java b/core-java-modules/core-java-lang-oop-modifiers/src/main/java/com/baeldung/staticsingletondifference/MyLock.java new file mode 100644 index 0000000000..3a124bd678 --- /dev/null +++ b/core-java-modules/core-java-lang-oop-modifiers/src/main/java/com/baeldung/staticsingletondifference/MyLock.java @@ -0,0 +1,8 @@ +package com.baeldung.staticsingletondifference; + +public class MyLock { + + protected String takeLock(int locks) { + return "Taken Specific Lock"; + } +} diff --git a/core-java-modules/core-java-lang-oop-modifiers/src/main/java/com/baeldung/staticsingletondifference/SerializableCloneableSingleton.java b/core-java-modules/core-java-lang-oop-modifiers/src/main/java/com/baeldung/staticsingletondifference/SerializableCloneableSingleton.java new file mode 100644 index 0000000000..64a422f9ec --- /dev/null +++ b/core-java-modules/core-java-lang-oop-modifiers/src/main/java/com/baeldung/staticsingletondifference/SerializableCloneableSingleton.java @@ -0,0 +1,49 @@ +package com.baeldung.staticsingletondifference; + +import java.io.ObjectStreamException; +import java.io.Serializable; + +public class SerializableCloneableSingleton implements SingletonInterface, Serializable, Cloneable { + + private static final long serialVersionUID = -1917003064592196223L; + + private int state; + + private SerializableCloneableSingleton() { + } + + private static class SingletonHolder { + public static final SerializableCloneableSingleton instance = new SerializableCloneableSingleton(); + } + + public static SerializableCloneableSingleton getInstance() { + return SingletonHolder.instance; + } + + @Override + public String describeMe() { + throw new UnsupportedOperationException("Not Supported Here"); + } + + @Override + public String passOnLocks(MyLock lock) { + throw new UnsupportedOperationException("Not Supported Here"); + } + + @Override + public void increment() { + this.state++; + } + + public int getState() { + return state; + } + + private Object readResolve() throws ObjectStreamException { + return SingletonHolder.instance; + } + + public Object cloneObject() throws CloneNotSupportedException { + return this.clone(); + } +} diff --git a/core-java-modules/core-java-lang-oop-modifiers/src/main/java/com/baeldung/staticsingletondifference/SingletonInterface.java b/core-java-modules/core-java-lang-oop-modifiers/src/main/java/com/baeldung/staticsingletondifference/SingletonInterface.java new file mode 100644 index 0000000000..34e14c5cac --- /dev/null +++ b/core-java-modules/core-java-lang-oop-modifiers/src/main/java/com/baeldung/staticsingletondifference/SingletonInterface.java @@ -0,0 +1,10 @@ +package com.baeldung.staticsingletondifference; + +public interface SingletonInterface { + + public String describeMe(); + + public String passOnLocks(MyLock lock); + + public void increment(); +} diff --git a/core-java-modules/core-java-lang-oop-modifiers/src/main/java/com/baeldung/staticsingletondifference/SingletonLock.java b/core-java-modules/core-java-lang-oop-modifiers/src/main/java/com/baeldung/staticsingletondifference/SingletonLock.java new file mode 100644 index 0000000000..35d9931597 --- /dev/null +++ b/core-java-modules/core-java-lang-oop-modifiers/src/main/java/com/baeldung/staticsingletondifference/SingletonLock.java @@ -0,0 +1,20 @@ +package com.baeldung.staticsingletondifference; + +public class SingletonLock extends MyLock { + + private SingletonLock() { + } + + private static class SingletonHolder { + public static final SingletonLock instance = new SingletonLock(); + } + + public static SingletonLock getInstance() { + return SingletonHolder.instance; + } + + @Override + public String takeLock(int locks) { + return "Taken Singleton Lock"; + } +} diff --git a/core-java-modules/core-java-lang-oop-modifiers/src/main/java/com/baeldung/staticsingletondifference/SubUtility.java b/core-java-modules/core-java-lang-oop-modifiers/src/main/java/com/baeldung/staticsingletondifference/SubUtility.java new file mode 100644 index 0000000000..c9661cbf70 --- /dev/null +++ b/core-java-modules/core-java-lang-oop-modifiers/src/main/java/com/baeldung/staticsingletondifference/SubUtility.java @@ -0,0 +1,8 @@ +package com.baeldung.staticsingletondifference; + +public class SubUtility extends SuperUtility { + + public static String echoIt(String data) { + return data; + } +} diff --git a/core-java-modules/core-java-lang-oop-modifiers/src/main/java/com/baeldung/staticsingletondifference/SuperUtility.java b/core-java-modules/core-java-lang-oop-modifiers/src/main/java/com/baeldung/staticsingletondifference/SuperUtility.java new file mode 100644 index 0000000000..00011f4697 --- /dev/null +++ b/core-java-modules/core-java-lang-oop-modifiers/src/main/java/com/baeldung/staticsingletondifference/SuperUtility.java @@ -0,0 +1,8 @@ +package com.baeldung.staticsingletondifference; + +public class SuperUtility { + + public static String echoIt(String data) { + return "SUPER"; + } +} diff --git a/core-java-modules/core-java-lang-oop-modifiers/src/test/java/com/baeldung/staticsingletondifference/ForSingletonsUnitTest.java b/core-java-modules/core-java-lang-oop-modifiers/src/test/java/com/baeldung/staticsingletondifference/ForSingletonsUnitTest.java new file mode 100644 index 0000000000..4b0b23b5ec --- /dev/null +++ b/core-java-modules/core-java-lang-oop-modifiers/src/test/java/com/baeldung/staticsingletondifference/ForSingletonsUnitTest.java @@ -0,0 +1,77 @@ +package com.baeldung.staticsingletondifference; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.util.stream.IntStream; + +import org.junit.Assert; +import org.junit.Test; + +public class ForSingletonsUnitTest { + + @Test + public void whenStaticUtilClassInheritance_thenOverridingFails() { + SuperUtility superUtility = new SubUtility(); + Assert.assertNotEquals("ECHO", superUtility.echoIt("ECHO")); + Assert.assertEquals("SUPER", superUtility.echoIt("ECHO")); + } + + @Test + public void whenSingletonDerivesBaseClass_thenRuntimePolymorphism() { + MyLock myLock = new MyLock(); + Assert.assertEquals("Taken Specific Lock", myLock.takeLock(10)); + myLock = SingletonLock.getInstance(); + Assert.assertEquals("Taken Singleton Lock", myLock.takeLock(10)); + } + + @Test + public void whenSingletonImplementsInterface_thenRuntimePolymorphism() { + SingletonInterface singleton = FileSystemSingleton.getInstance(); + Assert.assertEquals("File System Responsibilities", singleton.describeMe()); + singleton = CachingSingleton.getInstance(); + Assert.assertEquals("Caching Responsibilities", singleton.describeMe()); + } + + @Test + public void whenSingleton_thenPassAsArguments() { + SingletonInterface singleton = FileSystemSingleton.getInstance(); + Assert.assertEquals("Taken Singleton Lock", singleton.passOnLocks(SingletonLock.getInstance())); + } + + @Test + public void whenSingleton_thenAllowState() { + SingletonInterface singleton = FileSystemSingleton.getInstance(); + IntStream.range(0, 5) + .forEach(i -> singleton.increment()); + Assert.assertEquals(5, ((FileSystemSingleton) singleton).getFilesWritten()); + } + + @Test + public void whenSingleton_thenAllowSerializationDeserialization() { + SingletonInterface singleton = SerializableCloneableSingleton.getInstance(); + singleton.increment(); + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + try { + new ObjectOutputStream(baos).writeObject(singleton); + SerializableCloneableSingleton singletonNew = (SerializableCloneableSingleton) new ObjectInputStream(new ByteArrayInputStream(baos.toByteArray())).readObject(); + Assert.assertEquals(1, singletonNew.getState()); + Assert.assertEquals(singleton.hashCode(), singletonNew.hashCode()); + } catch (IOException | ClassNotFoundException e) { + e.printStackTrace(); + } + } + + @Test + public void whenSingleton_thenAllowCloneable() { + SerializableCloneableSingleton singleton = SerializableCloneableSingleton.getInstance(); + singleton.increment(); + try { + Assert.assertEquals(2, ((SerializableCloneableSingleton) singleton.cloneObject()).getState()); + } catch (CloneNotSupportedException e) { + e.printStackTrace(); + } + } +} \ No newline at end of file