gitweixin
  • 首页
  • 小程序代码
    • 资讯读书
    • 工具类
    • O2O
    • 地图定位
    • 社交
    • 行业软件
    • 电商类
    • 互联网类
    • 企业类
    • UI控件
  • 大数据开发
    • Hadoop
    • Spark
    • Hbase
    • Elasticsearch
    • Kafka
    • Flink
    • 数据仓库
    • 数据挖掘
    • flume
    • Kafka
    • Hive
    • shardingsphere
    • solr
  • 开发博客
    • Android
    • php
    • python
    • 运维
    • 技术架构
    • 数据库
  • 程序员网赚
  • bug清单
  • 量化投资
  • 在线查询工具
    • 去行号
    • 在线时间戳转换工具
    • 免费图片批量修改尺寸在线工具
    • SVG转JPG在线工具

分类归档Java

精品微信小程序开发门户,代码全部亲测可用

  • 首页   /  大数据开发
  • 分类归档: "Java"
  • ( 页面3 )
Java 8月 29,2023

Druid连接池关键代码解读

Druid连接池中的一个方法,作用是获取一个数据库连接(DruidPooledConnection)。下面对其中的主要逻辑进行解释:

  1. getConnectionInternal(maxWaitMillis):调用内部方法获取数据库连接。如果连接池已满或获取连接超时,则会抛出异常GetConnectionTimeoutException。
  2. isTestOnBorrow():检查是否需要在借用连接时进行连接有效性验证。
    • 如果需要验证连接有效性:
      • 调用testConnectionInternal(poolableConnection.getConnection())方法测试连接的有效性。如果连接有效,则跳出循环。
      • 如果连接无效,将其丢弃并从连接池中移除。
  3. 如果不需要在借用连接时进行连接有效性验证:
    • 检查连接是否已关闭,如果是,则丢弃该连接。
    • 如果开启了空闲连接验证(isTestWhileIdle()):
      • 计算连接的空闲时间。
      • 如果空闲时间超过了设定的时间间隔(timeBetweenEvictionRunsMillis),则检查连接的有效性。
      • 如果连接有效,则跳出循环。
      • 如果连接无效,将其丢弃并从连接池中移除。
  4. 如果开启了移除废弃连接(isRemoveAbandoned()):
    • 获取当前线程的堆栈信息,并将其设置到连接对象中。
    • 设置连接开始时间和追踪状态。
    • 将连接加入活跃连接集合中。
  5. 如果未开启默认自动提交(isDefaultAutoCommit()):
    • 将连接的自动提交设置为false。
  6. 返回获取的连接对象。

总体来说,这段代码的作用是从Druid连接池中获取一个可用的数据库连接,并在一系列条件判断和验证后返回该连接对象。其中包括了连接超时处理、连接有效性验证、废弃连接移除等功能,保证连接的可用性和质量。

解读的代码如下:

public DruidPooledConnection getConnectionDirect(long maxWaitMillis) throws SQLException {
        int notFullTimeoutRetryCnt = 0;

        DruidPooledConnection poolableConnection;
        while(true) {
            while(true) {
                try {
                    poolableConnection = this.getConnectionInternal(maxWaitMillis);
                    break;
                } catch (GetConnectionTimeoutException var17) {
                    if (notFullTimeoutRetryCnt > this.notFullTimeoutRetryCount || this.isFull()) {
                        throw var17;
                    }

                    ++notFullTimeoutRetryCnt;
                    if (LOG.isWarnEnabled()) {
                        LOG.warn("not full timeout retry : " + notFullTimeoutRetryCnt);
                    }
                }
            }

            if (this.isTestOnBorrow()) {
                boolean validate = this.testConnectionInternal(poolableConnection.getConnection());
                if (validate) {
                    break;
                }

                if (LOG.isDebugEnabled()) {
                    LOG.debug("skip not validate connection.");
                }

                Connection realConnection = poolableConnection.getConnection();
                this.discardConnection(realConnection);
            } else {
                Connection realConnection = poolableConnection.getConnection();
                if (realConnection.isClosed()) {
                    this.discardConnection((Connection)null);
                } else {
                    if (!this.isTestWhileIdle()) {
                        break;
                    }

                    long currentTimeMillis = System.currentTimeMillis();
                    long lastActiveTimeMillis = poolableConnection.getConnectionHolder().getLastActiveTimeMillis();
                    long idleMillis = currentTimeMillis - lastActiveTimeMillis;
                    long timeBetweenEvictionRunsMillis = this.getTimeBetweenEvictionRunsMillis();
                    if (timeBetweenEvictionRunsMillis <= 0L) {
                        timeBetweenEvictionRunsMillis = 60000L;
                    }

                    if (idleMillis < timeBetweenEvictionRunsMillis) {
                        break;
                    }

                    boolean validate = this.testConnectionInternal(poolableConnection.getConnection());
                    if (validate) {
                        break;
                    }

                    if (LOG.isDebugEnabled()) {
                        LOG.debug("skip not validate connection.");
                    }

                    this.discardConnection(realConnection);
                }
            }
        }

        if (this.isRemoveAbandoned()) {
            StackTraceElement[] stackTrace = Thread.currentThread().getStackTrace();
            poolableConnection.setConnectStackTrace(stackTrace);
            poolableConnection.setConnectedTimeNano();
            poolableConnection.setTraceEnable(true);
            synchronized(this.activeConnections) {
                this.activeConnections.put(poolableConnection, PRESENT);
            }
        }

        if (!this.isDefaultAutoCommit()) {
            poolableConnection.setAutoCommit(false);
        }

        return poolableConnection;
    }
作者 east
Java 8月 16,2023

当月最后一天的Java工具类

需求要求:
根据年月(YYYY-MM格式),返回该月最后一天(YYYY-MM-dd),例如输入 2023-06,返回2023-06-31

以下是用于根据年月返回该月最后一天的Java工具类实现:

java
import java.time.LocalDate;
import java.time.YearMonth;
import java.time.format.DateTimeFormatter;

public class LastDayOfMonthFinder {

