(二十二)反射

反射(Reflection)

1、概念

这里写图片描述

1.数据库

常见数据库:Oracle,MySQL,SQLServer(java中用的偏少,微软研发),DB2(IBM研发,银行领域用的偏多),SQLLite(用于移动端),

MySQL

目前是免费的,提供的是数据库最基本的操作,存储的数据量大概是千万级。

Oracle

收费的,存储的数据量达到上亿,售后服务良好。

2.集群(Cluster)

集群式一组相互独立的、通过高速网络互连的计算机,它们构成了一组,并以单一系统的模式加以管理。

3.耦合(Coupling)

模块之间绑定。程序结构中各个模块之间相互关联的度量。

4.解耦(Decoupling)

降低两个模块之间的依赖性。
高内聚,低耦合。

5.反射(Reflection)

反射主要是指程序可以访问,检测和修改它本身状态或行为的一种能力,并能根据自身行为的状态和结果,调整或修改应用所描述行为的状态和相关的语义。
反射提供封装程序集、模块和类型对象。
反射其实是解剖类,分析类的字节码。产生类所对应的实例对象。

作用:

实现解耦操作,便于模块化开发。

2、反射中的类

1.Class class

代表字节码的类,代表类的类。每一个Class对象都对应了一个类/接口。

重要方法

forName(String className);
获取指定的字节码对象。
forName(String name,boolean initialize,ClassLoader loader);

getConstructor(Class< ?>…parameterTypes);
获取指定的公有构造函数。

        Class<String> clz = String.class;
        String(byte[],int,int)
        // 只能获取public的构造函数
        Constructor<String> c = clz.getConstructor(byte[].class, int.class,int.class);
        String str = c.newInstance(new byte[] { 97, 98, 99, 100, 101, 102,103 }, 1, 3);
        System.out.println(str);

