Exception in thread "main" java.lang.ClassCastException: $Proxy0 利用匿名内部类创建InvocationHandler接口实现

本文详细解析了Java动态代理的概念及其在实际应用中的常见错误,特别强调了在创建动态代理类时,强转类型应使用接口而非其实现类的重要性。通过对比实例,清晰地展示了接口与其实现类之间的自动转换机制,并阐述了动态代理执行顺序的基本原理。旨在帮助开发者深入理解并有效避免此类编程陷阱。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

这里错误的描述大致为:不能将动态代理的返回对象强转为对应的类!
对于这个错误,最终原因还是没弄清楚,但是最后发现了错误的根源,再次跟大家分享一下!先贴出整个创建动态代理类需要的类以及接口。值得注意的是,这里介绍的是实现接口的类的动态代理,没有实现接口的动态代理怎么实现,参照高手的博客。
1、Caculate.java接口

package com.lds.util;

public interface Calculate {
    public int add(int i, int j);
    public int sub(int i, int j);
    public int mul(int i, int j);
    public float div(int i, int j);
}

2、Caculate接口的实现类CaculateImp.java

package com.lds.util;

public class CalculateImp implements Calculate {

    @Override
    public int add(int i, int j) {

        int result = i + j;
        return result;
    }

    @Override
    public int sub(int i, int j) {

        int result = i - j;
        return result;
    }

    @Override
    public int mul(int i, int j) {

        int result = i * j;
        return result;

    }

    @Override
    public float div(int i, int j) {

        float result = (float) i / j;
        return result;

    }

}

3、创建动态代理的实例对象

package com.lds.util;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

public class ProxyTest {

    public static void main(String args[]) {

        final CalculateImp target = new CalculateImp();
        Calculate proxy = (Calculate) 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("Before method excute ");
        Object result = method.invoke(target, args);
        System.out.println(result);
        System.out.println("After Method excute " + "\n");
        return result;
        }
});

        proxy.add(1, 2);
        proxy.sub(4, 3);
        proxy.mul(2, 2);
        proxy.div(3, 2);

    }

}

后来发现出错的地方就是这里:
Calculate proxy = (Calculate) Proxy.newProxyInstance
在上面的强转中,强转类型不能写成Calculate接口的实现类CalculateImp,而只能写成接口类型,否则会报上面的错;之前检查错误,从来没想到这个问题,后来仔细想想,转成接口类型,应该是很有道理的,而不能转成接口实现类类型。
因为对于Calculate接口,可以被任何类实现,实现之后的类型仍然可以写成接口类型,在java中会自动进行转换成对应的实现类类型。这样的例子比如:

List<?> list = new ArrayList<?>(); 

看到这里的List类型也就应该明白了,当然这个List可以换成ArrayList。

ArrayList<Integer> list = new ArrayList<Integer>(); 

从上面的实例也可以看出来,创建代理类后,实现类CalculateImp中的方法与InvocationHandler的实现类中的invoke()方法的执行顺序,是先执行invoke()方法。
上述的一点心得仅代表个人观点,或许有不对的地方,希望各位大虾可以指正,互相学习进步。

### Java 中 `ClassCastException` 的解决方案 #### 理解 `ClassCastException` `java.lang.ClassCastException` 是一种运行时异常,在尝试将对象强制转换为其不是实例的类时抛出。此异常通常发生在不兼容类型的对象之间进行显式类型转换的情况下。 #### 原因分析 此类异常的主要原因在于错误的对象类型被强制转换,这可能是由于编程逻辑中的误判或是对泛型使用的不当理解所致[^1]。 #### 预防措施 为了防止 `ClassCastException` 发生: - **使用泛型**:通过利用泛型可以减少不必要的类型转换需求,并让编译器帮助检测潜在的问题。 - **instanceof 关键字检查**:在执行任何向下转型之前先验证目标对象的实际类型是否匹配预期类型。 ```java if (obj instanceof TargetType) { TargetType target = (TargetType)obj; } ``` - **避免过度依赖原始类型**:尽可能使用参数化的集合而不是原始形式,从而降低非法类型混入的风险。 #### 处理已发生的 `ClassCastException` 对于已经遇到的 `ClassCastException` 错误,建议采取如下步骤排查并修复问题: 1. 定位到具体的异常堆栈跟踪信息指出的确切位置; 2. 检查涉及的变量声明及其赋值过程,确认数据流路径上是否有意外的数据传递; 3. 如果是在反序列化场景下遇到了该异常,则需特别注意枚举类型的特殊处理机制; #### 示例代码修正 假设有一个简单的例子展示了如何安全地进行类型转换而不引发 `ClassCastException`: ```java public static void safeCast(Object obj){ if(obj != null && obj instanceof String){ // Safe casting after checking with instanceof String str = (String)obj; System.out.println(str); } } ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值