    public static String getLastDayOfMonth(String yearMonth) {
        try {
            YearMonth ym = YearMonth.parse(yearMonth, DateTimeFormatter.ofPattern("yyyy-MM"));
            LocalDate lastDayOfMonth = ym.atEndOfMonth();
            return lastDayOfMonth.format(DateTimeFormatter.ofPattern("yyyy-MM-dd"));
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }

    public static void main(String[] args) {
        String yearMonth = "2023-06";
        String lastDay = getLastDayOfMonth(yearMonth);
        if (lastDay != null) {
            System.out.println("Last day of " + yearMonth + ": " + lastDay);
        } else {
            System.out.println("Invalid input or calculation error.");
        }
    }
}
在这个工具类中,我们使用YearMonth类来解析年月字符串,并通过atEndOfMonth()方法获取该月的最后一天。然后,我们使用DateTimeFormatter将最后一天的日期格式化为"yyyy-MM-dd"格式。请注意,在getLastDayOfMonth方法中,我捕获了通用的Exception来处理可能的解析和计算错误。你可以根据需要进一步优化错误处理部分。最后,示例的main方法演示了如何使用这个工具类来获取指定年月的最后一天。
作者 east
Java 5月 25,2023

Java 中的梯度下降

今天的大多数人工智能都是使用某种形式的神经网络实现的。在我的前两篇文章中,我介绍了神经网络并向您展示了如何在 Java 中构建神经网络。神经网络的力量主要来自于它的深度学习能力,而这种能力建立在梯度下降反向传播的概念和执行之上。我将通过快速深入了解 Java 中的反向传播和梯度下降来结束这个简短的系列文章。
有人说人工智能并不是那么智能,它主要是反向传播。那么,现代机器学习的基石是什么?
要了解反向传播,您必须首先了解神经网络的工作原理。基本上,神经网络是称为神经元的节点的有向图。神经元有一个特定的结构,它接受输入,将它们与权重相乘,添加一个偏差值,并通过激活函数运行所有这些。神经元将它们的输出馈送到其他神经元,直到到达输出神经元。输出神经元产生网络的输出。 (有关更完整的介绍,请参阅机器学习风格:神经网络简介。)
从这里开始,我假设您了解网络及其神经元的结构,包括前馈。示例和讨论将集中在梯度下降的反向传播上。我们的神经网络将有一个输出节点、两个“隐藏”节点和两个输入节点。使用一个相对简单的例子可以更容易地理解算法所涉及的数学。图 1 显示了示例神经网络的图表。
图 1. 我们将用于示例的神经网络图。
梯度下降反向传播的思想是将整个网络视为一个多元函数,为损失函数提供输入。损失函数通过将网络输出与已知的良好结果进行比较来计算一个表示网络执行情况的数字。与良好结果配对的输入数据集称为训练集。损失函数旨在随着网络行为远离正确而增加数值。
梯度下降算法采用损失函数并使用偏导数来确定网络中每个变量(权重和偏差)对损失值的贡献。然后它向后移动,访问每个变量并调整它以减少损失值。
理解梯度下降涉及微积分中的一些概念。首先是导数的概念。 MathsIsFun.com 对导数有很好的介绍。简而言之,导数为您提供函数在单个点处的斜率(或变化率)。换句话说,函数的导数为我们提供了给定输入的变化率。 (微积分的美妙之处在于它可以让我们在没有其他参考点的情况下找到变化——或者更确切地说,它可以让我们假设输入的变化非常小。)
下一个重要的概念是偏导数。偏导数让我们采用多维(也称为多变量)函数并仅隔离其中一个变量以找到给定维度的斜率。
导数回答了以下问题:函数在特定点的变化率(或斜率)是多少?偏导数回答了以下问题:给定方程的多个输入变量,仅这一个变量的变化率是多少?
梯度下降使用这些思想来访问方程中的每个变量并对其进行调整以最小化方程的输出。这正是我们训练网络时想要的。如果我们将损失函数视为绘制在图表上,我们希望以增量方式向函数的最小值移动。也就是说,我们要找到全局最小值。
请注意,增量的大小在机器学习中称为“学习率”。
当我们探索梯度下降反向传播的数学时,我们将紧贴代码。当数学变得过于抽象时,查看代码将有助于让我们脚踏实地。让我们首先查看我们的 Neuron 类,如清单 1 所示。
Neuron 类只有三个 Double 成员:weight1、weight2 和 bias。它也有一些方法。用于前馈的方法是 compute()。它接受两个输入并执行神经元的工作:将每个输入乘以适当的权重,加上偏差,然后通过 sigmoid 函数运行它。
在我们继续之前,让我们重新审视一下 sigmoid 激活的概念,我在神经网络简介中也讨论过它。清单 2 显示了一个基于 Java 的 sigmoid 激活函数。
sigmoid 函数接受输入并将欧拉数 (Math.exp) 提高到负数,加 1 再除以 1。效果是将输出压缩在 0 和 1 之间,越来越大和越来越小的数字逐渐接近极限。
DeepAI.org 对机器学习中的 sigmoid 函数有很好的介绍。
回到清单 1 中的 Neuron 类,除了 compute() 方法之外,我们还有 getSum() 和 getDerivedOutput()。 getSum() 只是进行权重 * 输入 + 偏差计算。请注意,compute() 采用 getSum() 并通过 sigmoid() 运行它。 getDerivedOutput() 方法通过一个不同的函数运行 getSum():sigmoid 函数的导数。
现在看一下清单 3,它显示了 Java 中的 sigmoid 导数函数。我们已经从概念上讨论了衍生品,下面是实际应用。
记住导数告诉我们函数在其图中的单个点的变化是什么,我们可以感受一下这个导数在说什么:告诉我给定输入的 sigmoid 函数的变化率。您可以说它告诉我们清单 1 中的预激活神经元对最终激活结果有何影响。
您可能想知道我们如何知道清单 3 中的 sigmoid 导数函数是正确的。答案是,如果它已经被其他人验证过,并且如果我们知道根据特定规则正确微分的函数是准确的,我们就会知道导数函数是正确的。一旦我们理解了它们在说什么并相信它们是准确的,我们就不必回到第一原理并重新发现这些规则——就像我们接受并应用简化代数方程式的规则一样。
所以,在实践中,我们是按照求导法则来求导数的。如果您查看 sigmoid 函数及其导数,您会发现后者可以通过遵循这些规则得出。出于梯度下降的目的,我们需要了解导数规则,相信它们有效,并了解它们的应用方式。我们将使用它们来找出每个权重和偏差在网络最终损失结果中所扮演的角色。
符号 f prime f'(x) 是“f 对 x 的导数”的一种表达方式。另一个是:
两者是等价的:
您很快就会看到的另一种表示法是偏导数表示法:
这就是说,给我变量 x 的 f 的导数。
最令人好奇的衍生规则是链式法则。它说当一个函数是复合的(函数中的函数,又名高阶函数)时,你可以像这样扩展它:
我们将使用链式法则来解压我们的网络并获得每个权重和偏差的偏导数。

作者 east
Java 5月 19,2023

mysql导出某个库所有表名和表名的注释并保存在excel

import java.io.File;
import java.io.FileOutputStream;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.Statement;

import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.Workbook;

public class ExportMysqlSchema {

    public static void main(String[] args) throws Exception {
        // 连接mysql数据库
        String url = "jdbc:mysql://localhost:3306/test?user=root&password=root";
        Connection conn = DriverManager.getConnection(url);
        Statement stmt = conn.createStatement();

        // 获取某个库所有表名和表名的注释
        String sql = "SELECT TABLE_NAME, TABLE_COMMENT FROM information_schema.TABLES WHERE TABLE_SCHEMA='test'";
        ResultSet rs = stmt.executeQuery(sql);

        // 创建excel文件
        File file = new File("mysql_schema.xls");
        FileOutputStream fos = new FileOutputStream(file);

        // 创建excel工作簿
        Workbook workbook = new HSSFWorkbook();
        // 创建excel工作表
        Sheet sheet = workbook.createSheet("test");
        // 创建excel表头
        Row header = sheet.createRow(0);
        header.createCell(0).setCellValue("TABLE_NAME");
        header.createCell(1).setCellValue("TABLE_COMMENT");

        // 写入excel数据
        int index = 1; // 行索引
        while (rs.next()) {
            // 获取表名和表名的注释
            String tableName = rs.getString(1);
            String tableComment = rs.getString(2);
            // 创建excel行
            Row row = sheet.createRow(index++);
            // 写入excel单元格
            row.createCell(0).setCellValue(tableName);
            row.createCell(1).setCellValue(tableComment);
        }

        // 保存excel文件
        workbook.write(fos);

        // 关闭资源
        fos.close();
        workbook.close();
        rs.close();
        stmt.close();
        conn.close();
    }
}
作者 east
Java 4月 28,2023

用java写一个统计这个文件夹中所有csv总共有多少行

  • 创建一个BufferedReader对象,用来读取文件夹中的csv文件。
  • 使用一个循环,每次读取一行数据,直到文件结束。
  • 使用一个计数器变量,每次读取一行数据就加一。
  • 返回计数器变量的值,就是csv文件的行数。

以下是一个可能的代码示例:

import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;

public class CSVLineCounter {

    // 定义一个方法,接受一个文件夹路径作为参数,返回该文件夹中所有csv文件的总行数
    public static int countLinesInFolder(String folderPath) throws IOException {
        // 创建一个File对象,表示文件夹
        File folder = new File(folderPath);
        // 创建一个数组,存储文件夹中的所有文件
        File[] files = folder.listFiles();
        // 创建一个计数器变量,初始化为0
        int count = 0;
        // 遍历文件数组
        for (File file : files) {
            // 判断文件是否是csv格式
            if (file.getName().endsWith(".csv")) {
                // 调用countLinesInFile方法,统计该文件的行数,并累加到计数器变量上
                count += countLinesInFile(file.getPath());
            }
        }
        // 返回计数器变量的值
        return count;
    }

    // 定义一个方法,接受一个文件路径作为参数,返回该文件的行数
    public static int countLinesInFile(String filePath) throws IOException {
        // 创建一个BufferedReader对象,用来读取文件
        BufferedReader br = new BufferedReader(new FileReader(filePath));
        // 创建一个计数器变量,初始化为0
        int count = 0;
        // 使用一个循环,每次读取一行数据,直到文件结束
        while (br.readLine() != null) {
            // 每次读取一行数据就加一
            count++;
        }
        // 关闭BufferedReader对象
        br.close();
        // 返回计数器变量的值
        return count;
    }

