`

应用Hash函数(java描述) .

阅读更多

计算理论中,没有Hash函数的说法,只有单向函数的说法。所谓的单向函数,是一个复杂的定义,大家可以去看计算理论或者密码学方面的数据。用“人类”的语言描述单向函数就是:如果某个函数在给定输入的时候,很容易计算出其结果来;而当给定结果的时候,很难计算出输入来,这就是单项函数。各种加密函数都可以被认为是单向函数的逼近。Hash函数(或者成为散列函数)也可以看成是单向函数的一个逼近。即它接近于满足单向函数的定义。

      Hash函数还有另外的含义。实际中的Hash函数是指把一个大范围映射到一个小范围。把大范围映射到一个小范围的目的往往是为了节省空间,使得数据容易保存。除此以外,Hash函数往往应用于查找上。所以,在考虑使用Hash函数之前,需要明白它的几个限制:

1. Hash的主要原理就是把大范围映射到小范围;所以,你输入的实际值的个数必须和小范围相当或者比它更小。不然冲突就会很多。
2. 由于Hash逼近单向函数;所以,你可以用它来对数据进行加密。
3. 不同的应用对Hash函数有着不同的要求;比如,用于加密的Hash函数主要考虑它和单项函数的差距,而用于查找的Hash函数主要考虑它映射到小范围的冲突率。

应用于加密的Hash函数已经探讨过太多了,在作者的博客里面有更详细的介绍。所以,本文只探讨用于查找的Hash函数。

Hash函数应用的主要对象是数组(比如,字符串),而其目标一般是一个int类型。以下我们都按照这种方式来说明。

一般的说,Hash函数可以简单的划分为如下几类:
1. 加法Hash;
2. 位运算Hash;
3. 乘法Hash;
4. 除法Hash;
5. 查表Hash;
6. 混合Hash;
下面详细的介绍以上各种方式在实际中的运用。

一 加法Hash

所谓的加法Hash就是把输入元素一个一个的加起来构成最后的结果。标准的加法Hash的构造如下:

 

 static int additiveHash(String key, int prime)
 {
  int hash, i;
  for (hash = key.length(), i = 0; i < key.length(); i++)
   hash += key.charAt(i);
  return (hash % prime);
 }

 

这里的prime是任意的质数,看得出,结果的值域为[0,prime-1]。

 

二 位运算Hash

这类型Hash函数通过利用各种位运算(常见的是移位和异或)来充分的混合输入元素。比如,标准的旋转Hash的构造如下:

 static int rotatingHash(String key, int prime)
 {
   int hash, i;
   for (hash=key.length(), i=0; i<key.length(); ++i)
     hash = (hash<<4)^(hash>>28)^key.charAt(i);
   return (hash % prime);
 }

 

先移位,然后再进行各种位运算是这种类型Hash函数的主要特点。比如,以上的那段计算hash的代码还可以有如下几种变形:

1.     hash = (hash<<5)^(hash>>27)^key.charAt(i);
2.     hash += key.charAt(i);
        hash += (hash << 10);
        hash ^= (hash >> 6);
3.     if((i&1) == 0)
        {
         hash ^= (hash<<7) ^ key.charAt(i) ^ (hash>>3);
        }
        else
        {
         hash ^= ~((hash<<11) ^ key.charAt(i) ^ (hash >>5));
        }
4.     hash += (hash<<5) + key.charAt(i);
5.     hash = key.charAt(i) + (hash<<6) + (hash>>16) – hash;
6.     hash ^= ((hash<<5) + key.charAt(i) + (hash>>2));

 

三 乘法Hash

这种类型的Hash函数利用了乘法的不相关性(乘法的这种性质,最有名的莫过于平方取头尾的随机数生成算法,虽然这种算法效果并不好)。比如,

 

 

 static int bernstein(String key)
 {
   int hash = 0;
   int i;
   for (i=0; i<key.length(); ++i) hash = 33*hash + key.charAt(i);
   return hash;
 }

 

jdk5.0里面的String类的hashCode()方法也使用乘法Hash。不过,它使用的乘数是31。推荐的乘数还有:131, 1313, 13131, 131313等等。

使用这种方式的著名Hash函数还有:

 //  32位FNV算法
 int M_SHIFT = 0;
    public int FNVHash(byte[] data)
    {
        int hash = (int)2166136261L;
        for(byte b : data)
            hash = (hash * 16777619) ^ b;
        if (M_SHIFT == 0)
            return hash;
        return (hash ^ (hash >> M_SHIFT)) & M_MASK;
}

 

以及改进的FNV算法:

    public static int FNVHash1(String data)
    {
        final int p = 16777619;
        int hash = (int)2166136261L;
        for(int i=0;i<data.length();i++)
            hash = (hash ^ data.charAt(i)) * p;
        hash += hash << 13;
        hash ^= hash >> 7;
        hash += hash << 3;
        hash ^= hash >> 17;
        hash += hash << 5;
        return hash;
}

 

除了乘以一个固定的数,常见的还有乘以一个不断改变的数,比如:

    static int RSHash(String str)
    {
        int b    = 378551;
        int a    = 63689;
        int hash = 0;

       for(int i = 0; i < str.length(); i++)
       {
          hash = hash * a + str.charAt(i);
          a    = a * b;
       }
       return (hash & 0x7FFFFFFF);
}

 

虽然Adler32算法的应用没有CRC32广泛,不过,它可能是乘法Hash里面最有名的一个了。关于它的介绍,大家可以去看RFC 1950规范。

四 除法Hash

除法和乘法一样,同样具有表面上看起来的不相关性。不过,因为除法太慢,这种方式几乎找不到真正的应用。需要注意的是,我们在前面看到的hash的结果除以一个prime的目的只是为了保证结果的范围。如果你不需要它限制一个范围的话,可以使用如下的代码替代”hash%prime”: hash = hash ^ (hash>>10) ^ (hash>>20)。

五 查表Hash

查表Hash最有名的例子莫过于CRC系列算法。虽然CRC系列算法本身并不是查表,但是,查表是它的一种最快的实现方式。下面是CRC32的实现:

 

static int crctab[256] = {
0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f,  0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988,  0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, 0x1db71064, 0x6ab020f2,  0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7,  0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9,  0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172,  0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, 0x35b5a8fa, 0x42b2986c,  0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59,  0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423,  0xcfba9599, 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924,  0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190, 0x01db7106,  0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433,  0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d,  0x91646c97, 0xe6635c01, 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e,  0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950,  0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65,  0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7,  0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0,  0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa,  0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,  0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81,  0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a,  0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, 0xe3630b12, 0x94643b84,  0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1,  0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb,
  0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc,  0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, 0xd6d6a3e8, 0xa1d1937e,  0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b,  0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55,  0x316e8eef, 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236,  0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe, 0xb2bd0b28,  0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d,  0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f,  0x72076785, 0x05005713, 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38,  0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242,  0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777,  0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69,  0x616bffd3, 0x166ccf45, 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2,  0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc,  0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,  0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693,  0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94,  0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d
};
int crc32(String key, int hash)
{
  int i;
  for (hash=key.length(), i=0; i<key.length(); ++i)
    hash = (hash >> 8) ^ crctab[(hash & 0xff) ^ k.charAt(i)];
  return hash;
}

 

查表Hash中有名的例子有:Universal Hashing和Zobrist Hashing。他们的表格都是随机生成的。

六 混合Hash

混合Hash算法利用了以上各种方式。各种常见的Hash算法,比如MD5、Tiger都属于这个范围。它们一般很少在面向查找的Hash函数里面使用。

七 对Hash算法的评价

http://www.burtleburtle.net/bob/hash/doobs.html 这个页面提供了对几种流行Hash算法的评价。我们对Hash函数的建议如下:

1. 字符串的Hash。最简单可以使用基本的乘法Hash,当乘数为33时,对于英文单词有很好的散列效果(小于6个的小写形式可以保证没有冲突)。复杂一点可以使用FNV算法(及其改进形式),它对于比较长的字符串,在速度和效果上都不错。

2. 长数组的Hash。可以使用http://burtleburtle.net/bob/c/lookup3.c这种算法,它一次运算多个字节,速度还算不错。

八 后记

本文简略的介绍了一番实际应用中的用于查找的Hash算法。Hash算法除了应用于这个方面以外,另外一个著名的应用是巨型字符串匹配(这时的Hash算法叫做:rolling hash,因为它必须可以滚动的计算)。设计一个真正好的Hash算法并不是一件容易的事情。做为应用来说,选择一个适合的算法是最重要的。

常用hash算法类:

 

package lotusroots.algorithms.math;

import java.security.MessageDigest;

/**
 * Hash算法大全<br>
 * 推荐使用FNV1算法
 * 
 * @algorithm None
 * @author Goodzzp 2006-11-20
 * @lastEdit Goodzzp 2006-11-20
 * @editDetail Create
 */
public class HashAlgorithms {
 /**
  * 加法hash
  * 
  * @param key
  *            字符串
  * @param prime
  *            一个质数
  * @return hash结果
  */
 public static int additiveHash(String key, int prime) {
  int hash, i;
  for (hash = key.length(), i = 0; i < key.length(); i++)
   hash += key.charAt(i);
  return (hash % prime);
 }

 /**
  * 旋转hash
  * 
  * @param key
  *            输入字符串
  * @param prime
  *            质数
  * @return hash值
  */
 public static int rotatingHash(String key, int prime) {
  int hash, i;
  for (hash = key.length(), i = 0; i < key.length(); ++i)
   hash = (hash << 4) ^ (hash >> 28) ^ key.charAt(i);
  return (hash % prime);
  // return (hash ^ (hash>>10) ^ (hash>>20));
 }

 // 替代:
 // 使用:hash = (hash ^ (hash>>10) ^ (hash>>20)) & mask;
 // 替代:hash %= prime;

 /**
  * MASK值,随便找一个值,最好是质数
  */
 static int M_MASK = 0x8765fed1;

 /**
  * 一次一个hash
  * 
  * @param key
  *            输入字符串
  * @return 输出hash值
  */
 public static int oneByOneHash(String key) {
  int hash, i;
  for (hash = 0, i = 0; i < key.length(); ++i) {
   hash += key.charAt(i);
   hash += (hash << 10);
   hash ^= (hash >> 6);
  }
  hash += (hash << 3);
  hash ^= (hash >> 11);
  hash += (hash << 15);
  // return (hash & M_MASK);
  return hash;
 }

 /**
  * Bernstein's hash
  * 
  * @param key
  *            输入字节数组
  * @param level
  *            初始hash常量
  * @return 结果hash
  */
 public static int bernstein(String key) {
  int hash = 0;
  int i;
  for (i = 0; i < key.length(); ++i)
   hash = 33 * hash + key.charAt(i);
  return hash;
 }

 //
 // // Pearson's Hash
 // char pearson(char[]key, ub4 len, char tab[256])
 // {
 // char hash;
 // ub4 i;
 // for (hash=len, i=0; i<len; ++i)
 // hash=tab[hash^key[i]];
 // return (hash);
 // }

 // // CRC Hashing,计算crc,具体代码见其他
 // ub4 crc(char *key, ub4 len, ub4 mask, ub4 tab[256])
 // {
 // ub4 hash, i;
 // for (hash=len, i=0; i<len; ++i)
 // hash = (hash >> 8) ^ tab[(hash & 0xff) ^ key[i]];
 // return (hash & mask);
 // }

 /**
  * Universal Hashing
  */
 public static int universal(char[] key, int mask, int[] tab) {
  int hash = key.length, i, len = key.length;
  for (i = 0; i < (len << 3); i += 8) {
   char k = key[i >> 3];
   if ((k & 0x01) == 0)
    hash ^= tab[i + 0];
   if ((k & 0x02) == 0)
    hash ^= tab[i + 1];
   if ((k & 0x04) == 0)
    hash ^= tab[i + 2];
   if ((k & 0x08) == 0)
    hash ^= tab[i + 3];
   if ((k & 0x10) == 0)
    hash ^= tab[i + 4];
   if ((k & 0x20) == 0)
    hash ^= tab[i + 5];
   if ((k & 0x40) == 0)
    hash ^= tab[i + 6];
   if ((k & 0x80) == 0)
    hash ^= tab[i + 7];
  }
  return (hash & mask);
 }

 /**
  * Zobrist Hashing
  */
 public static int zobrist(char[] key, int mask, int[][] tab) {
  int hash, i;
  for (hash = key.length, i = 0; i < key.length; ++i)
   hash ^= tab[i][key[i]];
  return (hash & mask);
 }

 // LOOKUP3
 // 见Bob Jenkins(3).c文件

 // 32位FNV算法
 static int M_SHIFT = 0;

 /**
  * 32位的FNV算法
  * 
  * @param data
  *            数组
  * @return int值
  */
 public static int FNVHash(byte[] data) {
  int hash = (int) 2166136261L;
  for (byte b : data)
   hash = (hash * 16777619) ^ b;
  if (M_SHIFT == 0)
   return hash;
  return (hash ^ (hash >> M_SHIFT)) & M_MASK;
 }

 /**
  * 改进的32位FNV算法1
  * 
  * @param data
  *            数组
  * @return int值
  */
 public static int FNVHash1(byte[] data) {
  final int p = 16777619;
  int hash = (int) 2166136261L;
  for (byte b : data)
   hash = (hash ^ b) * p;
  hash += hash << 13;
  hash ^= hash >> 7;
  hash += hash << 3;
  hash ^= hash >> 17;
  hash += hash << 5;
  return hash;
 }

 /**
  * 改进的32位FNV算法1
  * 
  * @param data
  *            字符串
  * @return int值
  */
 public static int FNVHash1(String data) {
  final int p = 16777619;
  int hash = (int) 2166136261L;
  for (int i = 0; i < data.length(); i++)
   hash = (hash ^ data.charAt(i)) * p;
  hash += hash << 13;
  hash ^= hash >> 7;
  hash += hash << 3;
  hash ^= hash >> 17;
  hash += hash << 5;
  return hash;
 }

 /**
  * Thomas Wang的算法,整数hash
  */
 public static int intHash(int key) {
  key += ~(key << 15);
  key ^= (key >>> 10);
  key += (key << 3);
  key ^= (key >>> 6);
  key += ~(key << 11);
  key ^= (key >>> 16);
  return key;
 }

 /**
  * RS算法hash
  */
 public static int RSHash(String str) {
  int b = 378551;
  int a = 63689;
  int hash = 0;

  for (int i = 0; i < str.length(); i++) {
   hash = hash * a + str.charAt(i);
   a = a * b;
  }

  return (hash & 0x7FFFFFFF);
 }

 /* End Of RS Hash Function */

 /**
  * JS算法
  */
 public static int JSHash(String str) {
  int hash = 1315423911;

  for (int i = 0; i < str.length(); i++) {
   hash ^= ((hash << 5) + str.charAt(i) + (hash >> 2));
  }

  return (hash & 0x7FFFFFFF);
 }

 /* End Of JS Hash Function */

 /**
  * PJW算法
  */
 public static int PJWHash(String str) {
  int BitsInUnsignedInt = 32;
  int ThreeQuarters = (BitsInUnsignedInt * 3) / 4;
  int OneEighth = BitsInUnsignedInt / 8;
  int HighBits = 0xFFFFFFFF << (BitsInUnsignedInt - OneEighth);
  int hash = 0;
  int test = 0;

  for (int i = 0; i < str.length(); i++) {
   hash = (hash << OneEighth) + str.charAt(i);

   if ((test = hash & HighBits) != 0) {
    hash = ((hash ^ (test >> ThreeQuarters)) & (~HighBits));
   }
  }

  return (hash & 0x7FFFFFFF);
 }

 /* End Of P. J. Weinberger Hash Function */

 /**
  * ELF算法
  */
 public static int ELFHash(String str) {
  int hash = 0;
  int x = 0;

  for (int i = 0; i < str.length(); i++) {
   hash = (hash << 4) + str.charAt(i);
   if ((x = (int) (hash & 0xF0000000L)) != 0) {
    hash ^= (x >> 24);
    hash &= ~x;
   }
  }

  return (hash & 0x7FFFFFFF);
 }

 /* End Of ELF Hash Function */

 /**
  * BKDR算法
  */
 public static int BKDRHash(String str) {
  int seed = 131; // 31 131 1313 13131 131313 etc..
  int hash = 0;

  for (int i = 0; i < str.length(); i++) {
   hash = (hash * seed) + str.charAt(i);
  }

  return (hash & 0x7FFFFFFF);
 }

 /* End Of BKDR Hash Function */

 /**
  * SDBM算法
  */
 public static int SDBMHash(String str) {
  int hash = 0;

  for (int i = 0; i < str.length(); i++) {
   hash = str.charAt(i) + (hash << 6) + (hash << 16) - hash;
  }

  return (hash & 0x7FFFFFFF);
 }

 /* End Of SDBM Hash Function */

 /**
  * DJB算法
  */
 public static int DJBHash(String str) {
  int hash = 5381;

  for (int i = 0; i < str.length(); i++) {
   hash = ((hash << 5) + hash) + str.charAt(i);
  }

  return (hash & 0x7FFFFFFF);
 }

 /* End Of DJB Hash Function */

 /**
  * DEK算法
  */
 public static int DEKHash(String str) {
  int hash = str.length();

  for (int i = 0; i < str.length(); i++) {
   hash = ((hash << 5) ^ (hash >> 27)) ^ str.charAt(i);
  }

  return (hash & 0x7FFFFFFF);
 }

 /* End Of DEK Hash Function */

 /**
  * AP算法
  */
 public static int APHash(String str) {
  int hash = 0;

  for (int i = 0; i < str.length(); i++) {
   hash ^= ((i & 1) == 0) ? ((hash << 7) ^ str.charAt(i) ^ (hash >> 3)) : (~((hash << 11) ^ str.charAt(i) ^ (hash >> 5)));
  }

  // return (hash & 0x7FFFFFFF);
  return hash;
 }

 /* End Of AP Hash Function */

 /**
  * JAVA自己带的算法
  */
 public static int java(String str) {
  int h = 0;
  int off = 0;
  int len = str.length();
  for (int i = 0; i < len; i++) {
   h = 31 * h + str.charAt(off++);
  }
  return h;
 }

 /**
  * 混合hash算法,输出64位的值
  */
 public static long mixHash(String str) {
  long hash = str.hashCode();
  hash <<= 32;
  hash |= FNVHash1(str);
  return hash;
 }

 /**
  * 计算sha1
  * 
  * @param text
  *            文本
  * @return 字节数组
  * @throws Exception
  */
 public static byte[] sha1(String text) throws Exception {
  MessageDigest md;
  md = MessageDigest.getInstance("SHA-1");
  byte[] sha1hash = new byte[40];
  byte[] input = text.getBytes("utf-8");
  md.update(input, 0, input.length);
  sha1hash = md.digest();
  return sha1hash;
 }

 // 4位值对应16进制字符
 static char[] m_byteToHexChar = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' };

 /**
  * 计算sha1
  * 
  * @param text
  *            文本
  * @return 16进制表示的hash值
  * @throws Exception
  */
 public static String sha1_text(String text) throws Exception {
  byte[] hash = sha1(text);
  StringBuilder ret = new StringBuilder(hash.length * 2);
  for (byte b : hash) {
   int d = (b & 0xff);
   ret.append(m_byteToHexChar[(d & 0xf)]);
   d >>= 4;
   ret.append(m_byteToHexChar[(d & 0xf)]);
  }
  return ret.toString();
 }
}

 

分享到:
评论

相关推荐

    Java 面试宝典

    一. Java 基础部分............................................................................................................43、Java 中的异常处理机制的简单原理和应用。 .....................................

    MySQL 5.1参考手册

    12.10. 与GROUP BY子句同时使用的函数和修改程序 12.10.1. GROUP BY(聚合)函数 12.10.2. GROUP BY修改程序 12.10.3. 具有隐含字段的GROUP BY 13. SQL语句语法 13.1. 数据定义语句 13.1.1. ALTER DATABASE语法 ...

    MySQL 5.1中文手冊

    12.10. 与GROUP BY子句同时使用的函数和修改程序 12.10.1. GROUP BY(聚合)函数 12.10.2. GROUP BY修改程序 12.10.3. 具有隐含字段的GROUP BY 13. SQL语句语法 13.1. 数据定义语句 13.1.1. ALTER DATABASE语法 ...

    mysql官方中文参考手册

    12.10. 与GROUP BY子句同时使用的函数和修改程序 12.10.1. GROUP BY(聚合)函数 12.10.2. GROUP BY修改程序 12.10.3. 具有隐含字段的GROUP BY 13. SQL语句语法 13.1. 数据定义语句 13.1.1. ALTER DATABASE语法 ...

    MYSQL中文手册

    12.10. 与GROUP BY子句同时使用的函数和修改程序 12.10.1. GROUP BY(聚合)函数 12.10.2. GROUP BY修改程序 12.10.3. 具有隐含字段的GROUP BY 13. SQL语句语法 13.1. 数据定义语句 13.1.1. ALTER DATABASE...

    MySQL5.1参考手册官方简体中文版

    12.10. 与GROUP BY子句同时使用的函数和修改程序 12.10.1. GROUP BY(聚合)函数 12.10.2. GROUP BY修改程序 12.10.3. 具有隐含字段的GROUP BY 13. SQL语句语法 13.1. 数据定义语句 13.1.1. ALTER DATABASE语法 ...

    MySQL 5.1参考手册中文版

    12.10. 与GROUP BY子句同时使用的函数和修改程序 12.10.1. GROUP BY(聚合)函数 12.10.2. GROUP BY修改程序 12.10.3. 具有隐含字段的GROUP BY 13. SQL语句语法 13.1. 数据定义语句 13.1.1. ALTER DATABASE语法...

    MySQL 5.1官方简体中文参考手册

    12.10. 与GROUP BY子句同时使用的函数和修改程序 12.10.1. GROUP BY(聚合)函数 12.10.2. GROUP BY修改程序 12.10.3. 具有隐含字段的GROUP BY 13. SQL语句语法 13.1. 数据定义语句 13.1.1. ALTER DATABASE语法 ...

    MySQL 5.1参考手册 (中文版)

    12.10. 与GROUP BY子句同时使用的函数和修改程序 12.10.1. GROUP BY(聚合)函数 12.10.2. GROUP BY修改程序 12.10.3. 具有隐含字段的GROUP BY 13. SQL语句语法 13.1. 数据定义语句 13.1.1. ALTER DATABASE语法 ...

    JAVA面试题最全集

    给定一个C语言函数,要求实现在java类中进行调用。 45.如何获得数组的长度? 46.访问修饰符“public/private/protected/缺省的修饰符”的使用 47.用关键字final修饰一个类或者方法时,有何意义? 48.掌握类和...

    java 面试题 总结

    多态性语言具有灵活、抽象、行为共享、代码共享的优势,很好的解决了应用程序函数同名问题。 2、String是最基本的数据类型吗? 基本数据类型包括byte、int、char、long、float、double、boolean和short。 java.lang....

    java基础题 很全面

    39. Java中的异常处理机制的简单原理和应用。 11 40. 垃圾回收的优点和原理。并考虑2种回收机制。 11 41. 你所知道的集合类都有哪些?主要方法? 12 42. 描述一下JVM加载class文件的原理机制? 12 43. char型变量中能不...

    超级有影响力霸气的Java面试题大全文档

    多态性语言具有灵活、抽象、行为共享、代码共享的优势,很好的解决了应用程序函数同名问题。 5、String是最基本的数据类型吗?  基本数据类型包括byte、int、char、long、float、double、boolean和short。  java....

    Java面试宝典-经典

    43、Java中的异常处理机制的简单原理和应用。 28 44、请写出你最常见到的5个runtime exception。 28 45、JAVA语言如何进行异常处理,关键字:throws,throw,try,catch,finally分别代表什么意义?在try块中可以抛出...

    java面试题大全(2012版)

    43、Java中的异常处理机制的简单原理和应用。 28 44、请写出你最常见到的5个runtime exception。 28 45、JAVA语言如何进行异常处理,关键字:throws,throw,try,catch,finally分别代表什么意义?在try块中可以抛出...

    mysql5.1中文手册

    MySQL本地化和国际应用 5.10.1. 数据和排序用字符集 5.10.2. 设置错误消息语言 5.10.3. 添加新的字符集 5.10.4. 字符定义数组 5.10.5. 字符串比较支持 5.10.6. 多字节字符支持 5.10.7. 字符集...

Global site tag (gtag.js) - Google Analytics