【问题标题】:Understanding Piece of Java code理解一段 Java 代码
【发布时间】:2014-10-08 16:42:55
【问题描述】:

在使用一些代码库时,我试图理解一段代码以便可以工作和自定义它,我能够理解几乎 90% 的代码流。这是整体流程

  1. 代码用于生成 15 位代码(字母数字),前 3 位是客户提供的。
  2. 最初代码生成 16 位字母数字并将其存储在缓存中。
  3. 客户可以通过指定数量生成任意数量的代码。
  4. 所有客户生成的代码都是从 16 位数字生成的(第 2 点)。生成的所有代码都包含来自该 16 位字母数字的数字/字母。
  5. 当有人尝试使用这些代码时,系统会尝试验证提供的代码是否有效。

我对用于确定提供的代码是否有效的逻辑感到震惊,这是那段代码,我正在生成 6 个代码作为示例,在这种情况下,生成并存储在缓存中的字母数字代码是

 initial-alphabet : M9W6K3TENDGSFAL4

基于initial-alphabet生成的代码是 myList=[123-MK93-ES6D-36F3, 123-MK93-EFTW-D3LG, 123-MK93-EALK-TGLD, 123-MK93-ELKK-DN6S, 123-MK93-E4D9-3A6T, 123-MK93-EMTW-LNME]

 protected  int getVoucherNumber(String voucherCode){
  int voucherNumberPos = voucherCode.length() - 12;
  String voucherNumberHex = voucherCode.substring(voucherNumberPos, voucherNumberPos + 6);
  int firstByte = getIntFromHexByte(voucherNumberHex.substring(0, 2), 0);
  int secondByte = getIntFromHexByte(voucherNumberHex.substring(2, 4), 1);
  int thirdByte = getIntFromHexByte(voucherNumberHex.substring(4, 6), 7);
  return firstByte << 16 | secondByte << 8 | thirdByte;
}

private int getIntFromHexByte(String value, int offset){
  return (getIntFromHexNibble(value.charAt(0), offset) << 4) + getIntFromHexNibble(value.charAt(1), offset + 4);
} 