    public static void main(String[] args) throws IOException {
        // 测试代码,假设有一个名为test的文件夹,里面有若干个csv文件
        String folderPath = "test";
        // 调用countLinesInFolder方法,打印出总行数
        System.out.println("The total number of lines in the folder is: " + countLinesInFolder(folderPath));
    }
}
作者 east
Java 8月 25,2022

Idea如何远程调试普通java程序

在开发过程中,常常遇到在本地运行好好的,一到服务器就出各种问题。除了使用日志可以帮助定位,更直观灵活的方式是通过远程调试的方式来定位问题。

如何使用IDEA远程调试

  1. 打开工程,在菜单栏中选择“Run > Edit Configurations”。
  2. 在弹出的配置窗口中用鼠标左键单击左上角的号,在下拉菜单中选择Remote
  3. 选择对应要调试的源码模块路径,并配置远端调试参数Host和Port,如下图2所示。 其中Host为Spark运行机器IP地址,Port为调试的端口号(确保该端口在运行机器上没被占用)。

4.在第3步所填的服务器,执行以下命令,远端启动java

例如:

java -Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=5005 -cp spark-examples_2.10.jar com.data.monitor.Main


5、设置调试断点。 在IDEA代码编辑窗口左侧空白处单击鼠标左键设置相应代码行断点

6、启动调试。 在IDEA菜单栏中选择“Run > Debug ‘Unnamed’”开启调试窗口,接着开始SparkPi的调试,比如单步调试、查看调用栈、跟踪变量值等,如下图所示。

作者 east
Java 8月 19,2022

Thread.currentThread().getContextClassLoader.getResourceAsStream空指针问题

在idea运行代码时,下面的代码一直空指针

Thread.currentThread().getContextClassLoader.getResourceAsStream(“core.properties”);

网上查解决方案,很多都是说idea需要把工程设置为Resources,查了已经是设置了。后来查到有的说是pom问题,经常摸索,果然是pom问题,是下面的pom设置影响到了。

<resources>
            <resource>
                <directory>${project.basedir}/libs</directory>
                <targetPath>BOOT-INF/lib/</targetPath>
                <includes>
                    <include>**/*.jar</include>
                </includes>
            </resource>
            <resource>
                <directory>src/main/resources</directory>
                <targetPath>BOOT-INF/classes/</targetPath>
            </resource>
        </resources> 

配置文件是否能访问,可以看在target/classes文件夹中是否存在

后来修改了pom文件,再运行果然没有报空指针的问题了

<resources>
<resource>
<directory>src/main/java</directory>
<includes>
<include>**/*.properties</include>
<include>**/*.xml</include>
</includes>
<filtering>false</filtering>
</resource>
<resource>
<directory>${project.basedir}/libs</directory>
<targetPath>BOOT-INF/lib/</targetPath>
<includes>
<include>**/*.jar</include>
</includes>
</resource>
</resources>

作者 east
Java 8月 17,2022

解决Failed to execute goal org.apache.maven.plugins:maven-enforcer-plugin:1.4.1:enforce

在编译spark-atlas-connector的源码时,遇到下面的报错:

[INFO] --- maven-enforcer-plugin:1.4.1:enforce (enforce-versions) @ spark-atlas-connector-main_2.11 ---
[WARNING] Rule 2: org.apache.maven.plugins.enforcer.RequireOS failed with message:
OS Arch: x86 Family: dos Name: windows 10 Version: 10.0 is not allowed by Family=unix
[INFO] ------------------------------------------------------------------------
[INFO] Reactor Summary:
[INFO] 
[INFO] spark-atlas-connector-main_2.11 .................... FAILURE [  2.116 s]
[INFO] spark-atlas-connector_2.11 ......................... SKIPPED
[INFO] spark-atlas-connector-assembly ..................... SKIPPED
[INFO] ------------------------------------------------------------------------
[INFO] BUILD FAILURE
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 2.189 s
[INFO] Finished at: 2022-08-17T17:06:06+08:00
[INFO] Final Memory: 26M/495M
[INFO] ------------------------------------------------------------------------
[ERROR] Failed to execute goal org.apache.maven.plugins:maven-enforcer-plugin:1.4.1:enforce (enforce-versions) on project spark-atlas-connector-main_2.11: Some Enforcer rules have failed. Look above for specific messages explaining why the rule failed. -> [Help 1]
[ERROR] 
[ERROR] To see the full stack trace of the errors, re-run Maven with the -e switch.
[ERROR] Re-run Maven using the -X switch to enable full debug logging.
[ERROR] 
[ERROR] For more information about the errors and possible solutions, please read the following articles:
[ERROR] [Help 1] http://cwiki.apache.org/confluence/display/MAVEN/MojoExecutionException

刚开始很头疼,搜索了不少“Failed to execute goal org.apache.maven.plugins:maven-enforcer-plugin:1.4.1:enforce”,还是没解决问题。后面发现上面的“

org.apache.maven.plugins.enforcer.RequireOS failed with message:
OS Arch: x86 Family: dos Name: windows 10 Version: 10.0 is not allowed by Family=unix”

原来, Maven Enforcer 插件提供了非常多的通用检查规则,比如检查 JDK 版本、检查 Maven 版本、 检查依赖版本,等等

<plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-enforcer-plugin</artifactId>
        <inherited>false</inherited>
        <configuration>
          <rules>
            <requireMavenVersion>
              <version>[3.0.0,)</version>
            </requireMavenVersion>
            <requireJavaVersion>
              <version>[${minJavaVersion}.0,${maxJavaVersion}.1000}]</version>
            </requireJavaVersion>
            <requireOS>
              <family>unix</family>
            </requireOS>
          </rules>
        </configuration>
        <executions>
          <execution>
            <id>clean</id>
            <goals>
              <goal>enforce</goal>
            </goals>
            <phase>pre-clean</phase>
          </execution>
          <execution>
            <id>default</id>
            <goals>
              <goal>enforce</goal>
            </goals>
            <phase>validate</phase>
          </execution>
          <execution>
            <id>site</id>
            <goals>
              <goal>enforce</goal>
            </goals>
            <phase>pre-site</phase>
          </execution>
        </executions>
      </plugin>

由于是在windows编译,而原来是如下配置的:

<requireOS>
<family>unix</family>
</requireOS>

需要修改如下:

<requireOS>
     <family>windows</family>
 </requireOS>

果然可以顺利编译了。

作者 east
Java 4月 16,2022

网格编号工具类


import java.math.BigDecimal;

/**
 * 网格编号工具类<br>
 * 一、业务数据坐标网格编号计算 <br>
 * 1)基于覆盖全国的要求,地理坐标以左下角为原点,采用经度72°及纬度 0°为网格坐标原点进行网格划分<br>
 * 2)根据不同的比例尺要求,将网格切分成不同的级别,并按照4x4进行逐级进行切割,精度保留到小数点后10位<br>
 * 3)从原点开始计算(原点处坐标为72°,0°),根据网格范围进行行列号换算,其中一次网格行号和列号采用1位或2位数据表示( 0,1,2,3,4…),其他均采用1位数表达(0,1,2,3)<br>
 * 二、计算最小网格的中心点坐标<br>
 * 1)通过入参确定需要计算的最小网格中心点坐标 <br>
 * 2)先计算出一次网格的跨度,如果有更小的网格则累加起来,并取最后一个网格的半个跨度
 * 
 */
public final class GridCodeUtil {

    /** 网格化原点经度72° */
    public static final double ORIGIN_X = 72d;

    /** 网格化原点纬度 0° */
    public static final double ORIGIN_Y = 0d;

    /** 网格化终点经度 136° */
    public static final double END_X = 136d;

    /** 网格化终点纬度 54° */
    private static final double END_Y = 54d;

    /** 网格化无效值 */
    public static final int INVALID_VALUE = -1;

    /** 一次网格大小,即经度 1度,纬度1度 */
    public static final double FIRST_GRID_SIZE = 1d;

    /** 二次网格大小,即经度0.25度,纬度0.25度 */
    public static final double SECOND_GRID_SIZE = 0.25d;

    /** 三次网格大小,即经度0.0625度,纬度0.0625度 */
    public static final double THIRD_GRID_SIZE = 0.0625d;

    /** 四次网格大小,即经度0.015625度,纬度0.015625度 */
    public static final double FOURTH_GRID_SIZE = 0.015625d;

    /** 五次网格大小,即经度0.00390625度,纬度0.00390625度 */
    public static final double FIFTH_GRID_SIZE = 0.00390625d;

    /** 六次网格大小,即经度0.0009765625度,纬度0.0009765625度 */
    public static final double SIXTH_GRID_SIZE = 0.0009765625d;

    /** 一次网格折半大小 */
    public static final double FIRST_GRID_HALF_SIZE = FIRST_GRID_SIZE / 2;

    /** 二次网格折半大小 */
    public static final double SECOND_GRID_HALF_SIZE = SECOND_GRID_SIZE / 2;

    /** 三次网格折半大小 */
    public static final double THIRD_GRID_HALF_SIZE = THIRD_GRID_SIZE / 2;

    /** 四次网格折半大小 */
    public static final double FOURTH_GRID_HALF_SIZE = FOURTH_GRID_SIZE / 2;

    /** 五次网格折半大小 */
    public static final double FIFTH_GRID_HALF_SIZE = FIFTH_GRID_SIZE / 2;

    /** 六次网格折半大小 */
    public static final double SIXTH_GRID_HALF_SIZE = SIXTH_GRID_SIZE / 2;

    /** 私有构造函数 */
    private GridCodeUtil() {
    }

    /**
     * 坐标网格编号计算
     * 
     * @param xcoord 点的x坐标值,即经度
     * @param ycoord 点的y坐标值,即纬度
     * @return
     */
    public static GridCode computeGridCode(Double xcoord, Double ycoord) {
        GridCode result = new GridCode();
        boolean isNullOrOutOfRange4x = xcoord == null || xcoord < ORIGIN_X || xcoord > END_X;
        boolean isNullOrOutOfRange4y = ycoord == null || ycoord < ORIGIN_Y || ycoord > END_Y;

        // 校验是否合法的坐标
        if (isNullOrOutOfRange4x || isNullOrOutOfRange4y) {
            result.setInvalidValue(INVALID_VALUE);
        } else {
            result.setFirstGridRowCode(computeRowCodeOfFirstGrid(ycoord));
            result.setFirstGridColCode(computeColumnCodeOfFirstGrid(xcoord));
            result.setSecondGridRowCode(computeRowCodeOfSecondGrid(ycoord));
            result.setSecondGridColCode(computeColumnCodeOfSecondGrid(xcoord));
            result.setThirdGridRowCode(computeRowCodeOfThirdGrid(ycoord));
            result.setThirdGridColCode(computeColumnCodeOfThirdGrid(xcoord));
            result.setFourthGridRowCode(computeRowCodeOfFourthGrid(ycoord));
            result.setFourthGridColCode(computeColumnCodeOfFourthGrid(xcoord));
            result.setFifthGridRowCode(computeRowCodeOfFifthGrid(ycoord));
            result.setFifthGridColCode(computeColumnCodeOfFifthGrid(xcoord));
            result.setSixthGridRowCode(computeRowCodeOfSixthGrid(ycoord));
            result.setSixthGridColCode(computeColumnCodeOfSixthGrid(xcoord));
        }
        return result;
    }

    /**
     * 计算最小网格的中心点坐标
     * 
     * @param gridCode 网格编号对象
     * @return 中心点坐标,数组的第一个值是x坐标,第二个值是y坐标
     */
    public static Double[] computeCentrePointOfMinGrid(GridCode gridCode) {
        Double xcoord = null;
        Double ycoord = null;
        int minGrid = 0;

        // 先计算出一次网格的跨度,如果有更小的网格则累加起来。因网格计算时,编号是从0开始的,因此不需要减去一
        if (gridCode.getFirstGridColCode() != null && gridCode.getFirstGridRowCode() != null) {
            xcoord = gridCode.getFirstGridColCode() * FIRST_GRID_SIZE;
            ycoord = gridCode.getFirstGridRowCode() * FIRST_GRID_SIZE;
            minGrid = 1;
        } else {
            // 如果连最基本的一次网格编号都为空,直接抛出参数异常
            throw new IllegalArgumentException("计算最小网格的中心点坐标时,传入的一次网格编号不能为空!");
        }

        if (gridCode.getSecondGridColCode() != null && gridCode.getSecondGridRowCode() != null) {
            xcoord += gridCode.getSecondGridColCode() * SECOND_GRID_SIZE;
            ycoord += gridCode.getSecondGridRowCode() * SECOND_GRID_SIZE;
            minGrid = 2;
        }

        if (gridCode.getThirdGridColCode() != null && gridCode.getThirdGridRowCode() != null) {
            // 如果二次网格编号为空,直接抛出参数异常
            if (minGrid != 2) {
                throw new IllegalArgumentException("计算最小网格的中心点坐标时,传入的二次网格编号不能为空!");
            }
            xcoord += gridCode.getThirdGridColCode() * THIRD_GRID_SIZE;
            ycoord += gridCode.getThirdGridRowCode() * THIRD_GRID_SIZE;
            minGrid = 3;
        }

        if (gridCode.getFourthGridColCode() != null && gridCode.getFourthGridRowCode() != null) {
            // 如果三次网格编号为空,直接抛出参数异常
            if (minGrid != 3) {
                throw new IllegalArgumentException("计算最小网格的中心点坐标时,传入的三次网格编号不能为空!");
            }
            xcoord += gridCode.getFourthGridColCode() * FOURTH_GRID_SIZE;
            ycoord += gridCode.getFourthGridRowCode() * FOURTH_GRID_SIZE;
            minGrid = 4;
        }

        if (gridCode.getFifthGridColCode() != null && gridCode.getFifthGridRowCode() != null) {
            // 如果四次网格编号为空,直接抛出参数异常
            if (minGrid != 4) {
                throw new IllegalArgumentException("计算最小网格的中心点坐标时,传入的四次网格编号不能为空!");
            }
            xcoord += gridCode.getFifthGridColCode() * FIFTH_GRID_SIZE;
            ycoord += gridCode.getFifthGridRowCode() * FIFTH_GRID_SIZE;
            minGrid = 5;
        }

        if (gridCode.getSixthGridColCode() != null && gridCode.getSixthGridRowCode() != null) {
            // 如果五次网格编号为空,直接抛出参数异常
            if (minGrid != 5) {
                throw new IllegalArgumentException("计算最小网格的中心点坐标时,传入的五次网格编号不能为空!");
            }
            xcoord += gridCode.getSixthGridColCode() * SIXTH_GRID_SIZE;
            ycoord += gridCode.getSixthGridRowCode() * SIXTH_GRID_SIZE;
            minGrid = 6;
        }
        return buildResult(xcoord, ycoord, minGrid);
    }

    /**
     * 计算指定的网格的中心点坐标
     *
     * @param gridCode 网格编号对象
     * @param minGrid 要计算的网格层级
     * @return 中心点坐标,数组的第一个值是x坐标,第二个值是y坐标
     */
    public static Double[] computeCentrePointOfMinGrid2(GridCode gridCode,int minGrid) {
        Double xcoord = null;
        Double ycoord = null;

        if (minGrid == 1) {
            xcoord = gridCode.getFirstGridColCode() * FIRST_GRID_SIZE;
            ycoord = gridCode.getFirstGridRowCode() * FIRST_GRID_SIZE;
        }

        if (minGrid == 2) {
            xcoord += gridCode.getSecondGridColCode() * SECOND_GRID_SIZE;
            ycoord += gridCode.getSecondGridRowCode() * SECOND_GRID_SIZE;
        }

        if (minGrid == 3) {
            xcoord += gridCode.getThirdGridColCode() * THIRD_GRID_SIZE;
            ycoord += gridCode.getThirdGridRowCode() * THIRD_GRID_SIZE;
        }

        if (minGrid == 4) {
            xcoord += gridCode.getFourthGridColCode() * FOURTH_GRID_SIZE;
            ycoord += gridCode.getFourthGridRowCode() * FOURTH_GRID_SIZE;
        }

        if (minGrid == 5) {
            xcoord += gridCode.getFifthGridColCode() * FIFTH_GRID_SIZE;
            ycoord += gridCode.getFifthGridRowCode() * FIFTH_GRID_SIZE;
            minGrid = 5;
        }

        if (minGrid == 6) {
            xcoord += gridCode.getSixthGridColCode() * SIXTH_GRID_SIZE;
            ycoord += gridCode.getSixthGridRowCode() * SIXTH_GRID_SIZE;
        }
        try {
            return buildResult(xcoord, ycoord, minGrid);
        } catch (Exception e) {
            return null;
        }
    }

    /**
     * 构建最后的结果值<br>
     * 添加网格化原点经纬度和最小网格的中点跨度,如果小数点大于八位,则四舍五入保留八位小数点
     * 
     * @param xcoord 网格跨度x坐标值
     * @param ycoord 网格跨度y坐标值
     * @param minGrid 需要计算的最小网格
     * @return
     */
    private static Double[] buildResult(Double xcoord, Double ycoord, int minGrid) {
        Double[] result = new Double[2];

        result[0] = ORIGIN_X + xcoord;
        result[1] = ORIGIN_Y + ycoord;

        switch (minGrid) {
        case 1:
            result[0] += FIRST_GRID_HALF_SIZE;
            result[1] += FIRST_GRID_HALF_SIZE;
            break;
        case 2:
            result[0] += SECOND_GRID_HALF_SIZE;
            result[1] += SECOND_GRID_HALF_SIZE;
            break;
        case 3:
            result[0] += THIRD_GRID_HALF_SIZE;
            result[1] += THIRD_GRID_HALF_SIZE;
            break;
        case 4:
            result[0] += FOURTH_GRID_HALF_SIZE;
            result[1] += FOURTH_GRID_HALF_SIZE;
            break;
        case 5:
            result[0] += FIFTH_GRID_HALF_SIZE;
            result[1] += FIFTH_GRID_HALF_SIZE;
            break;
        case 6:
            result[0] += SIXTH_GRID_HALF_SIZE;
            result[1] += SIXTH_GRID_HALF_SIZE;
            break;
        default:
            throw new IllegalArgumentException("计算最小网格的中心点坐标异常,当前只支持1-6次网格!");
        }
        BigDecimal bd0 = new BigDecimal(result[0]);
        BigDecimal bd1 = new BigDecimal(result[1]);
        result[0] = bd0.setScale(8, BigDecimal.ROUND_HALF_UP).doubleValue();
        result[1] = bd1.setScale(8, BigDecimal.ROUND_HALF_UP).doubleValue();
        return result;
    }

    /**
     * 计算一次网格的行编号
     * 
     * @param ycoord 点的y坐标值,即纬度
     * @return
     */
    private static int computeRowCodeOfFirstGrid(double ycoord) {
        return (int) (difOriginY(ycoord) / FIRST_GRID_SIZE);
    }

    /**
     * 计算一次网格的列编号
     * 
     * @param xcoord 点的x坐标值,即经度
     * @return
     */
    private static int computeColumnCodeOfFirstGrid(double xcoord) {
        return (int) (difOriginX(xcoord) / FIRST_GRID_SIZE);
    }

    /**
     * 获取当前一次网格最小y坐标值
     * 
     * @param ycoord 点的y坐标值,即纬度
     * @return
     */
    private static double getMiniYcoodOfFirstGrid(double ycoord) {
        return computeRowCodeOfFirstGrid(ycoord) * FIRST_GRID_SIZE;
    }

    /**
     * 获取当前一次网格最小x坐标值
     * 
     * @param xcoord 点的x坐标值,即经度
     * @return
     */
    private static double getMiniXcoodOfFirstGrid(double xcoord) {
        return computeColumnCodeOfFirstGrid(xcoord) * FIRST_GRID_SIZE;
    }

    /**
     * 计算二次网格的行编号
     * 
     * @param ycoord 点的y坐标值,即纬度
     * @return
     */
    private static int computeRowCodeOfSecondGrid(double ycoord) {
        return (int) ((difOriginY(ycoord) - getMiniYcoodOfFirstGrid(ycoord)) / SECOND_GRID_SIZE);
    }

    /**
     * 计算二次网格的列编号
     * 
     * @param xcoord 点的x坐标值,即经度
     * @return
     */
    private static int computeColumnCodeOfSecondGrid(double xcoord) {
        return (int) ((difOriginX(xcoord) - getMiniXcoodOfFirstGrid(xcoord)) / SECOND_GRID_SIZE);
    }

    /**
     * 获取当前二次网格最小y坐标值
     * 
     * @param ycoord 点的y坐标值,即纬度
     * @return
     */
    private static double getMiniYcoodOfSecondGrid(double ycoord) {
        return computeRowCodeOfSecondGrid(ycoord) * SECOND_GRID_SIZE;
    }

    /**
     * 获取当前二次网格最小x坐标值
     * 
     * @param xcoord 点的x坐标值,即经度
     * @return
     */
    private static double getMiniXcoodOfSecondGrid(double xcoord) {
        return computeColumnCodeOfSecondGrid(xcoord) * SECOND_GRID_SIZE;
    }

    /**
     * 计算三次网格的行编号
     * 
     * @param ycoord 点的y坐标值,即纬度
     * @return
     */
    private static int computeRowCodeOfThirdGrid(double ycoord) {
        return (int) ((difOriginY(ycoord) - getMiniYcoodOfFirstGrid(ycoord) - getMiniYcoodOfSecondGrid(ycoord))
                / THIRD_GRID_SIZE);
    }

    /**
     * 计算三次网格的列编号
     * 
     * @param xcoord 点的x坐标值,即经度
     * @return
     */
    private static int computeColumnCodeOfThirdGrid(double xcoord) {
        return (int) ((difOriginX(xcoord) - getMiniXcoodOfFirstGrid(xcoord) - getMiniXcoodOfSecondGrid(xcoord))
                / THIRD_GRID_SIZE);
    }

    /**
     * 获取当前三次网格最小y坐标值
     * 
     * @param ycoord 点的y坐标值,即纬度
     * @return
     */
    private static double getMiniYcoodOfThirdGrid(double ycoord) {
        return computeRowCodeOfThirdGrid(ycoord) * THIRD_GRID_SIZE;
    }

    /**
     * 获取当前三次网格最小x坐标值
     * 
     * @param xcoord 点的x坐标值,即经度
     * @return
     */
    private static double getMiniXcoodOfThirdGrid(double xcoord) {
        return computeColumnCodeOfThirdGrid(xcoord) * THIRD_GRID_SIZE;
    }

    /**
     * 计算四次网格的行编号
     * 
     * @param ycoord 点的y坐标值,即纬度
     * @return
     */
    private static int computeRowCodeOfFourthGrid(double ycoord) {
        return (int) ((difOriginY(ycoord) - getMiniYcoodOfFirstGrid(ycoord) - getMiniYcoodOfSecondGrid(ycoord)
                - getMiniYcoodOfThirdGrid(ycoord)) / FOURTH_GRID_SIZE);
    }

    /**
     * 计算四次网格的列编号
     * 
     * @param xcoord 点的x坐标值,即经度
     * @return
     */
    private static int computeColumnCodeOfFourthGrid(double xcoord) {
        return (int) ((difOriginX(xcoord) - getMiniXcoodOfFirstGrid(xcoord) - getMiniXcoodOfSecondGrid(xcoord)
                - getMiniXcoodOfThirdGrid(xcoord)) / FOURTH_GRID_SIZE);
    }

    /**
     * 获取当前四次网格最小y坐标值
     * 
     * @param ycoord 点的y坐标值,即纬度
     * @return
     */
    private static double getMiniYcoodOfFourthGrid(double ycoord) {
        return computeRowCodeOfFourthGrid(ycoord) * FOURTH_GRID_SIZE;
    }

    /**
     * 获取当前四次网格最小x坐标值
     * 
     * @param xcoord 点的x坐标值,即经度
     * @return
     */
    private static double getMiniXcoodOfFourthGrid(double xcoord) {
        return computeColumnCodeOfFourthGrid(xcoord) * FOURTH_GRID_SIZE;
    }

    /**
     * 计算五次网格的行编号
     * 
     * @param ycoord 点的y坐标值,即纬度
     * @return
     */
    private static int computeRowCodeOfFifthGrid(double ycoord) {
        return (int) ((difOriginY(ycoord) - getMiniYcoodOfFirstGrid(ycoord) - getMiniYcoodOfSecondGrid(ycoord)
                - getMiniYcoodOfThirdGrid(ycoord) - getMiniYcoodOfFourthGrid(ycoord)) / FIFTH_GRID_SIZE);
    }

