Java基础24--反射的应用2&3:动态创建对象&动态的设置或获取属性的值

    科技2024-03-12  87

    Java基础24–反射的应用2&3

    反射的应用2:动态创建对象

    2:在运行时能够创建任意引用数据类型的对象**

    方式一:使用Class对象直接new对象 步骤: (1)获取某个类型的Class对象 (2)通过Class对象来创建这个Class所代表的类型的对象 @Test public void test01() throws ClassNotFoundException, InstantiationException, IllegalAccessException{ //(1)获取某个类型的Class对象(四种方法选择合适的) Class clazz = Class.forName("com.atguigu.ext.demo.AtGuiguDemo"); //(2)创建对象 //obj的编译时类型,Object类型 //obj的运行时类型是AtGuiguDemo类型 Object obj = clazz.newInstance();//这里的newInstance()没有参数,因为它是用无参构造创建实例 System.out.println(obj); }

    ( 注意:在这里加载AtGuiguDemo这个类时,会优先加载扩展类加载器)

    有一个前提条件:有无参构造方法 若是将AtGuiguDemo无参构造去掉,会报错 当AtGuiguDemo没有无参构造时 java.lang.InstantiationException: com.atguigu.ext.demo.AtGuiguDemo Caused by: java.lang.NoSuchMethodException: com.atguigu.ext.demo.AtGuiguDemo.() 解决方法: a:加无参构造方法 b:方式二创建对象

    方式二:通过Class对象先获取有参构造,然后再创建对象 步骤: (1)获取某个类型的Class对象 (2)通过Class对象来获取Constructor对象 (2)通过Constructor对象来创建这个Class所代表的类型的对象 @Test public void test02() throws Exception{ //(1)获取某个类型的Class对象 Class clazz = Class.forName("com.atguigu.ext.demo.AtGuiguDemo"); /* * (1)Constructor clazz.getConstructor(Class<?>... parameterTypes)某个公共的构造器 * (2)Constructor clazz.getDeclaredConstructor(Class<?>... parameterTypes)某个声明的构造器 * 为什么通过形参列表就可以确认哪个构造器呢?---一个类中可能存在多个构造器,但是多个构造器重载的话,形参列表一定不一样(名称一样),所以通过形参列表就可以唯一的定位到一个构造器 * 如果Class<?>... parameterTypes,一个都不传,即获取无参构造 */ //(2)获取有参构造对象 Constructor c = clazz.getConstructor(int.class,String.class,int.class); //(3)通过Constructor对象来创建实例对象 Object obj = c.newInstance(1,"尚硅谷",10);//这里的newInstance(实参列表),因为它用有参构造创建对象 System.out.println(obj); }

    若是不知道声明的构造器形参列表,比如框架中spring创建对象时是怎样知道构造器里面的形参列表的呢?–需要自己配置告诉它(告诉它类名、构造器形参列表等),不然不知道,除非能得到所有的构造器,否则没办法知道

    若是构造器私有化了,再运行会报错:找不到这个形参方法,应该用:

    Constructor c = clazz.getDeclaredConstructor(int.class,String.class,int.class); @Test public void test02() throws Exception{ //(1)获取某个类型的Class对象 Class clazz = Class.forName("com.atguigu.ext.demo.AtGuiguDemo"); //(2)获取有参构造对象 Constructor c = clazz.getDeclaredConstructor(int.class,String.class,int.class); //(3)通过Constructor对象来创建实例对象 Object obj = c.newInstance(1,"尚硅谷",10);//这里的newInstance(实参列表),因为它用有参构造创建对象 System.out.println(obj); }

    还是报错:报非法的访问接近异常,不能访问构造器

    c.setAccessible(true);//设置私有构造器可以访问 @Test public void test02() throws Exception{ //(1)获取某个类型的Class对象 Class clazz = Class.forName("com.atguigu.ext.demo.AtGuiguDemo"); /* * (1)Constructor clazz.getConstructor(Class<?>... parameterTypes)某个公共的构造器 * (2)Constructor clazz.getDeclaredConstructor(Class<?>... parameterTypes)某个声明的构造器 * 一个类中可能存在多个构造器,但是多个构造器重载的话,形参列表一定不一样,所以通过形参列表就可以唯一的定位到一个构造器 * 如果Class<?>... parameterTypes,一个都不传,即获取无参构造 */ //(2)获取有参构造对象 Constructor c = clazz.getDeclaredConstructor(int.class,String.class,int.class); c.setAccessible(true);//设置私有构造器可以访问 //(3)通过Constructor对象来创建实例对象 Object obj = c.newInstance(1,"尚硅谷",10);//这里的newInstance(实参列表),因为它用有参构造创建对象 System.out.println(obj); }

    成功创建对象

    @Test public void test03(){ // AtGuiguDemo s = new AtGuiguDemo(2,"xx",20);//The constructor AtGuiguDemo(int, String, int) is not visible // System.out.println(s); }

    私有化构造器不能直接这样使用

    反射的应用3:动态的设置或获取属性的值

    3、在运行时可以为任意对象的任意属性赋值,或者获取任意对象的任意属性的值

    Field类: (1set(Object obj, Object value) (2)Object get(Object obj)3setAccessible(true)

    建议大家编写类时保留无参构造。(大部分情况下使用无参构造),原因: (1)创建对象方便 (2)继承时也方便 子类构造器默认调用父类的无参构造 (3)反射创建对象也方便

    步骤: (1)获取某个类型的Class对象 (2)创建实例对象 (3)为某个属性赋值 ①先获取某个属性Field对象 ②设置属性可访问 属性对象.setAccessible(true) ③为属性赋值

    @Test public void test01() throws Exception{ //(1)获取某个类型的Class对象 Class clazz = Class.forName("com.atguigu.ext.demo.AtGuiguDemo"); //(2)创建对象 //obj的编译时类型,Object类型 //obj的运行时类型是AtGuiguDemo类型 Object obj = clazz.newInstance();//这里的newInstance()没有参数,因为它是用无参构造创建实例 System.out.println(obj); //(3)为属性赋值 // ①获取id属性的Field对象 /* * Field clazz.getField(name) 获取公共的 Field clazz.getDeclaredField(name) 获取声明的 */ Field idField = clazz.getDeclaredField("id"); //设置id属性可访问 idField.setAccessible(true);//一般属性private修饰 // ②为id属性赋值 /* * 回忆之前,如何为属性赋值 * 对象.属性名 = 值 * * 属性的特点:(1)每一个对象的属性是独立(2)属性有默认值 * 所以在为属性赋值时,要说为哪个对象的属性赋值 */ // idField.set(obj, value);//obj是代表AtGuiguDemo的对象,value代表值 idField.set(obj, 3); System.out.println(obj); //(4)为info属性赋值 //①先获取info属性对象 Field infoField = clazz.getDeclaredField("info"); // ②设置info属性可访问 infoField.setAccessible(true); //③为info属性赋值 infoField.set(obj, "尚硅谷"); System.out.println(obj); //(5)获取num属性的值 //①先获取num属性的Field对象 Field numField = clazz.getDeclaredField("num"); //②设置num属性可以访问 numField.setAccessible(true); //③获取num属性值 /* * 回忆之前,获取属性的值 * 变量 = 对象名.属性名 */ // numField.get(obj);//obj就是代码哪个对象的属性 Object value = numField.get(obj); System.out.println(value); }

    Processed: 0.031, SQL: 8