SourceCode
package net.i2p.data;
/*
* free (adj.): unencumbered; not under the control of others
* Written by jrandom in 2003 and released into the public domain
* with no warranty of any kind, either expressed or implied.
* It probably won't make your computer catch on fire, or eat
* your children, but it might. Use at your own risk.
*
*/
import java.io.IOException;
import java.io.InputStream;
/**
* Defines the hash as defined by the I2P data structure spec.
* A hash is the SHA-256 of some data, taking up 32 bytes.
*
* @author jrandom
*/
public class Hash extends SimpleDataStructure {
private volatile String _base64ed;
private int _cachedHashCode;
public final static int HASH_LENGTH = 32;
public final static Hash FAKE_HASH = new Hash(new byte[HASH_LENGTH]);
private static final int CACHE_SIZE = 2048;
private static final SDSCache<Hash> _cache = new SDSCache<Hash>(Hash.class, HASH_LENGTH, CACHE_SIZE);
/**
* Pull from cache or return new
*
* WARNING - If the SDS is found in the cache, the passed-in
* byte array will be returned to the SimpleByteCache for reuse.
* Do NOT save a reference to the passed-in data, or use or modify it,
* after this call.
*
* Ignore this warning and you WILL corrupt the cache or other data structures.
*
* @throws IllegalArgumentException if data is not the correct number of bytes
* @since 0.8.3
*/
public static Hash create(byte[] data) {
return _cache.get(data);
}
/**
* Pull from cache or return new
* @throws ArrayIndexOutOfBoundsException if not enough bytes
* @since 0.8.3
*/
public static Hash create(byte[] data, int off) {
return _cache.get(data, off);
}
/**
* Pull from cache or return new
* @since 0.8.3
*/
public static Hash create(InputStream in) throws IOException {
return _cache.get(in);
}
public Hash() {
super();
}
/** @throws IllegalArgumentException if data is not 32 bytes (null is ok) */
public Hash(byte data[]) {
super();
setData(data);
}
public int length() {
return HASH_LENGTH;
}
/** @throws IllegalArgumentException if data is not 32 bytes (null is ok) */
@Override
public void setData(byte[] data) {
super.setData(data);
_base64ed = null;
_cachedHashCode = super.hashCode();
}
@Override
public void readBytes(InputStream in) throws DataFormatException, IOException {
super.readBytes(in);
_base64ed = null;
_cachedHashCode = super.hashCode();
}
/** a Hash is a hash, so just use the first 4 bytes for speed */
@Override
public int hashCode() {
return _cachedHashCode;
}
@Override
public String toBase64() {
if (_base64ed == null) {
_base64ed = super.toBase64();
}
return _base64ed;
}
/**
* For convenience.
* @return "{52 chars}.b32.i2p" or null if data not set.
* @since 0.9.25
*/
public String toBase32() {
if (_data == null)
return null;
return Base32.encode(_data) + ".b32.i2p";
}
/**
* @since 0.9.17
*/
public static void clearCache() {
_cache.clear();
}
}
从注释看,这是一个sha-256算法的类,sha-256算法是一种hash函数,接受任意长度的输入,输出为32字节(256位)
详细笔记
成员变量
- _base64ed privarte限定,String类型。volatile修饰说明-base74ed经常变化,并且是在本类内的函数经常对其改动,以至于每次使用都要回到内存中去取这个值而不是取存放在寄存器中的
- _cachedHashCode int类型,private
- HASH_LENGTH 常量,public类型,32 static限定
- FAKEHASH 常量,是一个Hash类,public类型,static限定
- CACHE_SIZE 常量 static限定,private, 常量2048
- _cache SDSCache< Hash>类型,static, private限定,缓存相关的。我们现在不知道什么意思,应该是一个泛型类,之后在看
成员方法
三个重载函数,
应对不同的参数类型,都返回Hash类型
public static Hash create(byte[] data) {
return _cache.get(data);
}
/**
* Pull from cache or return new
* @throws ArrayIndexOutOfBoundsException if not enough bytes
* @since 0.8.3
*/
public static Hash create(byte[] data, int off) {
return _cache.get(data, off);
}
/**
* Pull from cache or return new
* @since 0.8.3
*/
public static Hash create(InputStream in) throws IOException {
return _cache.get(in);
}
这个是从SDSCache这个类中的应用,是从cache中获取Hash类
两个构造函数
public Hash() {
super();
}
/** @throws IllegalArgumentException if data is not 32 bytes (null is ok) */
public Hash(byte data[]) {
super();
setData(data);
}
应对两个,都调用了父类的构造函数,这里找到父类SimpleDataStructue的构造函数
/** A new instance with the data set to null. Call readBytes(), setData(), or fromByteArray() after this to set the data */
public SimpleDataStructure() {
}
/** @throws IllegalArgumentException if data is not the legal number of bytes (but null is ok) */
public SimpleDataStructure(byte data[]) {
setData(data);
}
如火在Hash类的创建的时候,没有传入参数,那么创建data是null空的,如果是有data的,那么首先调用父类SImpleDataSTructure的setData,经过对输入数据的合法性检验后setdata,就一个简单的data赋值。
这里的setdata中的合法性检验中,是对data.length() 判断是否等于HASH_LENGTH即32的,
调用的还是父类的空构造函数,然后调用子类本身的setData函数
/** @throws IllegalArgumentException if data is not 32 bytes (null is ok) */
@Override
public void setData(byte[] data) {
super.setData(data);
_base64ed = null;
_cachedHashCode = super.hashCode();
}
调用父类SImpleDataSTructure的setData,经过对输入数据的合法性检验后setdata,就一个简单的data赋值。
这里的setdata中的合法性检验中,是对data.length() 判断是否等于HASH_LENGTH即32的检验
我们虽然在这里不知道data具体是什么,但是由于i2p用的是sha256算法,其hash的输出是32字节的,而data正式byte【】字节数组,所以推测data是hash值。至于之后怎么用,先不管
另外,Hash类中的setData有一个_cachedHashCode变量,调用父类的hashcode函数赋值
@Override
public int hashCode() {
if (_data == null)
return 0;
int rv = _data[0];
for (int i = 1; i < 4; i++)
rv ^= (_data[i] << (i*8));
return rv;
}
这是hash的一种,其中左移一位是*2 看不懂具体操作的可以自己写一下看看就明白了
其他方法
@Override
public void readBytes(InputStream in) throws DataFormatException, IOException {
super.readBytes(in);
_base64ed = null;
_cachedHashCode = super.hashCode();
}
/** a Hash is a hash, so just use the first 4 bytes for speed */
@Override
public int hashCode() {
return _cachedHashCode;
}
@Override
public String toBase64() {
if (_base64ed == null) {
_base64ed = super.toBase64();
}
return _base64ed;
}
/**
* For convenience.
* @return "{52 chars}.b32.i2p" or null if data not set.
* @since 0.9.25
*/
public String toBase32() {
if (_data == null)
return null;
return Base32.encode(_data) + ".b32.i2p";
}
/**
* @since 0.9.17
*/
public static void clearCache() {
_cache.clear();
}
}
- readByte函数:调用父类的readByte函数,父类的readbyte函数是data的另一种输入方法,用read函数,read函数从输入流中获取一个字节的数据,可以说这个函数是用输入六inputstream来定义_data的一种方法
- hashcode方法,就用前四个字节,也就是super。hash函数计算得到的,这样之所以只用四个就是为了速度
- clearCache方法:清空缓存,具体怎么清空之后再分析
- toBase32 方法:将_data转换成32位字节
- toBase64 方法: 将data转化成64字节
之所以要32 或者64字节是为了用来网络传输等