    /**
     * 计算五次网格的列编号
     * 
     * @param xcoord 点的x坐标值,即经度
     * @return
     */
    private static int computeColumnCodeOfFifthGrid(double xcoord) {
        return (int) ((difOriginX(xcoord) - getMiniXcoodOfFirstGrid(xcoord) - getMiniXcoodOfSecondGrid(xcoord)
                - getMiniXcoodOfThirdGrid(xcoord) - getMiniXcoodOfFourthGrid(xcoord)) / FIFTH_GRID_SIZE);
    }

    /**
     * 获取当前五次网格最小y坐标值
     * 
     * @param ycoord 点的y坐标值,即纬度
     * @return
     */
    private static double getMiniYcoodOfFifthGrid(double ycoord) {
        return computeRowCodeOfFifthGrid(ycoord) * FIFTH_GRID_SIZE;
    }

    /**
     * 获取当前五次网格最小x坐标值
     * 
     * @param xcoord 点的x坐标值,即经度
     * @return
     */
    private static double getMiniXcoodOfFifthGrid(double xcoord) {
        return computeColumnCodeOfFifthGrid(xcoord) * FIFTH_GRID_SIZE;
    }

    /**
     * 计算六次网格的行编号
     * 
     * @param ycoord 点的y坐标值,即纬度
     * @return
     */
    private static int computeRowCodeOfSixthGrid(double ycoord) {
        return (int) ((difOriginY(ycoord) - getMiniYcoodOfFirstGrid(ycoord) - getMiniYcoodOfSecondGrid(ycoord)
                - getMiniYcoodOfThirdGrid(ycoord) - getMiniYcoodOfFourthGrid(ycoord) - getMiniYcoodOfFifthGrid(ycoord))
                / SIXTH_GRID_SIZE);
    }

    /**
     * 计算六次网格的列编号
     * 
     * @param xcoord 点的x坐标值,即经度
     * @return
     */
    private static int computeColumnCodeOfSixthGrid(double xcoord) {
        return (int) ((difOriginX(xcoord) - getMiniXcoodOfFirstGrid(xcoord) - getMiniXcoodOfSecondGrid(xcoord)
                - getMiniXcoodOfThirdGrid(xcoord) - getMiniXcoodOfFourthGrid(xcoord) - getMiniXcoodOfFifthGrid(xcoord))
                / SIXTH_GRID_SIZE);
    }

    /**
     * 目标点和原点的纬度差值
     * 
     * @param ycoord 点的y坐标值,即纬度
     * @return
     */
    private static double difOriginY(double ycoord) {
        return ycoord - ORIGIN_Y;
    }

    /**
     * 目标点和原点的经度差值
     * 
     * @param xcoord 点的x坐标值,即经度
     * @return
     */
    private static double difOriginX(double xcoord) {
        return xcoord - ORIGIN_X;
    }

}
public class GridCode {

    /** 一次网格行号 */
    private Integer firstGridRowCode;

    /** 一次网格列号 */
    private Integer firstGridColCode;

    /** 二次网格行号 */
    private Integer secondGridRowCode;

    /** 二次网格列号 */
    private Integer secondGridColCode;

    /** 三次网格行号 */
    private Integer thirdGridRowCode;

    /** 三次网格列号 */
    private Integer thirdGridColCode;

    /** 四次网格行号 */
    private Integer fourthGridRowCode;

    /** 四次网格列号 */
    private Integer fourthGridColCode;

    /** 五次网格行号 */
    private Integer fifthGridRowCode;

    /** 五次网格列号 */
    private Integer fifthGridColCode;

    /** 六次网格行号 */
    private Integer sixthGridRowCode;

    /** 六次网格列号 */
    private Integer sixthGridColCode;

    /**
     * 设置无效值
     */
    public void setInvalidValue(int invalidValue) {
        this.firstGridRowCode = invalidValue;
        this.firstGridColCode = invalidValue;
        this.secondGridRowCode = invalidValue;
        this.secondGridColCode = invalidValue;
        this.thirdGridRowCode = invalidValue;
        this.thirdGridColCode = invalidValue;
        this.fourthGridRowCode = invalidValue;
        this.fourthGridColCode = invalidValue;
        this.fifthGridRowCode = invalidValue;
        this.fifthGridColCode = invalidValue;
        this.sixthGridRowCode = invalidValue;
        this.sixthGridColCode = invalidValue;
    }

    public Integer getFirstGridRowCode() {
        return firstGridRowCode;
    }

    public void setFirstGridRowCode(Integer firstGridRowCode) {
        this.firstGridRowCode = firstGridRowCode;
    }

    public Integer getFirstGridColCode() {
        return firstGridColCode;
    }

    public void setFirstGridColCode(Integer firstGridColCode) {
        this.firstGridColCode = firstGridColCode;
    }

    public Integer getSecondGridRowCode() {
        return secondGridRowCode;
    }

    public void setSecondGridRowCode(Integer secondGridRowCode) {
        this.secondGridRowCode = secondGridRowCode;
    }

    public Integer getSecondGridColCode() {
        return secondGridColCode;
    }

    public void setSecondGridColCode(Integer secondGridColCode) {
        this.secondGridColCode = secondGridColCode;
    }

    public Integer getThirdGridRowCode() {
        return thirdGridRowCode;
    }

    public void setThirdGridRowCode(Integer thirdGridRowCode) {
        this.thirdGridRowCode = thirdGridRowCode;
    }

    public Integer getThirdGridColCode() {
        return thirdGridColCode;
    }

    public void setThirdGridColCode(Integer thirdGridColCode) {
        this.thirdGridColCode = thirdGridColCode;
    }

    public Integer getFourthGridRowCode() {
        return fourthGridRowCode;
    }

    public void setFourthGridRowCode(Integer fourthGridRowCode) {
        this.fourthGridRowCode = fourthGridRowCode;
    }

    public Integer getFourthGridColCode() {
        return fourthGridColCode;
    }

    public void setFourthGridColCode(Integer fourthGridColCode) {
        this.fourthGridColCode = fourthGridColCode;
    }

    public Integer getFifthGridRowCode() {
        return fifthGridRowCode;
    }

    public void setFifthGridRowCode(Integer fifthGridRowCode) {
        this.fifthGridRowCode = fifthGridRowCode;
    }

    public Integer getFifthGridColCode() {
        return fifthGridColCode;
    }

    public void setFifthGridColCode(Integer fifthGridColCode) {
        this.fifthGridColCode = fifthGridColCode;
    }

    public Integer getSixthGridRowCode() {
        return sixthGridRowCode;
    }

    public void setSixthGridRowCode(Integer sixthGridRowCode) {
        this.sixthGridRowCode = sixthGridRowCode;
    }

    public Integer getSixthGridColCode() {
        return sixthGridColCode;
    }

    public void setSixthGridColCode(Integer sixthGridColCode) {
        this.sixthGridColCode = sixthGridColCode;
    }

}
作者 east
Java 4月 7,2022

地图不同坐标系的转换工具类

提供以下的坐标系互相转换:

GCJ-02(火星坐标系)转换为WGS84坐标系

BD-09(百度坐标系)转换为WGS84坐标系

BD-09(百度坐标系)转换为GCJ-02(火星坐标)

sogou转换为WGS84


/**
 * @author jy 地图转换测试/
 */
public final class MapUtil {

    /**
     * 辅助类禁止共有构造函数
     */
    private MapUtil() {

    }

    /**
     * 常量:pi
     */
    public static final double CONSTANT_PI = 3.1415926535897932384626;

    /**
     * 常量:a
     */
    public static final double CONSTANT_A = 6378245.0;

    /**
     * 常量:e
     */
    public static final double CONSTANT_E = 0.00669342162296594323;

    /**
     * 常量:ccc
     */
    private static final double[] CCC = new double[]{12890594.86, 8362377.87, 5591021, 3481989.83, 1678043.12, 0};

