【问题标题】:How to Compare between String object and literal using hex values如何使用十六进制值比较字符串对象和文字
【发布时间】:2018-09-26 10:35:18
【问题描述】:

下面的代码使用NTLM Windows身份验证方法从系统获取用户名,我需要比较用户名(current_user_eid)。

对预设值应用 intern() 方法似乎适用于初始化值。

文字字符串和对象字符串之间的字符串比较给了我 false 作为输出,但在屏幕上它们给出了相同的输出。

<%@ page import="sun.misc.BASE64Encoder" %>
<%
String auth = request.getHeader("Authorization");
String current_user_eid= null;
if (auth == null) {
        response.setStatus(response.SC_UNAUTHORIZED);
        response.setHeader("WWW-Authenticate", "NTLM");
        return;
}
if (auth.startsWith("NTLM")) { 
    byte[] msg = new sun.misc.BASE64Decoder().decodeBuffer(auth.substring(5));
    int off = 0, length, offset;

    if (msg[8] == 1) { 
        off = 18;
        byte z = 0;
        byte[] msg1 =
            {(byte)'N', (byte)'T', (byte)'L', (byte)'M', (byte)'S',
            (byte)'S', (byte)'P', z,
            (byte)2, z, z, z, z, z, z, z,
            (byte)40, z, z, z, (byte)1, (byte)130, z, z,
            z, (byte)2, (byte)2, (byte)2, z, z, z, z, // 
            z, z, z, z, z, z, z, z};

        response.setStatus(response.SC_UNAUTHORIZED);
        response.setHeader("WWW-Authenticate", "NTLM " + new sun.misc.BASE64Encoder().encodeBuffer(msg1).trim());
        return;
    } 
    else if (msg[8] == 3) { 
        off = 30;
        length = msg[off+17]*256 + msg[off+16];
        offset = msg[off+19]*256 + msg[off+18];
        current_user_eid = new String(msg, offset, length);
    } 
    else
        return;

    length = msg[off+1]*256 + msg[off];
    offset = msg[off+3]*256 + msg[off+2];
    current_user_eid = new String(msg, offset, length);
    length = msg[off+9]*256 + msg[off+8];
    offset = msg[off+11]*256 + msg[off+10];
    current_user_eid = new String(msg, offset, length); //current system user name "yaseer"

    // String Comparison starts here....

    String hard_str = new String("yaseer"); // 
    String hard_str_in=hard_str.intern();

    String eid_str=new String(current_user_eid.toString()); //passing the fetched username which is yaseer
    String eid_str_in = eid_str.intern(); // system username 

    String comp_str = "yaseer"; // String for comparison

    System.out.println(hard_str_in == comp_str); // give true

    System.out.println(eid_str_in == comp_str); // gives false


if(eid_str_in .equals(comp_str ))
{
    System.out.println("true");
}
else
{
    System.out.println("false");
}
}
%>

谁能帮我解决这个问题?

【问题讨论】:

    标签: java jsp ntlm


    【解决方案1】:

    String 的正确用法是:

    Charset charset = StandardCharsets.ISO_8859_1;
    ...
        current_user_eid = new String(msg, offset, length, charset);
    } 
    else
        return;
    
    length = msg[off+1]*256 + msg[off];
    offset = msg[off+3]*256 + msg[off+2];
    current_user_eid = new String(msg, offset, length, charset);
    length = msg[off+9]*256 + msg[off+8];
    offset = msg[off+11]*256 + msg[off+10];
    current_user_eid = new String(msg, offset, length, charset);
    //current system user name "yaseer"
    
    // String Comparison starts here....
    
    String hard_str = "yaseer"; // 
    
    String eid_str = current_user_eid; //passing the fetched username which is yaseer
    String eid_str_in = eid_str.intern(); // system username 
    
    String comp_str = "yaseer"; // String for comparison
    
    System.out.println(hard_str_in == comp_str); // give true
    
    System.out.println(eid_str_in == comp_str); // gives false
    System.out.println(eid_str_in.equals(comp_str));
    // gave true ("on screen"), expected to give false
    

    如果我理解正确,最后两行会给出不同的结果。

    对于纯 ASCII “yaseer”来说不应该是这样(假设您没有在带有错误 java 源代码/java 编译器编码的 EBCDIC 的 AS/400 上工作)。

    但是我看到current_user_eid 被分配了两次,第一次分配了 6 个字节,这可能对应于 6 个字母的“yaseer”。

    所以我认为第二个current_user_eid 是一个混淆。

    为它的值转储一个字符串:

    System.out.println(Arrays.toString(eid_str_in.toCharArray()));
    

    对于其余部分:.intern() 不再可以使用 w.r.t。效率;因此也不是==。在较早的版本中,如果过多且过于频繁地被实习,实习常量会进入大小有限的“永久内存生成”,这有其缺点。

    字节始终转换为 Unicode Stringchars (UTF-16),可能使用平台默认字符集。所以最好明确提供Charset,甚至Charset.defaultCharset(),因为它明确说明了平台依赖关系。

    【讨论】:

    • 如果长度为12,那么它可能是UTF-16LE。一个人根本无法说出任何明智的事情;记录/调试。
    • OP 在对我的评论的最后回复中说返回的字符串嵌入了 nul 字符。这意味着它被编码为 UTF16LE(在 Windows 上很常见)而不是 ISO 8859-1。
    • @DodgyCodeException 感谢您的确认,我不确定,但我认为是这样。 StandardCharsets.UTF_16LE 然后作为字符集。
    • @DodgyCodeException 和“Joop”你们拯救了我的日子。感谢它现在的工作...与StandardCharsets.UTF_16LE 谢谢
    【解决方案2】:

    1) 字符串字面量将存储在字符串常量池中。这里的值不能重复。例如,如果您尝试创建具有相同值的两个变量,则第二个变量值不能存储在 SCP 中,而是会获取第一个值地址。

    2) 但是使用 new String 会创建两个对象,即使两个对象具有相同的值。

    例子:

    public class TestFile {
    
        public static void main(String[] args) {
            String name1 = "AAA";
            String name2 = name1.intern();
    
            String name3 = new String("AAA");
            String name4 = name3.intern();
    
            System.out.println(name1 == name2); // true
            System.out.println(name2 == name4); // true
    
            System.out.println(name3 == name4); // false
            System.out.println(name3.equals(name4));
        }   
    }
    

    1) H name1 和 name2 都是文字。所以比较是真的。

    2) name3 是对象,但我们使用的是 intern(),因此将获取对象的值,这些值将作为文字存储在 name4 中。所以比较是真实的。

    3) 但是name3 和name4 的comaprsion 将为False。因为 name3 是对象,而 name4 是文字。但如果您使用的是 .equals(),这将是正确的。

    【讨论】:

    • 您的陈述都是真实的,但它们并不代表 OP 所询问的问题。也就是说,他正在比较两个 interned 字符串(就像 name2 == name4),他希望它们是相等的(因为它们在屏幕上出现相同),但是实际上并不相等。
    • 你是对的@DodgyCodeException 我觉得 current_user_eid 变量中的字符串值对于使用“new String(msg, offset, length)”有一些问题?其中 msg 以字节为单位。正如预期的那样(“yaseer”.equals(current_user_eid))条件在使用或不使用intern()的情况下给出错误。它们在 S.O.P 中完全相同的地方:(
    猜你喜欢
    • 1970-01-01
    • 2019-07-27
    • 1970-01-01
    • 2013-05-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多