java 相关问题(一)

 

一、 java Cloneable 详解 (clone,克隆)

 

    上面是GOF设计模式中对原型模式的图形结构描述,原型模式通过克隆使我们可以得到一个对象的复制版本.其好处就是让我们在需要一个与现有对象类似的实例时,不用一一进行每个成员的赋值,而是直接通过现有的对象复制.并且复制出来的对象是互相独立的.

 

 

 

       如上图,当对象进行了这样的赋值以后,两个变量指向了同一个对象实例,也就是说它们都引用是相同的,在这种情况下,其中一个对象的改变都会影响另一个对象的变化.两个对象互不独立.

 

 

      如果想得到互相独立的两个对象就要使用Clone方法,如上图,经Clone后,任何一个对象的改变都不会影响另一个对象。Object1上Object2是两个不同的引用.

 

 

      如果一个欲实现 Clone 方法的对象其成员中还包含其它对象 ,那么那些对象同样要实现Clone方法(也就是说,同样要实现 Cloneable 接口) ,而且在上一层的对象中要调用这些 Clone 方法.以此类推,直到最后一个对象中没有对象值为止(深拷贝) .
     在JAVA中,要实现 Clone方法就要实现 Cloneable 接口,但是 Clone 方法不是这个接口的方法,它只是一个标识接口Clone 方法是从 Object 对象继承下来的protected方法,在实现它的时候要声明为public 。在使用Clone的时候还要记得进行类型转换,因为Clone 方法返回的是一个Object


     下面是一小段简单的代码,是对对象克隆的实验:

package js;

/**
 * ImplClone
 * @author jiashuai
 *
 */
public class ImplClone implements Cloneable {

	private String name = "";
	private Birth birth;

	/** Creates a new instance of ImplClone */
	public ImplClone() {
		this.setName("bill");
		this.birth = new Birth();
	}

	public Object clone() {
		ImplClone cloned = new ImplClone();
		try {
			cloned = (ImplClone) super.clone();
			cloned.birth = (Birth) this.birth.clone();
		} catch (CloneNotSupportedException ex) {
			ex.printStackTrace();
		}
		//cloned.birth = (Birth) birth.clone();
		return cloned;
	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public Birth getBirth() {
		return birth;
	}

	public void setBirth(Birth birth) {
		this.birth = birth;
	}

}

/**
 * Birth
 * @author jiashuai
 *
 */
class Birth implements Cloneable {
	private String year;
	private String month;
	private String day;

	public Birth(String year, String month, String day) {
		this.year = year;
		this.month = month;
		this.day = day;
	}

	public Birth() {
	}

	public String getYear() {
		return year;
	}

	public void setYear(String year) {
		this.year = year;
	}

	public String getMonth() {
		return month;
	}

	public void setMonth(String month) {
		this.month = month;
	}

	public String getDay() {
		return day;
	}

	public void setDay(String day) {
		this.day = day;
	}

	public Object clone() {
		Birth cloned = new Birth();
		try {
			cloned = (Birth) super.clone();
		} catch (CloneNotSupportedException ex) {
			ex.printStackTrace();
		}
		return cloned;
	}
}

 

package js;

/**
 * CloneMain
 * @author jiashuai
 *
 */
public class CloneMain {
    
    /** Creates a new instance of CloneMain */
    public CloneMain() {
    }
   
    public static void main(String[] args){
            ImplClone cloneObj=new ImplClone();
           
            cloneObj.setName("Bill");
            cloneObj.setBirth(new Birth("2004","03","01"));
           
            System.out.println(cloneObj.getBirth().getYear()+" :1");
            //ImplClone cloned=new ImplClone();
            //cloned=cloneObj;
            ImplClone cloned=(ImplClone)cloneObj.clone();
            cloned.getBirth().setYear("1990");       //改变克隆对象的数据
            
            System.out.println(cloneObj.getBirth().getYear()+" :2");    //输出原对象
            System.out.println(cloned.getBirth().getYear()+" :3");    //输出改变数据后的克隆对象
    }
}

 

二、 用字节(byte) 截取字符串的问题

( 用字节(byte) 截取字符串的问题 )