    /**
     * 常量:ddd
     */
    private static final double[][] DDD = {
            new double[]{1.410526172116255e-8, 0.00000898305509648872, -1.9939833816331, 200.9824383106796,
                    -187.2403703815547, 91.6087516669843, -23.38765649603339, 2.57121317296198, -0.03801003308653,
                    17337981.2},
            new double[]{-7.435856389565537e-9, 0.000008983055097726239, -0.78625201886289, 96.32687599759846,
                    -1.85204757529826, -59.36935905485877, 47.40033549296737, -16.50741931063887, 2.28786674699375,
                    10260144.86},
            new double[]{-3.030883460898826e-8, 0.00000898305509983578, 0.30071316287616, 59.74293618442277,
                    7.357984074871, -25.38371002664745, 13.45380521110908, -3.29883767235584, 0.32710905363475,
                    6856817.37},
            new double[]{-1.981981304930552e-8, 0.000008983055099779535, 0.03278182852591, 40.31678527705744,
                    0.65659298677277, -4.44255534477492, 0.85341911805263, 0.12923347998204, -0.04625736007561,
                    4482777.06},
            new double[]{3.09191371068437e-9, 0.000008983055096812155, 0.00006995724062, 23.10934304144901,
                    -0.00023663490511, -0.6321817810242, -0.00663494467273, 0.03430082397953, -0.00466043876332,
                    2555164.4},
            new double[]{2.890871144776878e-9, 0.000008983055095805407, -3.068298e-8, 7.47137025468032,
                    -0.00000353937994, -0.02145144861037, -0.00001234426596, 0.00010322952773, -0.00000323890364,
                    826088.5}};

    /**
     * GCJ-02(火星坐标系)转换为WGS84坐标系<br>
     * GCJ-02:谷歌中国地图、搜搜中国地图、高德地图<br>
     *
     * @param lat 纬度
     * @param lon 经度
     * @return
     */
    public static Coord gcj02ToWgs84(double lat, double lon) {

        Coord coord = transform(lat, lon);

        double finalLon = lon * 2 - coord.getLon();
        double finalLat = lat * 2 - coord.getLat();

        return new Coord(finalLat, finalLon);

    }

    /**
     * BD-09(百度坐标系)转换为WGS84坐标系<br>
     *
     * @param lat 纬度
     * @param lon 经度
     * @return
     */
    public static Coord bd09ToWgs84(double lat, double lon) {

        Coord gcj02 = MapUtil.bd09ToGcj02(lat, lon);
        Coord wgs84 = MapUtil.gcj02ToWgs84(gcj02.getLat(), gcj02.getLon());

        return wgs84;
    }

    /**
     * BD-09(百度坐标系)转换为GCJ-02(火星坐标)<br>
     *
     * @param lat 纬度
     * @param lon 经度
     * @return
     */
    public static Coord bd09ToGcj02(double lat, double lon) {

        double x = lon - 0.0065;
        double y = lat - 0.006;
        double z = Math.sqrt(x * x + y * y) - 0.00002 * Math.sin(y * CONSTANT_PI);

        double theta = Math.atan2(y, x) - 0.000003 * Math.cos(x * CONSTANT_PI);

        double finalLon = z * Math.cos(theta);
        double finalLat = z * Math.sin(theta);

        return new Coord(finalLat, finalLon);

    }

    /**
     * sogou转换为WGS84
     *
     * @param lat 纬度
     * @param lon 经度
     * @return
     */
    public static Coord sogouToWgs84(double lat, double lon) {

        Coord coord = new Coord(lat, lon);

        Coord tmp = new Coord();
        tmp.setLon(Math.abs(coord.getLon()));
        tmp.setLat(Math.abs(coord.getLat()));

        double[] obj = new double[9];
        for (int i = 0; i < CCC.length; i++) {
            if (tmp.getLat() > CCC[i]) {
                obj = DDD[i];
                break;
            }
        }

        return MapUtil.convert(coord, obj);
    }

    /**
     * sogou内部转换函数
     *
     * @param coord
     * @param varAttr
     * @return
     */
    private static Coord convert(Coord coord, double[] varAttr) {
        Coord tmp = new Coord();
        tmp.setLon(varAttr[0] + varAttr[1] * Math.abs(coord.getLon()));
        double f = Math.abs(coord.getLat()) / varAttr[9];
        double tmpLat = varAttr[2] + varAttr[3] * f + varAttr[4] * f * f + varAttr[5] * f * f * f
                + varAttr[6] * f * f * f * f + varAttr[7] * f * f * f * f * f + varAttr[8] * f * f * f * f * f * f;
        tmp.setLat(tmpLat);
        tmp.setLon(tmp.getLon() * (coord.getLon() < 0 ? -1 : 1));
        tmp.setLat(tmp.getLat() * (coord.getLat() < 0 ? -1 : 1));

        return tmp;
    }

    /**
     * 坐标点转换函数
     *
     * @param lat 纬度
     * @param lon 经度
     * @return
     */
    private static Coord transform(double lat, double lon) {

        if (outOfChina(lat, lon)) {
            return new Coord(lat, lon);
        }

        double dLat = transformLat(lat - 35.0, lon - 105.0);
        double dLon = transformLon(lat - 35.0, lon - 105.0);

        double radLat = lat / 180.0 * CONSTANT_PI;

        double magic = Math.sin(radLat);
        magic = 1 - CONSTANT_E * magic * magic;
        double sqrtMagic = Math.sqrt(magic);
        dLat = (dLat * 180.0) / ((CONSTANT_A * (1 - CONSTANT_E)) / (magic * sqrtMagic) * CONSTANT_PI);
        dLon = (dLon * 180.0) / (CONSTANT_A / sqrtMagic * Math.cos(radLat) * CONSTANT_PI);
        double mgLat = lat + dLat;
        double mgLon = lon + dLon;

        return new Coord(mgLat, mgLon);

    }

    /**
     * 纬度转换函数
     *
     * @param lat 维度
     * @param lon 经度
     * @return
     */
    private static double transformLat(double lat, double lon) {

        double ret = -100.0 + 2.0 * lon + 3.0 * lat + 0.2 * lat * lat + 0.1 * lon * lat
                + 0.2 * Math.sqrt(Math.abs(lon));
        ret += (20.0 * Math.sin(6.0 * lon * CONSTANT_PI) + 20.0 * Math.sin(2.0 * lon * CONSTANT_PI)) * 2.0 / 3.0;
        ret += (20.0 * Math.sin(lat * CONSTANT_PI) + 40.0 * Math.sin(lat / 3.0 * CONSTANT_PI)) * 2.0 / 3.0;
        ret += (160.0 * Math.sin(lat / 12.0 * CONSTANT_PI) + 320 * Math.sin(lat * CONSTANT_PI / 30.0)) * 2.0 / 3.0;

        return ret;
    }

    /**
     * 经度转换函数
     *
     * @param lat 纬度
     * @param lon 经度
     * @return
     */
    private static double transformLon(double lat, double lon) {

        double ret = 300.0 + lon + 2.0 * lat + 0.1 * lon * lon + 0.1 * lon * lat + 0.1 * Math.sqrt(Math.abs(lon));

        ret += (20.0 * Math.sin(6.0 * lon * CONSTANT_PI) + 20.0 * Math.sin(2.0 * lon * CONSTANT_PI)) * 2.0 / 3.0;
        ret += (20.0 * Math.sin(lon * CONSTANT_PI) + 40.0 * Math.sin(lon / 3.0 * CONSTANT_PI)) * 2.0 / 3.0;
        ret += (150.0 * Math.sin(lon / 12.0 * CONSTANT_PI) + 300.0 * Math.sin(lon / 30.0 * CONSTANT_PI)) * 2.0 / 3.0;

        return ret;
    }

    /**
     * 判断坐标点是否在中国范围内
     *
     * @param lat
     * @param lon
     * @return
     */
    private static boolean outOfChina(double lat, double lon) {

        if (lon < 72.004 || lon > 137.8347) {
            return true;
        }

        if (lat < 0.8293 || lat > 55.8271) {
            return true;
        }

        return false;
    }

}
public class Coord implements Serializable {

    /**
     *
     */
    private static final long serialVersionUID = -229841606158709053L;
    /**
     * 纬度
     */
    private double lat;
    /**
     * 经度
     */
    private double lon;

    /**
     * 默认构造参数
     */
    public Coord() {

    }

    /**
     * 重载构造方法
     *
     * @param lat 纬度
     * @param lon 经度
     */
    public Coord(double lat, double lon) {
        this.lat = lat;
        this.lon = lon;
    }

