Java动态创建对象的执行方法

上一阶段小结

  • 在实际操作中,取得类的信息的操作代码,并不会经常使用。

  • 一定要熟悉java.lang.reflect包的作用,反射机制。

  • 如何取得属性、方法、构造器的名称,修饰符等。

有了Class对象能做什么

  • 创建类的对象:调用Class对象的newInstance()方法

    • 类必须有一个无参数的构造器

    • 类的构造器的访问权限需要足够

  • 没有无参构造器就不能创建对象了吗?并非如此。

  • 只要在操作的时候明确的调用类中的构造器,并将参数传递进去后就可以进行实例化操作。

  • 步骤如下:

    • 通过Class类的getDeclaredConstructor(Class...parameterType)取得本类的指定形参类型的构造器

    • 向构造器的形参中传递一个对象数组进去,里面包含了构造器中所需的各个参数。

    • 通过Constructor实例化对象

package com.kuang.reflection;
//通过反射动态的创建对象
public class Test09{
   public static void main(String[] args) throws ClassNotFoundException, IllegalAccessException, InstantiationException, NoSuchMethodException{
       //获得Class对象
       Class c1 = Class.forName("com.kuang.reflection.User");
       //构造一个对象(强制转换成User)
       //Object o = c1.newInstance();
       //User user = (User)c1.newInstance(); //本质上是调用了类的无参构造器
       //System.out.println(user);
       
       //通过构造器创建对象,User类要重写toString。
       //Constructor constructor = c1.getDeclaredConstructor(String.class, int.class, int.class);
       //User user2 = (User)constructor.newInstance("qingjiang", 001, 18);
       //System.out.println(user2);
       //如果你发现你输出的对象是一串字符串,说明你可能没在实体中加入toString方法。
       
       //通过反射调用普通方法
       User user3 = (User)c1.newInstance();
       //通过反射获取一个方法
       Method setName = c1.getDeclaredMethod("setName", String.class);
       //invoke:激活的意思
       //传入(对象, “方法的值”)
       setName.invoke(user3, "kuangshen");
       System.out.println(user3.getName);
       
       //通过反射操作属性,不能直接操作私有属性,需要关闭程序的安全检测,把属性或者方法的setAccessible设为true即可。
       System.out.println("*****************");
       User user4 = (User)c1.newInstance();
       Field name = c1.getDeclaredField("name");
       
       //关掉私有属性的保护权限
       name.setAccessible(true); //为true可访问
       name.set(user4, "狂神");
       System.out.println(user4.getName());
  }
}

调用指定的方法

  • 通过反射调用类中的方法,经由Method类完成。

    • 通过Class类的getMethod(String name,Class...parameterType)方法取得一个Method对象,并设置此方法操作时所需要的参数类型。

    • 之后使用Object invoke(Object obj, Object[] args)进行调用,并向方法中传递要设置的 obj 对象的参数信息。

      • 用 Class.forName()去获取 Person 的实例 Class

      • 用 getMethod(“sayHello”)去找到 sayHello() 方法

      • 再用 invoke(激活方法名,“方法需要的参数”) 去激活调用 sayHello 方法

  • Object invoke(Object obj, Object... args)

    • Object对应原方法的返回值,若原方法无返回值,则返回null。

    • 若原方法为静态方法,此时形参Object obj 可为 null。

    • 若原方法形参列表为空,则 Object[] args 为 null。

    • 若原方法声明为 private,则需要在调用此 invoke() 方法前,显示调用方法对象的 setAccessible(true) 方法,便能成功访问到 private 修饰的方法。

  • setAccessible

    • Method 和 Field、Constructor 对象都有 setAccessible() 方法

    • setAccessible 作用是启动和禁用访问的安全检查的开关

    • 参数值为 true 则指示反射的对象在使用时应该取消 Java 语言访问检查

      • 提高反射的效率,如果代码中必须使用反射,而该句代码需要频繁的被调用,那么请设置为 true。

      • 使得原本无法访问的私有成员也可以访问

    • 参数值为 false 则指示反射的对象应该实施 Java 语言访问检查

性能对比分析


package com.kuang.reflection;
//分析性能问题
public static class Test10{
   //普通方式调用
   public void Test01(){
       User user = new User();
       long startTime = System.currentTimeMillis();
       for(int i=0; i<1000000000; i++){
           user.getName();
      }
       long endTime = System.currentTimeMillis();
       System.out.println("普通方式执行十亿次:" + (endTime - startTime) + "ms");
  }
   //反射方式调用
   public void Test02() throws NoSuchMethodException, InvocationTargetException, IllegalAccessException{
       User user = new User();
       Class c1 = user.getClass();
       Method getName = c1.getDeclaredMethod("getName", null);
       
       long startTime = System.currentTimeMillis();
       for(int i=0; i<1000000000; i++){
           getName.invoke(user, null);
      }
       long endTime = System.currentTimeMillis();
       System.out.println("反射方式执行十亿次:" + (endTime - startTime) + "ms");
  }
   //反射方式调用 关闭安全检测
   public void Test03() throws NoSuchMethodException, InvocationTargetException, IllegalAccessException{
       User user = new User();
       Class c1 = user.getClass();
       Method getName = c1.getDeclaredMethod("getName", null);
       getName.setAccessible(true);
       
       long startTime = System.currentTimeMillis();
       for(int i=0; i<1000000000; i++){
           getName.invoke(user, null);
      }
       long endTime = System.currentTimeMillis();
       System.out.println("关闭检测的反射方式执行十亿次:" + (endTime - startTime) + "ms");
  }
   public static void main(String[] args) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException{
       test01();
       test02();
       test03();
  }
}