  编写一个截取字符串的函数,输入为一个字符串和字节数,输出为按字节截取的字符串。 但是要保证汉字不被截半个,如“我ABC”4,应该截为“我AB”,输入“我ABC汉DEF”,6,应该输出为“我ABC”而不是“我ABC+汉的半个”。

 

import java.io.UnsupportedEncodingException;

public class TestSubString {
	
	/**
	 * 变成 byte[] 截取,然后在转换成一个新的 String  如果旧的 String 包含 新的 String 
	 * 说明没有截取到半个汉字,如果不包含说明截取到半个汉字了,
	 * 那么就少截取一个字符来防止半个字符存在
	 * @param str
	 * @param sub
	 * @return
	 * @throws UnsupportedEncodingException 
	 */
	public String test(String str,int sub) throws UnsupportedEncodingException{		
		String retVal = "";
		if (str == null || str.equals("") || sub == 0) {
			return  retVal;
		}
		byte[] b = str.getBytes("GBK");
		if (b.length < sub) {
			return str;
		}
		byte[] temp = new byte[sub];
		for (int i = 0; i < sub; i++) {
			temp[i] = b[i];
		}
		
		String tempStr = new String(temp);
		if (str.contains(tempStr)) {
			return tempStr;
		}
		temp = new byte[sub-1];
		for (int i = 0; i < sub-1; i++) {
			temp[i] = b[i];
		}
		retVal = new String(temp);
		
		return  retVal;
	}
	
	
	/**
	 * 打印字符串在指定编码下的字节数和编码名称到控制台
	 * 
	 * @param s
	 *            字符串
	 * @param encodingName
	 *            编码格式
	 */
	public  void printByteLength(String s, String encodingName) {
		System.out.print("字节数:");
		try {
			System.out.print(s.getBytes(encodingName).length);
		} catch (UnsupportedEncodingException e) {
			e.printStackTrace();
		}
		System.out.println(";编码:" + encodingName);
	}

	
	public static void main(String[] args) throws UnsupportedEncodingException {
		TestSubString tss = new TestSubString();
		
		String en = "A";
		String ch = "人";

		// 计算一个英文字母在各种编码下的字节数
		System.out.println("英文字母:" + en);
		tss.printByteLength(en, "GB2312");
		tss.printByteLength(en, "GBK");
		tss.printByteLength(en, "GB18030");
		tss.printByteLength(en, "ISO-8859-1");
		tss.printByteLength(en, "UTF-8");
		tss.printByteLength(en, "UTF-16");
		tss.printByteLength(en, "UTF-16BE");
		tss.printByteLength(en, "UTF-16LE");

		System.out.println();

		// 计算一个中文汉字在各种编码下的字节数
		System.out.println("中文汉字:" + ch);
		tss.printByteLength(ch, "GB2312");
		tss.printByteLength(ch, "GBK");
		tss.printByteLength(ch, "GB18030");
		tss.printByteLength(ch, "ISO-8859-1");
		tss.printByteLength(ch, "UTF-8");
		tss.printByteLength(ch, "UTF-16");
		tss.printByteLength(ch, "UTF-16BE");
		tss.printByteLength(ch, "UTF-16LE");
		
//-------------------------------------------------------------------------------		
		System.out.println();
		
		String t1 = "我ABC汉DEF";
		System.out.println(tss.test(t1, 4));
		System.out.println(tss.test(t1, 6));
	}
}

 

运行结果:

英文字母:A
字节数:1;编码:GB2312
字节数:1;编码:GBK
字节数:1;编码:GB18030
字节数:1;编码:ISO-8859-1
字节数:1;编码:UTF-8
字节数:4;编码:UTF-16
字节数:2;编码:UTF-16BE
字节数:2;编码:UTF-16LE

中文汉字:人
字节数:2;编码:GB2312
字节数:2;编码:GBK
字节数:2;编码:GB18030
字节数:1;编码:ISO-8859-1
字节数:3;编码:UTF-8
字节数:4;编码:UTF-16
字节数:2;编码:UTF-16BE
字节数:2;编码:UTF-16LE

我AB
我ABC

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

可知,GB2312、GBK、GB18030 三种编码格式都符合题目要求

注意 .java 文件也要是相同编码,否则控制台显示乱码

 

三、 Java URL 工具类(解决 url 和 java 之间的乱码问题)

Java URL 工具类

 

package ssh.util;

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.UnsupportedEncodingException;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLConnection;
import java.net.URLDecoder;
import java.net.URLEncoder;
import java.util.Iterator;
import java.util.Map;

import javax.servlet.http.HttpServletRequest;

/**
 * URL工具
 * @author gary
 *
 */
public class URLUtil {

	/**
	 * 对url进行编码
	 */
	public static String encodeURL(String url) {
		try {
			return URLEncoder.encode(url, "UTF-8");
		} catch (UnsupportedEncodingException e) {
			e.printStackTrace();
			return null;
		}
	}
	
	/**
	 * 对url进行解码
	 * @param url
	 * @return
	 */
	public static String decodeURL(String url){
		try {
			return URLDecoder.decode(url, "UTF-8");
		} catch (UnsupportedEncodingException e) {
			e.printStackTrace();
			return null;
		}
	}

	/**
	 * 判断URL地址是否存在
	 * @param url
	 * @return
	 */
	public static boolean isURLExist(String url) {
		try {
			URL u = new URL(url);
			HttpURLConnection urlconn = (HttpURLConnection) u.openConnection();
			int state = urlconn.getResponseCode();
			if (state == 200) {
				return true;
			} else {
				return false;
			}
		} catch (Exception e) {
			return false;
		}
	}
	
	/**
	 * 将请求参数还原为key=value的形式,for struts2
	 * @param params
	 * @return
	 */
	public static String getParamString(Map<?, ?> params) {
		StringBuffer queryString = new StringBuffer(256);
		Iterator<?> it = params.keySet().iterator();
		int count = 0;
		while (it.hasNext()) {
			String key = (String) it.next();
			String[] param = (String[]) params.get(key);
			for (int i = 0; i < param.length; i++) {
				if (count == 0) {
					count++;
				} else {
					queryString.append("&");
				}
				queryString.append(key);
				queryString.append("=");
				try {
					queryString.append(URLEncoder.encode((String) param[i], "UTF-8"));
				} catch (UnsupportedEncodingException e) {
				}
			}
		}
		return queryString.toString();
	}

	/**
	 * 获得请求的路径及参数
	 * @param request
	 * @return
	 */
	public static String getRequestURL(HttpServletRequest request) {
		StringBuffer originalURL = new StringBuffer(request.getServletPath());
		Map<?,?> parameters = request.getParameterMap();
		if (parameters != null && parameters.size() > 0) {
			originalURL.append("?");
			originalURL.append(getParamString(parameters));
		}
		return originalURL.toString();
	}

	/**
	 * 抓取网页内容,自动识别编码
	 * @param urlString
	 * @return
	 */
	public static String url2Str(String urlString) {
		try {
			StringBuffer html = new StringBuffer();
			URL url = new URL(urlString);
			HttpURLConnection conn = (HttpURLConnection) url.openConnection();
			URLConnection c = url.openConnection();
			c.connect();
			String contentType = c.getContentType();
			String characterEncoding = null;
			int index = contentType.indexOf("charset=");
			if(index == -1){
				characterEncoding = "UTF-8";
			}else{
				characterEncoding = contentType.substring(index + 8, contentType.length());
			}
	        InputStreamReader isr = new InputStreamReader(conn.getInputStream(), characterEncoding);
	        BufferedReader br = new BufferedReader(isr);
	        String temp;
	        while ((temp = br.readLine()) != null) {
	            html.append(temp).append("\n");
	        }
	        br.close();
	        isr.close();
	        return html.toString();
	     } catch (Exception e) {
	        e.printStackTrace();
	        return null;
	     }
	 }
		 
     public static void main(String[] args) {
    	 String content = URLUtil.url2Str("http://www.baidu.com");;
    	 System.out.println(content);
     }
}

 

JS 中 编码解码

encodeURI(URI)
decodeURI(encodedURI);

 

 

 

四、 Java HTML 工具类

Java HTML 工具类

 

package ssh.util;

import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * HTML工具
 * @author gary
 *
 */
public class HTMLUtil {

	//>
	public static final String GT = "&gt;";
	//<
	public static final String LT = "&lt;";
	//"
	public static final String QUOT = "&quot;";
	//&
	public static final String AMP = "&amp;";
	//空格
	public static final String SPACE = "&nbsp;";
	//©
	public static final String COPYRIGHT = "&copy;";
	//®
	public static final String REG = "&reg;";
	//™
	public static final String TM = "&trade;";
	//¥
	public static final String RMB = "&yen;";
	
	
	/**
	 * 删除script标签
	 * @param str
	 * @return
	 */
	public static String delScriptTag(String str){
		String regEx_script = "<script[^>]*?>[\\s\\S]*?<\\/script>";
		Pattern p_script = Pattern.compile(regEx_script,Pattern.CASE_INSENSITIVE);
		Matcher m_script = p_script.matcher(str); 
        str = m_script.replaceAll("");
        return str.trim();
	}

	/**
	 * 删除style标签
	 * @param str
	 * @return
	 */
	public static String delStyleTag(String str){
		String regEx_style="<style[^>]*?>[\\s\\S]*?<\\/style>";
        Pattern p_style = Pattern.compile(regEx_style,Pattern.CASE_INSENSITIVE); 
        Matcher m_style = p_style.matcher(str); 
        str = m_style.replaceAll("");
        return str;
	}
	
	/**
	 * 删除HTML标签
	 * @param str
	 * @return
	 */
	public static String delHTMLTag(String str){
		String regEx_html = "<[^>]+>"; 
        Pattern p_html = Pattern.compile(regEx_html,Pattern.CASE_INSENSITIVE); 
        Matcher m_html = p_html.matcher(str); 
        str = m_html.replaceAll("");
        return str;
	}
	
	/**
	 * 删除所有标签
	 * @param str
	 * @return
	 */
	public static String delAllTag(String str){ 
        //删script
        str = delScriptTag(str);
        //删style
        str = delStyleTag(str);
        //删HTML
        str = delHTMLTag(str);
        return str;
    }
	
	/**
	 * 清除标签,恢复HTML转义字符
	 * @param str
	 * @return
	 */
	public static String clean(String str){
		str = delAllTag(str);
		str = str.replaceAll(SPACE, " ");
		str = str.replaceAll(GT, ">");
		str = str.replaceAll(LT, "<");
		str = str.replaceAll(QUOT, "\"");
		str = str.replaceAll(AMP, "&");
		str = str.replaceAll(COPYRIGHT, "©");
		str = str.replaceAll(REG,"®");
		str = str.replaceAll(TM,"™");
		str = str.replaceAll(RMB,"¥");
		return str;
	}
	
	/**
	 * 过滤指定标签
	 * @param str
	 * @param tag
	 *            指定标签
	 * @return String
	 */
	public static String fiterHtmlTag(String str, String tag) {
		String regxp = "<\\s*" + tag + "\\s+([^>]*)\\s*>";
		Pattern pattern = Pattern.compile(regxp);
		Matcher matcher = pattern.matcher(str);
		StringBuffer sb = new StringBuffer();
		boolean result1 = matcher.find();
		while (result1) {
			matcher.appendReplacement(sb, "");
			result1 = matcher.find();
		}
		matcher.appendTail(sb);
		return sb.toString();
	}

	/**
	 * 替换指定的标签
	 * @param str
	 * @param beforeTag
	 *            要替换的标签
	 * @param tagAttrib
	 *            要替换的标签属性值
	 * @param startTag
	 *            新标签开始标记
	 * @param endTag
	 *            新标签结束标记
	 * @return String
	 * example:	替换img标签的src属性值为[img]属性值[/img]
	 */
	public static String replaceHtmlTag(String str, String beforeTag,
			String tagAttrib, String startTag, String endTag) {
		String regxpForTag = "<\\s*" + beforeTag + "\\s+([^>]*)\\s*>";
		String regxpForTagAttrib = tagAttrib + "=\"([^\"]+)\"";
		Pattern patternForTag = Pattern.compile(regxpForTag);
		Pattern patternForAttrib = Pattern.compile(regxpForTagAttrib);
		Matcher matcherForTag = patternForTag.matcher(str);
		StringBuffer sb = new StringBuffer();
		boolean result = matcherForTag.find();
		while (result) {
			StringBuffer sbreplace = new StringBuffer();
			Matcher matcherForAttrib = patternForAttrib.matcher(matcherForTag
					.group(1));
			if (matcherForAttrib.find()) {
				matcherForAttrib.appendReplacement(sbreplace, startTag
						+ matcherForAttrib.group(1) + endTag);
			}
			matcherForTag.appendReplacement(sb, sbreplace.toString());
			result = matcherForTag.find();
		}
		matcherForTag.appendTail(sb);
		return sb.toString();
	}

	public static void main(String[] args) {
		System.out.println(clean(URLUtil.url2Str("http://www.baidu.com")));
	}
	
}

 

 

五、 用 Java 判断一个URL是否有效

    针对一些 URL 地址进行检测是否可用,使用 java.net 下的类来实现,主要用到了 URL HttpURLConnection 二个类 , URL 是统一资源标识符的引用,一个 URL 实例代表着一个 url 的引用,开始使用了 URL 中的的 openStream() 方法,这样使用倒是可以,但是速度慢,代码如下:

try {
     url = new URL("http://127.0.0.1/sj/user/getUser");
     in = url.openStream();
} catch (Exception e1) {
     System.out.println("连接打不开!");
     url = null;
}

 

下面判断 url 是不是 null 就可以了,速度慢

最后使用了HttpURLConnection 中的 getResponseCode() ;方法,HttpURLConnection : 通常一个HttpURLConnection 的实例可以生成一个请求,它有个方法 getResponseCode() ;可以得到请求的响应状态,该方法返回一个 int 分别是 200 and 404 如无法从响应中识别任何代码则返回 -1 ,代码如下:

import java.net.HttpURLConnection;
import java.net.URL;

public class URLAvailability {
    private static URL url;
    private static HttpURLConnection con;
    private static int state = -1;

