• Java 异常与反射 总结


          1.异常  

            异常,简单来说,就是一个程序执行过程中发生的不正常情况的事件。它发生在程序的运行期间,干扰了正常的指令流程。如果没有处理异常,那么出现异常之后,程序会停止运行。异常分为运行异常和非运行异常。非运行异常也叫编译异常。对于编译异常编译器要求必须处理。否则无法运行。运行时异常编译器不要求强制处理。运行时异常一般是由程序逻辑错误引起的,程序应该从逻辑角度尽可能避免这类异常的发生。它们都继承于Exception类。运行异常和非运行异常也下分各类异常。异常发生的原因是程序错误或偶然的外在因素导致的一般性问题。

    继承关系如图

    如果一个方法内抛出异常,该异常会被抛到调用方法中。如果异常没有在调用方法中处理,它继续被抛给这个方法的调用者。这个过程将一直继续下去,直到异常被处理。这一过程称为捕获异常。

    2.反射

    在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;

    对于任意一个对象,都能够调用它的任意一个方法和属性;

    这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制。

    反射的思维导图如下

          当使用反射时候,首先需要获取到Class类的对象,得到了这个类之后,就可以得到class文件里面的所有内容。

    以下是具体的反射应用方式

    1.类型转换:将Map转成Person的示范

    Person类是一个普通的实体类,里面包含三个私有的成员属性及它们的Set和Get函数。Map是集合框架里使用的Map类型框架,里面可以加入泛型。具体转换代码如下

     1 //param1:要转化的数据类型Person.class        String.class
     2 public static Object toBean(Class<?> type,Map<String,? extends Object> map) throws Exception{
     3     
     4     //Introspector专门处理Bean的工具类。比如获取Class的属性或者方法或构造
     5     BeanInfo beanInfo = Introspector.getBeanInfo(type);//参数传递的就是类的类型
     6     //调用newInstance方法创建这个类
     7     Object o = type.newInstance();
     8     //获取o的方法
     9     PropertyDescriptor[] ps = beanInfo.getPropertyDescriptors();
    10     for (int i = 0; i < ps.length; i++) {
    11 
    12         PropertyDescriptor p = ps[i];
    13         //获取方法描述的名称(属性名称)如果是Person --->name(name,age,sex)
    14         String name = p.getName();
    15         //name是否就是map中的key?
    16         if(map.containsKey(name)){
    17             //通过key获取map的值
    18             Object value = map.get(name);
    19             //通过反射,value赋给o
    20             //p.getWriteMethod();//set方法
    21             //p.getReadMethod();//get方法
    22             p.getWriteMethod().invoke(o, value);
    23         }
    24     }
    25     //获取map中的key的值,以及value的值
    26     return o;
    27 }
    28 public static void main(String[] args) throws Exception {    
    29     Map pMap = new HashMap();
    30     pMap.put("name", "张三");
    31     pMap.put("age", 1);
    32     pMap.put("sex", 2);
    33     //Map--->Object
    34     Person p = new Person("张三");
    35     p.setAge(1);
    36     p.setSex(2);
    37     Person o = (Person)toBean(Person.class,pMap);
    38     System.out.println(" "+o.toString());
    39 }

            以上代码的思想就是,创建一个相对于想要的类的BeanInfo,然后通过这个BeanInfo对象得到所有的属性名称(对应到Map里就是所有键值对的键),然后判断Map里是否有与获取的键名称同名的键,如果有的话就通过Map获取那个键的值,然后通过PropertyDescriptor对象获取需要的对象的set方法,将值赋值给相应的属性,最后返回相应的类型的对象。

    2.Java中五种创建新对象的方法

     1>直接用new调用该类的构造函数

    new Person("张三");

    2>使用class类中的newInstance方法创建对象,调用构造函数

    1 public static void test1() throws ClassNotFoundException, InstantiationException, IllegalAccessException{
    2         //1、获取Class类的对象    
    3         Class c = Class.forName("com.Person");
    4         //2、通过Class类中的newInstance方法创建Person对象
    5         Person p = (Person)c.newInstance();
    6         //3、检测一下
    7         p.setName("张三");
    8         System.out.println(p.getName());
    9     }

    3>使用class类型中的构造函数中的newInstance方法

    public static void test2() throws NoSuchMethodException, SecurityException, InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException{
            //1、获取Person类型
            Constructor c = Person.class.getConstructor();
            //2、创建方法
            Person p = (Person)c.newInstance();
            //3、检测
            p.setName("张三");
            System.out.println(p.getName());
        }

    4>通过clone方法创建。前提是需要在实体类里重写clone()方法

    /**
    *实体类
    **/
    public class Person implements Cloneable{
        private String name;
        private int  age;
        private int  sex;
    @Override
        protected Person clone() throws CloneNotSupportedException {
            Person person = null;
            person = (Person)super.clone();
            return person;
        }
    }
    /**
    *功能类中clone功能函数
    **/
    public static void test3(){
            //需要重写clone方法,重写cloneable接口。非常特殊
            //在Person类里实现cloneable接口
            Person p1 =new Person("王五");
            //调用clone方法创建一个新的对象p2
            Person p2 = null;
            try {
                 p2 = p1.clone();
            } catch (CloneNotSupportedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
            System.out.println(p1==p2);
            
        }

    5>序列化和反序列化的方法,通过这种方法可以将对象转换为字节序列的方式,把对象传输到另一台机器上。

    3.通过反射获取方法和操作属性

    1>通过反射获取方法

    通过反射获取方法的方式是先申明一个Class对象,然后通过该对象的getDeclaredMethod方法创建Method对象,通过Method对象的invoke方法调用获取到的方法实现功能。具体示例代码如下

     1 public static void test5() {
     2         try { 
     3             Class c = Class.forName("com.hpe.ref.Person");
     4             //获取方法        Person setName  getName
     5             //param1:方法名的String类型
     6             //param2:方法的参数类型
     7             Method m = c.getDeclaredMethod("setName", String.class);
     8             //创建Object对象
     9             Object obj = c.newInstance();
    10             //invoke调用方法(反射的方式调用方法)
    11             //param1:反射的类,param2:m方法的值
    12             m.invoke(obj, "张三");
    13             //验证
    14             Method gM =c.getDeclaredMethod("getName");
    15             System.out.println(gM.invoke(obj));
    16         } catch (Exception e) {
    17             // TODO Auto-generated catch block
    18             e.printStackTrace();
    19         }
    20     }

    2>通过反射获取属性

            通过反射获取属性的方法是通过Class获取该对象的Class对象形式,之后通过Field以字符串的形式获取类中的属性,然后通过Field对象来操作该属性。具体代码如下。

    public static void test4(){
            //通过反射,在运行阶段创建这个person对象
            try {
                Class c = Class.forName("com.hpe.ref.Person");
                
                Field field = c.getDeclaredField("name");
                //通过字符串的形式获取类中的属性。
                Field[] fs = c.getDeclaredFields();
                //设置对属性,如果是私有的,可以有权限访问
                field.setAccessible(true);
                Object o  =c.newInstance();
                //set方法----操作属性的方式
                field.set(o, "张三");
                System.out.println(field.get(o));
            } catch (ClassNotFoundException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            } catch (NoSuchFieldException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            } catch (SecurityException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            } catch (InstantiationException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            } catch (IllegalAccessException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }

    3.小注:分析下列代码功能

    段代码的功能分析

    public int indexOf(int ch)

    返回指定字符第一次出现的字符串内的索引。 如果与值的字符ch在此表示的字符序列发生String第一事件发生之对象,则索引(在Unicode代码单元)被返回。

    public StringBuffer insert(int offset, char c)

    在此序列中插入char参数的字符串表示形式。

    总体效果就好像第二个参数通过方法String.valueOf(char)转换为一个字符串,并且该字符串中的字符然后是inserted到指定的偏移量的这个字符序列。

    offset参数必须大于或等于0 ,小于或等于该序列的length

    所以它的功能是,以小数点为界,每往前数三位,就在str字符串里插入一个逗号。以达到计算数字的位数效果。

  • 相关阅读:
    Docker 设置阿里云镜像
    Linux 安装Navicat Premium 15
    Ubuntu常用工具安装
    Docker安装MongoDB、MySQL、Jenkins、Gitlab、Nginx
    Ubuntu18.04修改apt-get源
    Spring定时任务
    Quartz学习总结
    cron表达式
    将VirtualBox里安装的虚拟机在后台运行方法(在状态栏隐藏窗口)
    npm小结
  • 原文地址:https://www.cnblogs.com/Andrea-null/p/9416387.html
Copyright © 2020-2023  润新知