反射操作泛型

  • Java 采用泛型(一种约束机制)擦除的机制来引入泛型,Java 中的泛型仅仅是给编译器 javac 使用的,确保数据的安全性和免去强制类型转换问题,但是存在一旦编译完成,所有和泛型有关的类型全部擦除的机制。

  • 为了通过反射操作这些类型,Java新增了 ParameterizedType ,GenericArriayType,TypeVariable 和 WildcardType 几种类型来代表不能被归一到 Class 类中的类型但是又和原始类型齐名的类型。

  • ParameterizedType:表示一种参数化类型,比如 Collection<String>

  • GenericArrayType:表示一种元素类型是参数化类型或者类型变量的数组类型

  • TypeVarriable:是个种类型变量的公共父接口

  • WildcardType:代表一种通配符类型表达式


package com.kuang.reflection;
//通过反射获取泛型
public class Test11{
   public void test01(Map<String, User> map, List<User> list){
       System.out.println("test01");
  }
   public Map<String, User> test02(){
       System.out.println("test02");
       return null;
  }
   
   public static void main(String[] args) throws NoSuchMethodException{
       Method method = Test11.class.getMethod("test01", Map.class, List.class);
       Type[] genericParameterTypes = method.getGenericParameterTypes();
       for(Type genericParameterType : genericParameterTypes){
           System.out.println("#" + genericParameterType);
           if(genericParameterType instanceof ParameterizedType){
               Type[] actualTypeArguments = ((ParameterType)genericParameterType).getActualTypeArguments();
               for(Type actualTypeArgument : actualTypeArguments){
                   System.out.println(actualTypeArgument);
              }
          }
      }
       
       method = Test11.class.getMethod("test02", null);
       Type genericReturnType = method.getGenericReturnType();
if(genericReturnType instanceof ParameterizedType){
               Type[] actualTypeArguments = ((ParameterType)genericReturnType).getActualTypeArguments();
               for(Type actualTypeArgument : actualTypeArguments){
                   System.out.println(actualTypeArgument);
              }
          }
  }
}

获取注解信息

  • 反射操作注解

    • getAnnotations

    • getAnnotation

  • 了解什么是ORM

    • Object relationship Mapping → 对象关系映射


class Student{
   int id;
   String name;
   int age;
}
idnameage
001 秦疆 23
002 老师 30

  • 类和表结构对应

  • 属性和字段对应

  • 对象和记录对应

package com.kuang.reflection;
//练习反射操作注解
public class Test12{
   public static void main(String[] args) throws ClassNotFoundException{
       Class c1 = Class.forName("com.kuang.reflection.student2");
       
       //通过反射获得注解
       Annotation[] annotations = c1.getAnnotations();
       for(Annotation annotation : annotations){
           System.out.println(annotation);
      }
       
       //获得类的注解的 value 的值
       //Annotation annotation = c1.getAnnotation(TableKuang.class);
       TableKuang tableKuang = (TableKuang)c1.getAnnotaion(TableKuang.class);
       String value = tableKuang.value();
       System.out.println(value);
       
       //获得类指定的字段注解
       Field f = c1.getDeclaredField("name");
       FieldKuang annotation = f.getAnnotation(FieldKuang.class);
       System.out.println(annotation.columnName());
       System.out.println(annotation.type());
       System.out.println(annotation.length());
  }
}

@TableKuang("db_student")
class Student2{
   @FieldKuang(columnName = "db_id", type = "int", length = 10)
   private int id;
   @FieldKuang(columnName = "db_age", type = "int", length = 10)
   private int age;
   @FieldKuang(columnName = "db_name", type = "varchar", length = 3)
   private String name;
   
   public Student2(){
       
  }
   public Student2(int id, int age, String name){
       this.id = id;
       this.age = age;
       this.name = name;
  }
   
   public int getId(){
       return id;
  }
   public void setId(int id){
       this.id = id;
  }
   public int getAge(){
       return age;
  }
   public void setAge(int age){
       this.age = age;
  }
   public String getName(){
       return name;
  }
   public void setName(String name){
       this.name = name;
  }
   
   //重写toString 方便后续调试
   @Override
   public String toString(){
       return "Strudent2{" +
           "id=" + id +
           ", age=" + age +
           ", name='" + name + '\'' +
           '}';
  }
   
   //类名的注解
   @Target(ElementType.TYPE)
   @Retention(RetentionPolicy.RUNTIME)
   @interface TableKuang{
       String value();
  }
   
   //属性的注解
   @Target(ElementType.FIELD)
   @Retention(RetentionPolicy.RUNTIME)
   @interface FieldKuang{
       String columnName();
       String type();
       int length();
  }
}

本章小结

posted on   愿将过往均储藏  阅读(628)  评论(0编辑  收藏  举报

编辑推荐:
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
阅读排行:
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 【自荐】一款简洁、开源的在线白板工具 Drawnix
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
< 2025年3月 >
23 24 25 26 27 28 1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28 29
30 31 1 2 3 4 5

导航

统计

点击右上角即可分享
微信分享提示