黑马程序员技术交流社区

标题: 使用反射来创建对象以及它一些案例 [打印本页]

作者: Lws    时间: 2016-9-5 20:08
标题: 使用反射来创建对象以及它一些案例
创建对象:
1、使用Class对象的newInstance()方法创建该Class对象的实例,此时该Class对象必须要有无参数的构造方法。
2、使用Class对象获取指定的Constructor对象,再调用Constructor的newInstance()方法创建对象类的实例,此时可以选择使用某个构造方法。如果这个构造方法被私有化起来,那么必须先申请访问,将可以访问设置为true;

Eg:
最简单的:
package junereflect624;

class User{
        /*private User(){//将默认的构造方法私有化的话就不可以再创建对象,两种方法都是这样
        }*/
        public String toString() {
                return "User对象创建成功!";
        }
}

public class NewInstanceDemo6 {
        public static void main(String[] args) throws Exception {
                //传统方式创建对象
                 System.out.println(new User());
                 
                 //使用反射的方式
                 Class<User> c = User.class;
                 User u = c.newInstance();(直接newInstance的话必须保证默认的构造方法正常存在,也就是没有被私有化!这是前提条件)
                 System.out.println(u);
        }
}


复杂点的:更强大的第二种:

使用指定构造方法来创建对象:
获取该类的Class对象。
利用Class对象的getConstructor()方法来获取指定的构造方法。
调用Constructor的newInstance()方法创建对象。

AccessibleObject对象的setAccessible(boolean flag)方法,当flag为true的时候,就会忽略访问权限(可访问私有的成员)。
其子类有Field, Method, Constructor;
若要访问对象private的成员?
在调用之前使用setAccessible(true),
        Xxx x = getDeclaredXxxx();//才能得到私有的类字段.

总结步骤:

1.获取该类的Class对象。
2.利用Class对象的getConstructor()方法来获取指定的构造方法。
3.申请访问(设置为可访问)
4.调用Constructor(构造方法)的newInstance()方法创建对象。

例子
package junereflect624;

import java.lang.reflect.Constructor;

class Per{
        private String name;
        private int age;
        private Per(){       
        }
        private Per(String name){
        }
        public String toString() {
                return "对象!!!";
        }
}

public class NewInstanceDemo7 {
        public static void main(String[] args) throws Exception {
                Class<Per> c = Per.class;
                //System.out.println(c.newInstance());;//证明利用无参的可以
               
                ////先获得需要被调用的构造器(private 修饰的构造方法)
                Constructor<Per> con = c.getDeclaredConstructor();//调用默认的,什么都不要写
                System.out.println(con);//private junereflect624.Per()
                /*con = c.getDeclaredConstructor(String.class);获取指定的构造方法
                System.out.println(con);//private junereflect624.Per(java.lang.String)*/               
                //现在只需要执行这个构造器,
                /**
                 *  T newInstance(Object... initargs)
                                 使用此 Constructor 对象表示的构造方法来创建该构造方法的声明类的新实例,并用指定的初始化参数初始化该实例。
                 */
               
                //私有的成员是受保护的,不能直接访问
                //若要访问私有的成员,得先申请一下
                con.setAccessible(true);//允许访问
                Per p = con.newInstance();//成功,通过私有的受保护的构造方法创建了对象
                System.out.println("无参构造方法"+p);
               
                con = c.getDeclaredConstructor(String.class);
                System.out.println(con);//private junereflect624.Per(java.lang.String)
                       
                con.setAccessible(true);//允许访问
                p = con.newInstance("liuzhao");//成功,通过私有的受保护的构造方法创建了对象
                System.out.println("String构造方法"+p);
        }
}
备注:对于此时的话,单例模式就不再安全了!反射可破之!!



验证:对于枚举而言,反射依然没有办法重新创建对象
对于枚举,安全!

package junereflect624;

import java.lang.reflect.Constructor;

enum Color{
        RED,BLUE,GREEN;
        private Color(){
        }
}

public class EnumDemo8 {
        public static void main(String[] args) throws Exception {
                Class<Color> c = Color.class;
               
                Constructor<Color> con = c.getDeclaredConstructor();//(错误在这一行发生,就是说对枚举而言这种方法连构造器都获得不了,)编译可以通过,但是运行就通不过了!
                Color co = (Color) con.newInstance();
                System.out.println(co);//失败,证明对枚举而言不行,所以枚举的单例模式更加安全
                System.out.println(c.isEnum());//true是枚举
        }
}




欢迎光临 黑马程序员技术交流社区 (http://bbs.itheima.com/) 黑马程序员IT技术论坛 X3.2