本文涉及的概念:
1.在面向對象編程中,在什么場景下會需要做到讓一個類不能被實例化
2.讓一個類不能被實例化的方法
什么樣的場景會需要讓一個類不能被實例化
工具類(utility class),實例化對它們沒有意義的工具類。這時候,就要做到不讓該類被實例化
java.lang.Math:
把與Math相關的基本類型的值和相關的方法組合到該Math類中。Math類不需要實例化,使用了私有構造器。不過,它可以在Math類中內部被實例化。
使用私有構造器,沒有子類;使用final修飾,沒有子類。
package java.lang; import java.util.Random; public final class Math { /** * Don't let anyone instantiate this class. */ private Math() {} /** * The {@code double} value that is closer than any other to * <i>e</i>, the base of the natural logarithms. */ public static final double E = 2.7182818284590452354; public static final double PI = 3.14159265358979323846; public static double sin(double a) { return StrictMath.sin(a); // default impl. delegates to StrictMath } .... public static double toRadians(double angdeg) { return angdeg / 180.0 * PI; } public static float scalb(float f, int scaleFactor) { return sun.misc.FpUtils.scalb(f, scaleFactor); } }
讓一個類不能被實例化的方法
0.不寫顯式的構造器---不可行,編譯器會自動提供一個公有的,無參的缺省的構造器
1.抽象類的方式---不可行
子類可以繼承父類,從而實例化
public abstract class Parent { public Parent() { } public static void main(String[] args){ // Parent one = new Parent(); } } public class Child extends Parent { public Child() { } }
2.使用私有構造器----可行,需要在構造器中添加限制
在使用私有構造器的基礎下,再在構造方法中返回一個異常,因為雖然外部類無法實例化該類,但是內部類可以實例化該類.
如果只是通過私有化構造器,那么通過反射的方式,還是可以實例化該類。
必須在私有構造器中添加一個異常,這樣,當執行構造方法的時候,就會拋出異常,從而停止實例化
import java.lang.reflect.Constructor; import java.lang.reflect.InvocationTargetException; public class Elvis2 { private Elvis2(){ throw new AssertionError(); } public void getIt(){ System.out.println("Now you get it"); } public static void main(String[] args){ try { Class<?> classType = Elvis2.class; Constructor<?> c = classType.getDeclaredConstructor(null); c.setAccessible(true); Elvis2 e1 = (Elvis2)c.newInstance(); e1.getIt(); } catch (InstantiationException | IllegalAccessException | IllegalArgumentException | InvocationTargetException | NoSuchMethodException | SecurityException e) { e.printStackTrace(); } } }
輸出結果: 拋出了AssertionError異常,達到期望
java.lang.reflect.InvocationTargetException
at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62)
at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
at java.lang.reflect.Constructor.newInstance(Constructor.java:422)
at chapterOne.Elvis2.main(Elvis2.java:21)
Caused by: java.lang.AssertionError
at chapterOne.Elvis2.<init>(Elvis2.java:8)
... 5 more
引用: