Showing posts with label java. Show all posts
Showing posts with label java. Show all posts

Thursday, December 17, 2009

在Java中,什么是Overriding?什么是Overloading?

更多精彩请到 http://www.139ya.com

Java中,什么是Overriding?什么是Overloading

1.Overriding
Overriding翻译过来是重写/覆盖 它是覆盖了一个方法并且对其重写,以求达到不同的作用。对我们来说最熟悉的覆盖就是对接口方法的实现,在接口中一般只是对方法进行了声明,而我们在实现时,就需要实现接口声明的所有方法。除了这个典型的用法以外,我们在继承中也可能会在子类覆盖父类中的方法。
重写的主要特点是:
1)方法名必须与被重写方法一致。
2)方法参数列表必须与被重写方法一致。
3)返回类型必须与被重写方法一致。
4重写的方法不能降低原方法的"可见度"
例如:被重写方法为protected void do(int i,double d),则重写方法可以为protected void do(int i,double d),或者public void do(int i,double d),但是不可以是private void do(int i,double d)
5)不能抛出新的异常或者"更宽的"异常。
例如:被重写方法为public void do(int i,double d) throws IOException,则重写方法可以为public void do(int i,double d) throws IOException ,或者public void do(int i,double d) throws ddeeException(IOException的子类),但是不可以是public void do(int i,double d) throws Exception,因为ExceptionIOException的父类,比IOException"更宽"
6)被覆盖的方法不能为private,否则在其子类中只是新定义了一个方法,并没有对其进行覆盖。
2.Overloading
Overloading,翻译成重载 它是指我们可以定义一些名称相同的方法,通过定义不同的输入参数来区分这些方法,然后再调用时,VM就会根据不同的参数样式,来选择合适的方法执行。
其特点是:
1)各重载的方法名一致。
2)各重载方法的参数列表不一样(包括参数类型,参数个数,参数顺序3项中的一项或多项)。
3)返回类型任意。(不能通过方法的返回值来区分重载方法。)
4)访问控制符任意。(不能通过方法的访问权限来区分重载方法。)
5)可以任意抛出自身的异常,而不管被重载方法。(不能通过抛出的异常来区分重载方法。)
Overloading是指“Two or more methods can have the same name if they have different numbers or types of parameters and thus different signatures. ”显然,对重载的唯一要求就是参数列表必须改变,否则就不是重载了。
3.类型转换中的重载
在一些情况下,Java 的自动类型转换也适用于重载方法的自变量。例如,看下面的程序:

// Automatic type conversions apply to overloading.
class OverloadDemo {
void test() {
System.out.println("No parameters");
}
// Overload test for two integer parameters.
void test(int a, int b) {
System.out.println("a and b: " + a + " " + b);
}
// overload test for a double parameter
void test(double a) {
System.out.println("Inside test(double) a: " + a);
}
}
class Overload {
public static void main(String args[]) {
OverloadDemo ob = new OverloadDemo();
int i = 88;
ob.test();
ob.test(10, 20);
ob.test(i); // this will invoke test(double)
ob.test(123.2); // this will invoke test(double)
}
}

该程序产生如下输出:
No parameters
a and b: 10 20
Inside test(double) a: 88
Inside test(double) a: 123.2
在本例中,OverloadDemo 的这个版本没有定义test(int) 。因此当在Overload 内带整数参数调用test()时,找不到和它匹配的方法。但是,Java 可以自动地将整数转换为double 型,这种转换就可以解决这个问题。因此,在test(int) 找不到以后,Java i扩大到double 型,然后调用test(double) 。当然,如果定义了test(int) ,当然先调用test(int) 而不会调用test(double) 。只有在找不到精确匹配时,Java 的自动转换才会起作用,而且总是找到参数类型最"匹配"的方法,即它的形参比实参且是最接近的。
4.参考资料
[1]Thinking in Java 3rd
[2] OverridingOverloading
[url]http://blog.csdn.net/andyjava2006/archive/[/url]2006/09/13/1218858.aspx
[3] 彻底学习Java语言中的覆盖和重载
[url]http://www.blog.edu.cn/user2/41584/archives/2006/1325849.shtml[/url]
[4] JAVA 方法重载
[url]http://blog.sina.com.cn/u/[/url]538402f901000685

Thursday, November 19, 2009

Installing and Configuring SSL Support

更多精彩请到 http://www.139ya.com

http://java.sun.com/j2ee/1.4/docs/tutorial/doc/Security6.html



Installing and Configuring SSL Support

What Is Secure Socket Layer Technology?

Secure Socket Layer (SSL) technology allows web browsers and web servers to communicate over a secure connection. In this secure connection, the data that is being sent is encrypted before being sent and then is decrypted upon receipt and before processing. Both the browser and the server encrypt all traffic before sending any data. SSL addresses the following important security considerations.

  • Authentication: During your initial attempt to communicate with a web server over a secure connection, that server will present your web browser with a set of credentials in the form of a server certificate. The purpose of the certificate is to verify that the site is who and what it claims to be. In some cases, the server may request a certificate that the client is who and what it claims to be (which is known as client authentication).
  • Confidentiality: When data is being passed between the client and the server on a network, third parties can view and intercept this data. SSL responses are encrypted so that the data cannot be deciphered by the third party and the data remains confidential.
  • Integrity: When data is being passed between the client and the server on a network, third parties can view and intercept this data. SSL helps guarantee that the data will not be modified in transit by that third party.

To install and configure SSL support on your stand-alone web server, you need the following components. SSL support is already provided if you are using the Application Server. If you are using a different web server, consult the documentation for your product.

To verify that SSL support is enabled, see Verifying SSL Support.

Understanding Digital Certificates


Note: Digital certificates for the Application Server have already been generated and can be found in the directory <J2EE_HOME>/domains/domain1/config/. These digital certificates are self-signed and are intended for use in a development environment; they are not intended for production purposes. For production purposes, generate your own certificates and have them signed by a CA.


To use SSL, an application server must have an associated certificate for each external interface, or IP address, that accepts secure connections. The theory behind this design is that a server should provide some kind of reasonable assurance that its owner is who you think it is, particularly before receiving any sensitive information. It may be useful to think of a certificate as a "digital driver's license" for an Internet address. It states with which company the site is associated, along with some basic contact information about the site owner or administrator.

The digital certificate is cryptographically signed by its owner and is difficult for anyone else to forge. For sites involved in e-commerce or in any other business transaction in which authentication of identity is important, a certificate can be purchased from a well-known certificate authority (CA) such as VeriSign or Thawte.

Sometimes authentication is not really a concern--for example, an administrator may simply want to ensure that data being transmitted and received by the server is private and cannot be snooped by anyone eavesdropping on the connection. In such cases, you can save the time and expense involved in obtaining a CA certificate and simply use a self-signed certificate.

SSL uses public key cryptography, which is based on key pairs. Key pairs contain one public key and one private key. If data is encrypted with one key, it can be decrypted only with the other key of the pair. This property is fundamental to establishing trust and privacy in transactions. For example, using SSL, the server computes a value and encrypts the value using its private key. The encrypted value is called a digital signature. The client decrypts the encrypted value using the server's public key and compares the value to its own computed value. If the two values match, the client can trust that the signature is authentic, because only the private key could have been used to produce such a signature.

Digital certificates are used with the HTTPS protocol to authenticate web clients. The HTTPS service of most web servers will not run unless a digital certificate has been installed. Use the procedure outlined later to set up a digital certificate that can be used by your web server to enable SSL.

One tool that can be used to set up a digital certificate is keytool, a key and certificate management utility that ships with the J2SE SDK. It enables users to administer their own public/private key pairs and associated certificates for use in self-authentication (where the user authenticates himself or herself to other users or services) or data integrity and authentication services, using digital signatures. It also allows users to cache the public keys (in the form of certificates) of their communicating peers. For a better understanding of keytool and public key cryptography, read the keytool documentation at the following URL:

http://java.sun.com/j2se/1.5.0/docs/tooldocs/solaris/key-
tool.html

Creating a Server Certificate

A server certificate has already been created for the Application Server. The certificate can be found in the <J2EE_HOME>/domains/domain1/config/ directory. The server certificate is in keystore.jks. The cacerts.jks file contains all the trusted certificates, including client certificates.

If necessary, you can use keytool to generate certificates. The keytool stores the keys and certificates in a file termed a keystore, a repository of certificates used for identifying a client or a server. Typically, a keystore contains one client or one server's identity. The default keystore implementation implements the keystore as a file. It protects private keys by using a password.

The keystores are created in the directory from which you run keytool. This can be the directory where the application resides, or it can be a directory common to many applications. If you don't specify the keystore file name, the keystores are created in the user's home directory.

To create a server certificate follow these steps:

  1. Create the keystore.
  2. Export the certificate from the keystore.
  3. Sign the certificate.
  4. Import the certificate into a trust-store: a repository of certificates used for verifying the certificates. A trust-store typically contains more than one certificate. An example using a trust-store for SSL-based mutual authentication is discussed in Example: Client-Certificate Authentication over HTTP/SSL with JAX-RPC.

Run keytool to generate the server keystore, which we will name keystore.jks. This step uses the alias server-alias to generate a new public/private key pair and wrap the public key into a self-signed certificate inside keystore.jks. The key pair is generated using an algorithm of type RSA, with a default password of changeit. For more information on keytool options, see its online help at http://java.sun.com/j2se/1.5.0/docs/tooldocs/solaris/keytool.html.


Note: RSA is public-key encryption technology developed by RSA Data Security, Inc. The acronym stands for Rivest, Shamir, and Adelman, the inventors of the technology.


From the directory in which you want to create the keystore, run keytool with the following parameters.

  1. Generate the server certificate.
  2. <JAVA_HOME>\bin\keytool -genkey -alias server-alias
    -keyalg RSA -keypass changeit -storepass changeit
    -keystore keystore.jks

    When you press Enter, keytool prompts you to enter the server name, organizational unit, organization, locality, state, and country code. Note that you must enter the server name in response to keytool's first prompt, in which it asks for first and last names. For testing purposes, this can be localhost. The host specified in the keystore must match the host identified in the host variable specified in the <INSTALL>/j2eetutorial14/examples/common/build.properties when running the example applications.

  3. Export the generated server certificate in keystore.jks into the file server.cer.
  4. <JAVA_HOME>\bin\keytool -export -alias server-alias
    -storepass changeit -file server.cer -keystore keystore.jks

  5. If you want to have the certificate signed by a CA, read Signing Digital Certificates for more information.
  6. To create the trust-store file cacerts.jks and add the server certificate to the trust-store, run keytool from the directory where you created the keystore and server certificate. Use the following parameters:
  7. <JAVA_HOME>\bin\keytool -import -v -trustcacerts
    -alias server-alias -file server.cer
    -keystore cacerts.jks -keypass changeit
    -storepass changeit

    Information on the certificate, such as that shown next, will display.

    <INSTALL>/j2eetutorial14/examples/gs 60% keytool -import
    -v -trustcacerts -alias server-alias -file server.cer
    -keystore cacerts.jks -keypass changeit -storepass changeit
    Owner: CN=localhost, OU=Sun Micro, O=Docs, L=Santa Clara, ST=CA, C=US
    Issuer: CN=localhost, OU=Sun Micro, O=Docs, L=Santa Clara, ST=CA, C=US
    Serial number: 3e932169
    Valid from: Tue Apr 08
    Certificate fingerprints:
    MD5: 52:9F:49:68:ED:78:6F:39:87:F3:98:B3:6A:6B:0F:90
    SHA1: EE:2E:2A:A6:9E:03:9A:3A:1C:17:4A:28:5E:97:20:78:3F:
    Trust this certificate? [no]:

  8. Enter yes, and then press the Enter or Return key. The following information displays:
  9. Certificate was added to keystore
    [Saving cacerts.jks]

Signing Digital Certificates

After you've created a digital certificate, you will want to have it signed by its owner. After the digital certificate has been cryptographically signed by its owner, it is difficult for anyone else to forge. For sites involved in e-commerce or any other business transaction in which authentication of identity is important, a certificate can be purchased from a well-known certificate authority such as VeriSign or Thawte.

As mentioned earlier, if authentication is not really a concern, you can save the time and expense involved in obtaining a CA certificate and simply use the self-signed certificate.

Using a Different Server Certificate with the Application Server

Follow the steps in Creating a Server Certificate, to create your own server certificate, have it signed by a CA, and import the certificate into keystore.jks.

Make sure that when you create the certificate, you follow these rules:

  • When you press create the server certificate, keytool prompts you to enter your first and last name. In response to this prompt, you must enter the name of your server. For testing purposes, this can be localhost.
  • The server/host specified in the keystore must match the host identified in the host variable specified in the <INSTALL>/j2eetutorial14/examples/common/build.properties file for running the example applications.
  • Your key/certificate password in keystore.jks should match the password of your keystore, keystore.jks. This is a bug. If there is a mismatch, the Java SDK cannot read the certificate and you get a "tampered" message.
  • If you want to replace the existing keystore.jks, you must either change your keystore's password to the default password (changeit) or change the default password to your keystore's password:

To specify that the Application Server should use the new keystore for authentication and authorization decisions, you must set the JVM options for the Application Server so that they recognize the new keystore. To use a different keystore than the one provided for development purposes, follow these steps.

  1. Start the Application Server if you haven't already done so. Information on starting the Application Server can be found in Starting and Stopping the Application Server.
  2. Start the Admin Console. Information on starting the Admin Console can be found in Starting the Admin Console.
  3. Select Application Server in the Admin Console tree.
  4. Select the JVM Settings tab.
  5. Select the JVM Options tab.
  6. Change the following JVM options so that they point to the location and name of the new keystore. There current settings are shown below:
  7. -Djavax.net.ssl.keyStore=${com.sun.aas.instanceRoot}/config/keystore.jks
    -Djavax.net.ssl.trustStore=${com.sun.aas.instanceRoot}/config/cacerts.jks

  8. If you've changed the keystore password from its default value, you need to add the password option as well:
    -Djavax.net.ssl.keyStorePassword=your_new_password
  9. Logout of the Admin Console and restart the Application Server.

Creating a Client Certificate for Mutual Authentication

This section discusses setting up client-side authentication. When both server-side and client-side authentication are enabled, it is called mutual, or two-way, authentication. In client authentication, clients are required to submit certificates that are issued by a certificate authority that you choose to accept. From the directory where you want to create the client certificate, run keytool as outlined here. When you press Enter, keytool prompts you to enter the server name, organizational unit, organization, locality, state, and country code.


Note: You must enter the server name in response to keytool's first prompt, in which it asks for first and last names. For testing purposes, this can be localhost. The host specified in the keystore must match the host identified in the host variable specified in the <INSTALL>/j2eetutorial14/examples/common/build.properties file. If this example is to verify mutual authentication and you receive a runtime error stating that the HTTPS host name is wrong, re-create the client certificate, being sure to use the same host name that you will use when running the example. For example, if your machine name is duke, then enter duke as the certificate CN or when prompted for first and last names. When accessing the application, enter a URL that points to the same location--for example, https://duke:8181/mutualauth/hello. This is necessary because during SSL handshake, the server verifies the client certificate by comparing the certificate name and the host name from which it originates.


To create a keystore named client-keystore.jks that contains a client certificate named client.cer, follow these steps:

  1. Generate the client certificate.
  2. <JAVA_HOME>\bin\keytool -genkey -alias client-alias -keyalg RSA -keypass changeit
    -storepass changeit -keystore keystore.jks

  3. Export the generated client certificate into the file client.cer.
  4. <JAVA_HOME>\bin\keytool -export -alias client-alias
    -storepass changeit -file client.cer -keystore keystore.jks

  5. Add the certificate to the trust-store file <J2EE_HOME>/domains/domain1/config/cacerts.jks. Run keytool from the directory where you created the keystore and client certificate. Use the following parameters:
  6. <JAVA_HOME>\bin\keytool -import -v -trustcacerts
    -alias client-alias -file client.cer
    -keystore <
    J2EE_HOME>/domains/domain1/config/cacerts.jks
    -keypass changeit -storepass changeit

    The keytool utility returns this message:

    Owner: CN=J2EE Client, OU=Java Web Services, O=Sun, L=Santa Clara, ST=CA, C=US
    Issuer: CN=J2EE Client, OU=Java Web Services, O=Sun, L=Santa Clara, ST=CA, C=US
    Serial number: 3e39e66a
    Valid from: Thu Jan 30 18:58:50 PST 2003 until: Wed Apr 30
    19:58:50 PDT 2003
    Certificate fingerprints:
    MD5: 5A:B0:4C:88:4E:F8:EF:E9:E5:8B:53:BD:D0:AA:8E:5A
    SHA1:90:00:36:5B:E0:A7:A2:BD:67:DB:EA:37:B9:61:3E:26:B3:89:46:
    32
    Trust this certificate? [no]: yes
    Certificate was added to keystore

For an example application that uses mutual authentication, see Example: Client-Certificate Authentication over HTTP/SSL with JAX-RPC. For information on verifying that mutual authentication is running, see Verifying That Mutual Authentication Is Running.

Miscellaneous Commands for Certificates

To check the contents of a keystore that contains a certificate with an alias server-alias, use this command:

keytool -list -keystore keystore.jks -alias server-alias -v

To check the contents of the cacerts file, use this command:

keytool -list -keystore cacerts.jks

Using SSL

An SSL connector is preconfigured for the Application Server. You do not have to configure anything. If you are working with another application server, see its documentation for setting up its SSL connector.

Verifying SSL Support

For testing purposes, and to verify that SSL support has been correctly installed, load the default introduction page with a URL that connects to the port defined in the server deployment descriptor:

https://localhost:8181/ 

The https in this URL indicates that the browser should be using the SSL protocol. The localhost in this example assumes that you are running the example on your local machine as part of the development process. The 8181 in this example is the secure port that was specified where the SSL connector was created in Using SSL. If you are using a different server or port, modify this value accordingly.

The first time a user loads this application, the New Site Certificate or Security Alert dialog box displays. Select Next to move through the series of dialog boxes, and select Finish when you reach the last dialog box. The certificates will display only the first time. When you accept the certificates, subsequent hits to this site assume that you still trust the content.

Tips on Running SSL

The SSL protocol is designed to be as efficient as securely possible. However, encryption and decryption are computationally expensive processes from a performance standpoint. It is not strictly necessary to run an entire web application over SSL, and it is customary for a developer to decide which pages require a secure connection and which do not. Pages that might require a secure connection include login pages, personal information pages, shopping cart checkouts, or any pages where credit card information could possibly be transmitted. Any page within an application can be requested over a secure socket by simply prefixing the address with https: instead of http:. Any pages that absolutely require a secure connection should check the protocol type associated with the page request and take the appropriate action if https: is not specified.

Using name-based virtual hosts on a secured connection can be problematic. This is a design limitation of the SSL protocol itself. The SSL handshake, where the client browser accepts the server certificate, must occur before the HTTP request is accessed. As a result, the request information containing the virtual host name cannot be determined before authentication, and it is therefore not possible to assign multiple certificates to a single IP address. If all virtual hosts on a single IP address need to authenticate against the same certificate, the addition of multiple virtual hosts should not interfere with normal SSL operations on the server. Be aware, however, that most client browsers will compare the server's domain name against the domain name listed in the certificate, if any (this is applicable primarily to official, CA-signed certificates). If the domain names do not match, these browsers will display a warning to the client. In general, only address-based virtual hosts are commonly used with SSL in a production environment.

Enabling Mutual Authentication over SSL

This section discusses setting up client-side authentication. As mentioned earlier, when both server-side and client-side authentication are enabled, it is called mutual, or two-way, authentication. In client authentication, clients are required to submit certificates that are issued by a certificate authority that you choose to accept. If you regulate it through the application (via the Client-Certificate authentication requirement), the check is performed when the application requires client authentication. You must enter the keystore location and password in the web server configuration file to enable SSL, as discussed in Using SSL.

Here are two ways to enable mutual authentication over SSL:

  • PREFERRED: Set the method of authentication to Client-Certificate using deploytool. This enforces mutual authentication by modifying the deployment descriptor of the given application. By enabling client authentication in this way, client authentication is enabled only for a specific resource controlled by the security constraint. Setting client authentication in this way is discussed in Example: Client-Certificate Authentication over HTTP/SSL with JAX-RPC.
  • RARELY: Set the clientAuth property in the certificate realm to true. To do this, follow these steps:
    1. Start the Application Server if you haven't already done so. Information on starting the Application Server can be found in Starting and Stopping the Application Server.
    2. Start the Admin Console. Information on starting the Admin Console can be found in Starting the Admin Console.
    3. In the Admin Console tree, expand Configuration, expand Security, then expand Realms, and then select certificate. The certificate realm is used for all transfers over HTTP with SSL.
    4. Select Add to add the property of clientAuth to the server. Enter clientAuth in the Name field, and enter true in the Value field.
    5. Click Save to save these new properties.
    6. Log out of the Admin Console.

When client authentication is enabled in both of these ways, client authentication will be performed twice.

Verifying That Mutual Authentication Is Running

You can verify that mutual authentication is working by obtaining debug messages. This should be done at the client end, and this example shows how to pass a system property in targets.xml so that targets.xml forks a client with javax.net.debug in its system properties, which could be added in a file such as <INSTALL>/j2eetutorial14/examples/security/common/targets.xml.

To enable debug messages for SSL mutual authentication, pass the system property javax.net.debug=ssl,handshake, which will provide information on whether or not mutual authentication is working. The following example modifies the run-mutualauth-client target from the <INSTALL>/j2eetutorial14/examples/security/common/targets.xml file by adding sysproperty as shown in bold:

description="Runs a client with mutual authentication over
SSL">



value="${key.store}" />
value="${key.store.password}"/>



Wednesday, April 22, 2009

httpurlconnection 超时设置 (jdk1.4)

更多精彩请到 http://www.139ya.com


import java.util.*;
import java.net.*;
import java.io.*;
public class TimedUrlConnection implements Observer {
private URLConnection ucon = null;
private int time = 300000;//max time out
private boolean connected = false;
public TimedUrlConnection (URLConnection ucon,int time) {
this.ucon = ucon;
this.time = time;
}
public boolean connect() {
ObservableURLConnection ouc = new
ObservableURLConnection(ucon);
ouc.addObserver(this);
Thread ouct = new Thread(ouc);
ouct.start();
try {
ouct.join(time);
}
catch (InterruptedException i) {
//false, but should already be false
}
return(connected);
}
public void update(Observable o, Object arg) {
connected = true;
}//end of public void update(Observable o, Object arg)
}
class ObservableURLConnection extends Observable implements Runnable {
private URLConnection ucon;
public ObservableURLConnection(URLConnection ucon) {
this.ucon = ucon;
}//end of constructor
public void run() {
try {
ucon.connect();
setChanged();
notifyObservers();
}
catch (IOException e) {
}
}//end of public void run()
}



//~~~~~~~~~~~~~~~~~~~Usage~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
URL url=new URL(someurlname);
URLConnection urlconn=url.openConnection();
TimedUrlConnection timeoutconn=new TimedUrlConnection(urlconn,100000);//time out: 100seconds
boolean bconnectok=timeoutconn.connect();
if(bconnectok==false)
{
//urlconn fails to connect in 100seconds
}
else
{
//connect ok
}

http://topic.csdn.net/t/20010823/09/252141.html

(二)

HttpURLConnection中如何设置网络超时
2005年02月03日 益众网
作者:happy_fish


Java中可以使用HttpURLConnection来请求WEB资源。
HttpURLConnection对象不能直接构造,需要通过URL.openConnection()来获得HttpURLConnection对象,示例代码如下:
String szUrl = "http://www.ee2ee.com/";
URL url = new URL(szUrl);
HttpURLConnection urlCon = (HttpURLConnection)url.openConnection();

HttpURLConnection是基于HTTP协议的,其底层通过socket通信实现。如果不设置超时(timeout),在网络异常的情况下,可能会导致程序僵死而不继续往下执行。可以通过以下两个语句来设置相应的超时:
System.setProperty("sun.net.client.defaultConnectTimeout", 超时毫秒数字符串);
System.setProperty("sun.net.client.defaultReadTimeout", 超时毫秒数字符串);
其中: sun.net.client.defaultConnectTimeout:连接主机的超时时间(单位:毫秒)
sun.net.client.defaultReadTimeout:从主机读取数据的超时时间(单位:毫秒)

例如:
System.setProperty("sun.net.client.defaultConnectTimeout", "30000");
System.setProperty("sun.net.client.defaultReadTimeout", "30000");

JDK 1.5以前的版本,只能通过设置这两个系统属性来控制网络超时。在1.5中,还可以使用HttpURLConnection的父类URLConnection的以下两个方法:
setConnectTimeout:设置连接主机超时(单位:毫秒)
setReadTimeout:设置从主机读取数据超时(单位:毫秒)

例如:
HttpURLConnection urlCon = (HttpURLConnection)url.openConnection();
urlCon.setConnectTimeout(30000);
urlCon.setReadTimeout(30000);

需要注意的是,笔者在JDK1.4.2环境下,发现在设置了defaultReadTimeout的情况下,如果发生网络超时,HttpURLConnection会自动重新提交一次请求,出现一次请求调用,请求服务器两次的问题(Trouble)。

【Java】java.net.HttpURLConnection的使用

更多精彩请到 http://www.139ya.com


1.网页内容获取
java.io.inputstream in;
java.net.url url = new java.net.url(www.xyz.com/content.html);
java.net.httpurlconnection connection = (java.net.httpurlconnection)
url.openconnection();
connection = (java.net.httpurlconnection) url.openconnection();
//模拟成ie
connection.setrequestproperty("user-agent","mozilla/4.0 (compatible; msie 6.0; windows 2000)");
connection.connect();
in = connection.getinputstream();
java.io.bufferedreader breader =
new bufferedreader(new inputstreamreader(in , "gbk"));
string str=breader.readline());
while(st != null){
system.out.println(str);
str=breader.readline());
}
2.cookie管理

