前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
社区首页 >专栏 >Java 动态判断数组维数并取值

Java 动态判断数组维数并取值

作者头像
明明如月学长
发布2022-11-28 16:07:12
发布2022-11-28 16:07:12
1K00
代码可运行
举报
运行总次数:0
代码可运行

一、背景

技术交流群里有同学提了一个看似基础但挺有意思的问题。

问题描述

一个对象是一个未知的数组类型,可能是 short 二维数组,可能是 int 的三维数组等。

诉求

  • 想要遍历修改(获取)它的值
  • 不想写太多 if else (该同学的最初方案是通过 instance of 枚举出所有类型,通过 if else 来写代码)

群里 程序员 DMZ 给出了很专业的建议,使用策略模式或者采用递归的方式取值。

我的解法也与之类似,本文给出相对具体的参考代码(因为虽然很多同学也能考虑到递归,但递归时如何取值并不太会;如果用策略模式该怎么写也不太会)。

二、推荐方案

2.1 采用递归

这里主要演示传入一维或者 N 维数组,可以获取到每个元素,实际开发中可以根据示例修改变通即可。

代码语言:javascript
代码运行次数:0
运行
复制
import java.lang.reflect.Array;
import java.util.ArrayList;
import java.util.List;

public class ArrayDemo2 {

    public static void main(String[] args) {

        // 测试三维数组
        System.out.println(" ------- 测试 3 维数组 ------- ");
        int[][][] data = new int[][][]{{{1},{2}},{{3,4}}};

        Object obj = data;

        List<Float>  result= test(obj);

        System.out.println(" ------- 测试 2 维数组 ------- ");
        // 测试二维数组

        int[][] data2 = new int[][]{{1,2},{3,4,5}};
        result= test(data2);

        System.out.println(" ------- 测试 1 维数组 ------- ");
        // 测试二维数组

        int[] data3 = new int[]{1,2,3};
        result= test(data3);
    }


   // 开发中并不需要使用方感知到默认的 turn 为1 ,因此再次封装
   // 大家也可以想其他办法去优化,如果不需要知道当前是几维数组 turn 可以去掉,就不需要这个方法了
    private static List<Float>  test(Object array){
        return test(array, 1);
    }
    /**
     * 伪代码,result 的逻辑根据业务需要来写,这里就不处理了
     * turn 是为了记录维数,默认1 维,递归一次 +1
     */
    private static List<Float>  test(Object array, int turn){
        // 伪代码模拟结果
        List<Float> result = new ArrayList<>();

        if(array.getClass().isArray()){
            for(int i = 0; i< Array.getLength(array); ++i) {
                Object obj = Array.get(array, i);
                if(obj.getClass().isArray()){
                    test(obj,turn+1);
                }else{
                    System.out.println("值:"+obj+",几维数组:"+turn);
                    // result.add(// 计算结果放到  result里);
                }
            }
        }
        return result;
    }
}

打印结果

代码语言:javascript
代码运行次数:0
运行
复制
 ------- 测试 3 维数组 ------- 
值:1,几维数组:3
值:2,几维数组:3
值:3,几维数组:3
值:4,几维数组:3
 ------- 测试 2 维数组 ------- 
值:1,几维数组:2
值:2,几维数组:2
值:3,几维数组:2
值:4,几维数组:2
值:5,几维数组:2
 ------- 测试 1 维数组 ------- 
值:1,几维数组:1
值:2,几维数组:1
值:3,几维数组:1

可以看到,符合预期。

2.2 使用策略模式

这个问题不推荐使用策略模式,但为了演示为了更通用,提供了策略模式的解决示例。

假设我们遇到类似的需求,不会写递归或者无法写递归,或者数组的类型非常少,我们可以使用策略模式或者责任链模式来破解 If else 的问题。

定义策略接口:

代码语言:javascript
代码运行次数:0
运行
复制
public interface ArrayStrategy {

     /**
      * 当前策略是否可以处理该对象
      */
     Class type();

     /**
      * 执行处理并返回结果
      */
     Object  handle(Object object);
}

int[] 类型的处理策略(其他类型的自行编写):

代码语言:javascript
代码运行次数:0
运行
复制
/**
 * int [] 处理策略
 */
public class IntArrayStrategy implements  ArrayStrategy{

    public Class type(){
        return int[].class;
    }

    public  Object handle(Object object) {
        int[] array = (int[])object;
        // 处理逻辑
        for (int j : array) {
            System.out.println("int 数组,元素:" + j);
        }

       // 这里是伪代码,返回空数组
        return new float[array.length];
    }
}

示例代码:

代码语言:javascript
代码运行次数:0
运行
复制
public class ArrayDemo {
    private static Map<Class, ArrayStrategy > arrayStrategies = new HashMap<>(16);

    static {
        // int 一维数组
        ArrayStrategy strategy = new IntArrayStrategy();
        arrayStrategies.put(strategy.type(),strategy);
        // short 一维数组
        strategy = new ShortArrayStrategy();
        arrayStrategies.put(strategy.type(),strategy);
     
     //  int 二维数组等,
    }

    public static void main(String[] args) {
        int[] data1 = new int[]{1, 2};
        // 模拟传入 object 类型
        Object obj = data1;
        ArrayStrategy strategy = arrayStrategies.get( obj.getClass());
        // 需要判断 strategy 是否为空
        Object result = strategy.handle(obj);
        System.out.println(result);
    }
}

构造 Map 映射这里,也可以定义 List 将支持策略放进去, for 循环构造 Map; 也可以将策略定义为 Spring 的 Bean ,通过后置处理器构造类型到 Bean 的映射 Map

参考《巧用 Spring 自动注入实现策略模式升级版》

运行的结果:

代码语言:javascript
代码运行次数:0
运行
复制
int 数组,元素:1
int 数组,元素:2
[F@3f99bd52

这样就可以将不同类型的特有处理逻辑内聚到对应的策略中,如果需要支持新的数组类型(如要支持 double[][] ),加一个新的策略即可。

三、总结

日常开发中,遇到觉得“不太对劲” 、“不太优雅” 的地方(其实只要不符合高内聚、弱耦合的场景都有问题),要主动思考如何解决,可以和其他同学交流下,努力写出更简洁和优雅的代码。

日常开发中,多了解 JDK 中反射相关的类,多了解一些知名的三方工具类,很多功能实现起来就会容易一些。

要了解常见的设计模式,很多问题优先考虑是否可以使用某种设计模式或者某种设计模式的变种来解决问题。

总之,写代码是良心活,工作中写代码是项目时间和代码质量之间权衡的结果。

对代码没太大追求的同学有一万种理由不去写出更好的代码。想写出好代码的同学会在项目工期紧张的情况下,尽量写出更简洁、优雅的、健壮、拓展性更强代码。


创作不易,如果本文对你有帮助,欢迎点赞、收藏加关注,你的支持和鼓励,是我创作的最大动力。

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2022/11/24 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 一、背景
  • 二、推荐方案
    • 2.1 采用递归
    • 2.2 使用策略模式
  • 三、总结
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档