Redis源码和java jdk源码中hashcode的不同实现_java hashcode方法能不能作为redis key-程序员宅基地

技术标签: 算法和数据结构  Java  Redis  

一.redis实际上是使用了siphash

这个比较简单,我说的简单是指redis代码比较少不像jdk一样调用C++代码调用栈非常深。

先看这个rehashing.c

主要就是dictKeyHash函数,需要调用dict.h头文件中定义的dictGenHashFunction

#include "redis.h"
#include "dict.h"

void _redisAssert(char *x, char *y, int l) {
    printf("ASSERT: %s %s %d\n",x,y,l);
    exit(1);
}

unsigned int dictKeyHash(const void *keyp) {
    unsigned long key = (unsigned long)keyp;
    key = dictGenHashFunction(&key,sizeof(key));
    key += ~(key << 15);
    key ^=  (key >> 10);
    key +=  (key << 3);
    key ^=  (key >> 6);
    key += ~(key << 11);
    key ^=  (key >> 16);
    return key;
}

int dictKeyCompare(void *privdata, const void *key1, const void *key2) {
    unsigned long k1 = (unsigned long)key1;
    unsigned long k2 = (unsigned long)key2;
    return k1 == k2;
}

dictType dictTypeTest = {
    dictKeyHash,                   /* hash function */
    NULL,                          /* key dup */
    NULL,                          /* val dup */
    dictKeyCompare,                /* key compare */
    NULL,                          /* key destructor */
    NULL                           /* val destructor */
};

dict.h

uint64_t dictGenHashFunction(const void *key, int len);
uint64_t dictGenCaseHashFunction(const unsigned char *buf, int len);
void dictEmpty(dict *d, void(callback)(void*));
void dictEnableResize(void);
void dictDisableResize(void);
int dictRehash(dict *d, int n);
int dictRehashMilliseconds(dict *d, int ms);
void dictSetHashFunctionSeed(uint8_t *seed);
uint8_t *dictGetHashFunctionSeed(void);
unsigned long dictScan(dict *d, unsigned long v, dictScanFunction *fn, dictScanBucketFunction *bucketfn, void *privdata);
uint64_t dictGetHash(dict *d, const void *key);
dictEntry **dictFindEntryRefByPtrAndHash(dict *d, const void *oldptr, uint64_t hash);

代码实现是在dict.c

注释已经说明了是实现在siphash.c

/* The default hashing function uses SipHash implementation
 * in siphash.c. */

uint64_t siphash(const uint8_t *in, const size_t inlen, const uint8_t *k);
uint64_t siphash_nocase(const uint8_t *in, const size_t inlen, const uint8_t *k);

uint64_t dictGenHashFunction(const void *key, int len) {
    return siphash(key,len,dict_hash_function_seed);
}

uint64_t dictGenCaseHashFunction(const unsigned char *buf, int len) {
    return siphash_nocase(buf,len,dict_hash_function_seed);
}

其实这个siphash.c是第三方实现的github上有源码,这里只应用作者的说明就行了: 

/*
   SipHash reference C implementation

   Copyright (c) 2012-2016 Jean-Philippe Aumasson
   <[email protected]>
   Copyright (c) 2012-2014 Daniel J. Bernstein <[email protected]>
   Copyright (c) 2017 Salvatore Sanfilippo <[email protected]>

   To the extent possible under law, the author(s) have dedicated all copyright
   and related and neighboring rights to this software to the public domain
   worldwide. This software is distributed without any warranty.

   You should have received a copy of the CC0 Public Domain Dedication along
   with this software. If not, see
   <http://creativecommons.org/publicdomain/zero/1.0/>.

   ----------------------------------------------------------------------------

   This version was modified by Salvatore Sanfilippo <[email protected]>
   in the following ways:

   1. We use SipHash 1-2. This is not believed to be as strong as the
      suggested 2-4 variant, but AFAIK there are not trivial attacks
      against this reduced-rounds version, and it runs at the same speed
      as Murmurhash2 that we used previously, why the 2-4 variant slowed
      down Redis by a 4% figure more or less.
   2. Hard-code rounds in the hope the compiler can optimize it more
      in this raw from. Anyway we always want the standard 2-4 variant.
   3. Modify the prototype and implementation so that the function directly
      returns an uint64_t value, the hash itself, instead of receiving an
      output buffer. This also means that the output size is set to 8 bytes
      and the 16 bytes output code handling was removed.
   4. Provide a case insensitive variant to be used when hashing strings that
      must be considered identical by the hash table regardless of the case.
      If we don't have directly a case insensitive hash function, we need to
      perform a text transformation in some temporary buffer, which is costly.
   5. Remove debugging code.
   6. Modified the original test.c file to be a stand-alone function testing
      the function in the new form (returing an uint64_t) using just the
      relevant test vector.
 */

