JAVA-如何修改源码(重写JAR包里的类)

        今天写代码的时候发现alibaba的druid工具对postgresql数据库的union all语法支持不够完善,具体场景:

select id,name from a

union all

(select id,name from b order by id);

该语法在druid工具中被解析为:

select id,name from a

union all

select id,name from b

order by id;

显而易见,解析后将括号"()"去掉了,去掉之后SQL语义发生了改变,本意是想a表与根据id排序后的b表进行union all,但是解析之后语义为a表与b表union all之后再进行排序,SQL语义发生了巨大变化。那么如何修复呢?目前有三种方法。

第一种:给druid官方提issue(等他们解决,猴年马月了,不适用)

第二种:将使用版本的jar包源码下载下来进行正确修改,编译,上传到私服进行引用(如果遇到版本升级,可能之前修改的就不再生效了)

(建议使用)

第三种:找到要修改的源码的全路径,在项目路径下新建一个相同全路径的类,将源码贴入新建的类中,然后在该类中对相应代码进行正确修改即可,需要注意的一个问题,版本升级时需要注意,该新建的类需要在最新版本的基础之上进行正确修改,防止串版本问题!另外,做好备注,防止后续开发人员不理解相关代码。

最后说一下,项目新建类覆盖源码的原理

1、maven遇到同名类,在pom中先声明的先加载
2、本地类的加载顺序,优先于依赖包中的类

加载顺序实验

maven在遇到同名类时,加载顺序如何?我们做实验测试下。

出现同名类的情况如下,不同包下的MyApi类完全一样:
1、demo应用依赖了api-v1的MyApi类
2、demo应用依赖了api-v2的MyApi类

api-v1版本的代码如下:

api-v2版本的代码如下:

demo调用如下:

package org.example.demo;

import org.example.api.MyApi;

/**
 * @author xxx
 * @date 2022/4/22 11:22 下午
 */
public class App {

    public static void main(String[] args) {
        MyApi myApi = new MyApi();
        myApi.echo();
    }
}

当pom中的引入顺序是下面这种情况,控制台输出:api-v1:

    <dependencies>
        <dependency>
            <groupId>org.example.api</groupId>
            <artifactId>api-v1</artifactId>
            <version>1.0-SNAPSHOT</version>
        </dependency>
        <dependency>
            <groupId>org.example.api</groupId>
            <artifactId>api-v2</artifactId>
            <version>1.0-SNAPSHOT</version>
        </dependency>
    </dependencies>

当pom中的引入顺序是下面这种情况,控制台输出:api-v2:

    <dependencies>
        <dependency>
            <groupId>org.example.api</groupId>
            <artifactId>api-v2</artifactId>
            <version>1.0-SNAPSHOT</version>
        </dependency>
        <dependency>
            <groupId>org.example.api</groupId>
            <artifactId>api-v1</artifactId>
            <version>1.0-SNAPSHOT</version>
        </dependency>
    </dependencies>

再做一个实验,在demo工程本地也新建一个同名的MyApi类:

package org.example.api;

/**
 * @author xxx
 * @date 2022/4/22 11:25 下午
 */
public class MyApi {

    public void echo() {
        System.out.println("api-demo");
    }
}

目录结构如下:

再次执行main函数,控制台输出:api-demo

才疏学浅,大佬们多指教!

  • 9
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
// 对overload测试的文件:OverloadTest.java public class OverloadTest { // 下面几个方法用来验证可以通过定义不同的参数型和参数的数目进行方法重载。 public void fun(){ System.out.println("method fun in OverloadTest, no parameter"); } public void fun(float f) { System.out.println("method fun in OverloadTest, parameter type: float"); } public void fun(int i){ System.out.println("method fun in OverloadTest, parameter type: int"); } public void fun(int i1, int i2) { System.out.println("method fun in OverloadTest, parameter type: int, int"); } // 下面的两个方法用来验证可以通过定义不同的参数顺序进行方法重载。 // 需要注意:这的参数肯定不是相同的型,否则的顺序的先后就毫无意义。 public void fun1(int i, float f) { System.out.println("method fun1 in OverloadTest, sequence of parameters is: int, float"); } public void fun1(float f, int i) { System.out.println("method fun1 in OverloadTest, sequence of parameters is: float, int"); } // 下面的两个方法用来验证方法抛出的异常对于重载的影响. // 无论是异常的型还是异常的个数都不会对重载造成任何的影响。 public void fun2() throws TestException { System.out.println("fun2 in OverloadTest, exception: TestException"); } public void fun2(int i) throws TestException, TestException1 { System.out.println("fun2 in OverloadTest, exception: TestException, TestException1"); } public void fun2(float f) throws Exception { System.out.println("fun2 in OverloadTest, exception: Exception"); } // 不能通过抛出的异常型来重载fun方法。 //public void fun(int i) throws Exception { // System.out.println("method fun in OverloadTest, parameter type: int, exception: Exception"); //} // ? 不能通过返回值重载fun方法。 //public boolean fun(int i) throws Exception { // System.out.println("method fun in OverloadTest, parameter type: int, exception: Exception, return: boolean"); // return true; //} private void fun3() { } // 不能通过不同的访问权限进行重载 public void fun3() { } public static void main(String[] args) { // 这只是定义了OverloadTest的实例,所以test不会调用 // OverloadTest1中的方法。 OverloadTest test = new OverloadTest1(); // 这定义了OverloadTest1的实例,因为OverloadTest1是OverloadTest // 的子,所以test1会调用OverloadTest中的方法。 OverloadTest1 test1 = new OverloadTest1(); try { int i = 1, j = 2, m = 3; // 这不会调用OverloadTest1的fun方法 // test.fun(i, m, j); test1.fun(i, j, m); test1.fun(); // 这个调用不会执行,因为fun3()在OverloadTest中访问权限是priavte //test1.fun3(); test1.fun3(i); } catch(Exception e) { } } } class OverloadTest1 extends OverloadTest{ // 在子中重载fun public void fun(int i, int m, int n) { System.out.println("Overload fun1 in OverloadTest1, parameter type: int, int, int"); } // 这个不是对父中方法的重载,只是一个新的方法。 public void fun3(int i) { System.out.println("fun2 in OverloadTest1"); } } // 对override测试的文件:OverrideTest.java public class OverrideTest { public void fun() throws TestException { System.out.println("method fun in OverrideTest"); } private void fun1() { System.out.println("method fun1 in OverrideTest"); } public static void main(String[] args) { OverrideTest test = new OverrideTest1(); try { test.fun(); test.fun1(); } catch(Exception e) { } } } class OverrideTest1 extends OverrideTest{ // 以下正常Override public void fun() throws TestException2 { System.out.println("fun in OverrideTest1"); } // 不能Override父中的方法,因为它定义了不同的异常型和 // 返回值。 //public int fun() throws TestException1 { // System.out.println("method fun in Test"); // return 1; //} // 不能Override父中的方法,因为它抛出了比父中非法范围 // 更大的异常。 //public void fun() throws Exception { // System.out.println("fun in OverrideTest1"); //} // 这个方法并没有Override父中的fun1方法,因为这个方法在 // 父是private型,所以这只是相当于定义了一个新方法。 public void fun1() { System.out.println("method fun1 in Test"); } } class TestException extends Exception{ public TestException(String msg) { super(msg); } } class TestException1 extends TestException { public TestException1(String msg) { super(msg); } } class TestException2 extends TestException { public TestException2(String msg) { super(msg); } }

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值