1.直接的方式
取得cookie:
httpurlconnection huc= (httpurlconnection) url.openconnection();
inputstream is = huc.getinputstream();
// 取得sessionid.
string cookieval = hc.getheaderfield("set-cookie");
string sessionid;
if(cookieval != null)
{
sessionid = cookieval.substring(0, cookieval.indexof(";"));
}

发送设置cookie:
httpurlconnection huc= (httpurlconnection) url.openconnection();
if(sessionid != null)
{
huc.setrequestproperty("cookie", sessionid);
}
inputstream is = huc.getinputstream();



2.利用的jcookie包(http://jcookie.sourceforge.net/ )
获取cookie:
url url = new url("http://www.site.com/");
httpurlconnection huc = (httpurlconnection) url.openconnection();
huc.connect();
inputstream is = huc.getinputstream();
client client = new client();
cookiejar cj = client.getcookies(huc);


新的请求,利用上面获取的cookie:

url = new url("http://www.site.com/");
huc = (httpurlconnection) url.openconnection();
client.setcookies(huc, cj);


3.post方式的模拟
url url = new url("www.xyz.com");
httpurlconnection huc = (httpurlconnection) url.openconnection();
//设置允许output
huc.setdooutput(true);
//设置为post方式
huc.setrequestmethod("post");
huc.setrequestproperty("user-agent","mozilla/4.7 [en] (win98; i)");
stringbuffer sb = new stringbuffer();
sb.append("username="+usernme);
sb.append("&password="+password);

//post信息
outputstream os = huc.getoutputstream();
os.write(sb.tostring().getbytes("gbk"));
os.close();

bufferedreader br = new bufferedreader(new inputstreamreader(huc.getinputstream()))


huc.connect();

string line = br.readline();

while(line != null){

l

system.out.printli(line);


line = br.readline();

}

[JAVA]使用HttpURLConnection进行POST方式提交

更多精彩请到 http://www.139ya.com

转自: http://www.blogjava.net/sunfruit/archive/2006/03/13/35048.html

[JAVA]使用HttpURLConnection进行POST方式提交

--sunfruit

用HttpURLConnection进行Post方式提交,下面给出一个例子

URL url = null;
HttpURLConnection httpurlconnection = null;
try
{
url = new URL("http://xxxx");

httpurlconnection = (HttpURLConnection) url.openConnection();
httpurlconnection.setDoOutput(true);
httpurlconnection.setRequestMethod("POST");
String username="username=02000001";
httpurlconnection.getOutputStream().write(username.getBytes());
httpurlconnection.getOutputStream().flush();
httpurlconnection.getOutputStream().close();
int code = httpurlconnection.getResponseCode();
System.out.println("code " + code);

}
catch(Exception e)
{
e.printStackTrace();
}
finally
{
if(httpurlconnection!=null)
httpurlconnection.disconnect();
}

其中HttpURLConnection中的addRequestProperty方法,并不是用来添加Parameter 的,而是用来设置请求的头信息,比如:
setRequestProperty("Content-type","text/html");
setRequestProperty("Connection", "close");
setRequestProperty("Content-Length",xxx);

当然如果不设置的话,可以走默认值,上面的例子中就没有进行相关设置,但是也可以正确执行

利用java的HttpURLConnection和Servlet通信,Post方式

更多精彩请到 http://www.139ya.com


利用java的HttpURLConnection和Servlet通信,Post方式


import java.net.*;
import java.io.*;

public class testPost {
public static void main() {
URL url = null;
HttpURLConnection conn = null;

try {
url = new URL("http://localhost/projectname/servletname"); //构造好这个URL对象,参数就是你要通信的servlet地址,实际测试的时候,这个URL可以从Properties文件中取得,以增加灵活性
conn = (HttpURLConnection)url.openConnection(); //打开,创建Connection对象

conn.setRequestMethod("POST"); //设定请求方式为POST
conn.setDoOutput(true); //一定要设为true,因为要发送数据

//下面开始设定Http头
conn.setRequestProperty("Content-Type","multipart/form-data; boundary=Bounday---");
conn.setRequestProperty("Cache-Control","no-cache");
.......

// 传送送据
OutputStream buf = conn.getOutoutStream();
buf = new BufferedOutputStream(buf);

OutputStreamWriter out = new OutputStreamWriter (buf);
out.write("这里是要传送的数据");
//比方说如下的格式,当然这是自己规定的格式,这些都可以从配置文件中设定,然后读取
//Bounday---
//Content-Disposition: form-data; name="testRequestHeader"
// Data = aabbccddeeffgghh
//--Bounday---
out.flush(); //这个一定要
out.clost();

//接收数据
InputStream in = conn.getInputStream();
in = new BufferedOutputStream(buf);
Reader rData = new InputStreamReader(in);

int c;

System.out.println("=====================Result==========================");
while((c=rData.read()) != -1)
System.out.print((char)c);
System.out.println("===================================================");

in.close();
} catch (Exception e) {
e.printStackTrace();
} finally {
}
}
}

java httpurlconnection 登录网站 完整代码

更多精彩请到 http://www.139ya.com



1. import java.io.*;
2. import java.util.*;
3. import java.net.*;
4.
5. public class WebTest {
6.
7. public static void main(String[] args) {
8.
9. System.out.println("beging...");
10. DownLoadPages("http://login.xiaonei.com/Login.do", "d:/fileDown.txt");
11. // visit("http://www.xiaonei.com");
12. System.out.println("end.");
13. }
14.
15. public static void DownLoadPages(String urlStr, String outPath) {
16. int chByte = 0;
17.
18. URL url = null;
19.
20. HttpURLConnection httpConn = null;
21.
22. InputStream in = null;
23.
24. FileOutputStream out = null;
25.
26. try {
27. String post = "email=" + URLEncoder.encode("e-mail", "UTF-8")
28. + "&password=" + "password";
29. url = new URL(urlStr);
30.
31. httpConn = (HttpURLConnection) url.openConnection();
32.
33. //setInstanceFollowRedirects can then be used to set if
34. //redirects should be followed or not and this should be used before the
35. //connection is established (via getInputStream, getResponseCode, and other
36. //methods that result in the connection being established).
37.
38. httpConn.setFollowRedirects(false);
39.
40. //inorder to disable the redirects
41. httpConn.setInstanceFollowRedirects(false);
42.
43. httpConn.setDoOutput(true);
44. httpConn.setDoInput(true);
45. httpConn.setRequestProperty("User-Agent",
46. "Mozilla/5.0 (compatible; MSIE 6.0; Windows NT)");
47. httpConn.setRequestProperty("Content-Type",
48. "application/x-www-form-urlencoded");
49.
50. //ok now, we can post it
51. PrintStream send = new PrintStream(httpConn.getOutputStream());
52. send.print(post);
53. send.close();
54. URL newURL = new URL(httpConn.getHeaderField("Location"));
55. System.out.println("the URL has move to "
56. + httpConn.getHeaderField("Location"));
57. httpConn.disconnect();
58.
59. // OK, now we are ready to get the cookies out of the URLConnection
60. String cookies = getCookies(httpConn);
61. System.out.println(cookies);
62. httpConn = (HttpURLConnection) newURL.openConnection();
63. httpConn.setRequestProperty("User-Agent",
64. "Mozilla/5.0 (compatible; MSIE 6.0; Windows NT)");
65. httpConn.setRequestProperty("Content-Type",
66. "application/x-www-form-urlencoded");
67. httpConn.setRequestProperty("Cookie", cookies);
68.
69. httpConn.setDoInput(true);
70. in = httpConn.getInputStream();
71. out = new FileOutputStream(new File(outPath));
72.
73. chByte = in.read();
74. while (chByte != -1) {
75. out.write(chByte);
76. //System.out.println(chByte);
77. chByte = in.read();
78. }
79. } catch (Exception e) {
80. e.printStackTrace();
81. }
82. }
83.
84. public static String getCookies(HttpURLConnection conn) {
85. StringBuffer cookies = new StringBuffer();
86. String headName;
87. for (int i = 7; (headName = conn.getHeaderField(i)) != null; i++) {
88. StringTokenizer st = new StringTokenizer(headName, "; ");
89. while (st.hasMoreTokens()) {
90. cookies.append(st.nextToken() + "; ");
91. }
92. }
93. return cookies.toString();
94. }
95. }

Tuesday, April 21, 2009

java异常机制介绍

更多精彩请到 http://www.139ya.com

java异常机制介绍 : http://hwangita.blog.ccidnet.com/blog-htm-do-showone-uid-45279-itemid-137486-type-blog.html

java异常机制介绍

Java 语言要求 java 程序中(无论是谁写的代码),所有抛出( throw )的异常都必须是从 Throwable 派生而来。当然,实际的 Java 编程中,由于 JDK 平台已经为我们设计好了非常丰富和完整的异常对象分类模型。因此, java 程序员一般是不需要再重新定义自己的异常对象。而且即便是需要扩展自定义的异常对象,也往往会从 Exception 派生而来。所以,对于 java 程序员而言,它一般只需要在它的顶级函数中 catch(Exception ex) 就可以捕获出所有的异常对象。 所有异常对象的根基类是 Throwable , Throwable 从 Object 直接继承而来(这是 java 系统所强制要求的),并且它实现了 Serializable 接口(这为所有的异常对象都能够轻松跨越 Java 组件系统做好了最充分的物质准备)。从 Throwable 直接派生出的异常类有 Exception 和 Error 。 Exception 是 java 程序员所最熟悉的,它一般代表了真正实际意义上的异常对象的根基类。也即是说, Exception 和从它派生而来的所有异常都是应用程序能够 catch 到的,并且可以进行异常错误恢复处理的异常类型。而 Error 则表示 Java 系统中出现了一个非常严重的异常错误,并且这个错误可能是应用程序所不能恢复的,例如 LinkageError ,或 ThreadDeath 等。


首先还是看一个例子吧!代码如下:
import java.io.*;
public class Trans
{
public static void main(String[] args)
{
try
{
BufferedReader rd=null;
Writer wr=null;
try
{
File srcFile = new File((args[0]));
File dstFile = new File((args[1]));
rd = new BufferedReader(new InputStreamReader(new FileInputStream(srcFile), args[2]));
wr = new OutputStreamWriter(new FileOutputStream(dstFile), args[3]);
// 注意下面这条语句,它有什么问题吗?
if (rd == null || wr == null) throw new Exception("error! test!");
while(true)
{
String sLine = rd.readLine();
if(sLine == null) break;
wr.write(sLine);
wr.write("\r\n");
}
}
finally
{
wr.flush();
wr.close();
rd.close();
}
}
catch(IOException ex)
{
ex.printStackTrace();
}
}
}
熟悉 java 语言的程序员朋友们,你们认为上面的程序有什么问题吗?编译能通过吗?如果不能,那么原因又是为何呢?好了,有了自己的分析和预期之后,不妨亲自动手编译一下上面的小程序,呵呵!结果确实如您所料?是的,的确是编译时报错了,错误信息如下:
E:\Trans.java:20: unreported exception java.lang.Exception; must be caught or declared to be thrown
if (rd == null || wr == null) throw new Exception("error! test!");
1 error
上面这种编译错误信息,相信 Java 程序员肯定见过(可能还是屡见不鲜!)!
相信老练一些的 Java 程序员一定非常清楚上述编译出错的原因。那就是如错误信息中(“ must be caught ”)描述的那样, 在 Java 的异常处理模型中,要求所有被抛出的异常都必须要有对应的“异常处理模块” 。也即是说,如果你在程序中 throw 出一个异常,那么在你的程序中(函数中)就必须要 catch 这个异常(处理这个异常)。例如上面的例子中,你在第 20 行代码处,抛出了一个 Exception 类型的异常,但是在该函数中,却没有 catch 并处理掉此异常的地方。因此,这样的程序即便是能够编译通过,那么运行时也是致命的(可能导致程序的崩溃),所以, Java 语言干脆在编译时就尽可能地检查(并卡住)这种本不应该出现的错误,这无疑对提高程序的可靠性大有帮助。
但是,在 Java 语言中,这就是必须的。 如果一个函数中,它运行时可能会向上层调用者函数抛出一个异常,那么,它就必须在该函数的声明中显式的注明(采用 throws 关键字) 。还记得刚才那条编译错误信息吗?“ must be caught or declared to be thrown ”,其中“ must be caught ”上面已经解释了,而后半部分呢?“ declared to be thrown ”是指何意呢?其实指的就是“必须显式地声明某个函数可能会向外部抛出一个异常”,也即是说,如果一个函数内部,它可能抛出了一种类型的异常,但该函数内部并不想(或不宜) catch 并处理这种类型的异常,此时,它就必须使用 throws 关键字来声明该函数可能会向外部抛出一个异常,以便于该函数的调用者知晓并能够及时处理这种类型的异常。下面列出了这几种情况的比较,代码如下:
// 示例程序 1 ,这种写法能够编译通过
package com.ginger.exception;
import java.io.*;
public class Trans {
public static void main(String[] args) {
try {
test();
} catch (Exception ex) {
ex.printStackTrace();
}
}
static void test() {
try {
throw new Exception("To show Exception Successed");
} catch (Exception ex) {
ex.printStackTrace();
}
}
}
// 示例程序 2 ,这种写法就不能够编译通过
import java.io.*;
public class Trans {
public static void main(String[] args) {
try {
test();
}
// 虽然这里能够捕获到 Exception 类型的异常
catch (Exception ex) {
ex.printStackTrace();
}
}
static void test() {
throw new Exception("test");
}
}
// 示例程序 3 ,这种写法又能够被编译通过
import java.io.*;
public class Trans
{
public static void main(String[] args)
{
try
{
test();
}
catch(Exception ex)
{
ex.printStackTrace();
}
}
// 由于函数声明了可能抛出 Exception 类型的异常
static void test() throws Exception
{
throw new Exception("test");
}
}
// 示例程序 4 ,它又不能够被编译通过了
import java.io.*;
public class Trans
{
public static void main(String[] args)
{
try
{
// 虽然 test() 函数并没有真正抛出一个 Exception 类型的异常
// 但是由于它函数声明时,表示它可能抛出一个 Exception 类型的异常
// 所以,这里仍然不能被编译通过。
// 呵呵!体会到了 Java 异常处理模型的严谨吧!
test();
}
catch(IOException ex)
{
ex.printStackTrace();
}
}
static void test() throws Exception
{
}
}

总结:用throw时,一定要在函数体内要有对应的catch(),意思是说,抛出IOException e,你就要catch IOException,抛出Exception,就要catch Exception;要对应。
用throws时,上层调用者去catch()就可以了.

不知上面几个有联系的示例是否能够给大家带来“豁然开朗”的感觉,坦率的说, Java 提供的异常处理模型并不复杂,相信太多太多 Java 程序员有着比我更深刻的认识。最后,补充一种例外情况,请看如下代码:
import java.io.*;
public class Trans {
public static void main(String[] args) {
try {
test();
} catch (Exception ex) {
ex.printStackTrace();
}
}
static void test() throws Error {
throw new Error(" 故意抛出一个 Error");
}
}
朋友们!上面的程序能被编译通过吗?注意,按照刚才上面所总结出的规律:在 Java 的异常处理模型中,要求所有被抛出的异常都必须要有对应的 catch 块!那么上面的程序肯定不能被编译通过,因为 Error 和 Exception 都是从 Throwable 直接派生而来,而 test 函数声明了它可能抛出 Error 类型的异常,但在 main 函数中却并没有 catch(Error) 或 catch(Throwable) 块,所以它理当是会编译出错的!真的吗?不妨试试!呵呵!结果并非我们之预料,而它恰恰是正确编译通过了。为何? WHY ? WHY ?
其实,原因很简单,那就是因为 Error 异常的特殊性。 Java 异常处理模型中规定: Error 和从它派生而来的所有异常,都表示系统中出现了一个非常严重的异常错误,并且这个错误可能是应用程序所不能恢复的(其实这在前面的内容中已提到过)。因此,如果系统中真的出现了一个 Error 类型的异常,那么则表明,系统已处于崩溃不可恢复的状态中,此时,作为编写 Java 应用程序的你,已经是没有必要(也没能力)来处理此等异常错误。所以, javac 编译器就没有必要来保证:“在编译时,所有的 Error 异常都有其对应的错误处理模块”。当然, Error 类型的异常一般都是由系统遇到致命的错误时所抛出的,它最后也由 Java 虚拟机所处理。而作为 Java 程序员的你,可能永远也不会考虑抛出一个 Error 类型的异常。因此 Error 是一个特例情况!
特别关注一下 RuntimeException
上面刚刚讨论了一下 Error 类型的异常处理情况, Java 程序员一般无须关注它(处理这种异常)。另外,其实在 Exception 类型的异常对象中,也存在一种比较特别的“异常”类型,那就是 RuntimeException ,虽然它是直接从 Exception 派生而来,但是 Java 编译器( javac )对 RuntimeException 却是特殊待遇,而且是照顾有加。不信,看看下面的两个示例吧!代码如下:
// 示例程序 1
// 它不能编译通过,我们可以理解
import java.io.*;

public class Trans {
public static void main(String[] args) {
test();
}

static void test() {
// 注意这条语句
throw new Exception(" 故意抛出一个 Exception");
}
}
// 示例程序 2
// 可它却为什么能够编译通过呢?
import java.io.*;

public class Trans {
public static void main(String[] args) {
test();
}

static void test() {
// 注意这条语句
throw new RuntimeException(" 故意抛出一个 RuntimeException");
}
}
对上面两个相当类似的程序, javac 编译时却遭遇了两种截然不同的处理,按理说,第 2 个示例程序也应该像第 1 个示例程序那样,编译时报错!但是 javac 编译它时,却例外地让它通过它,而且在运行时, java 虚拟机也捕获到了这个异常,并且会在 console 打印出详细的异常信息。运行结果如下:
java.lang.RuntimeException: 故意抛出一个 RuntimeException
at Trans.test(Trans.java:13)
at Trans.main(Trans.java:8)
Exception in thread "main"
为什么对于 RuntimeException 类型的异常(以及从它派生而出的异常类型), javac 和 java 虚拟机都特殊处理呢?要知道,这可是与“ Java 异常处理模型更严谨和更安全”的设计原则相抵触的呀!究竟是为何呢?这简直让人不法理解呀!
只不过, Java 语言中, RuntimeException 被统一纳入到了 Java 语言和 JDK 的规范之中。请看如下代码,来验证一下我们的理解!
import java.io.*;
public class Trans
{
public static void main(String[] args)
{
test();
}
static void test()
{
int i = 4;
int j = 0;
// 运行时,这里将触发了一个 ArithmeticException
// ArithmeticException 从 RuntimeException 派生而来
System.out.println("i / j = " + i / j);
}
}
运行结果如下:
java.lang.ArithmeticException: / by zero
at Trans.test(Trans.java:16)
at Trans.main(Trans.java:8)
Exception in thread "main"
又如下面的例子,也会产生一个 RuntimeException ,代码如下:
import java.io.*;
public class Trans
{
public static void main(String[] args)
{
test();
}
static void test()
{
String str = null;
// 运行时,这里将触发了一个 NullPointerException
// NullPointerException 从 RuntimeException 派生而来
str.compareTo("abc");
}
}
所以,针对 RuntimeException 类型的异常, javac 是无法通过编译时的静态语法检测来判断到底哪些函数(或哪些区域的代码)可能抛出这类异常(这完全取决于运行时状态,或者说运行态所决定的),也正因为如此, Java 异常处理模型中的“ must be caught or declared to be thrown ”规则也不适用于 RuntimeException (所以才有前面所提到过的奇怪编译现象,这也属于特殊规则吧)。但是, Java 虚拟机却需要有效地捕获并处理此类异常。当然, RuntimeException 也可以被程序员显式地抛出,而且为了程序的可靠性,对一些可能出现“运行时异常( RuntimeException )”的代码区域,程序员最好能够及时地处理这些意外的异常,也即通过 catch(RuntimeExcetion) 或 catch(Exception) 来捕获它们。如下面的示例程序,代码如下:
import java.io.*;
public class Trans
{
public static void main(String[] args)
{
try
{
test();
}
// 在上层的调用函数中,最好捕获所有的 Exception 异常!
catch(Exception e)
{
System.out.println("go here!");
e.printStackTrace();
}
}
// 这里最好显式地声明一下,表明该函数可能抛出 RuntimeException
static void test() throws RuntimeException
{
String str = null;
// 运行时,这里将触发了一个 NullPointerException
// NullPointerException 从 RuntimeException 派生而来
str.compareTo("abc");
}
}

Java异常处理机制的详细讲解和使用技巧

更多精彩请到 http://www.139ya.com

Java异常处理机制的详细讲解和使用技巧: http://www.cn-java.com/www1/?action-viewnews-itemid-3730

1. 异常机制

1.1

异常机制是指当程序出现错误后,程序如何处理。具体来说,异常机制提供了程序退出的安全通道。当出现错误后,程序执行的流程发生改变,程序的控制权转移到异常处理器。

1.2

传统的处理异常的办法是,函数返回一个特殊的结果来表示出现异常(通常这个特殊结果是大家约定俗称的),调用该函数的程序负责检查并分析函数返回的结果。这样做有如下的弊端:例如函数返回-1代表出现异常,但是如果函数确实要返回-1这个正确的值时就会出现混淆;可读性降低,将程序代码与处理异常的代码混爹在一起;由调用函数的程序来分析错误,这就要求客户程序员对库函数有很深的了解。

1.3 异常处理的流程

1.3.1 遇到错误,方法立即结束,并不返回一个值;同时,抛出一个异常对象

1.3.2 调用该方法的程序也不会继续执行下去,而是搜索一个可以处理该异常的异常处理器,并执行其中的代码


2 异常的分类

2.1 异常的分类

2.1.1

异常的继承结构:基类为Throwable,Error和Exception继承Throwable,RuntimeException和IOException等继承Exception,具体的RuntimeException继承RuntimeException。

2.1.2

Error和RuntimeException及其子类成为未检查异常(unchecked),其它异常成为已检查异常(checked)。

2.2 每个类型的异常的特点

2.2.1 Error体系

Error类体系描述了Java运行系统中的内部错误以及资源耗尽的情形。应用程序不应该抛出这种类型的对象(一般是由虚拟机抛出)。如果出现这种错误,除了尽力使程序安全退出外,在其他方面是无能为力的。所以,在进行程序设计时,应该更关注Exception体系。

2.2.2 Exception体系

Exception体系包括RuntimeException体系和其他非RuntimeException的体系

2.2.2.1 RuntimeException

RuntimeException体系包括错误的类型转换、数组越界访问和试图访问空指针等等。处理RuntimeException的原则是:如果出现RuntimeException,那么一定是程序员的错误。例如,可以通过检查数组下标和数组边界来避免数组越界访问异常。

2.2.2.2 其他(IOException等等)

这类异常一般是外部错误,例如试图从文件尾后读取数据等,这并不是程序本身的错误,而是在应用环境中出现的外部错误。

2.3 与C++异常分类的不同

2.3.1

其实,Java中RuntimeException这个类名起的并不恰当,因为任何异常都是运行时出现的。(在编译时出现的错误并不是异常,换句话说,异常就是为了解决程序运行时出现的的错误)。

2.3.2

C++中logic_error与Java中的RuntimeException是等价的,而runtime_error与Java中非RuntimeException类型的异常是等价的。

3 异常的使用方法


3.1 声明方法抛出异常

3.1.1 语法:throws(略)

3.1.2 为什么要声明方法抛出异常?

方法是否抛出异常与方法返回值的类型一样重要。假设方法抛出异常确没有声明该方法将抛出异常,那么客户程序员可以调用这个方法而且不用编写处理异常的代码。那么,一旦出现异常,那么这个异常就没有合适的异常控制器来解决。

3.1.3 为什么抛出的异常一定是已检查异常?

RuntimeException与Error可以在任何代码中产生,它们不需要由程序员显示的抛出,一旦出现错误,那么相应的异常会被自动抛出。而已检查异常是由程序员抛出的,这分为两种情况:客户程序员调用会抛出异常的库函数(库函数的异常由库程序员抛出);客户程序员自己使用throw语句抛出异常。遇到Error,程序员一般是无能为力的;遇到RuntimeException,那么一定是程序存在逻辑错误,要对程序进行修改(相当于调试的一种方法);只有已检查异常才是程序员所关心的,程序应该且仅应该抛出或处理已检查异常。

3.1.4

注意:覆盖父类某方法的子类方法不能抛出比父类方法更多的异常,所以,有时设计父类的方法时会声明抛出异常,但实际的实现方法的代码却并不抛出异常,这样做的目的就是为了方便子类方法覆盖父类方法时可以抛出异常。

3.2 如何抛出异常

3.2.1 语法:throw(略)

3.2.2 抛出什么异常?

对于一个异常对象,真正有用的信息时异常的对象类型,而异常对象本身毫无意义。比如一个异常对象的类型是ClassCastException,那么这个类名就是唯一有用的信息。所以,在选择抛出什么异常时,最关键的就是选择异常的类名能够明确说明异常情况的类。

3.2.3

异常对象通常有两种构造函数:一种是无参数的构造函数;另一种是带一个字符串的构造函数,这个字符串将作为这个异常对象除了类型名以外的额外说明。

3.2.4

创建自己的异常:当Java内置的异常都不能明确的说明异常情况的时候,需要创建自己的异常。需要注意的是,唯一有用的就是类型名这个信息,所以不要在异常类的设计上花费精力。

3.3 捕获异常

如果一个异常没有被处理,那么,对于一个非图形界面的程序而言,该程序会被中止并输出异常信息;对于一个图形界面程序,也会输出异常的信息,但是程序并不中止,而是返回用Ы缑娲

Friday, April 10, 2009

JAVA 1.5 generics

更多精彩请到 http://www.139ya.com


https://www.cs.auckland.ac.nz/references/java/java1.5/tutorial/java/generics/gentypes.html

关于generics naming conventions的一些说法:


Type Parameter Naming Conventions

By convention, type parameter names are single, uppercase letters. This stands in sharp contrast to the variable naming conventions that you already know about, and with good reason: Without this convention, it would be difficult to tell the difference between a type variable and an ordinary class or interface name.

The most commonly used type parameter names are:

  • E - Element (used extensively by the Java Collections Framework)
  • K - Key
  • N - Number
  • T - Type
  • V - Value
  • S,U,V etc. - 2nd, 3rd, 4th types

Wednesday, January 14, 2009

全面分析Java的垃圾回收机制

更多精彩请到 http://www.139ya.com

转自:http://www.enet.com.cn/article/2006/0119/A20060119495081.shtml

【简 介】
Java的堆是一个运行时数据区,类的实例(对象)从中分配空间。 Java虚拟机(JVM)的堆中储存着正在运行的应用程序所建立的所有对象,这些对象通过new、newarray、anewarray和 multianewarray等指令建立,但是它们不需要程序代码来显式地释放。

引言

  Java的堆是一个运行时数据区,类的实例(对象)从中分配空间。Java虚拟机(JVM)的堆中储存着正在运行的应用程序所建立的所有对象,这些对象通过new、newarray、anewarray和multianewarray等指令建立,但是它们不需要程序代码来显式地释放。一般来说,堆的是由垃圾回收来负责的,尽管JVM规范并不要求特殊的垃圾回收技术,甚至根本就不需要垃圾回收,但是由于内存的有限性,JVM在实现的时候都有一个由垃圾回收所管理的堆。垃圾回收是一种动态存储管理技术,它自动地释放不再被程序引用的对象,按照特定的垃圾收集算法来实现资源自动回收的功能。

  垃圾收集的意义

  在C++中,对象所占的内存在程序结束运行之前一直被占用,在明确释放之前不能分配给其它对象;而在Java中,当没有对象引用指向原先分配给某个对象的内存时,该内存便成为垃圾。JVM的一个系统级线程会自动释放该内存块。垃圾收集意味着程序不再需要的对象是"无用信息",这些信息将被丢弃。当一个对象不再被引用的时候,内存回收它占领的空间,以便空间被后来的新对象使用。事实上,除了释放没用的对象,垃圾收集也可以清除内存记录碎片。由于创建对象和垃圾收集器释放丢弃对象所占的内存空间,内存会出现碎片。碎片是分配给对象的内存块之间的空闲内存洞。碎片整理将所占用的堆内存移到堆的一端,JVM将整理出的内存分配给新的对象。

  垃圾收集能自动释放内存空间,减轻编程的负担。这使Java 虚拟机具有一些优点。首先,它能使编程效率提高。在没有垃圾收集机制的时候,可能要花许多时间来解决一个难懂的存储器问题。在用Java语言编程的时候,靠垃圾收集机制可大大缩短时间。其次是它保护程序的完整性, 垃圾收集是Java语言安全性策略的一个重要部份。

  垃圾收集的一个潜在的缺点是它的开销影响程序性能。Java虚拟机必须追踪运行程序中有用的对象, 而且最终释放没用的对象。这一个过程需要花费处理器的时间。其次垃圾收集算法的不完备性,早先采用的某些垃圾收集算法就不能保证100%收集到所有的废弃内存。当然随着垃圾收集算法的不断改进以及软硬件运行效率的不断提升,这些问题都可以迎刃而解。

  垃圾收集的算法分析

  Java语言规范没有明确地说明JVM使用哪种垃圾回收算法,但是任何一种垃圾收集算法一般要做2件基本的事情:(1)发现无用信息对象;(2)回收被无用对象占用的内存空间,使该空间可被程序再次使用。

  大多数垃圾回收算法使用了根集(root set)这个概念;所谓根集就量正在执行的Java程序可以访问的引用变量的集合(包括局部变量、参数、类变量),程序可以使用引用变量访问对象的属性和调用对象的方法。垃圾收集首选需要确定从根开始哪些是可达的和哪些是不可达的,从根集可达的对象都是活动对象,它们不能作为垃圾被回收,这也包括从根集间接可达的对象。而根集通过任意路径不可达的对象符合垃圾收集的条件,应该被回收。下面介绍几个常用的算法。

  1、 引用计数法(Reference Counting Collector)

  引用计数法是唯一没有使用根集的垃圾回收的法,该算法使用引用计数器来区分存活对象和不再使用的对象。一般来说,堆中的每个对象对应一个引用计数器。当每一次创建一个对象并赋给一个变量时,引用计数器置为1。当对象被赋给任意变量时,引用计数器每次加1当对象出了作用域后(该对象丢弃不再使用),引用计数器减1,一旦引用计数器为0,对象就满足了垃圾收集的条件。

  基于引用计数器的垃圾收集器运行较快,不会长时间中断程序执行,适宜地必须 实时运行的程序。但引用计数器增加了程序执行的开销,因为每次对象赋给新的变量,计数器加1,而每次现有对象出了作用域生,计数器减1。

  2、tracing算法(Tracing Collector)

  tracing算法是为了解决引用计数法的问题而提出,它使用了根集的概念。基于tracing算法的垃圾收集器从根集开始扫描,识别出哪些对象可达,哪些对象不可达,并用某种方式标记可达对象,例如对每个可达对象设置一个或多个位。在扫描识别过程中,基于tracing算法的垃圾收集也称为标记和清除(mark-and-sweep)垃圾收集器.

  3、compacting算法(Compacting Collector)

  为了解决堆碎片问题,基于tracing的垃圾回收吸收了Compacting算法的思想,在清除的过程中,算法将所有的对象移到堆的一端,堆的另一端就变成了一个相邻的空闲内存区,收集器会对它移动的所有对象的所有引用进行更新,使得这些引用在新的位置能识别原来的对象。在基于Compacting算法的收集器的实现中,一般增加句柄和句柄表。


4、copying算法(Coping Collector)

  该算法的提出是为了克服句柄的开销和解决堆碎片的垃圾回收。它开始时把堆分成 一个对象 面和多个空闲面,程序从对象面为对象分配空间,当对象满了,基于coping算法的垃圾 收集就从根集中扫描活动对象,并将每个活动对象复制到空闲面(使得活动对象所占的内存之间没有空闲洞),这样空闲面变成了对象面,原来的对象面变成了空闲面,程序会在新的对象面中分配内存。

  一种典型的基于coping算法的垃圾回收是stop-and-copy算法,它将堆分成对象面和空闲区域面,在对象面与空闲区域面的切换过程中,程序暂停执行。

  5、generation算法(Generational Collector)

  stop-and-copy垃圾收集器的一个缺陷是收集器必须复制所有的活动对象,这增加了程序等待时间,这是coping算法低效的原因。在程序设计中有这样的规律:多数对象存在的时间比较短,少数的存在时间比较长。因此,generation算法将堆分成两个或多个,每个子堆作为对象的一代(generation)。由于多数对象存在的时间比较短,随着程序丢弃不使用的对象,垃圾收集器将从最年轻的子堆中收集这些对象。在分代式的垃圾收集器运行后,上次运行存活下来的对象移到下一最高代的子堆中,由于老一代的子堆不会经常被回收,因而节省了时间。

  6、adaptive算法(Adaptive Collector)

  在特定的情况下,一些垃圾收集算法会优于其它算法。基于Adaptive算法的垃圾收集器就是监控当前堆的使用情况,并将选择适当算法的垃圾收集器。


透视Java垃圾回收

  1、命令行参数透视垃圾收集器的运行

  2、使用System.gc()可以不管JVM使用的是哪一种垃圾回收的算法,都可以请求Java的垃圾回收。在命令行中有一个参数-verbosegc可以查看Java使用的堆内存的情况,它的格式如下:

java -verbosegc classfile

  可以看个例子:

class TestGC
{
 public static void main(String[] args)
 {
  new TestGC();
  System.gc();
  System.runFinalization();
 }
}

  在这个例子中,一个新的对象被创建,由于它没有使用,所以该对象迅速地变为可达,程序编译后,执行命令: java -verbosegc TestGC 后结果为:

[Full GC 168K->97K(1984K), 0.0253873 secs]

  机器的环境为,Windows 2000 + JDK1.3.1,箭头前后的数据168K和97K分别表示垃圾收集GC前后所有存活对象使用的内存容量,说明有168K-97K=71K的对象容量被回收,括号内的数据1984K为堆内存的总容量,收集所需要的时间是0.0253873秒(这个时间在每次执行的时候会有所不同)。

  2、finalize方法透视垃圾收集器的运行

  在JVM垃圾收集器收集一个对象之前 ,一般要求程序调用适当的方法释放资源,但在没有明确释放资源的情况下,Java提供了缺省机制来终止化该对象心释放资源,这个方法就是finalize()。它的原型为:

protected void finalize() throws Throwable

  在finalize()方法返回之后,对象消失,垃圾收集开始执行。原型中的throws Throwable表示它可以抛出任何类型的异常。

  之所以要使用finalize(),是由于有时需要采取与Java的普通方法不同的一种方法,通过分配内存来做一些具有C风格的事情。这主要可以通过" 固有方法"来进行,它是从Java里调用非Java方法的一种方式。C和C++是目前唯一获得固有方法支持的语言。但由于它们能调用通过其他语言编写的子程序,所以能够有效地调用任何东西。在非Java代码内部,也许能调用C的malloc()系列函数,用它分配存储空间。而且除非调用了free(),否则存储空间不会得到释放,从而造成内存"漏洞"的出现。当然,free()是一个C和C++函数,所以我们需要在 finalize()内部的一个固有方法中调用它。也就是说我们不能过多地使用finalize(),它并不是进行普通清除工作的理想场所。

  在普通的清除工作中,为清除一个对象,那个对象的用户必须在希望进行清除的地点调用一个清除方法。这与C++"破坏器"的概念稍有抵触。在C++中,所有对象都会破坏(清除)。或者换句话说,所有对象都"应该"破坏。若将C++对象创建成一个本地对象,比如在堆栈中创建(在Java中是不可能的),那么清除或破坏工作就会在"结束花括号"所代表的、创建这个对象的作用域的末尾进行。若对象是用new创建的(类似于Java),那么当程序员调用C++的 delete命令时(Java没有这个命令),就会调用相应的破坏器。若程序员忘记了,那么永远不会调用破坏器,我们最终得到的将是一个内存"漏洞",另外还包括对象的其他部分永远不会得到清除。

  相反,Java不允许我们创建本地(局部)对象--无论如何都要使用new。但在Java 中,没有"delete"命令来释放对象,因为垃圾收集器会帮助我们自动释放存储空间。所以如果站在比较简化的立场,我们可以说正是由于存在垃圾收集机制,所以Java没有破坏器。然而,随着以后学习的深入,就会知道垃圾收集器的存在并不能完全消除对破坏器的需要,或者说不能消除对破坏器代表的那种机制的需要(而且绝对不能直接调用finalize(),所以应尽量避免用它)。若希望执行除释放存储空间之外的其他某种形式的清除工作,仍然必须调用 Java中的一个方法。它等价于C++的破坏器,只是没后者方便。

  下面这个例子向大家展示了垃圾收集所经历的过程,并对前面的陈述进行了总结。

class Chair {
 static boolean gcrun = false;
 static boolean f = false;
 static int created = 0;
 static int finalized = 0;
 int i;
 Chair() {
  i = ++created;
  if(created == 47)
   System.out.println("Created 47");
 }
 protected void finalize() {
  if(!gcrun) {
   gcrun = true;
   System.out.println("Beginning to finalize after " + created + " Chairs have been created");
  }
  if(i == 47) {
   System.out.println("Finalizing Chair #47, " +"Setting flag to stop Chair creation");
   f = true;
  }
  finalized++;
  if(finalized >= created)
   System.out.println("All " + finalized + " finalized");
 }
}

public class Garbage {
 public static void main(String[] args) {
  if(args.length == 0) {
   System.err.println("Usage: \n" + "java Garbage before\n or:\n" + "java Garbage after");
   return;
  }
  while(!Chair.f) {
   new Chair();
   new String("To take up space");
  }
  System.out.println("After all Chairs have been created:\n" + "total created = " + Chair.created +
", total finalized = " + Chair.finalized);
  if(args[0].equals("before")) {
    System.out.println("gc():");
    System.gc();
    System.out.println("runFinalization():");
    System.runFinalization();
  }
  System.out.println("bye!");
  if(args[0].equals("after"))
   System.runFinalizersOnExit(true);
 }
}

  上面这个程序创建了许多Chair对象,而且在垃圾收集器开始运行后的某些时候,程序会停止创建Chair。由于垃圾收集器可能在任何时间运行,所以我们不能准确知道它在何时启动。因此,程序用一个名为gcrun的标记来指出垃圾收集器是否已经开始运行。利用第二个标记f,Chair可告诉main() 它应停止对象的生成。这两个标记都是在finalize()内部设置的,它调用于垃圾收集期间。另两个static变量--created以及 finalized--分别用于跟踪已创建的对象数量以及垃圾收集器已进行完收尾工作的对象数量。最后,每个Chair都有它自己的(非 static)int i,所以能跟踪了解它具体的编号是多少。编号为47的Chair进行完收尾工作后,标记会设为true,最终结束Chair对象的创建过程。


关于垃圾收集的几点补充

  经过上述的说明,可以发现垃圾回收有以下的几个特点:

  (1)垃圾收集发生的不可预知性:由于实现了不同的垃圾收集算法和采用了不同的收集机制,所以它有可能是定时发生,有可能是当出现系统空闲CPU资源时发生,也有可能是和原始的垃圾收集一样,等到内存消耗出现极限时发生,这与垃圾收集器的选择和具体的设置都有关系。

  (2)垃圾收集的精确性:主要包括2 个方面:(a)垃圾收集器能够精确标记活着的对象;(b)垃圾收集器能够精确地定位对象之间的引用关系。前者是完全地回收所有废弃对象的前提,否则就可能造成内存泄漏。而后者则是实现归并和复制等算法的必要条件。所有不可达对象都能够可靠地得到回收,所有对象都能够重新分配,允许对象的复制和对象内存的缩并,这样就有效地防止内存的支离破碎。

  (3)现在有许多种不同的垃圾收集器,每种有其算法且其表现各异,既有当垃圾收集开始时就停止应用程序的运行,又有当垃圾收集开始时也允许应用程序的线程运行,还有在同一时间垃圾收集多线程运行。

  (4)垃圾收集的实现和具体的JVM 以及JVM的内存模型有非常紧密的关系。不同的JVM 可能采用不同的垃圾收集,而JVM 的内存模型决定着该JVM可以采用哪些类型垃圾收集。现在,HotSpot 系列JVM中的内存系统都采用先进的面向对象的框架设计,这使得该系列JVM都可以采用最先进的垃圾收集。

  (5)随着技术的发展,现代垃圾收集技术提供许多可选的垃圾收集器,而且在配置每种收集器的时候又可以设置不同的参数,这就使得根据不同的应用环境获得最优的应用性能成为可能。

  针对以上特点,我们在使用的时候要注意:

  (1)不要试图去假定垃圾收集发生的时间,这一切都是未知的。比如,方法中的一个临时对象在方法调用完毕后就变成了无用对象,这个时候它的内存就可以被释放。

  (2)Java中提供了一些和垃圾收集打交道的类,而且提供了一种强行执行垃圾收集的方法--调用System.gc(),但这同样是个不确定的方法。Java 中并不保证每次调用该方法就一定能够启动垃圾收集,它只不过会向JVM发出这样一个申请,到底是否真正执行垃圾收集,一切都是个未知数。

  (3)挑选适合自己的垃圾收集器。一般来说,如果系统没有特殊和苛刻的性能要求,可以采用JVM的缺省选项。否则可以考虑使用有针对性的垃圾收集器,比如增量收集器就比较适合实时性要求较高的系统之中。系统具有较高的配置,有比较多的闲置资源,可以考虑使用并行标记/清除收集器。

  (4)关键的也是难把握的问题是内存泄漏。良好的编程习惯和严谨的编程态度永远是最重要的,不要让自己的一个小错误导致内存出现大漏洞。

  (5)尽早释放无用对象的引用。大多数程序员在使用临时变量的时候,都是让引用变量在退出活动域(scope)后,自动设置为null,暗示垃圾收集器来收集该对象,还必须注意该引用的对象是否被监听,如果有,则要去掉监听器,然后再赋空值。

  结束语

  一般来说,Java开发人员可以不重视JVM中堆内存的分配和垃圾处理收集,但是,充分理解Java的这一特性可以让我们更有效地利用资源。同时要注意finalize()方法是Java的缺省机制,有时为确保对象资源的明确释放,可以编写自己的finalize方法。