创建型工厂设计模式之前置黑魔法(反射)

红烧土豆泥
• 阅读 1320

什么是反射? 为什么说反射是黑魔法? 为什么要在工厂设计模式前扯反射这东西? 首先,既然在工厂设计模式前整它,肯定是在处理工厂设计模式时会用到它;既然都用黑魔法来形容它了,肯定是它异常强大; 那什么是反射嘞?既然能被称为"反",那就肯定会有"正",那,正。。。是啥子嘞?想当然,既然平时我们都不怎么搞反射,那我们平日整的就是正了呗!平时我们实例化一个对象都是是使用new关键字,例如:

  Person per = new Person();

那反的自然就是不使用new关键字了嘛~ 在正式了解不使用new来实例化一个类前,我们需要先了解反射手下的几名大将(类)及它们的一些技能特效(方法使用)。


军师 -> Class类(java.lang.Class) 是不是突然眼前一亮,我好像在哪见过,好像还用过它,他不是关键字吗?怎么突然变成一个类了???是不是突然又突然发现经常用的那个class和这个Class还是有点区别的,没错,这个首字母大写了。那这个Class是干啥子的嘞? 首先让我们先看一个小demo

  public class Person {
    public Person() {}

    @Test
    public void fun() {
        Class<Person> clazz = Person.class;
        System.out.println(clazz);
        System.out.println(clazz.getName());
    }

}

输出的是:class test.reflect.Bean.Person test.reflect.Bean.Person 首先我们写了一个Person类,里面我们什么都没写,然后写了一个测试方法,通过Person.class获取了Class对象,输出后发现,就是此类的各级包路径+本类名。如果是clazz.getName则是没有了class这个头,也就是说它的Name值实际上就是test.reflect.Bean.Person。但是这个东东它有什么作用嘞?还不怎么清楚。继续再看,

  public class Person {
    public Person() {}

    @Test
    public void fun() {
        Person per = new Person();
        Class<? extends Person> clazz = per.getClass();
        System.out.println(clazz);
        System.out.println(clazz.getName());
    }
}

