异常、反射、注解知识点

发布时间:2024年01月03日

1. Java 中的异常

是 Java 提供的一种处理程序中错误的机制。

当发生异常时,JVM 会将异常封装成一个异常对象抛出。此对象用来描述异常信息。

当 JVM 遇到程序异常就会自动停止。

2. 异常分类

  • Throwable:是 Java 异常的根类,Error 和 Exception 是 Throwable 的子类;

  • Error:是程序无法处理的错误,表示运行程序中较严重的问题,它们在应用程序控制和处理范围之外,而且绝大多数是程序运行时不允许出现的状况(是处理不到的)。

  • Exception:是程序本身可以处理的异常。异常处理通常指针对这种类型异常处理。

    • RuntimeException:非检查异常(编译器不要求强制处理的异常)【包括 RuntimeException 及其相关子类】
    • CheckExcepton:检查异常(编译器要求处理的异常)【包括 IO 异常,SQL 异常等】

图片描述

3. 异常处理

异常的产生是不可避免的,那么为了保证程序有效地执行,需要对发生的异常进行相应的处理。

Java 的异常处理通过 5 个关键字来实现:try、catch、throw、throws 和 finally。

3.1 捕获

try catch 语句用于捕获并处理异常,finally 语句用于在任何情况下(除特殊情况外)都必须执行的代码。

  • try:try 块中放可能发生异常的代码。

  • catch:每一个 catch 块用于捕获并处理一个特定的异常,或者这异常类型的子类。

  • finally:finally 块不是必须的,通常是可选的。无论异常是否发生,异常是否匹配被处理,finally 中的代码都会执行。

    import java.io.FileInputStream;
    import java.io.FileNotFoundException;
    import java.io.InputStream;
    
    public class TestCatch {
    
        public static void main(String[] args) {
            //捕获异常
            try {
                //可能产生异常的代码
                readFile();
            } catch (FileNotFoundException e) {
                //异常的处理逻辑,将异常记录日志,异常封装后显示
              System.out.println("系统找不到指定的文件~~~~");
            }
            System.out.println("后续操作代码~~~~");
    
        }
        public static  void readFile() throws FileNotFoundException {
            InputStream is = new FileInputStream("D:/01.txt");
        }
    }
    

异常信息的输出方式

  • e.getMessage();:打印异常信息
  • e.printStackTrace();:打印异常栈信息。

3.2 抛出

throw 语句用于拋出异常,throws 语句用于声明可能会出现的异常。

  • throw:用在方法内,用来抛出一个异常对象,将这个异常对象传递到调用者处,并结束当前方法的执行。
  • throws:运用于方法声明之上,用于表示当前方法不处理异常,而是提醒该方法的调用者来处理异常。
import java.io.FileNotFoundException;

public class ThrowsEx {
    public void setAge(int age) throws FileNotFoundException {
        if (age < 0) {
            throw new FileNotFoundException("输入的年龄小于 0");
        }
    }

    public static void main(String[] args) {
        ThrowsEx te=new ThrowsEx();
        try {
            te.setAge(10);
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        }
    }
}

4. 自定义异常

除了 JDK 定义好的异常类外,在开发过程中根据业务的异常情况自定义异常类。

自定义异常步骤:

  • 继承某 Exception 类

  • 构造方法(可选)

    以下为自定义异常的示例代码:

/**
 * 自定义异常类
 * 用户不存在异常信息类
 */
public class UserNotExistsException extends RuntimeException{

    public UserNotExistsException() {
        super();
    }

    public UserNotExistsException(String message) {
        super(message);
    }
}

5. 常见异常

5.1 运行时异常

异常类型说明
ArithmeticException算术错误异常,如以零做除数
ArraylndexOutOfBoundException数组索引越界
ArrayStoreException向类型不兼容的数组元素赋值
ClassCastException类型转换异常
IllegalArgumentException使用非法实参调用方法
lIIegalStateException环境或应用程序处于不正确的状态
lIIegalThreadStateException被请求的操作与当前线程状态不兼容
IndexOutOfBoundsException某种类型的索引越界
NullPointerException尝试访问 null 对象成员,空指针异常
NegativeArraySizeException在负数范围内创建的数组
NumberFormatException数字转化格式异常,比如字符串到 float 型数字的转换无效
TypeNotPresentException类型未找到

5.2 非运行时异常

异常类型说明
ClassNotFoundException没有找到类
IllegalAccessException访问类被拒绝
InstantiationException试图创建抽象类或接口的对象
InterruptedException线程被另一个线程中断
NoSuchFieldException请求的域不存在
NoSuchMethodException请求的方法不存在
ReflectiveOperationException与反射有关的异常的超类

6. 反射

JAVA 反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性;这种动态获取的信息以及动态调用对象的方法的功能称为 Java 语言的反射机制。

7. 反射相关类

  • java.lang.Class;//包名,修饰符,类名,基类,实现的接口

  • java.lang.reflect.Constructor;//类的构造方法的信息:修饰符,类名,参数列表,抛出的异常

  • java.lang.reflect.Field;//类的属性的信息:修饰符,属性类型,属性名称,属性值

  • java.lang.reflect.Method;//类的方法的信息:修饰符,返回类型,方法名称,参数列表,抛出的异常

  • java.lang.reflect.Modifier;//类提供了用于代表类和成员访问修饰符的静态方法和常量。

8. 获得 Class 方式

8.1 获得基本类型

  • 基本类型。class ; 例如:int.class 获取到的是 int 对应的 Class
  • 包装器类型。TYPE . 例如:Integer.TYEP , 获取的是 int 对应的 Class

8.2 获得引用类型

  • 引用类型。class ; 例如:String.class 获取的是 String 对应的 Class
  • Class.forName()
  • 通过对象来获取 Class . 例如:obj.getClass()