private int getIntFromHexNibble(char value, int offset){
  int pos = getAlphabet().indexOf(value);
  if (pos == -1) {// nothing found}
    pos -= offset;
  while (pos < 0) {
    pos += 16;
  }
    return pos % 16;
 }

这是试图验证代码的代码

 int voucherNumber = getVoucherNumber(kyList.get(4));

在这种情况下voucherNumber 的值是4 即列表中的第四个元素,以防我传递任何不属于列表的值getVoucherNumber 方法返回一个更高的值(大于列表计数)。

让我困惑的主要事情之一是这两行

int voucherNumberPos = voucherCode.length() - 12;
String voucherNumberHex = voucherCode.substring(voucherNumberPos, voucherNumberPos + 6);

据我了解,他们首先从客户提供的支票中移出前 3 位数字,但他们再次没有使用字符串的其余部分,而只使用了字符串的特定部分。

谁能帮我理解这个

【问题讨论】:

  • 为什么标记为java8?此代码示例中是否有关于 Java 8 的特定内容?我没有看到它,但也许我错过了它......
  • @FrustratedWithFormsDesigner:与java-8无关,我标记错了,谢谢指正

标签: java logic


【解决方案1】:

您似乎继承了一些编写不佳的代码的责任。我们都去过那里,所以我会尝试本着这种精神来回答。我不肯定这个问题是这个网站的主题,但帮助中心似乎没有禁止它。为了保持主题不变,我将提出一些一般性建议,不限于问题的高度本地化细节。

myList.get(4)

Java 中的数组是从零开始的,因此是 123-MK93-E4D9-3A6T。您可能知道这一点,但您的问题并不清楚您是否知道。

initial-alphabet : M9W6K3TENDGSFAL4

我假设这是在getIntFromHexNibble 中调用getAlphabet 返回的内容。因此,代码中的字母数字字符是十六进制的,但使用了一组非标准的 16 个字符作为数字。

protected  int getVoucherNumber(String voucherCode){

忽略连字符和客户提供的前三位数字,代码为“MK93E4D93A6T”。十二个十六进制数字编码为 48 位,但 Java 中的 int 只有 32 位长,所以代码已经被破坏了。不管它做什么,它都不会返回优惠券代码所代表的优惠券号。

int voucherNumberPos = voucherCode.length() - 12;
String voucherNumberHex = voucherCode.substring(voucherNumberPos, voucherNumberPos + 6);

这是将凭证NumberHex 设置为一个六字符长的字符串,从voucherCode 的末尾开始十二个字符,在本例中为93-E4D。在第一次编写此代码时,作者似乎没有预料到调用者会包含连字符。即便如此,其意图似乎是忽略了一半的优惠券代码。

int firstByte = getIntFromHexByte(voucherNumberHex.substring(0, 2), 0);
int secondByte = getIntFromHexByte(voucherNumberHex.substring(2, 4), 1);
int thirdByte = getIntFromHexByte(voucherNumberHex.substring(4, 6), 7);

起初看起来很简单,但参数017 根本不是偏移量,尽管参数的名称如此。它试图将每对十六进制数字转换为一个字节,如果不是连字符,这将是足够明智的。现在是有趣的部分:

private int getIntFromHexNibble(char value, int offset) {
    int pos = getAlphabet().indexOf(value);
    if (pos == -1) {// nothing found}
        pos -= offset;

        while (pos < 0) {
            pos += 16;
        }
        return pos % 16;
    }

“found”后面的右大括号被注释掉了,所以你贴的代码其实是不完整的。我会假设还有一两行写着

    return pos;
}

所以基本思想是 M 变为 0,9 变为 1,依此类推,通过调用 indexOf。但是如果这个方法看到一个不在提供的字母表中的字符,比如一个连字符,它会使用所谓的offset 来计算一个默认值(在这种情况下是 14,如果我已经在我的脑海中完成了数学计算),并将其作为十六进制半字节值返回。

最终结果是您返回一个 0(含)到 2^24(不含)范围内的数字。但是在这样一个数字应该有的 2^24 个可能的值中,只有 2^20 个不同的值会被返回。因此,从看起来像 12 位 base-32 的优惠券代码(其值将是天文数字)来看,每个客户前缀中的不同优惠券编号仅限于略超过一百万。

一般建议:

  • 使用同行评审来防止这样的代码进入 生产。
  • 使用单元测试来证明代码做了什么功能 名字说它确实。
  • 如果输入不正确,请使用异常提前失败 你所期待的。

【讨论】:

  • 同行评议只有在没有演变成肚脐检查时才有用,随着时间的推移,他们会变成这样,几乎无一例外。 IMO 配对更好——与大多数同行评审相比,它在“磨砺斧头”和“完成工作”之间取得了更好的平衡。一个大脑可以解决一个问题,两个可以很好地解决问题,三个只是稍微好一点,当你使用四个大脑时,你基本上只是在浪费金钱和时间。
  • @JoeRounceville 我同意让一两个以上的人审查一段给定的代码往往是徒劳的。我的组织这样做只是为了知识转移或演示原型方法。我们所做的同行评审是指每个人的代码由他们的一两个同行评审。
  • @gatkin:感谢您的精彩回复,不幸的是我无法更改此代码:(。if (pos == -1) {},这里返回了一个异常。我很困惑的是凭证代码的部分是用于验证,因为该代码没有获取完整的凭证代码,而只是其中的特定部分。您认为这背后有什么逻辑吗?
  • @UmeshAwasthi 显然,我的回答不会说明您的问题中没有的 Java 代码。您包含的所有代码都没有进行任何验证;它只是在较大的字符串中提取编码(以复杂的方式)的数字。如果我设计了它(不知道您的任何要求),则凭证代码将以 32 为基数,而不是伪装的十六进制,其中一些位是凭证号,其余的是 HMAC,以验证凭证号的真实性。 (我假设它具有经济价值,所以你不希望人们自己编造。)
猜你喜欢
  • 2018-01-27
  • 1970-01-01
  • 2015-08-22
  • 1970-01-01
  • 1970-01-01
  • 2018-02-18
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多