zoukankan      html  css  js  c++  java
  • “不让工具类能够实例化”的做法是适合的

    工具类往往没有对象层面的域(非static域),

    那么每个工具类的对象除了内存地址不同以外,是完全一样的

    并且,工具类里定义的全是static方法,

    那么为了调用这些方法,仅仅用类名调用就可以了

    结合以上两点,工具类没有必要实例化,也就没有必要向客户端提供实例化的解决方案。

    最先想到的应该是将显式的将构造方法私有化

    class OneUtil {
        private OneUtil() {}
        
        public static void method() {
            // Do something.
        }
    }

    这样一来,客户端的“new OneUtil();”被阻止了,客户端的开发者可能会去寻找valueOf()、getInstance()之类的方法。当他们找不到后,他们才会觉得OneUtil是个工具类。

    但是,仅仅如此OneUtil还是能够通过反射来产生实例。

    public class OneUtilTest {
        public static void main(String[] args) {
            OneUtil oneUtil = null;
    //        oneUtil = new OneUtil();
            try {
                oneUtil = (OneUtil) Class.forName("OneUtil").newInstance();
            } catch (InstantiationException e) {
            } catch (IllegalAccessException e) {
            } catch (ClassNotFoundException e) {
            }
            oneUtil.method();
        }
    }

    更进一步的方法是在构造方法里追加异常,保证异常能在运行期尽可能早的发生,

    RuntimeException的派生异常类,可以满足这个需求。

    class OneUtil {
        private OneUtil() {
            throw new UnsupportedOperationException("This class should not be instantiated.");
        }
        
        public static void method() {
            System.out.println("Do something."); 
        }
    }

    用恶意的方法测试一下

    public class OneUtilTest {
        public static void main(String[] args) throws Exception {
            OneUtil oneUtil = null;
    //        oneUtil = new OneUtil();
            Constructor<OneUtil> constructor=OneUtil.class.getDeclaredConstructor();  
            constructor.setAccessible(true);
            oneUtil = constructor.newInstance();
    
            oneUtil.method();
        }
    }
    Exception in thread "main" 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:423)
        at io.deolin.OneUtilTest.main(OneUtilTest.java:22)
    Caused by: java.lang.UnsupportedOperationException: This class should not be instantiated.
        at io.deolin.OneUtil.<init>(OneUtilTest.java:7)
        ... 5 more

    其实用abstract来修饰工具类也能达到类似的效果,

    但是,abstract的作用更像是对外声明“这个类无法实例化,是用来被继承的”

    工具类作为一个过程化的反oop的东西,用abstract来修饰它显然是不合适的。

  • 相关阅读:
    读入输出优化模板
    HDU-2647 Reward(拓扑排序)
    HDU-2647 Reward(拓扑排序)
    HDU-2647 Reward(拓扑排序)
    HDU-2647 Reward(拓扑排序)
    Using KafkaBolt to write to a kafka topic
    Using KafkaBolt to write to a kafka topic
    Using KafkaBolt to write to a kafka topic
    Using KafkaBolt to write to a kafka topic
    getElementById() 获取指定ID的第一个元素
  • 原文地址:https://www.cnblogs.com/deolin/p/7146117.html
Copyright © 2011-2022 走看看