9. 代理模式

代理 ( Proxy ) 是一种设计模式,提供了对目标对象另外的访问方式;即通过代理对象访问目标对象。这样做的好处是:可以在目标对象实现的基础上,增强额外的功能操作,即扩展目标对象的功能。? 这里使用到编程中的一个思想:不要随意去修改别人已经写好的代码或者方法,如果需改修改,可以通过代理的方式来扩展该方法

举个例子来说明代理的作用:假设我们想邀请一位明星,那么并不是直接连接明星,而是联系明星的经纪人,来达到同样的目的。明星就是一个目标对象,他只要负责活动中的节目,而其他琐碎的事情就交给他的代理人(经纪人)来解决。这就是代理思想在现实中的一个例子

9.1 静态代理

静态代理在使用时,需要定义接口或者父类,被代理对象与代理对象一起实现相同的接口或者是继承相同父类。

9.1.1 接口
/**
 * 接口
 */
public interface IUserDao {

    void save();
}

9.1.2 目标对象
/**
 * 接口实现
 * 目标对象
 */
public class UserDao implements IUserDao {
    public void save() {
        System.out.println("----已经保存数据!----");
    }
}

9.1.3 代理对象
/**
 * 代理对象,静态代理
 */
public class UserDaoProxy implements IUserDao{
    //接收保存目标对象
    private IUserDao target;
    public UserDaoProxy(IUserDao target){
        this.target=target;
    }

    public void save() {
        System.out.println("开始事务。..");
        target.save();//执行目标对象的方法
        System.out.println("提交事务。..");
    }
}

9.1.4 测试
/**
 * 测试类
 */
public class App {
    public static void main(String[] args) {
        //目标对象
        UserDao target = new UserDao();

        //代理对象,把目标对象传给代理对象,建立代理关系
        UserDaoProxy proxy = new UserDaoProxy(target);

        proxy.save();//执行的是代理的方法
    }
}

图片描述

9.1.5 总结
  1. 可以做到在不修改目标对象的功能前提下,对目标功能扩展。? 2. 缺点:因为代理对象需要与目标对象实现一样的接口,所以会有很多代理类。同时,一旦接口增加方法,目标对象与代理对象都要维护。

如何解决静态代理中的缺点呢?答案是可以使用动态代理方式。

9.2 动态代理

动态代理有以下特点:

  1. 代理对象,不需要实现接口
  2. 代理对象的生成是利用 JDK 的 API ,动态的在内存中构建代理对象(需要我们指定创建代理对象/目标对象实现的接口的类型)。
  3. 动态代理也叫做:JDK 代理,接口代理。
9.2.1 代理工厂

/**
 * 创建动态代理对象
 * 动态代理不需要实现接口,但是需要指定接口类型
 */
public class ProxyFactory{

    //维护一个目标对象
    private Object target;
    public ProxyFactory(Object target){
        this.target=target;
    }

   //给目标对象生成代理对象
    public Object getProxyInstance(){
        return Proxy.newProxyInstance(
                target.getClass().getClassLoader(),
                target.getClass().getInterfaces(),
                new InvocationHandler() {
                    @Override
                    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                        System.out.println("开始事务 2");
                        //执行目标对象方法
                        Object returnValue = method.invoke(target, args);
                        System.out.println("提交事务 2");
                        return returnValue;
                    }
                }
        );
    }

}

图片描述

9.2.2 测试
/**
 * 测试类
 */
public class App {
    public static void main(String[] args) {
        // 目标对象
        IUserDao target = new UserDao();
        // 【原始的类型 UserDao】
        System.out.println(target.getClass());

        // 给目标对象,创建代理对象
        IUserDao proxy = (IUserDao) new ProxyFactory(target).getProxyInstance();
        // class $Proxy0   内存中动态生成的代理对象
        System.out.println(proxy.getClass());

        // 执行方法   【代理对象】
        proxy.save();
    }
}

9.2.3 总结

代理对象不需要实现接口,但是目标对象一定要实现接口,否则不能用动态代理。

使用第三方的 Cglib 方式生成代理对象,不需要目标对象一定实现接口。

10. 注解

Annotation 注解可以看作是 Java 中的一种标记记号,用来给 Java 中的类,成员,方法,参数等元素添加一个写额外的说明信息。

注解可以分为三类:基本注解、元注解、自定义注解。

10.1 基本注解

  • @Deprecated:用来说明程序中的某个元素已经不再使用。如果使用的话,编译器会给出警告。
  • @SuppressWarnings:用来抑制各种可能出现的警告。
  • @Override:用来说明子类覆盖了父类的方法,保护覆盖方法的准确性。
  • @SafeVarargs:1.7 新出的注解,用来说明使用了该注解的方法或构造函数不会对 varargs 参数执行可能不安全的操作。

10.2 元注解

元注解也称为元数据注解,是对注解进行标注的注解。

  • @Target:用来限制注解的使用范围。
  • @Retention:用来说明注解的生存周期。
  • @Document:用来说明生成文档的时候是否包含该注解的说明。
  • @Inherited:用来说明使用了该注解的父类,其子类会自动继承该注解。
  • @Repeatable:1.8 新出的元注解,如果需要在给程序元素使用相同类型的注解,则需将该注解标注上。
  • @FunctionalInterface:1.8 新出的元注解,主要用于编译级错误检查,加上该注解,当你写的接口不符合函数式接口定义的时候,编译器会报错。

10.3 自定义注解

  • @Interface:用来声明注解。
@Target({ElementType.METHOD, ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
public @interface UserMessage {

    String name() default "tom";

    int num() default 0;

    String desc();

}
文章来源:https://blog.csdn.net/qq_57747969/article/details/135365401
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。