    /**
     * 功能:检测当前URL是否可连接或是否有效, 描述:最多连接网络 5 次, 如果 5 次都不成功,视为该地址不可用
     * 
     * @param urlStr 指定URL网络地址
     * @return URL
     */
    public synchronized URL isConnect(String urlStr) {
        int counts = 0;
        if (urlStr == null || urlStr.length() <= 0) {
            return null;
        }
        while (counts < 5) {
            try {
                url = new URL(urlStr);
                con = (HttpURLConnection) url.openConnection();
                state = con.getResponseCode();
                System.out.println(counts + "= " + state);
                if (state == 200) {
                    System.out.println("URL可用!");
                }
                break;
            } catch (Exception ex) {
                counts++;
                System.out.println("URL不可用,连接第 " + counts + " 次");
                urlStr = null;
                continue;
            }
        }
        return url;
    }
}

 

六、  Java 对象序列化

java对象序列化
     所谓对象序列化就是将对象的状态转换成字节流,以后可以通过这些值再生成相同状态的对象。这个过程也可以通过网络实现,可以先在Windows机器上创建一个对象,对其序列化,然后通过网络发给一台Unix机器,然后在那里准确无误地重新"装配"。像RMI、Socket、JMS、EJB它们中的一种,彼此为什么能够传递Java对象,当然都是对象序列化机制的功劳。 
java对象序列化机制一般来讲有两种用途:
       1. Java的JavaBeans: Bean的状态信息通常是在设计时配置的,Bean的状态信息必须被存起来,以便当程序运行时能恢复这些状态信息,这需要将对象的状态保存到文件中,而后能够通过读入对象状态来重新构造对象,恢复程序状态。
       2. RMI允许象在本机上一样操作远程机器上的对象;或使用套接字在网络上传送对象的程序来说,这些都是需要实现serializaiton机制的。
       我们通过让类实现java.io.Serializable 接口可以将类序列化。这个接口是一个制造者(marker)接口。也就是说,对于要实现它的类来说,该接口不需要实现任何方法。它主要用来通知Java虚拟机(JVM),需要将一个对象序列化。
       对于这个,有几点我们需要明确:
       (1). 并非所有类都可以序列化,在cmd下,我们输入serialver java.net.Socket,可以得到socket是否可序列化的信息,实际上socket是不可序列化的。
       (2). java有很多基础类已经实现了serializable接口,比如string,vector等。但是比如hashtable就没有实现serializable接口。
       将对象读出或者写入流的主要类有两个: ObjectOutputStream与ObjectInputStream 。ObjectOutputStream 提供用来将对象写入输出流的writeObject方法, ObjectInputStream提供从输入流中读出对象的readObject方法。使用这些方法的对象必须已经被序列化的。也就是说,必须已经实现 Serializable接口。如果你想writeobject一个hashtable对象,那么,会得到一个异常。
序列化的过程就是对象写入字节流和从字节流中读取对象。将对象状态转换成字节流之后,可以用java.io包中的各种字节流类将其保存到文件中,管道到另一线程中或通过网络连接将对象数据发送到另一主机。对象序列化功能非常简单、强大,在RMI、Socket、JMS、EJB都有应用。对象序列化问题在网络编程中并不是最激动人心的课题,但却相当重要,具有许多实用意义。
1.     对象序列化可以实现分布式对象。主要应用例如:RMI要利用对象序列化运行远程主机上的服务,就像在本地机上运行对象时一样。
2.     java对象序列化不仅保留一个对象的数据,而且递归保存对象引用的每个对象的数据。可以将整个对象层次写入字节流中,可以保存在文件中或在网络连接上传递。利用对象序列化可以进行对象的“深复制”,即复制对象本身及引用的对象本身。序列化一个对象可能得到整个对象序列。
     java序列化比较简单,通常不需要编写保存和恢复对象状态的定制代码。实现java.io.Serializable接口的类对象可以转换成字节流或从字节流恢复,不需要在类中增加任何代码。只有极少数情况下才需要定制代码保存或恢复对象状态。这里要注意:不是每个类都可序列化,有些类是不能序列化的,例如涉及线程的类与特定JVM有非常复杂的关系。
序列化机制:
     序列化分为两大部分:序列化 和反序列化 。序列化是这个过程的第一部分,将数据分解成字节流,以便存储在文件中或在网络上传输。反序列化就是打开字节流并重构对象。对象序列化不仅要将基本数据类型转换成字节表示,有时还要恢复数据。恢复数据要求有恢复数据的对象实例。ObjectOutputStream中的序列化过程与字节流连接,包括对象类型和版本信息。反序列化时,JVM用头信息生成对象实例,然后将对象字节流中的数据复制到对象数据成员中。下面我们分两大部分来阐述:
处理对象流:
(序列化过程和反序列化过程)

