package com.xiaoleilu.hutool.util;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
import java.lang.reflect.Array;
import java.util.Collection;
import java.util.Enumeration;
import java.util.Iterator;
import java.util.Map;
import com.xiaoleilu.hutool.exceptions.UtilException;
import com.xiaoleilu.hutool.io.FastByteArrayOutputStream;
import com.xiaoleilu.hutool.io.IoUtil;
/**
* 一些通用的函数
*
* @author Looly
*
*/
public final class ObjectUtil {
private ObjectUtil() {
}
/**
* 比较两个对象是否相等。<br>
* 相同的条件有两个,满足其一即可:<br>
* <ol>
* <li>obj1 == null && obj2 == null</li>
* <li>obj1.equals(obj2)</li>
* </ol>
* 1. obj1 == null && obj2 == null
* 2. obj1.equals(obj2)
*
* @param obj1 对象1
* @param obj2 对象2
* @return 是否相等
*/
public static boolean equal(Object obj1, Object obj2) {
return (obj1 != null) ? (obj1.equals(obj2)) : (obj2 == null);
}
/**
* 计算对象长度,如果是字符串调用其length函数,集合类调用其size函数,数组调用其length属性,其他可遍历对象遍历计算长度<br>
* 支持的类型包括:
* <ul>
* <li>CharSequence</li>
* <li>Map</li>
* <li>Iterator</li>
* <li>Enumeration</li>
* <li>Array</li>
* </ul>
*
* @param obj 被计算长度的对象
* @return 长度
*/
public static int length(Object obj) {
if (obj == null) {
return 0;
}
if (obj instanceof CharSequence) {
return ((CharSequence) obj).length();
}
if (obj instanceof Collection) {
return ((Collection<?>) obj).size();
}
if (obj instanceof Map) {
return ((Map<?, ?>) obj).size();
}
int count;
if (obj instanceof Iterator) {
Iterator<?> iter = (Iterator<?>) obj;
count = 0;
while (iter.hasNext()) {
count++;
iter.next();
}
return count;
}
if (obj instanceof Enumeration) {
Enumeration<?> enumeration = (Enumeration<?>) obj;
count = 0;
while (enumeration.hasMoreElements()) {
count++;
enumeration.nextElement();
}
return count;
}
if (obj.getClass().isArray() == true) {
return Array.getLength(obj);
}
return -1;
}
/**
* 对象中是否包含元素<br>
* 支持的对象类型包括:
* <ul>
* <li>String</li>
* <li>Collection</li>
* <li>Map</li>
* <li>Iterator</li>
* <li>Enumeration</li>
* <li>Array</li>
* </ul>
*
* @param obj 对象
* @param element 元素
* @return 是否包含
*/
public static boolean contains(Object obj, Object element) {
if (obj == null) {
return false;
}
if (obj instanceof String) {
if (element == null) {
return false;
}
return ((String) obj).contains(element.toString());
}
if (obj instanceof Collection) {
return ((Collection<?>) obj).contains(element);
}
if (obj instanceof Map) {
return ((Map<?, ?>) obj).values().contains(element);
}
if (obj instanceof Iterator) {
Iterator<?> iter = (Iterator<?>) obj;
while (iter.hasNext()) {
Object o = iter.next();
if (equal(o, element)) {
return true;
}
}
return false;
}
if (obj instanceof Enumeration) {
Enumeration<?> enumeration = (Enumeration<?>) obj;
while (enumeration.hasMoreElements()) {
Object o = enumeration.nextElement();
if (equal(o, element)) {
return true;
}
}
return false;
}
if (obj.getClass().isArray() == true) {
int len = Array.getLength(obj);
for (int i = 0; i < len; i++) {
Object o = Array.get(obj, i);
if (equal(o, element)) {
return true;
}
}
}
return false;
}
/**
* 检查对象是否为null
*
* @param obj 对象
* @return 是否为null
*/
public static boolean isNull(Object obj) {
return null == obj;
}
/**
* 检查对象是否不为null
*
* @param obj 对象
* @return 是否为null
*/
public static boolean isNotNull(Object obj) {
return null != obj;
}
/**
* 克隆对象<br>
* 如果对象实现Cloneable接口,调用其clone方法<br>
* 如果实现Serializable接口,执行深度克隆<br>
* 否则返回<code>null</code>
*
* @param obj 被克隆对象
* @return 克隆后的对象
*/
public static <T> T clone(T obj) {
T result = ArrayUtil.clone(obj);
if (null == result) {
if(obj instanceof Cloneable){
result = ClassUtil.invoke(obj, "clone", new Object[] {});
}else{
result = cloneByStream(obj);
}
}
return result;
}
/**
* 返回克隆后的对象,如果克隆失败,返回原对象
* @param obj 对象
* @return 克隆后或原对象
*/
public static <T> T cloneIfPossible(final T obj) {
T clone = null;
try {
clone = clone(obj);
} catch (Exception e) {
//pass
}
return clone == null ? obj : clone;
}
/**
* 序列化后拷贝流的方式克隆<br>
* 对象必须实现Serializable接口
*
* @param obj 被克隆对象
* @return 克隆后的对象
* @throws IOException
* @throws ClassNotFoundException
*/
@SuppressWarnings("unchecked")
public static <T> T cloneByStream(T obj) {
if(null == obj || false == (obj instanceof Serializable)){
return null;
}
final FastByteArrayOutputStream byteOut = new FastByteArrayOutputStream();
ObjectOutputStream out = null;
try {
out = new ObjectOutputStream(byteOut);
out.writeObject(obj);
out.flush();
final ObjectInputStream in = new ObjectInputStream(new ByteArrayInputStream(byteOut.toByteArray()));
return (T) in.readObject();
} catch (Exception e) {
throw new UtilException(e);
} finally {
IoUtil.close(out);
}
}
/**
* 序列化<br>
* 对象必须实现Serializable接口
*
* @param <T>
* @param obj 要被序列化的对象
* @return 序列化后的字节码
*/
public static <T> byte[] serialize(T obj) {
if(null == obj || false == (obj instanceof Serializable)){
return null;
}
FastByteArrayOutputStream byteOut = new FastByteArrayOutputStream();
ObjectOutputStream oos = null;
try {
oos = new ObjectOutputStream(byteOut);
oos.writeObject(obj);
oos.flush();
} catch (Exception e) {
throw new UtilException(e);
} finally {
IoUtil.close(oos);
}
return byteOut.toByteArray();
}
/**
* 反序列化<br>
* 对象必须实现Serializable接口
*
* @param <T>
* @param bytes 反序列化的字节码
* @return 反序列化后的对象
*/
@SuppressWarnings("unchecked")
public static <T> T unserialize(byte[] bytes) {
ObjectInputStream ois = null;
try {
ByteArrayInputStream bais = new ByteArrayInputStream(bytes);
ois = new ObjectInputStream(bais);
return (T) ois.readObject();
} catch (Exception e) {
throw new UtilException(e);
}
}
/**
* 是否为基本类型,包括包装类型和非包装类型
*
* @see ClassUtil#isBasicType(Class)
* @param object 被检查对象
* @return 是否为基本类型
*/
public static boolean isBasicType(Object object) {
return ClassUtil.isBasicType(object.getClass());
}
/**
* 检查是否为有效的数字<br>
* 检查Double和Float是否为无限大,或者Not a Number<br>
* 非数字类型和Null将返回true
*
* @param obj 被检查类型
* @return 检查结果,非数字类型和Null将返回true
*/
public static boolean isValidIfNumber(Object obj) {
if (obj != null && obj instanceof Number) {
if (obj instanceof Double) {
if (((Double) obj).isInfinite() || ((Double) obj).isNaN()) {
return false;
}
} else if (obj instanceof Float) {
if (((Float) obj).isInfinite() || ((Float) obj).isNaN()) {
return false;
}
}
}
return true;
}
}