输出的是:class test.reflect.Bean.Person test.reflect.Bean.Person 我们在测试中,首先是将Person实例化了,然后通过getClass获取到了Class对象,输出的结果是不是发现他们竟然是一样子的,是不是突然感觉他们之间有着啥不可告人的秘密~ 再看下面的一个

  @Test
    public void fun() {
        try {
            Class<?> clazz = Class.forName("test.reflect.Bean.Person");
            System.out.println(clazz);
            System.out.println(clazz.getName());
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
    }

输出的是:class test.reflect.Bean.Person test.reflect.Bean.Person 是不是想,噫 ~ 这东西有啥用哇?看出来了,看出来了,他们都是一样的,但是他们有啥子用嘛! 别急,别急,有没有注意到这边开始有异常抛出了,还是ClassNotFoundException异常,所以听我继续跟你们扯

  public class Person {
    private String name;

    public Person() {
    }

    public Person(String name) {
        super();
        this.name = name;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public static void main(String[] args) {
        try {
            Class<?> clazz = Class.forName("test.reflect.Bean.Person");
            Person per = (Person) clazz.getDeclaredConstructor().newInstance();
            per.setName("老王");
            System.out.println(per.getName());
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

输出:老王 在这个例子中,有没有注意到,没有new关键字的出现,感觉我没有对Person对象进行实例化,但是我却调用了它的getter和setter方法,还成功输出了"老王"。但是,既然输出了老王,那也就证明了Person这个对象被实例化了。怎么实例化的?没看到,偷麽麽的,那就是反的了呗!即通过反射对这个对象进行了实例化。 首先我们先看Class类的两个方法, 方法一:getDeclaredConstructor(类<?>... parameterTypes) -> 返回一个 Constructor对象,该对象反映 Constructor对象表示的类或接口的指定 类函数。 方法二:newInstance() -> 创建由此 类对象表示的类的新实例。 看到这,你可能会想直接用newInstance()不就好了,为啥还要用上面的那个,如果你去翻看jdk的API的话你就会注意到这个方法在1.9版本就已经被废弃了,但是还可以使用,原文如下图 创建型工厂设计模式之前置黑魔法(反射) 文档上明确表述了它的作用Creates a new instance of the class represented by this Class object以及它的用法clazz.getDeclaredConstructor().newInstance(),到此,是不是可以联想到我们之前写的三个获取类的class对象的作用了。


来再看反射手下的第二名大将 大元帅 -> Method类(java.lang.reflect.Method) 我们先来看一段代码

  public class Person {
    private String name;

    public Person() {
    }

    public Person(String name) {
        super();
        this.name = name;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public static void main(String[] args) {
        try {
            Class<?> clazz = Class.forName("test.reflect.Bean.Person");
            Method[] method = clazz.getDeclaredMethods();

            for(Method str:method) {
                System.out.println("方法名:"+str.getName()+"\t方法类型:"+Modifier.toString(str.getModifiers())+"\t返回值类型:"+str.getReturnType());
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

输出: 方法名:getName 方法类型:public 返回值类型:class java.lang.String 方法名:main 方法类型:public static 返回值类型:void 方法名:setName 方法类型:public 返回值类型:void

是不是感觉输出这些东西很熟悉啊!但是你可能回想,这有啥用嘛! 别急,继续看下面的一个例子:

  public class Person {
    private String name;

    public Person() {
    }

    public Person(String name) {
        super();
        this.name = name;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public static void main(String[] args) {
        try {
            Class<?> clazz = Class.forName("test.reflect.Bean.Person");
            Person per = (Person) clazz.getDeclaredConstructor().newInstance();
            Method[] method = clazz.getDeclaredMethods();

            for(Method str:method) {
                if("setName".equals(str.getName())) {
                    str.invoke(per, "老王");
                }
            }
            System.out.println(per.getName());
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

看它的输出:老王 是不是感觉很神奇!到这可能还没搞清楚反射究竟是一个啥东西啊?扯了这么多,还没说明白!按照JAVA核心技术卷一的解释就是一个能分析类的能力的程序。 欲知后事如何,请看下篇黑魔法工厂的爱恨情仇 ~

点赞
收藏
评论区
推荐文章
技术小男生 技术小男生
4个月前
linux环境jdk环境变量配置
1:编辑系统配置文件vi/etc/profile2:按字母键i进入编辑模式,在最底部添加内容:JAVAHOME/opt/jdk1.8.0152CLASSPATH.:$JAVAHOME/lib/dt.jar:$JAVAHOME/lib/tools.jarPATH$JAVAHOME/bin:$PATH3:生效配置
光头强的博客 光头强的博客
4个月前
Java面向对象试题
1、请创建一个Animal动物类,要求有方法eat()方法,方法输出一条语句“吃东西”。创建一个接口A,接口里有一个抽象方法fly()。创建一个Bird类继承Animal类并实现接口A里的方法输出一条有语句“鸟儿飞翔”,重写eat()方法输出一条语句“鸟儿吃虫”。在Test类中向上转型创建b对象,调用eat方法。然后向下转型调用eat()方
刚刚好 刚刚好
4个月前
css问题
1、在IOS中图片不显示(给图片加了圆角或者img没有父级)<div<imgsrc""/</divdiv{width:20px;height:20px;borderradius:20px;overflow:h
blmius blmius
1年前
MySQL:[Err] 1292 - Incorrect datetime value: ‘0000-00-00 00:00:00‘ for column ‘CREATE_TIME‘ at row 1
文章目录问题用navicat导入数据时,报错:原因这是因为当前的MySQL不支持datetime为0的情况。解决修改sql\mode:sql\mode:SQLMode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。全局s
红烧土豆泥 红烧土豆泥
1年前
软件设计模式-创建型模式之工厂进阶版
简介:所谓工厂模式,创建一个对象的接口,让子类决定实例化哪一个工厂类,使其创建过程延迟到了子类。所谓的万能工厂类,通过反射调用的方式,获取到子类对象,并实例化返回,此外本案例还通过重载的方式,允许了有参和无参两种获取到实例的方式。language/@author:demo@date:2021/8/7@describe:/public
Wesley13 Wesley13
1年前
java 成神之路 (二)
前一篇博客介绍了如何通过注解反射来实例化一个对象。前面提出的一个优化建议。上一版本,每个含有@DAL(http://my.oschina.net/daL)注解的变量都会通过反射去得到实例化对象。要是同一个工程里面每次都对同一个类通过反射实例化一个对象出来,这样太浪费资源了。现在我们就模拟spring的bean工厂,
Wesley13 Wesley13
1年前
Unity C# 设计模式(二)简单工厂模式
定义:简单工厂模式是属于创建型模式,又叫做静态工厂方法(StaticFactoryMethod)模式,但不属于23种GOF设计模式之一。简单工厂模式是由一个工厂对象决定创建出哪一种产品类的实例。简单工厂模式是工厂模式家族中最简单实用的模式,可以理解为是不同工厂模式的一个特殊实现。简单工厂模式的实质是由一个工厂类根据传入的参数,动态决定应该
Wesley13 Wesley13
1年前
C#设计模式 —— 工厂模式
。  工厂模式同样是项目中最常用的设计模式,工厂模式中又分为简单工厂,工厂方法,抽象工厂。下面我们由简单的开始逐一介绍。1.简单工厂模式  简单工厂又被称为静态工厂,在设计模式中属于创建型模式。主要解决的问题是封装了实例化的过程,通过传入参数来获不同实例。下面我们举一个项目中可能会用到的例子。  假设我们程序的数据保存在几个不同
Wesley13 Wesley13
1年前
Java重点基础:反射机制
一、什么是反射?Java反射说的是在运行状态中,对于任何一个类,我们都能够知道这个类有哪些方法和属性。对于任何一个对象,我们都能够对它的方法和属性进行调用。我们把这种动态获取对象信息和调用对象方法的功能称之为反射机制。二、反射的三种方式
Wesley13 Wesley13
1年前
00_设计模式之语言选择
设计模式之语言选择设计模式简介背景设计模式是一套被反复使用的、多数人知晓的、经过分类编目的、代码设计经验的总结。设计模式(Designpattern)代表了最佳的实践,通常被有经验的面向对象的软件开发人员所采用。设计模式是软件开发人员在软件开发过程中面临的