作者官网:https://131002.net/siphash/

源代码:https://github.com/veorq/SipHash

SipHash:快速短输入PRF

下载  |  攻击  |  用户  |  CRYPTANALYSIS  |  第三方实施

SipHash是一系列伪随机函数(也称为键控散列函数),针对短消息的速度进行了优化。 

目标应用程序包括网络流量身份验证和 防止散列泛滥 DoS攻击。 

SipHash 安全,快速,简单(真实):

  • SipHash比以前的加密算法更简单,更快(例如基于通用哈希的MAC)
  • SipHash在性能上与不安全的 非加密算法竞争(例如MurmurHash)

我们建议哈希表切换到SipHash作为哈希函数。 SipHash的用户已经包括FreeBSD,OpenDNS,Perl 5,Ruby或Rust。 

原始SipHash返回64位字符串。随后根据用户的需求创建了返回128位字符串的版本。 

知识产权: 我们不了解与SipHash相关的任何专利或专利申请,我们也不打算申请任何专利。SipHash 的参考代码是在CC0许可下发布的,这是一种类似公共领域的许可。 

SipHash的设计者是

联系方式:[email protected]   [email protected]

下载

=============================================================

二.java的实现比较复杂

又要分字符串的hashCode()和object的hashCode()

1.字符串的hashCode()

    /**
     * Returns a hash code for this string. The hash code for a
     * {@code String} object is computed as
     * <blockquote><pre>
     * s[0]*31^(n-1) + s[1]*31^(n-2) + ... + s[n-1]
     * </pre></blockquote>
     * using {@code int} arithmetic, where {@code s[i]} is the
     * <i>i</i>th character of the string, {@code n} is the length of
     * the string, and {@code ^} indicates exponentiation.
     * (The hash value of the empty string is zero.)
     *
     * @return  a hash code value for this object.
     */
    public int hashCode() {
        int h = hash;
        if (h == 0 && value.length > 0) {
            char val[] = value;

            for (int i = 0; i < value.length; i++) {
                h = 31 * h + val[i];
            }
            hash = h;
        }
        return h;
    }

需要注意的是为什么 String hashCode 方法选择数字31作为乘子,可以看看这篇帖子,这个属于数学问题了。

原因就是

第一,31是一个不大不小的质数,是作为 hashCode 乘子的优选质数之一。另外一些相近的质数,比如37、41、43等等,也都是不错的选择。

第二、31可以被 JVM 优化,31 * i = (i << 5) - i

 Stack Overflow 上关于这个问题的讨论,Why does Java's hashCode() in String use 31 as a multiplier?。其中排名第一的答案引用了《Effective Java》中的一段话,这里也引用一下:

选择值31是因为它是奇数素数。 如果它是偶数并且乘法溢出,则信息将丢失,因为乘以2相当于移位。
使用素数的优势不太明显,但它是传统的。 
31的一个很好的特性是乘法可以用移位和减法代替以获得更好的性能:
31 * i ==(i << 5) -  i`。 现代VM自动执行此类优化。

其他解释:

正如 Goodrich 和 Tamassia 指出的那样,如果你对超过 50,000 个英文单词
(由两个不同版本的 Unix 字典合并而成)进行 hash code 运算,
并使用常数 31, 33, 37, 39 和 41 作为乘子,每个常数算出的哈希值冲突数都小于7个,
所以在上面几个常数中,常数 31 被 Java 实现所选用也就不足为奇了。

这个问题到底完结。

------------------------------------

2.jdk1.8 Object的hashCode()

完整的流程:

此图出自:《hotspot中java对象默认hashcode的生成方式 》

先看hashmap算key的hashCode源码

大量使用hash函数

翻译如下:

/ * ----------------静态实用程序-------------- * /
  计算key.hashCode()并将散列(XOR)更高的散列位降低。
因为该Table使用2次幂掩蔽,所以仅在当前掩码之上的位中变化的散列组将始终发生冲突。 (在已知的例子中是一组Float键,在小表中保存连续的整数。)
因此,我们应用一种向下传播较高位的影响的变换。
在速度,效用和比特扩展质量之间存在权衡。 因为许多常见的哈希集合已经合理分布(因此不会受益于传播),并且因为我们使用树来处理容器中的大量冲突,所以我们只是以最简易的方式对一些移位的位进行异或,以减少系统损失, 以及由于Table边界而包含最高位的影响,否则这些位将永远不会用于索引计算。

直接是native的实现了

如何在jvm源码中定位到某个Java本地方法对应的本地方法源码 

比如说java.lang.Object#hashCode(),如何在jvm源码定位它?

从 jdk/src/share/native/java/lang/Object.c 文件里, 你可以找到

    {"hashCode",    "()I",                    (void *)&JVM_IHashCode},
    {"wait",        "(J)V",                   (void *)&JVM_MonitorWait},
    {"notify",      "()V",                    (void *)&JVM_MonitorNotify},
    {"notifyAll",   "()V",                    (void *)&JVM_MonitorNotifyAll},
    {"clone",       "()Ljava/lang/Object;",   (void *)&JVM_Clone},

大致调用链是:

jvm.cpp中定义了JVM_IHashCode()函数, 他又调用ObjectSynchronizer::FastHashCode;

FastHashCode在 synchronizer.cpp, FastHashCode调用get_next_hash()。

真正的计算hashcode的代码在 synchronizer.cpp的get_next_hash()。

jvm.cpp

// java.lang.Object ///


JVM_ENTRY(jint, JVM_IHashCode(JNIEnv* env, jobject handle))
  JVMWrapper("JVM_IHashCode");
  // as implemented in the classic virtual machine; return 0 if object is NULL
  return handle == NULL ? 0 : ObjectSynchronizer::FastHashCode (THREAD, JNIHandles::resolve_non_null(handle)) ;
JVM_END

synchronizer.cpp 

intptr_t ObjectSynchronizer::FastHashCode (Thread * Self, oop obj) {
  if (UseBiasedLocking) {
    // NOTE: many places throughout the JVM do not expect a safepoint
    // to be taken here, in particular most operations on perm gen
    // objects. However, we only ever bias Java instances and all of
    // the call sites of identity_hash that might revoke biases have
    // been checked to make sure they can handle a safepoint. The
    // added check of the bias pattern is to avoid useless calls to
    // thread-local storage.
    if (obj->mark()->has_bias_pattern()) {
      // Box and unbox the raw reference just in case we cause a STW safepoint.
      Handle hobj (Self, obj) ;
      // Relaxing assertion for bug 6320749.
      assert (Universe::verify_in_progress() ||
              !SafepointSynchronize::is_at_safepoint(),
             "biases should not be seen by VM thread here");
      BiasedLocking::revoke_and_rebias(hobj, false, JavaThread::current());
      obj = hobj() ;
      assert(!obj->mark()->has_bias_pattern(), "biases should be revoked by now");
    }
  }

  // hashCode() is a heap mutator ...
  // Relaxing assertion for bug 6320749.
  assert (Universe::verify_in_progress() ||
          !SafepointSynchronize::is_at_safepoint(), "invariant") ;
  assert (Universe::verify_in_progress() ||
          Self->is_Java_thread() , "invariant") ;
  assert (Universe::verify_in_progress() ||
         ((JavaThread *)Self)->thread_state() != _thread_blocked, "invariant") ;

  ObjectMonitor* monitor = NULL;
  markOop temp, test;
  intptr_t hash;
  markOop mark = ReadStableMark (obj);

  // object should remain ineligible for biased locking
  assert (!mark->has_bias_pattern(), "invariant") ;

  if (mark->is_neutral()) {
    hash = mark->hash();              // this is a normal header
    if (hash) {                       // if it has hash, just return it
      return hash;
    }
    hash = get_next_hash(Self, obj);  // allocate a new hash code
    temp = mark->copy_set_hash(hash); // merge the hash code into header
    // use (machine word version) atomic operation to install the hash
    test = (markOop) Atomic::cmpxchg_ptr(temp, obj->mark_addr(), mark);
    if (test == mark) {
      return hash;
    }
    // If atomic operation failed, we must inflate the header
    // into heavy weight monitor. We could add more code here
    // for fast path, but it does not worth the complexity.
  } else if (mark->has_monitor()) {
    monitor = mark->monitor();
    temp = monitor->header();
    assert (temp->is_neutral(), "invariant") ;
    hash = temp->hash();
    if (hash) {
      return hash;
    }
    // Skip to the following code to reduce code size
  } else if (Self->is_lock_owned((address)mark->locker())) {
    temp = mark->displaced_mark_helper(); // this is a lightweight monitor owned
    assert (temp->is_neutral(), "invariant") ;
    hash = temp->hash();              // by current thread, check if the displaced
    if (hash) {                       // header contains hash code
      return hash;
    }
    // WARNING:
    //   The displaced header is strictly immutable.
    // It can NOT be changed in ANY cases. So we have
    // to inflate the header into heavyweight monitor
    // even the current thread owns the lock. The reason
    // is the BasicLock (stack slot) will be asynchronously
    // read by other threads during the inflate() function.
    // Any change to stack may not propagate to other threads
    // correctly.
  }

  // Inflate the monitor to set hash code
  monitor = ObjectSynchronizer::inflate(Self, obj);
  // Load displaced header and check it has hash code
  mark = monitor->header();
  assert (mark->is_neutral(), "invariant") ;
  hash = mark->hash();
  if (hash == 0) {
    hash = get_next_hash(Self, obj);
    temp = mark->copy_set_hash(hash); // merge hash code into header
    assert (temp->is_neutral(), "invariant") ;
    test = (markOop) Atomic::cmpxchg_ptr(temp, monitor, mark);
    if (test != mark) {
      // The only update to the header in the monitor (outside GC)
      // is install the hash code. If someone add new usage of
      // displaced header, please update this code
      hash = test->hash();
      assert (test->is_neutral(), "invariant") ;
      assert (hash != 0, "Trivial unexpected object/monitor header usage.");
    }
  }
  // We finally get the hash
  return hash;
}
// hashCode() generation :
//
// Possibilities:
// * MD5Digest of {obj,stwRandom}
// * CRC32 of {obj,stwRandom} or any linear-feedback shift register function.
// * A DES- or AES-style SBox[] mechanism
// * One of the Phi-based schemes, such as:
//   2654435761 = 2^32 * Phi (golden ratio)
//   HashCodeValue = ((uintptr_t(obj) >> 3) * 2654435761) ^ GVars.stwRandom ;
// * A variation of Marsaglia's shift-xor RNG scheme.
// * (obj ^ stwRandom) is appealing, but can result
//   in undesirable regularity in the hashCode values of adjacent objects
//   (objects allocated back-to-back, in particular).  This could potentially
//   result in hashtable collisions and reduced hashtable efficiency.
//   There are simple ways to "diffuse" the middle address bits over the
//   generated hashCode values:
//

static inline intptr_t get_next_hash(Thread * Self, oop obj) {
  intptr_t value = 0 ;
  if (hashCode == 0) {
     // This form uses an unguarded global Park-Miller RNG,
     // so it's possible for two threads to race and generate the same RNG.
     // On MP system we'll have lots of RW access to a global, so the
     // mechanism induces lots of coherency traffic.
     value = os::random() ;
  } else
  if (hashCode == 1) {
     // This variation has the property of being stable (idempotent)
     // between STW operations.  This can be useful in some of the 1-0
     // synchronization schemes.
     intptr_t addrBits = cast_from_oop<intptr_t>(obj) >> 3 ;
     value = addrBits ^ (addrBits >> 5) ^ GVars.stwRandom ;
  } else
  if (hashCode == 2) {
     value = 1 ;            // for sensitivity testing
  } else
  if (hashCode == 3) {
     value = ++GVars.hcSequence ;
  } else
  if (hashCode == 4) {
     value = cast_from_oop<intptr_t>(obj) ;
  } else {
     // Marsaglia's xor-shift scheme with thread-specific state
     // This is probably the best overall implementation -- we'll
     // likely make this the default in future releases.
     unsigned t = Self->_hashStateX ;
     t ^= (t << 11) ;
     Self->_hashStateX = Self->_hashStateY ;
     Self->_hashStateY = Self->_hashStateZ ;
     Self->_hashStateZ = Self->_hashStateW ;
     unsigned v = Self->_hashStateW ;
     v = (v ^ (v >> 19)) ^ (t ^ (t >> 8)) ;
     Self->_hashStateW = v ;
     value = v ;
  }

  value &= markOopDesc::hash_mask;
  if (value == 0) value = 0xBAD ;
  assert (value != markOopDesc::no_hash, "invariant") ;
  TEVENT (hashCode: GENERATE) ;
  return value;
}

翻译下:

hashCode()生成:

 可能性:
  * {obj,stwRandom}的MD5Digest
  * {obj,stwRandom}的CRC32或任何线性反馈移位寄存器功能。
  * DES或AES风格的SBox []机制
  *基于Phi的方案之一,例如:
    
2654435761 = 2^32 * Phi (golden ratio)
    HashCodeValue =((uintptr_t(obj)>> 3)* 2654435761)^ GVars.stwRandom;
  * Marsaglia的shift-xor RNG方案的变体。
*(obj ^ stwRandom)很有吸引力,但可能导致相邻对象(特别是背靠背分配的对象)的hashCode值出现不合需要的规律性。 这可能会导致哈希表冲突并降低哈希表效率。
有一些简单的方法可以在生成的hashCode值上“扩散”中间地址位。

该函数提供了基于某个hashCode 变量值的六种方法。怎么生成最终值取决于hashCode这个变量值。

0 - 使用Park-Miller伪随机数生成器(跟地址无关)
1 - 使用地址与一个随机数做异或(地址是输入因素的一部分)
2 - 总是返回常量1作为所有对象的identity hash code(跟地址无关)
3 - 使用全局的递增数列(跟地址无关)
4 - 使用对象地址的“当前”地址来作为它的identity hash code(就是当前地址)
5 - 使用线程局部状态来实现Marsaglia's xor-shift随机数生成(跟地址无关)

Xorshift随机数生成器是George Marsaglia发现的一类伪随机数生成器: 

VM到底用的是哪种方法?

JDK 8 和 JDK 9 默认值:


JDK 8 以前默认值:是传0

虽然方式不一样,但有个共同点:java生成的hashCode和对象内存地址没什么关系。
HotSpot提供了一个VM参数来让用户选择identity hash code的生成方式:

#-XX:hashCode

参考:https://zhuanlan.zhihu.com/p/28270828

    public static void main(String[] args) {
        int[] arr0 = new int[3];
        int[] arr1 = new int[3];
        //arr0.hashCode(); // 触发arr0计算identity hash code
        //arr1.hashCode(); // 触发arr1计算identity hash code
        System.out.println(arr0);
        System.out.println(arr1);
    }

实验:

交互arr0和1

两次输出一样的地址,加上hashCode()就和顺序有关了:

原因是:

对象的hashcode并不是在创建对象时就计算好的,而是在第一次使用的时候,也就是首次调用hashCode方法时进行计算,并存储在对象的标记字中的。 

在VM里,Java对象会在首次真正使用到它的identity hash code(例如通过Object.hashCode() / System.identityHashCode())时调用VM里的函数来计算出值,然后会保存在对象里,后面对同一对象查询其identity hash code时总是会返回最初记录的值。
不是在对象创建时计算的。

这组实现代码在HotSpot VM里自从JDK6的早期开发版开始就没变过,只是hashCode选项的默认值变了而已。

上面的程序在执行到这个 hashCode() 调用时,VM看到对象之前还没计算 identity hash code,才去计算并记录它。

这样的话,先 println(arr1) 就会使得 arr0 所引用的数组对象先被计算 identity hash code,在VM上就是从伪随机数列中取出某一项,然后再 println(arr2) 就会计算并记录 arr2 所引用的数组对象的 hash code,也就是取出那个伪随机数列的下一项。反之亦然。

所以无论先 println(arr1) 还是先 println(arr2) ,看到的都是 VM用来实现 identity hash code 的伪随机数列的某个位置的相邻两项,自然怎么交换都会看到一样的结果。

而如果不调用hash code自然就会触发identity hash code,所以交换顺序就没用...

这篇帖子也写得很好可以看看,作者对jvm是有一些深入的研究的:《How does the default hashCode() work?

--------------

Java Challengers #4: Comparing Java objects with equals() and hashcode()

Java Challengers #2: String comparisons How String methods, keywords, and operators process comparisons in the String pool

先看源码

Object.java的equals:

    public boolean equals(Object obj) {
        return (this == obj);
    }

String.java中的equals:

使用String类的Equals方法

equals()方法用于验证两个Java类的状态是否相同。因为equals()来自Object类,所以每个Java类都继承它。但equals()必须重写该方法才能使其正常工作。当然,String覆盖equals()

关于字符串要记住什么

  • Strings是不可变的,所以String不能改变状态。
  • 为了节省内存,JVM将Strings 保留在常量池中。String创建new时,JVM会检查其值并将其指向现有对象。如果常量池中没有该值,则JVM会创建一个新值String
  • 使用==运算符比较对象引用。使用该equals()方法比较的值String。相同的规则将应用于所有对象。
  • 使用new运算符时,即使存在具有相同值的值,String也会在String池中创建新的运算符String

-------------------------

下面都是Object的equals

equals()和hashcode()的常见错误

  • 忘记hashcode()equals()方法一起覆盖,反之亦然
  • 不覆盖equals()hashcode()使用哈希集合时HashSet
  • 返回方法中的常量值,hashcode()而不是返回每个对象的唯一代码。
  • 使用==equals互换。的==比较Object参考,而equals()比较对象值。

关于equals()和hashcode()要记住什么

  • POJO中始终覆盖equals()hashcode()方法是一种很好的做法。
  • 使用有效算法生成唯一的哈希码。
  • 覆盖equals()方法时,也始终覆盖该hashcode()方法。
  • equals()方法应该比较整个对象的状态:来自字段的值。
  • hashcode()方法可以是POJO的ID。
  • 当比较两个对象的哈希码的结果为假时,该equals()方法也应该为假。
  • 如果equals()hashcode()使用哈希集合时没有被重载,集合会有重复的元素。

使用equals()和hashcode()的准则

您应该只equals()为具有相同唯一哈希码ID的对象执行方法。当哈希码ID 同时,不应执行equals()

表1.哈希码比较

如果hashcode()比较...... 然后 …
返回true 执行 equals()
返回false 不要执行 equals()

出于性能原因,该原则主要用于SetHash收集。

对象比较规则

hashcode()比较返回false,该equals()方法也必须返回false。如果哈希码不同,则对象肯定不相等。

表2.与hashcode()的对象比较

当哈希码比较返回时...... equals()方法应该返回...
真正 对或错

equals()方法返回true,这意味着该对象相等的所有的值和属性。在这种情况下,哈希码比较也必须为真。

表3.与equals()的对象比较

equals()方法返回时...... hashcode()方法应该返回...
真正 真正
对或错

总结:

==永远是比较地址;

new出来的两个对象地址自然也是不相等的;

equals默认比较地址也就是和==等效,如果是字符串是比较内容而不是地址。

如果重写了equals需要同步重写 hashCode()

 

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/21aspnet/article/details/88749056

智能推荐

【转】[VHDL+Verilog]良好的代码编写风格(二十五条)-程序员宅基地

文章浏览阅读60次。转自http://www.cnblogs.com/crazybingo/archive/2010/05/14/1735347.html良好代码编写风格可以满足信、达、雅的要求。在满足功能和性能目标的前提下,增强代码的可读性、可移植性,首要的工作是在项目开发之前为整个设计团队建立一个命名约定和缩略语清单,以文档的形式记录下来,并要求每位设计人员在代码编写过程中都要严格遵守。良好代码编写风格的..._vhdl代码转verilog代码经验总结

docker 安装kvm管理Webvirtmgr_webvirtmgr docker-程序员宅基地

文章浏览阅读2.7k次。Webvirtmgr docker实战下载docker镜像和必要的配置docker pull primiano/docker-webvirtmgrmkdir -p /data/vmgroupadd -g 1010 webvirtmgruseradd -u 1010 -g webvirtmgr -s /sbin/nologin -d /data/vm webvirtmgrchown -R..._webvirtmgr docker

Access to XMLHttpRequest at ‘http://localhost:8080/VXApplets/UserInfoService/login‘ from origin ‘htt_access to xmlhttprequest at 'http://localhost:8080-程序员宅基地

文章浏览阅读1k次。报错信息Access to XMLHttpRequest at 'http://localhost:8080/VXApplets/UserInfoService/login' from origin 'http://localhost:8082' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' _access to xmlhttprequest at 'http://localhost:8080/login' from origin 'http:

DevC++出现[Error] ld returned 1 exit status解决_devb++输出错误-程序员宅基地

文章浏览阅读3.7w次,点赞10次,收藏5次。打代码遇到这种情况。。。然后编译不正常运行是正常的试了几次 找到俩个可能解决的方案1.是你的程序已经在运行,关闭原来的程序就可以正常了2.你机器上有杀毒(安全)软件阻止了你程序的生成,退出杀毒(安全)软件再试下。_devb++输出错误

开发者分享 | AXI 基础第 3 讲-使用 AXI VIP 作为 AXI4 主 (Master) 接口的协议检查工具...-程序员宅基地

文章浏览阅读1.2k次。点击“蓝字”关注我们在AXI 基础第 2 讲一文中,曾提到赛灵思 Verification IP (AXI VIP) 可用作为 AXI 协议检查工具。在本次第4讲中,我们将来了解下如何使用它在 AXI4 (Full) 主接口中执行验证(和查找错误)。1. 下载设计文件(请输入以下网址进行下载https://forums.xilinx.com/xlnx/attachm..._axi_vip_pkg文件在哪里

深度学习-TF、keras两种padding方式:vaild和sam_sam深度学习百度百科-程序员宅基地

文章浏览阅读3.7k次,点赞6次,收藏6次。前言在使用Keras的时候会遇到这样的代码x = Conv2D(filters, kernel_size=5, strides=2, padding=‘same’)(x),与pytorch不同,keras和TensorFlow设置卷积层的过程中可以设置padding参数,vaild和same。“valid”代表只进行有效的卷积,对边界数据不处理。“same”代表保留边界处的卷积结果,通常会导致输..._sam深度学习百度百科

随便推点

OpenLdap 使用上的记录-程序员宅基地

文章浏览阅读839次。OpenLdap ,添加索引后会导致被添加的索引的属性作为查询条件无法找出老的数据,这时可以通过重建索引来解决问题。命令为: slapindex -f slap.conf LDAPObject 的异步执行接口

js 递归数组_js数组递归-程序员宅基地

文章浏览阅读1.6k次。//json对象const json = { code: 200, data: [ { children: [ { id: 85, path: [0, 1, 85], pid: 1 }, { id: 86, path: [0, 1, 86], pid: 1 }, { id: 87, path: [0, 1, 87], pid: 1 }, { id: 153, path: [0, 1, 153], pid: 1 },_js数组递归

JAVA毕业设计飞羽羽毛球馆管理系统计算机源码+lw文档+系统+调试部署+数据库-程序员宅基地

文章浏览阅读191次。JAVA毕业设计飞羽羽毛球馆管理系统计算机源码+lw文档+系统+调试部署+数据库。springboot基于Springboot技术的装潢公司网站开发。springboot基于springboot的音乐网站管理系统。jsp基于JavaEE技术的“日进斗金”理财大师系统设计与实现。springboot晨曦文学社在线投稿系统的设计与实现。jsp基于JavaWeb的社区商超系统的设计与实现。ssm基于JAVA的求职招聘网站的设计与实现。springboot衣橱系统的设计与实现。

利用attrs.xml和 styles.xml定义Preference-程序员宅基地

文章浏览阅读1k次。1.attrs.xml/android/frameworks/base/core/res/res/values/attrs.xmlattrs.xml文件为View/ViewGroup定义了所有可用的属性。它的根元素是,它包含了俩个子元素:a.attr子元素:定义的属性。b.declare-styleable子元素:定义一个styleabl

时间戳-程序员宅基地

文章浏览阅读946次,点赞2次,收藏2次。时间戳时间戳是个什么东西?时间戳是一个自增的整数,它表示从1970年1月1日零时整的GMT时区开始的那一刻,到现在的毫秒数。假设浏览器所在电脑的时间是准确的,那么世界上无论哪个时区的电脑,它们此刻产生的时间戳数字都是一样的,所以,时间戳可以精确地表示一个时刻,并且与时区无关。所以,我们只需要传递时间戳,或者把时间戳从数据库里读出来,再让JavaScript自动转换为当地时间就可以了。要获取当...

(PTA)数据结构(作业)11、树和图_权重为3的叶结点的哈夫曼编码为a已知下图所示的一个图,若从顶点v1出发,按深度请选-程序员宅基地

文章浏览阅读3k次。作业而已,仅供参考,欢迎指正_权重为3的叶结点的哈夫曼编码为a已知下图所示的一个图,若从顶点v1出发,按深度请选