getConstructors();
获取所有公有构造函数。返回的是一个构造函数数组。

        // 表示获取String类中所有public的构造函数
        Constructor[] cs = clz.getConstructors();
        for (Constructor constructor : cs) {
         System.out.println(constructor);

getDeclaredConstructor(Class< ?>…parameterTypes);
获取指定的构造函数。

    // 表示获取指定的形式的构造函数
    Constructor<String> c = clz.getDeclaredConstructor(char[].class, boolean.class);
    // 暴力破解/暴力拆除
    c.setAccessible(true);
    String str = c.newInstance(new char[] { 'a', 'b', 'c' }, true);
    System.out.println(str);

getDeclaredConstructors();
获取所有构造函数。返回的是一个构造函数数组。
getDeclaredField(String name);
获取指定属性。
getDeclaredFields();
获取所有属性,返回一个数组。
getDeclaredMethod(String name,Class< ?>…parameterTypes);
获取实例对象的方法,返回的是一个方法对象。

        Class<String> clz = String.class;
        String str = "abcdefg";
        // 获取getBytes()
        // byte[] bs = str.getBytes();
        Method m = clz.getDeclaredMethod("getBytes");
        // 执行方法对象
        // 第一个参数表示方法作用的对象
        // 第二个参数表示方法执行需要的实际参数
        byte[] bs = (byte[]) m.invoke(str);
        System.out.println(bs);

getDeclaredMethods();
获取所有方法。返回一个数组。
getField(String name);
获取公有属性。
getFields();
获取所有公有属性。
getInterfaces();
表示获取这个类或者接口实现的所有接口。返回的是一个数组类型。

        Class<String> clz = String.class;
        // 获取这个类/接口实现的所有接口
        Class[] cs = clz.getInterfaces();
        for (Class class1 : cs) {
            System.out.println(class1);
        }

getSuperclass();
获取父类。
getName();
获取全路径名称。
getSimpleName();
获取类名简称。
getPackage();
获取类所在包。

isAnonymousClass();
判断是否是匿名内部类。
isAssignableFrom();
判断参数是否是字节码对象的子类。
isInstance();
判断参数是否是字节码对象以及子类的实例。
isLocalClass();
判断是否是方法内部类。
isMemberClass();
判断是否是成员内部类。
isArray();
判断是否是数组。
isEnum();
判断是否是枚举。
isInterface();
判断是否是接口。
isPrimitive();
判断是否是基本类型。

newInstance();
创建一个字节码对象的实例。

获取Class对象的方法

1.通过类型名.class的方式来获取该类/接口/数组包括基本类型的字节码对象。可以添加泛型。

Class clz = String.class;           //代表了String的字节码
Class<List> clz = List.class;           //代表了List的字节码
Class<String[]> clz = String[].class;   //代表了String[]数组的字节码
Class<int[]> clz = int[].class;     //代表了int[]数组的字节码
Class clz = double.class;           //代表了double的字节码

2.可以通过对象身上的getClass();方法获这个对象对应的实际类型的字节码对象。

        Object str = "abc";
        // 获取的对象的实际类型对应的字节码对象
        @SuppressWarnings("unchecked")
        Class<Object> clz = (Class<Object>) str.getClass();
        System.out.println(clz);

3.通过Class.forName(类的全路径名);来获取指定的字节码对象。

        // 获取代表String类的字节码
        @SuppressWarnings("unchecked")
        Class<String> clz = (Class<String>) Class.forName("java.lang.String");
        System.out.println(clz);
产生实例对象的方法

1.通过Class类中的newInstance();方法来产生实例对象。这个方法要求实例对象所对应的类必须有无参构造方法。

        // 获取了代表Object类的字节码?
        @SuppressWarnings("unchecked")
        Class<Object> clz = (Class<Object>)
        Class.forName("java.lang.Object");
        // 产生一个Object对象
        // 要求这个类中必须有无参的构造函数
        Object o = clz.newInstance();
        System.out.println(o);

2.通过Class类中的getConstructor();方法来获取实例对象对应类的构造函数。

        Class<Integer> clz = Integer.class;
        // 获取构造函数
        // 获取到了Integer类中Integer(String)的构造函数
        // Integer in = new Integer("123");
        Constructor<Integer> c = clz.getConstructor(String.class);
        Integer in = c.newInstance("123");
        System.out.println(in);

如果一个类只提供了含参构造,需要获取这个类中指定形式的构造函数对象,然后利用这个构造函数对象来产生度应对的实例对象;如果一个类提供了无参构造,那么这个时候可以利用这个类的字节码对象来产生实例对象

2.Constructor class

代表构造方法的类。

重要方法

setAccessible();
暴力破解、暴力拆除。
从AccessibleObject class继承过来的方法,Field,Method,也继承了这个类。

3.Method class

代表方法的类。

重要方法

invoke(Object o , Object… args);
第一个参数表示方法作用的对象;第二个参数表示方法执行需要的实际参数。如果返回值类型为void,则返回值为null。

        Class<String> clz = String.class;
        String str = "abcdefg";
        // 获取getBytes()
        // byte[] bs = str.getBytes();
        Method m = clz.getDeclaredMethod("getBytes");
        // 执行方法对象
        // 第一个参数表示方法作用的对象
        // 第二个参数表示方法执行需要的实际参数
        byte[] bs = (byte[]) m.invoke(str);
        System.out.println(bs);

        Class<Demo> clz = Demo.class;
        Demo d = new Demo();
        // 如果返回值类型为void,则返回值为null
        Method m = clz.getDeclaredMethod("m");
        Object o = m.invoke(d);
        System.out.println(o);

getAnnotation();
返回方法上带的注解。
getExceptionTypes();
获取这个方法抛出的异常。返回一个数组。

        // 获取这个方法抛出的异常
        Class[] es = m.getExceptionTypes();
        for (Class class1 : es) {
            System.out.println(class1);
        }

getParameterTypes();
获取方法参数类型。
getReturnType();
获取方法的返回值类型。
getName();
获取方法名。
isVarArgs();
判断方法中是否含有可变参数。

4.Field class

代表属性的类。

重要方法

set(Object o,Object value);
设置属性值。
get(Object o);
获取属性值。
getType();
获取属性类型。

public class ClassDemo6 {
    @SuppressWarnings("rawtypes")
    public static void main(String[] args) throws Exception {
        Class<String> clz = String.class;
        String str = "abc";
        // 获取指定的属性
        // str.setHash(123);
        Field f = clz.getDeclaredField("hash");
        f.setAccessible(true);
        // 设置属性值
        f.set(str, 123);
        // 获取属性值
        System.out.println(f.get(str));
        // 获取属性的声明类型
        Class c = f.getType();
        System.out.println(c);
    }
}

5.Annotation class

代表注解的类。

6.Package class

代表包的类。
代码示例
为了省略简单的代码,我将两个类中的get和set方法都省略了,看的时候注意一下就行。

public interface Person {
    public void eat();
    public void work();
    public void sax();
}
public class Doctor implements Person {
    private String name;
    private int age;
    private char gender;
    private Date entry;
    private double salary;
//……对应get/set方法……
    @Override
    public void eat() {
        System.out.println(name + "医生在手术室吃饭中~~~");
    }

    @Override
    public void work() {
        System.out.println(name + "医生在治病救人~~~");
    }

    @Override
    public void sax() {
        System.out.println(name + "医生缴税:" + salary * 0.5);
    }
}
public class Teacher implements Person {
    private String name;
    private int age;
    private char gender;
    private Date entry;
    private double salary;
//……对应get/set方法……
    public void setEntry(Date entry) {
        this.entry = entry;
    }
    @Override
    public void eat() {
        System.out.println(name + "老师在教室吃饭中~~");
    }
    @Override
    public void work() {
        System.out.println(name + "老师在教书育人~~~");
    }
    @Override
    public void sax() {
        System.out.println(name + "老师缴税:" + salary * 0.09);
    }
}
public class ReflectionDemo {
    @SuppressWarnings({ "unchecked", "rawtypes" })
    public static void main(String[] args) throws Exception {
        while (true) {
            // 读取Properties文件
            Properties prop = new Properties();
            FileInputStream in = new FileInputStream("config.properties");
            prop.load(in);
            in.close();
            // 获取指定的类
            Class<Person> clz = (Class<Person>) Class.forName(prop.getProperty("classname"));
            // 根据字节码对象来产生对应的实例对象
            Person p = clz.newInstance();
            // 获取指定的属性
            String[] attrnames = prop.getProperty("attrname").split("/");
            // 获取属性值
            String[] attrvalues = prop.getProperty("attrvalue").split("/");
            for (int i = 0; i < attrnames.length; i++) {
                // 获取属性对应的set方法的名字
                String set = "set" + attrnames[i].substring(0, 1).toUpperCase() + attrnames[i].substring(1);
                // 获取属性的类型
                Class fc = clz.getDeclaredField(attrnames[i]).getType();
                // 获取这个属性对应的set方法
                Method m = clz.getDeclaredMethod(set, fc);
                // 需要判断属性类型之后再赋值
                if (fc == int.class || fc == Integer.class) {
                    m.invoke(p, Integer.parseInt(attrvalues[i]));
                } else if (fc.equals(double.class) || fc.equals(Double.class)) {
                    m.invoke(p, Double.parseDouble(attrvalues[i]));
                } else if (fc == char.class || fc == Character.class) {
                    // m.invoke(p, attrvalues[i].charAt(0));
                    m.invoke(p, attrvalues[i].toCharArray()[0]);
                } else if (fc == Date.class) {
                    m.invoke(p, new SimpleDateFormat("yyyy-MM-dd").parse(attrvalues[i]));
                } else {
                    m.invoke(p, attrvalues[i]);
                }
            }
            // 获取这个指定的方法
            Method m = clz.getDeclaredMethod(prop.getProperty("method"));
            // 执行方法
            m.invoke(p);
            Thread.sleep(10000);
        }
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Java官方编程手册第十二版是由Oracle官方出品的一本权威的Java编程指南。该手册汇集了Java语言的最佳实践和编码规范,无论是初学者还是有经验的开发者,都可以从中获得宝贵的指导和建议。 该手册主要分为以下几个部分: 1. 基础知识:这部分介绍了Java语言的基本概念、语法和特性。包括数据类型、运算符、流程控制等内容,适合初学者入门学习。 2. 核心库:Java的核心库提供了丰富的类和方法,用于开发各种应用程序。该部分详细介绍了Java核心库的常用类和使用方法,例如集合框架、IO操作、多线程等,对于日常开发非常有帮助。 3. 高级特性:这部分主要介绍了Java的高级功能和特性,如泛型、反射、注解等。这些特性可以帮助开发者编写更灵活、可扩展的代码,并提供了一些解决复杂问题的思路。 4. 最佳实践:在这一部分,手册提供了一些编码规范和最佳实践,旨在帮助开发者写出更高效、可读性更强的代码。这些实践包括命名规范、异常处理、并发编程等方面。 总的来说,Java官方编程手册第十二版是一本全面而深入的Java编程指南,涵盖了Java语言的方方面面。无论是学习Java基础知识,还是进一步提升自己的编程能力,该手册都是一本很好的参考资料。初学者可以通过阅读该手册系统地学习Java编程,而有经验的开发者则可以借鉴其中的最佳实践来提高代码质量和效率。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值