美文网首页
(7)Constructor类的基本使用

(7)Constructor类的基本使用

作者: Mrsunup | 来源:发表于2018-10-06 12:11 被阅读0次

    上一小节主要讲解了Method的invoke的深度解析,Constructor打算从下面几个方面来讲解:

    查找指定的构造函数
    解析检索构造函数的修饰符
    创建实例
    常见的构造错误
    为什么构造方法newInstance就可以创建一个实例出来

    可以发现,构造函数,要比方法要少些内容,比如返回值信息,其他的基本一样的,构造函数是不能被继承的,类中只能查找当前类的构造函数,不能找到父类的构造函数

    1.查找指定的构造函数

    import java.lang.reflect.Constructor;
    import java.lang.reflect.Type;
    import static java.lang.System.out;
    
    public class ConstructorSift {
        public static void main(String... args) {
    //      args =new String[]{Formatter.class.getName(),Locale.class.getName()};
            //[C 代表char[]数组
    //      args =new String[]{String.class.getName(),"[C"};
            args  =new String[]{ProcessBuilder.class.getName(),"[Ljava.lang.String;"};
            try {
                Class<?> cArg = Class.forName(args[1]);
                Class<?> c = Class.forName(args[0]);
                Constructor[] allConstructors = c.getDeclaredConstructors();
                for (Constructor ctor : allConstructors) {
    
                    Class<?>[] pType  = ctor.getParameterTypes();
                    for (int i = 0; i < pType.length; i++) {
                        if (pType[i].equals(cArg)) {
                            //ctor.isVarArgs()  是区分可变参数与数组参数的区别,如果是可变参数则为true
                            System.out.println("ctor:"+ctor.isVarArgs());
                            out.format("%s%n", ctor.toGenericString());
                            Type[] gpType = ctor.getGenericParameterTypes();
                            for (int j = 0; j < gpType.length; j++) {
                                char ch = (pType[j].equals(cArg) ? '*' : ' ');
                                out.format("%7c%s[%d]: %s%n", ch,
                                        "GenericParameterType", j, gpType[j]);
                            }
                            break;
                        }
                    }
                }
                // production code should handle this exception more gracefully
            } catch (ClassNotFoundException x) {
                x.printStackTrace();
            }
        }
    }
    

    输出结果为: ProcessBuilder类中构造函数中有String的可变参数的构造函数,所有Constructor.isVarArgs()表示构造函数包含可变参数

    ctor:true
    public java.lang.ProcessBuilder(java.lang.String...)
          *GenericParameterType[0]: class [Ljava.lang.String;
    

    2.解析检索构造函数的修饰符

    构造函数的修饰符,与方法的修饰符以及类的修饰符获取差不多。
    下面展示了一种内部类的构造函数中引用外部类时,类会默认生成一种带有内部类参数的构造函数

    /**
     *   构造函数访问修饰符  测试
     */
    public class ConstructorAccess {
        public static void main(String... args) {
    //      args = new String[]{File.class.getName(),"private"};
            args = new String[]{SyntheticConstructor.class.getName(), "package-private"};
            try {
                Class<?> c = Class.forName(args[0]);
                Constructor[] allConstructors = c.getDeclaredConstructors();
                for (Constructor ctor : allConstructors) {
                    int searchMod = modifierFromString(args[1]); //如果是package-private,这里是0
                    int mods = accessModifiers(ctor.getModifiers());
                    if (searchMod == mods) {
                        out.format("%s%n", ctor.toGenericString());
                        out.format("  [ synthetic=%-5b var_args=%-5b ]%n",
                                ctor.isSynthetic(), ctor.isVarArgs());
                    }
                }
            } catch (ClassNotFoundException x) {
                x.printStackTrace();
            }
        }
        private static int accessModifiers(int m) {
            return m & (Modifier.PUBLIC | Modifier.PRIVATE | Modifier.PROTECTED);
        }
    
        private static int modifierFromString(String s) {
            if ("public".equals(s)) return Modifier.PUBLIC;
            else if ("protected".equals(s)) return Modifier.PROTECTED;
            else if ("private".equals(s)) return Modifier.PRIVATE;
            else if ("package-private".equals(s)) return 0;
            else return -1;
        }
    }
    
    class SyntheticConstructor {
        private SyntheticConstructor() {
        }
       // SyntheticConstructor(Inner inner){ }
         class Inner {
            Inner() {
                /**
                 * 这里Inner()函数引用了外部的构造函数,于是编译器会生成一个构造函数,等同上面注释的SyntheticConstructor(Inner inner){ }
                 * 而这个构造函数是package-private的构造函数
                 */
                new SyntheticConstructor();
            }
        }
    }
    

    输出结果如下: 多了个参数为com.java.reflect.merbers.constructors.SyntheticConstructor$1的构造函数,可以了解SyntheticConstructor(Inner inner){ }是编译器自动生成的

    com.java.reflect.merbers.constructors.SyntheticConstructor(com.java.reflect.merbers.constructors.SyntheticConstructor$1)
      [ synthetic=true  var_args=false ]
    

    3.创建实例

    import java.lang.reflect.Constructor;
    import java.lang.reflect.InvocationTargetException;
    import java.util.HashMap;
    import java.util.Map;
    import java.util.Set;
    
    import static java.lang.System.out;
    
    class EmailAliases {
        private Set<String> aliases;
    
        private EmailAliases(HashMap<String, String> h) {
            aliases = h.keySet();
        }
    
        public void printKeys() {
            out.format("Mail keys:%n");
            for (String k : aliases)
                out.format("  %s%n", k);
        }
    }
    
    public class RestoreAliases {
    
        private static Map<String, String> defaultAliases = new HashMap<String, String>();
    
        static {
            defaultAliases.put("Duke", "duke@i-love-java");
            defaultAliases.put("Fang", "fang@evil-jealous-twin");
        }
    
        public static void main(String... args) {
            try {
                Constructor ctor = EmailAliases.class.getDeclaredConstructor(HashMap.class);
                ctor.setAccessible(true);
                EmailAliases email = (EmailAliases) ctor.newInstance(defaultAliases);
                email.printKeys();
    
                // production code should handle these exceptions more gracefully
            } catch (InstantiationException x) {
                x.printStackTrace();
            } catch (IllegalAccessException x) {
                x.printStackTrace();
            } catch (InvocationTargetException x) {
                x.printStackTrace();
            } catch (NoSuchMethodException x) {
                x.printStackTrace();
            }
        }
    }
    

    输出结果如下:可以发现把defaultAliases值传入了构造函数中,并创建了一个新的实例

    Mail keys:
      Fang
      Duke
    

    4.常见的构造错误

    • constructor.newInstance()时没有无参的构造函数
    /**
     * 没有无参的构造函数 引发错误
     */
    public class ConstructorTrouble {
        public static void main(String... args){
        try {
            Class<?> c =ConstructorTroubleTest.class ;
            Object o = c.newInstance();  // InstantiationException
    
            // production code should handle these exceptions more gracefully
        } catch (InstantiationException x) {
            x.printStackTrace();
        } catch (IllegalAccessException x) {
            x.printStackTrace();
        }
        }
    }
    class  ConstructorTroubleTest{
        //声明了带参数的构造方法,会阻止编译器生成无参的构造方法
        private ConstructorTroubleTest(int i) {}
    }
    
    
    • 访问私有的构造函数报错
    /**
     * 访问私有的构造函数报错
     */
    public class ConstructorTroubleAccess {
        public static void main(String... args) {
        try {
            Constructor c = Deny.class.getDeclaredConstructor();
    //          c.setAccessible(true);   // solution 解决方案
            c.newInstance();
            // production code should handle these exceptions more gracefully
        } catch (InvocationTargetException x) {
            x.printStackTrace();
        } catch (NoSuchMethodException x) {
            x.printStackTrace();
        } catch (InstantiationException x) {
            x.printStackTrace();
        } catch (IllegalAccessException x) {
            x.printStackTrace();
        }
        }
    }
    class Deny {
        private Deny() {
            System.out.format("Deny constructor%n");
        }
    }
    

    5.为什么构造方法newInstance就可以创建一个实例出来

    这里构造函数的newInstance创建实例,跟之前的方法的invoke方法类似,newInstance是由具体的 ConstructorAccessor来创建实例的,这里不再详细讲解,默认的具体的ConstructorAccessor为NativeConstructorAccessorImpl和DelegatingConstructorAccessorImpl,见下面的代码

      public ConstructorAccessor newConstructorAccessor(Constructor<?> var1) {
            checkInitted();
            Class var2 = var1.getDeclaringClass();
            if (Modifier.isAbstract(var2.getModifiers())) {
                return new InstantiationExceptionConstructorAccessorImpl((String)null);
            } else if (var2 == Class.class) {
                return new InstantiationExceptionConstructorAccessorImpl("Can not instantiate java.lang.Class");
            } else if (Reflection.isSubclassOf(var2, ConstructorAccessorImpl.class)) {
                return new BootstrapConstructorAccessorImpl(var1);
            } else if (noInflation && !ReflectUtil.isVMAnonymousClass(var1.getDeclaringClass())) {
                return (new MethodAccessorGenerator()).generateConstructor(var1.getDeclaringClass(), var1.getParameterTypes(), var1.getExceptionTypes(), var1.getModifiers());
            } else {
                NativeConstructorAccessorImpl var3 = new NativeConstructorAccessorImpl(var1);
                DelegatingConstructorAccessorImpl var4 = new DelegatingConstructorAccessorImpl(var3);
                var3.setParent(var4);
                return var4;
            }
        }
    

    NativeConstructorAccessorImpl的invoke也是由次数调用限制,小于ReflectionFactory.inflationThreshold()是由本地方法newInstance0创建实例的,重复调用次数大于ReflectionFactory.inflationThreshold()也就是15,是由jdk的MethodAccessorGenerator的方法访问生成器创建具体的ConstructorAccessorImpl实例,从而创建newInstance实例

      public Object newInstance(Object[] var1) throws InstantiationException, IllegalArgumentException, InvocationTargetException {
            if (++this.numInvocations > ReflectionFactory.inflationThreshold() && !ReflectUtil.isVMAnonymousClass(this.c.getDeclaringClass())) {
                ConstructorAccessorImpl var2 = (ConstructorAccessorImpl)(new MethodAccessorGenerator()).generateConstructor(this.c.getDeclaringClass(), this.c.getParameterTypes(), this.c.getExceptionTypes(), this.c.getModifiers());
                this.parent.setDelegate(var2);
            }
    
            return newInstance0(this.c, var1);
        }
        private static native Object newInstance0(Constructor<?> var0, Object[] var1) throws InstantiationException, IllegalArgumentException, InvocationTargetException;
    
    

    相关文章

      网友评论

          本文标题:(7)Constructor类的基本使用

          本文链接:https://www.haomeiwen.com/subject/pzthaftx.html