    public double getLat() {
        return lat;
    }

    public void setLat(double lat) {
        this.lat = lat;
    }

    public double getLon() {
        return lon;
    }

    public void setLon(double lon) {
        this.lon = lon;
    }

}
作者 east
Java, python 3月 6,2022

Python基础语法规则和Java不同的地方

Java是现在最流行的语言,也是广大程序员最熟悉的语言,而Python作为在人工智能领域的新星,通过对比Java语言来学习Python语言,可以起到事半功倍的效果。

和Java单行注释不同,Python注释更像shell等脚本语言, python语言单行注释通常是以“#”号开头,在“#”号后面紧跟注释说明的文字。

Java语言用{ } 来区分代码块, Python是用缩进代码 , 缩进相同的一组语句构成一个代码块,也称为代码组。

在数学运算上,Java使用除法,如果除数和被除数都是整数,那么结果还是整数。如果结果要为准确的浮点数,要对其中一个数进行强制转换。Python就没有那么麻烦。 Python数值的除法包含两个运算符:“/”返回一个浮点数,“//”返回一个整数 , 在混合计算时,Python会把整数转换成为浮点数 。

在字符串的定义上,Python更加灵活。 可以使用单引号(’)、双引号(”)或三引号(”’或”””)来标识字符串,引号的开始与结束必须是相同类型的 。

Python中没有switch和case语句 , 多路分支语句只能通过if…elif…else流程控制语句来实现,并且每个分支语句都要有严格的缩进。 for循环中也可以使用else语句 。

作者 east
Java 12月 14,2021

Java多线程使用总结

Java线程的3种创建方式,使用继承方式的好处是方便传参,你可以在子类里面添加成员变量,通过set方法设置参数或者通过构造函数进行传递,而如果使用Runnable方式,则只能使用主线程里面被声明为final的变量。不好的地方是Java不支持多继承,如果继承了Thread类,那么子类不能再继承其他类,而Runable则没有这个限制。前两种方式都没办法拿到任务的返回结果,但是Futuretask方式可以。

sleep与yield方法的区别在于,当线程调用sleep方法时调用线程会被阻塞挂起指定的时间,在这期间线程调度器不会去调度该线程。而调用yield方法时,线程只是让出自己剩余的时间片,并没有被阻塞挂起,而是处于就绪状态,线程调度器下一次调度时就有可能调度到当前线程执行。

守护线程并非只有虚拟机内部可以提供,用户也可以手动将一个用户线程设定/转换为守护线程。在Thread类中提供了一个setDaemon(true)方法来将一个普通的线程(用户线程)设置为守护线

public final void setDaemon(boolean on);

如果你希望在主线程结束后JVM进程马上结束,那么在创建线程时可以将其设置为守护线程,如果你希望在主线程结束后子线程继续工作,等子线程结束后再让JVM进程结束,那么就将子线程设置为用户线程。

作者 east

上一 1 2 3 4 … 6 下一个

关注公众号“大模型全栈程序员”回复“小程序”获取1000个小程序打包源码。回复”chatgpt”获取免注册可用chatgpt。回复“大数据”获取多本大数据电子书

标签

AIGC AI创作 bert chatgpt github GPT-3 gpt3 GTP-3 hive mysql O2O tensorflow UI控件 不含后台 交流 共享经济 出行 图像 地图定位 外卖 多媒体 娱乐 小程序 布局 带后台完整项目 开源项目 搜索 支付 效率 教育 日历 机器学习 深度学习 物流 用户系统 电商 画图 画布(canvas) 社交 签到 联网 读书 资讯 阅读 预订

官方QQ群

小程序开发群:74052405

大数据开发群: 952493060

近期文章

  • 详解Python当中的pip常用命令
  • AUTOSAR如何在多个供应商交付的配置中避免ARXML不兼容?
  • C++thread pool(线程池)设计应关注哪些扩展性问题?
  • 各类MCAL(Microcontroller Abstraction Layer)如何与AUTOSAR工具链解耦?
  • 如何设计AUTOSAR中的“域控制器”以支持未来扩展?
  • C++ 中避免悬挂引用的企业策略有哪些?
  • 嵌入式电机:如何在低速和高负载状态下保持FOC(Field-Oriented Control)算法的电流控制稳定?
  • C++如何在插件式架构中使用反射实现模块隔离?
  • C++如何追踪内存泄漏(valgrind/ASan等)并定位到业务代码?
  • C++大型系统中如何组织头文件和依赖树?

文章归档

  • 2025年6月
  • 2025年5月
  • 2025年4月
  • 2025年3月
  • 2025年2月
  • 2025年1月
  • 2024年12月
  • 2024年11月
  • 2024年10月
  • 2024年9月
  • 2024年8月
  • 2024年7月
  • 2024年6月
  • 2024年5月
  • 2024年4月
  • 2024年3月
  • 2023年11月
  • 2023年10月
  • 2023年9月
  • 2023年8月
  • 2023年7月
  • 2023年6月
  • 2023年5月
  • 2023年4月
  • 2023年3月
  • 2023年1月
  • 2022年11月
  • 2022年10月
  • 2022年9月
  • 2022年8月
  • 2022年7月
  • 2022年6月
  • 2022年5月
  • 2022年4月
  • 2022年3月
  • 2022年2月
  • 2022年1月
  • 2021年12月
  • 2021年11月
  • 2021年9月
  • 2021年8月
  • 2021年7月
  • 2021年6月
  • 2021年5月
  • 2021年4月
  • 2021年3月
  • 2021年2月
  • 2021年1月
  • 2020年12月
  • 2020年11月
  • 2020年10月
  • 2020年9月
  • 2020年8月
  • 2020年7月
  • 2020年6月
  • 2020年5月
  • 2020年4月
  • 2020年3月
  • 2020年2月
  • 2020年1月
  • 2019年7月
  • 2019年6月
  • 2019年5月
  • 2019年4月
  • 2019年3月
  • 2019年2月
  • 2019年1月
  • 2018年12月
  • 2018年7月
  • 2018年6月

分类目录

  • Android (73)
  • bug清单 (79)
  • C++ (34)
  • Fuchsia (15)
  • php (4)
  • python (43)
  • sklearn (1)
  • 云计算 (20)
  • 人工智能 (61)
    • chatgpt (21)
      • 提示词 (6)
    • Keras (1)
    • Tensorflow (3)
    • 大模型 (1)
    • 智能体 (4)
    • 深度学习 (14)
  • 储能 (44)
  • 前端 (4)
  • 大数据开发 (488)
    • CDH (6)
    • datax (4)
    • doris (30)
    • Elasticsearch (15)
    • Flink (78)
    • flume (7)
    • Hadoop (19)
    • Hbase (23)
    • Hive (40)
    • Impala (2)
    • Java (71)
    • Kafka (10)
    • neo4j (5)
    • shardingsphere (6)
    • solr (5)
    • Spark (99)
    • spring (11)
    • 数据仓库 (9)
    • 数据挖掘 (7)
    • 海豚调度器 (10)
    • 运维 (34)
      • Docker (3)
  • 小游戏代码 (1)
  • 小程序代码 (139)
    • O2O (16)
    • UI控件 (5)
    • 互联网类 (23)
    • 企业类 (6)
    • 地图定位 (9)
    • 多媒体 (6)
    • 工具类 (25)
    • 电商类 (22)
    • 社交 (7)
    • 行业软件 (7)
    • 资讯读书 (11)
  • 嵌入式 (70)
    • autosar (63)
    • RTOS (1)
    • 总线 (1)
  • 开发博客 (16)
    • Harmony (9)
  • 技术架构 (6)
  • 数据库 (32)
    • mongodb (1)
    • mysql (13)
    • pgsql (2)
    • redis (1)
    • tdengine (4)
  • 未分类 (6)
  • 程序员网赚 (20)
    • 广告联盟 (3)
    • 私域流量 (5)
    • 自媒体 (5)
  • 量化投资 (4)
  • 面试 (14)

功能

  • 登录
  • 文章RSS
  • 评论RSS
  • WordPress.org

All Rights Reserved by Gitweixin.本站收集网友上传代码, 如有侵犯版权,请发邮件联系yiyuyos@gmail.com删除.