     java.io包有两个序列化对象的类。ObjectOutputStream负责将对象写入字节流,ObjectInputStream从字节流重构对象。
     我们先了解ObjectOutputStream类吧。ObjectOutputStream类扩展DataOutput接口。
writeObject() 方法是最重要的方法,用于对象序列化。如果对象包含其他对象的引用,则writeObject()方法递归序列化这些对象。每个 ObjectOutputStream维护序列化的对象引用表,防止发送同一对象的多个拷贝。(这点很重要)由于writeObject()可以序列化整组交叉引用的对象,因此同一ObjectOutputStream实例可能不小心被请求序列化同一对象。这时,进行反引用序列化,而不是再次写入对象字节流。
下面,让我们从例子中来了解ObjectOutputStream这个类吧。
 

// 序列化 today's date 到一个文件中.
        FileOutputStream f = new FileOutputStream ("tmp" );
        ObjectOutputStream s = new ObjectOutputStream (f);
         s.writeObject("Today" );
         s.writeObject(new Date ());
         s.flush(); 

 

  
     现在,让我们来了解ObjectInputStream这个类。它与ObjectOutputStream相似。它扩展DataInput接口。 ObjectInputStream中的方法镜像DataInputStream中读取Java基本数据类型的公开方法。readObject()方法从字节流中反序列化对象。每次调用readObject()方法都返回流中下一个Object。对象字节流并不传输类的字节码,而是包括类名及其签名。 readObject()收到对象时,JVM装入头中指定的类。如果找不到这个类,则readObject()抛出 ClassNotFoundException,如果需要传输对象数据和字节码,则可以用RMI框架。ObjectInputStream的其余方法用于定制反序列化过程。
例子如下:
   

//从文件中反序列化 string 对象和 date 对象
        FileInputStream in = new FileInputStream ("tmp" );
        ObjectInputStream s = new ObjectInputStream (in);
        String today = (String )s.readObject();
        Date date = (Date )s.readObject(); 

 

定制序列化过程:


     序列化通常可以自动完成,但有时可能要对这个过程进行控制。java可以将类声明为serializable,但仍可手工控制声明为static或transient的数据成员。
例子:一个非常简单的序列化类。
   

public class simpleSerializableClass implements Serializable {
        String sToday="Today:" ;
        transient Date dtToday=new Date ();
    } 

 


     序列化时,类的所有数据成员应可序列化除了声明为transient 或static的成员。将变量声明为transient告诉JVM我们会负责将变元序列化。将数据成员声明为transient后,序列化过程就无法将其加进对象字节流中,没有从transient数据成员发送的数据。后面数据反序列化时,要重建数据成员(因为它是类定义的一部分),但不包含任何数据,因为这个数据成员不向流中写入任何数据。记住,对象流不序列化static或transient。我们的类要用writeObject()与 readObject()方法以处理这些数据成员。使用writeObject()与readObject()方法时,还要注意按写入的顺序读取这些数据成员。
关于如何使用定制序列化的部分代码如下:
   

//重写writeObject()方法以便处理transient的成员。
    public void writeObject(ObjectOutputStream outputStream) throws IOException {
         outputStream.defaultWriteObject();//使定制的writeObject()方法可以
                             利用自动序列化中内置的逻辑。
         outputStream.writeObject(oSocket.getInetAddress());
         outputStream.writeInt(oSocket.getPort());
    }
    //重写readObject()方法以便接收transient的成员。
    private void readObject(ObjectInputStream inputStream) throws IOException ,ClassNotFoundException {
         inputStream.defaultReadObject();//defaultReadObject()补充自动序列化
        InetAddress oAddress=(InetAddress )inputStream.readObject();
        int iPort =inputStream.readInt();
         oSocket = new Socket (oAddress,iPort);
         iID=getID();
         dtToday =new Date ();
    } 

 

完全定制序列化过程:

     如果一个类要完全负责自己的序列化,则实现Externalizable接口而不是Serializable接口。Externalizable接口定义包括两个方法writeExternal()与readExternal()。利用这些方法可以控制对象数据成员如何写入字节流.类实现 Externalizable时,头写入对象流中,然后类完全负责序列化和恢复数据成员,除了头以外,根本没有自动序列化。这里要注意了。声明类实现 Externalizable接口会有重大的安全风险。writeExternal()与readExternal()方法声明为public,恶意类可以用这些方法读取和写入对象数据。如果对象包含敏感信息,则要格外小心。这包括使用安全套接或加密整个字节流。到此为至,我们学习了序列化的基础部分知识。

 

 

 

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值