public static JSONPath of(
            String[] paths,
            Type[] types,
            String[] formats,
            long[] pathFeatures,
            ZoneId zoneId,
            JSONReader.Feature... features
    ) {
        if (paths.length == 0) {
            throw new JSONException("illegal paths, not support 0 length");
        }

        if (types == null) {
            types = new Type[paths.length];
            Arrays.fill(types, Object.class);
        }

        if (types.length != paths.length) {
            throw new JSONException("types.length not equals paths.length");
        }

        JSONPath[] jsonPaths = new JSONPath[paths.length];
        for (int i = 0; i < paths.length; i++) {
            jsonPaths[i] = of(paths[i]);
        }

        boolean allSingleName = true, allSinglePositiveIndex = true;
        boolean allTwoName = true, allTwoIndexPositive = true;
        boolean allThreeName = true;
        boolean sameMultiLength = true;
        JSONPathMulti firstMulti = null;
        for (int i = 0; i < jsonPaths.length; i++) {
            JSONPath path = jsonPaths[i];
            if (i == 0) {
                if (path instanceof JSONPathMulti) {
                    firstMulti = (JSONPathMulti) path;
                } else {
                    sameMultiLength = false;
                }
            } else {
                if (sameMultiLength) {
                    if (path instanceof JSONPathMulti) {
                        if (((JSONPathMulti) path).segments.size() != firstMulti.segments.size()) {
                            sameMultiLength = false;
                        }
                    }
                }
            }

            if (allSingleName && !(path instanceof JSONPathSingleName)) {
                allSingleName = false;
            }

            if (allSinglePositiveIndex) {
                if (!(path instanceof JSONPathSingleIndex)
                        || ((JSONPathSingleIndex) path).index < 0) {
                    allSinglePositiveIndex = false;
                }
            }

            if (allTwoName) {
                if (path instanceof JSONPathTwoSegment) {
                    JSONPathTwoSegment two = (JSONPathTwoSegment) path;
                    if (!(two.second instanceof JSONPathSegmentName)) {
                        allTwoName = false;
                    }
                } else {
                    allTwoName = false;
                }
            }

            if (allTwoIndexPositive) {
                if (path instanceof JSONPathTwoSegment) {
                    JSONPathTwoSegment two = (JSONPathTwoSegment) path;
                    if (!(two.second instanceof JSONPathSegmentIndex) || ((JSONPathSegmentIndex) two.second).index < 0) {
                        allTwoIndexPositive = false;
                    }
                } else {
                    allTwoIndexPositive = false;
                }
            }

            if (allThreeName) {
                if (path instanceof JSONPathMulti) {
                    JSONPathMulti multi = (JSONPathMulti) path;
                    if (multi.segments.size() == 3) {
                        JSONPathSegment three = multi.segments.get(2);
                        if (multi.segments.get(0) instanceof JSONPathSegment.AllSegment
                                || multi.segments.get(1) instanceof JSONPathSegment.AllSegment
                                || !(three instanceof JSONPathSegmentName)) {
                            allThreeName = false;
                        }
                    } else {
                        allThreeName = false;
                    }
                } else {
                    allThreeName = false;
                }
            }
        }

        long featuresValue = JSONReader.Feature.of(features);

        if (allSingleName) {
            return new JSONPathTypedMultiNames(
                    jsonPaths,
                    null,
                    jsonPaths,
                    types,
                    formats,
                    pathFeatures,
                    zoneId,
                    featuresValue
            );
        }

        if (allSinglePositiveIndex) {
            return new JSONPathTypedMultiIndexes(jsonPaths, null, jsonPaths, types, formats, pathFeatures, zoneId, featuresValue);
        }

        if (allTwoName || allTwoIndexPositive) {
            boolean samePrefix = true;
            JSONPathSegment first0 = ((JSONPathTwoSegment) jsonPaths[0]).first;
            for (int i = 1; i < jsonPaths.length; i++) {
                JSONPathTwoSegment two = (JSONPathTwoSegment) jsonPaths[i];
                if (!first0.equals(two.first)) {
                    samePrefix = false;
                    break;
                }
            }

            if (samePrefix) {
                JSONPath firstPath = jsonPaths[0];

                if (allTwoName) {
                    JSONPathSingleName[] names = new JSONPathSingleName[jsonPaths.length];
                    for (int i = 0; i < jsonPaths.length; i++) {
                        JSONPathTwoSegment two = (JSONPathTwoSegment) jsonPaths[i];
                        JSONPathSegmentName name = (JSONPathSegmentName) two.second;
                        names[i] = new JSONPathSingleName("$." + name, name);
                    }

                    String prefixPath = firstPath.path.substring(0, firstPath.path.length() - names[0].name.length() - 1);
                    if (first0 instanceof JSONPathSegmentName) {
                        JSONPathSegmentName name = (JSONPathSegmentName) first0;
                        JSONPath prefix = new JSONPathSingleName(prefixPath, name);

                        return new JSONPathTypedMultiNamesPrefixName1(
                                jsonPaths,
                                prefix,
                                names,
                                types,
                                formats,
                                pathFeatures,
                                zoneId,
                                featuresValue
                        );
                    } else if (first0 instanceof JSONPathSegmentIndex) {
                        JSONPathSegmentIndex first0Index = ((JSONPathSegmentIndex) first0);
                        if (first0Index.index >= 0) {
                            JSONPathSingleIndex prefix = new JSONPathSingleIndex(prefixPath, first0Index);
                            return new JSONPathTypedMultiNamesPrefixIndex1(
                                    jsonPaths,
                                    prefix,
                                    names,
                                    types,
                                    formats,
                                    pathFeatures,
                                    zoneId,
                                    featuresValue
                            );
                        }
                    }
                } else {
                    JSONPathSingleIndex[] indexes = new JSONPathSingleIndex[jsonPaths.length];
                    for (int i = 0; i < jsonPaths.length; i++) {
                        JSONPathTwoSegment two = (JSONPathTwoSegment) jsonPaths[i];
                        JSONPathSegmentIndex name = (JSONPathSegmentIndex) two.second;
                        indexes[i] = new JSONPathSingleIndex("$" + name, name);
                    }

                    JSONPath prefix = null;
                    if (first0 instanceof JSONPathSegmentName) {
                        JSONPathSegmentName name = (JSONPathSegmentName) first0;
                        prefix = new JSONPathSingleName("$." + name.name, name);
                    } else if (first0 instanceof JSONPathSegmentIndex) {
                        JSONPathSegmentIndex index = (JSONPathSegmentIndex) first0;
                        prefix = new JSONPathSingleIndex("$[" + index.index + "]", index);
                    }

                    if (prefix != null) {
                        return new JSONPathTypedMultiIndexes(
                                jsonPaths,
                                prefix,
                                indexes,
                                types,
                                formats,
                                pathFeatures,
                                zoneId,
                                featuresValue
                        );
                    }
                }
            }
        } else if (allThreeName) {
            boolean samePrefix = true;
            JSONPathSegment first0 = ((JSONPathMulti) jsonPaths[0]).segments.get(0);
            JSONPathSegment first1 = ((JSONPathMulti) jsonPaths[0]).segments.get(1);
            for (int i = 1; i < jsonPaths.length; i++) {
                JSONPathMulti multi = (JSONPathMulti) jsonPaths[i];
                if (!first0.equals(multi.segments.get(0))) {
                    samePrefix = false;
                    break;
                }
                if (!first1.equals(multi.segments.get(1))) {
                    samePrefix = false;
                    break;
                }
            }

            if (samePrefix) {
                JSONPathSingleName[] names = new JSONPathSingleName[jsonPaths.length];
                for (int i = 0; i < jsonPaths.length; i++) {
                    JSONPathMulti multi = (JSONPathMulti) jsonPaths[i];
                    JSONPathSegmentName name = (JSONPathSegmentName) multi.segments.get(2);
                    names[i] = new JSONPathSingleName("$." + name, name);
                }

                JSONPath firstPath = jsonPaths[0];
                String prefixPath = firstPath.path.substring(0, firstPath.path.length() - names[0].name.length() - 1);
                JSONPathTwoSegment prefix = new JSONPathTwoSegment(prefixPath, first0, first1);

                if (first0 instanceof JSONPathSegmentName && first1 instanceof JSONPathSegmentName) {
                    return new JSONPathTypedMultiNamesPrefixName2(
                            jsonPaths,
                            prefix,
                            names,
                            types,
                            formats,
                            pathFeatures,
                            zoneId,
                            featuresValue
                    );
                }

                return new JSONPathTypedMultiNames(
                        jsonPaths,
                        prefix,
                        names,
                        types,
                        formats,
                        pathFeatures,
                        zoneId,
                        featuresValue
                );
            }
        }

        if (sameMultiLength && paths.length > 1) {
            boolean samePrefix = true;
            boolean sameType = true;
            int lastIndex = firstMulti.segments.size() - 1;
            JSONPathSegment lastSegment = firstMulti.segments.get(lastIndex);

            for (int i = 0; i < lastIndex; i++) {
                JSONPathSegment segment = firstMulti.segments.get(i);
                for (int j = 1; j < paths.length; j++) {
                    JSONPath jsonPath = jsonPaths[j];

                    JSONPathSegment segment1;
                    if (jsonPath instanceof JSONPathMulti) {
                        JSONPathMulti path = (JSONPathMulti) jsonPath;
                        segment1 = path.segments.get(i);
                    } else if (jsonPath instanceof JSONPathSingleName) {
                        segment1 = ((JSONPathSingleName) jsonPath).segment;
                    } else if (jsonPath instanceof JSONPathSingleIndex) {
                        segment1 = ((JSONPathSingleIndex) jsonPath).segment;
                    } else {
                        segment1 = null;
                    }

                    if (!segment.equals(segment1)) {
                        samePrefix = false;
                        break;
                    }
                }
                if (!samePrefix) {
                    break;
                }
            }

            if (samePrefix) {
                for (int i = 1; i < paths.length; i++) {
                    JSONPathMulti path = (JSONPathMulti) jsonPaths[i];
                    if (!lastSegment.getClass().equals(path.segments.get(lastIndex).getClass())) {
                        sameType = false;
                        break;
                    }
                }
                if (sameType) {
                    List<JSONPathSegment> prefixSegments = firstMulti.segments.subList(0, lastIndex - 1);
                    String prefixPath = null;
                    int dotIndex = firstMulti.path.lastIndexOf('.');
                    if (dotIndex != -1) {
                        prefixPath = firstMulti.path.substring(0, dotIndex - 1);
                    }
                    if (prefixPath != null) {
                        JSONPathMulti prefix = new JSONPathMulti(prefixPath, prefixSegments);
                        if (lastSegment instanceof JSONPathSegmentIndex) {
                            JSONPath[] indexPaths = new JSONPath[paths.length];
                            for (int i = 0; i < jsonPaths.length; i++) {
                                JSONPathMulti path = (JSONPathMulti) jsonPaths[i];
                                JSONPathSegmentIndex lastSegmentIndex = (JSONPathSegmentIndex) path.segments.get(lastIndex);
                                indexPaths[i] = new JSONPathSingleIndex(lastSegmentIndex.toString(), lastSegmentIndex);
                            }
                            return new JSONPathTypedMultiIndexes(
                                    jsonPaths,
                                    prefix,
                                    indexPaths,
                                    types,
                                    formats,
                                    pathFeatures,
                                    zoneId,
                                    featuresValue
                            );
                        }
                    }
                }
            }
        }

        return new JSONPathTypedMulti(jsonPaths, types, formats, pathFeatures, zoneId, featuresValue);
    }
create multi-path jsonpath

@param paths jsonpath array
@param types item types
@param formats item format
@param zoneId zonedId
@param features parse use JSONReader.Features
@since 2.0.20
core/src/main/java/com/alibaba/fastjson2/JSONPath.java