??xml version="1.0" encoding="utf-8" standalone="yes"?>
System.out.print("a");
}
public static void sayOther(String s){
System.out.print(s);
}
public int say(String s){
System.out.print(s);
return 0;
}
{
System.out.print("c");
inner.innerMethed("d");
}
static
{
System.out.print("e");
inner.innerMethed("f");
}
private int i=say("g");
private static inner t= new inner();
private inner tt=new inner();
private innerOther ttt=new innerOther();
static class inner{
public inner(){
System.out.print("h");
}
public static void innerMethed(String s){
System.out.print(s);
}
{
System.out.print("i");
}
static
{
System.out.print("j");
}
}
class innerOther{
public innerOther(){
System.out.print("k");
}
{
System.out.print("l");
}
}
public static void main(String[] args) {
System.out.print("m");
Outer outer = new Outer();
System.out.print("n");
}
}
{案是:ejfihmcdgihlkan
]]>
01: public class StringExample
02: {
03: public static void main (String args[])
04: {
05: String s0 = "Programming";
06: String s1 = new String ("Programming");
07: String s2 = "Program" + "ming";
08:
09: System.out.println("s0.equals(s1): " + (s0.equals(s1)));
10: System.out.println("s0.equals(s2): " + (s0.equals(s2)));
11: System.out.println("s0 == s1: " + (s0 == s1));
12: System.out.println("s0 == s2: " + (s0 == s2));
13: }}
q个例子包含? 个String 型变?其中两个被赋g帔R表达式“Programming?另一个被赋g一个新建的gؓ“Programming”的String cȝ实例。用equals(...)Ҏ和? =”运符q行比较产生了下列结?
s0。equals(s1): true
s0。equals(s2): true
s0 == s1: false
s0 == s2: true
String.equals()Ҏ比较的是字符串的内容,使用equals(...)Ҏ会对字符串中的所有字W一个接一个地q行比较,如果完全相等那么q回true?在这U情况下全部字符串都是相同的,所以当字符串s0 与s1 或s2 比较时我们得到的q回值均为true 。运符?=”比较的是String 实例的引用。在q种情况下很明显s0 和s1 q不是同一个String 实例,但s0 和s2 是同一个。读者也怼问s0 和s2 怎么是同一个对象呢Q?BR> q个问题的答案来自于Java语言规范中关于字W串帔RString Literals 的章节。本例中“Programming?,“Program”和“ming”都是字W串帔R!!它们在编译期p定了当一个字W串由多个字W串帔Rq接而成?例如s2 ,它同样在~译期就被确定ؓ一个字W串帔R。Java 保一个字W串帔R只有一份拷?所以当Programming”和“Program?“ming”被定为值相{时,Java 会设|两个变量的引用为同一个常量的引用。在帔R池constant pool ?Java 会跟t所有的字符串常量?BR> 帔R池指的是在编译期被确?q被保存在已~译?class 文g中的一些数据。它包含了关于方?c?接口{等,当然q有字符串常量的信息。当JVM 装蝲了这?class 文g。变量s0 和s2 被确?JVM 执行了一名为常量池解析constant pool resolution 的操作。该Ҏ作针对字W串的处理过E包括下? 个步?摘自JVM 规范5? ?:
¹ 如果另一个常量池入口constant pool entry 被标CؓCONSTANT_String2 ,q且指出同样的Unicode 字符序列已经被确?那么q项操作的结果就是ؓ之前的常?BR>池入口创建的String 实例的引用?BR> ̔ 否则,如果intern()Ҏ已经被这个常量池描述的一个包含同样Unicode 字符序列的String 实例调用q了,那么q项操作的结果就是那个相同String 实例的引用?BR> 否则,一个新的String 实例会被创徏它包含了CONSTANT_String 入口描述的Unicode 字符;序列q个String 实例是该项操作的结果?BR> 也就是说,当常量池W一ơ确定一个字W串,在Java 内存栈中创Z个String 实例。在帔R池中,后来的所有针对同样字W串内容的引?都会得到之前创徏的String 实例。当JVM 处理到第6 行时,它创Z字符串常量Programming 的一份拷贝到另一个String 实例中。所以对s0 和s1 的引用的比较l果是false ,因ؓ它们不是同一个对象。这是Zs0==s1 的操作在某些情况下与s0.equals(s1)不同。s0==s1 比较的是对象引用的?而s0.equals(s1)实际上执行的是字W串内容的比较?BR> 存在?class 文g中的帔R?在运行期被JVM 装蝲,q且可以扩充。此前提到的intern()Ҏ针对String 实例的这个意图提供服务。当针对一个String 实例调用了intern()Ҏ,intern()Ҏ遵守前面概括的第3 步以外的帔R池解析规?因ؓ实例已经存在,而不需要另外创Z个新的。所以已存在的实例的引用被加入到该常量池。来看看另一个例?
01: import java.io.*;
02:
03: public class StringExample2
04: {
05: public static void main (String args[])
06:{
07: String sFileName = "test.txt";
08: String s0 = readStringFromFile(sFileName);
09: String s1 = readStringFromFile(sFileName);
10:
11: System.out.println("s0 == s1: " + (s0 == s1));
12: System.out.println("s0.equals(s1): " + (s0.equals(s1)));
13:
14: s0.intern();
15: s1.intern();
16:
17: System.out.println("s0 == s1: " + (s0 == s1));
18: System.out.println("s0 == s1.intern(): " +
19: (s0 == s1.intern()));
20: }
21:
22: private static String readStringFromFile (String sFileName)
23: {
24: //…read string from file?BR>25: }
26: }
q个例子没有讄s0 和s1 的gؓ字符串常?取而代之的是在q行期它从一个文件中d字符?q把值分配给readStringFromFile(...)Ҏ创徏的String 实例。从W? 行开?E序对两个被新创Zؓh同样字符值的String 实例q行处理。当你看CW?1 行到12 行的输出l果?你会再次注意到这两个对象q不是同一?但它们的内容是相同的。输出结果如?
s0 == s1: false
s0.equals(s1): true
s0 == s1: false
s0 == s1.intern(): true
W?4 行所做的是将String 实例的引用s0 存入帔R池。当W?5 行被处理?对s1.intern()Ҏ的调?会简单地q回引用s0?q样一来第17 行和18 行的输出l果正是我们所期望?s0 与s1 仍旧是截然不同的两个String 。实例因此s0==s1 的结果是false?而s1.intern()q回的是帔R池中的引用值即s0 所,以表辑ּs0==s1.intern()的结果是true?假如我们希望实例s1 存入帔R池中,我们必须首先讄s0 为null, 然后h垃圾回收器garbagecollector 回收被指向s0 的String 实例。在s0 被回收后s1.intern()Ҏ的调?会把s1存入帔R池?BR> ȝ来说在执行等式比较时,应该始终使用String.equals(...)Ҏ,而不?=q算W。如果你q是习惯性地使用==q算W?那么intern()Ҏ可以帮助你得到正的{案。因为当n 和m 均ؓString 实例的引用时,语句n.equals(m)与n.intern() ==m.intern()得到的结果是一致的。假如你打算充分利用帔R池的优势那么你就应该选择String.intern()Ҏ?/P>
Class
对象。若l定一个类或接口的完整路径名,那么此方法将试图定位、装载和q接该类。若成功Q返回该cd象。否则,抛出 ClassNotFoundException 异常?例如Q下面代码段q回名ؓjava.lang.Thread
的运?Class
描述器?/FONT>Class t = Class.forName("java.lang.Thread") ; 此方法是需要指定类加蝲器的Q当用到仅有一个String参数的forNameҎӞClass对象默认调用当前类加蝲器作为加载器和将W二参数为true。第二个参数说明Q如果是falseӞ调用forNameҎ只是在命令类加蝲器蝲入该c,而不初始化该cȝ静态区块,只有当该cȝ一ơ实例化Ӟ静态区块才被调用。当为trueӞ则蝲入时p用静态区块?/FONT>
getClassLoader()
获取该类的类装蝲器?
getComponentType()
如果当前c表CZ个数l,则返回表C数组lg?Class 对象Q否则返?null?STRONG>
getConstructor(Class[])
q回当前 Class 对象表示的类的指定的公有构造子对象?STRONG>
getConstructors()
q回当前 Class 对象表示的类的所有公有构造子对象数组?STRONG>
getDeclaredConstructor(Class[])
q回当前 Class 对象表示的类的指定已说明的一个构造子对象?
getDeclaredConstructors()
q回当前 Class 对象表示的类的所有已说明的构造子对象数组?
getDeclaredField(String)
q回当前 Class 对象表示的类或接口的指定已说明的一个域对象?STRONG>
getDeclaredFields()
q回当前 Class 对象表示的类或接口的所有已说明的域对象数组?STRONG>
getDeclaredMethod(String, Class[])
q回当前 Class 对象表示的类或接口的指定已说明的一个方法对象?STRONG>
getDeclaredMethods()
q回 Class 对象表示的类或接口的所有已说明的方法数l?STRONG>
getField(String)
q回当前 Class 对象表示的类或接口的指定的公有成员域对象?STRONG>
getFields()
q回当前 Class 对象表示的类或接口的所有可讉K的公有域对象数组?STRONG>
getInterfaces()
q回当前对象表示的类或接口实现的接口?
getMethod(String, Class[])
q回当前 Class 对象表示的类或接口的指定的公有成员方法对象?STRONG>
getMethods()
q回当前 Class 对象表示的类或接口的所有公有成员方法对象数l,包括已声明的和从父类l承的方法?STRONG>
getModifiers()
q回该类或接口的 Java 语言修改器代码?STRONG>
getName()
q回 Class 对象表示的类?cR接口、数l或基类?的完整\径名字符丌Ӏ?STRONG>
getResource(String)
按指定名查找资源?STRONG>
getResourceAsStream(String)
用给定名查找资源?STRONG>
getSigners()
获取cL记?STRONG>
getSuperclass()
如果此对象表C除 Object 外的Mc? 那么q回此对象的父类对象?STRONG>
isArray()
如果 Class 对象表示一个数l则q回 true, 否则q回 false?STRONG>
isAssignableFrom(Class)
判定 Class 对象表示的类或接口是否同参数指定?Class 表示的类或接口相同,或是其父cR?STRONG>
isInstance(Object)
此方法是 Java 语言 instanceof 操作的动态等h法?STRONG>
isInterface()
判定指定?Class 对象是否表示一个接口类型?STRONG>
isPrimitive()
判定指定?Class 对象是否表示一?Java 的基cd?
newInstance()
创徏cȝ新实例?STRONG>
toString()
对象{换ؓ字符丌Ӏ?nbsp;
For use as a base class:
getConnection()
to pass any connection you want. Typically this is used to enable application wide connection pooling.
closeConnection(Connection con)
-- if you override getConnection make sure to implement closeConnection
to handle the connection you generated. Typically this would return the connection to the pool it came from.
getLogStatement(LoggingEvent event)
to produce specialized or dynamic statements. The default uses the sql option value.原来log4j我们把其提供的JDBCAppender作ؓ基类来用,然后Override三个父类的方法:getConnection(),closeConnection(Connection con)和getLogStatement(LoggingEvent event)?BR>原来如此Q那写一个子cJDBCPoolAppender来替代这个JDBCAppender
JDBCPoolAppender代码和其相关代码如下Q?BR>
JDBCPoolAppender.java:
package common.log;
import java.sql.Connection;
import org.apache.log4j.spi.LoggingEvent;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Iterator;
import org.apache.log4j.spi.ErrorCode;
import org.apache.log4j.PatternLayout;
import common.sql.MyDB;
import common.sql.GeneralDb;
public class JDBCPoolAppender extends org.apache.log4j.jdbc.JDBCAppender {
private MyDB mydb = null;
protected String sqlname=""; //增加一个数据库jndiName的属?BR> protected Connection connection = null;
protected String sqlStatement = "";
/**
* size of LoggingEvent buffer before writting to the database.
* Default is 1.
*/
protected int bufferSize = 1;
public JDBCPoolAppender() {
super();
}
/**
* ArrayList holding the buffer of Logging Events.
*/
public void append(LoggingEvent event) {
buffer.add(event);
if (buffer.size() >= bufferSize)
flushBuffer();
}
/**
* By default getLogStatement sends the event to the required Layout object.
* The layout will format the given pattern into a workable SQL string.
*
* Overriding this provides direct access to the LoggingEvent
* when constructing the logging statement.
*
*/
protected String getLogStatement(LoggingEvent event) {
return getLayout().format(event);
}
/**
*
* Override this to provide an alertnate method of getting
* connections (such as caching). One method to fix this is to open
* connections at the start of flushBuffer() and close them at the
* end. I use a connection pool outside of JDBCAppender which is
* accessed in an override of this method.
* */
protected void execute(String sql) throws SQLException {
Connection con = null;
Statement stmt = null;
try {
con = getConnection();
stmt = con.createStatement();
stmt.executeUpdate(sql);
} catch (SQLException e) {
if (stmt != null)
stmt.close();
throw e;
}
stmt.close();
closeConnection(con);
//System.out.println("Execute: " + sql);
}
/**
* Override this to return the connection to a pool, or to clean up the
* resource.
*
* The default behavior holds a single connection open until the appender
* is closed (typically when garbage collected).
*/
protected void closeConnection(Connection con) {
mydb=null;
try {
if (connection != null && !connection.isClosed())
connection.close();
} catch (SQLException e) {
errorHandler.error("Error closing connection", e,
ErrorCode.GENERIC_FAILURE);
}
}
/**
* Override 此函数来利用q接池返回一个Connetion对象
*
*/
protected Connection getConnection() throws SQLException {
try {
mydb = GeneralDb.getInstance(sqlname);
connection = mydb.getConnection();
} catch (Exception e) {
errorHandler.error("Error opening connection", e, ErrorCode.GENERIC_FAILURE);
}
return connection;
}
/**
* Closes the appender, flushing the buffer first then closing the default
* connection if it is open.
*/
public void close() {
flushBuffer();
try {
if (connection != null && !connection.isClosed())
connection.close();
} catch (SQLException e) {
errorHandler.error("Error closing connection", e,
ErrorCode.GENERIC_FAILURE);
}
this.closed = true;
}
/**
* loops through the buffer of LoggingEvents, gets a
* sql string from getLogStatement() and sends it to execute().
* Errors are sent to the errorHandler.
*
* If a statement fails the LoggingEvent stays in the buffer!
*/
public void flushBuffer() {
//Do the actual logging
removes.ensureCapacity(buffer.size());
for (Iterator i = buffer.iterator(); i.hasNext(); ) {
try {
LoggingEvent logEvent = (LoggingEvent) i.next();
String sql = getLogStatement(logEvent);
execute(sql);
removes.add(logEvent);
} catch (SQLException e) {
errorHandler.error("Failed to excute sql", e,
ErrorCode.FLUSH_FAILURE);
}
}
// remove from the buffer any events that were reported
buffer.removeAll(removes);
// clear the buffer of reported events
removes.clear();
}
/** closes the appender before disposal */
public void finalize() {
close();
}
/**
* JDBCAppender requires a layout.
* */
public boolean requiresLayout() {
return true;
}
/**
*
*/
public void setSql(String s) {
sqlStatement = s;
if (getLayout() == null) {
this.setLayout(new PatternLayout(s));
} else {
((PatternLayout) getLayout()).setConversionPattern(s);
}
}
/**
* Returns pre-formated statement eg: insert into LogTable (msg) values ("%m")
*/
public String getSql() {
return sqlStatement;
}
public void setSqlname(String sqlname){
sqlname=sqlname;
}
public String getSqlname(){
return sqlname;
}
public void setBufferSize(int newBufferSize) {
bufferSize = newBufferSize;
buffer.ensureCapacity(bufferSize);
removes.ensureCapacity(bufferSize);
}
public int getBufferSize() {
return bufferSize;
}
}
MyDB.java:
package common.sql;
import java.sql.*;
import com.codestudio.sql.*; //引入开源项目Poolman数据库连接池的包
public class MyDB {
public static final String module = MyDB.class.getName();
private String dbName = "";
private PoolMan plmn = null;
public MyDB(String dbName) {
try {
if (plmn == null) {
plmn = (PoolMan) Class.forName("com.codestudio.sql.PoolMan").
newInstance();
}
} catch (Exception ec) {
System.out.println(ec.toString()+module);
}
this.dbName = dbName;
}
private Connection getNewConnection() {
Connection conn = null;
try {
conn = plmn.connect("jdbc:poolman://" + dbName);
conn.setAutoCommit(true);
} catch (Exception ec) {
System.out.println(ec.toString()+"First:Connect sqlsever failed"+module);
try {
Thread.sleep(1000);
conn = plmn.connect("jdbc:poolman://" + dbName);
conn.setAutoCommit(true);
} catch (Exception ecs) {
System.out.println(ecs.toString()+"Again:Connect sqlsever faile"+module);
}
}
return conn;
}
public Connection getConnection() {
return getNewConnection();
}
}
GeneralDb.java:
import java.util.*;
public class GeneralDb {
private static Hashtable dbPool;
public static MyDB getInstance(String dbname) {
if (dbPool == null) {
dbPool = new Hashtable();
}
MyDB db = (MyDB) dbPool.get(dbname);
if (db == null) {
db = new MyDB(dbname);
dbPool.put(dbname, db);
}
return db;
}
}
Log4j数据库连接池的配|如下:
log4j.appender.JDBC=common.log.JDBCPoolAppender
log4j.appender.JDBC.sqlname=log
log4j.appender.JDBC.layout=org.apache.log4j.PatternLayout
log4j.appender.JDBC.sql=INSERT INTO LOGGING (log_date, log_level, location, message) VALUES ('%d{ISO8601}', '%-5p', '%C,%L', '%m')
poolman.xml配置如下Q?BR>
〈poolman>
〈management-mode>local?management-mode>
〈datasource>
〈dbname>log?dbname>
〈jndiName>log?jndiName>
〈driver>com.mysql.jdbc.Driver?driver>
〈url>jdbc:mysql://localhost:3306/test?url>
〈username>use?username>
〈password>password?password>
〈minimumSize>0?minimumSize>
〈maximumSize>10?maximumSize>
〈logFile>logs/mysql.log?logFile>
?datasource>
?poolman>
q行成功Q对于JDBCPoolAppender的属性(比如sqlname属性)我们可以利用Log4j的反机刉便添加,只要在配|文件给光上值即可应用,而原来的父类里面的一些属性(username什么的)和其get,setҎ׃在连接池中不需要,所以删除。而在JDBCPoolAppendercMQ我也只是将getConnection ҎOverride Q在q个Ҏ中我们可以根据需要生成我们的Connection对象Q另外两个方法大家可以根据需求来军_怎样Override。:Q?BR>
java.compiler Name of JIT compiler to use
java.ext.dirs Path of extension directory or directories
os.name Operating system name
os.arch Operating system architecture
os.version Operating system version
file.separator File separator ("/" on UNIX) path.separator Path separator (":" on UNIX)
line.separator Line separator ("\n" on UNIX)
user.name User's account name
user.home User's home directory
user.dir User's current working directory
Java中文问题一直困扰着很多初学者,如果了解了Javapȝ的中文问题原理,我们可以对中文问题能够采取Ҏ的解决之道?/P>
最古老的解决Ҏ是用String的字节码转换Q这U方案问题是不方便,我们需要破坏对象封装性,q行字节码{换?/P>
q有一U方式是对J2EE容器q行~码讄Q如果J2EE应用pȝq该容器,则会发生qQ而且指定容器配置不符合J2EE应用和容器分ȝ原则?/P>
在Java内部q算中,涉及到的所有字W串都会被{化ؓUTF-8~码来进行运。那么,在被Java转化之前Q字W串是什么样的字W集Q?JavaLҎ操作pȝ的默认编码字W集来决定字W串的初始编码,而且Javapȝ的输入和输出的都是采取操作系l的默认~码?/P>
因此Q如果能l一Javapȝ的输入、输出和操作pȝ3者的~码字符集合Q将能够使Javapȝ正确处理和显C汉字。这是处理Javapȝ汉字的一个原则,但是在实际项目中Q能够正抓住和控制住Javapȝ的输入和输出部分是比较难的。J2EE中,׃涉及到外部浏览器和数据库{,所以中文问题ؕ码显得非常突出?/P>
J2EE应用E序是运行在J2EE容器中。在q个pȝ中,输入途径有很多种Q一U是通过面表单打包成请求(requestQ发往服务器的Q第二种是通过数据库读入;q有W?U输入比较复杂,JSP在第一ơ运行时L被编译成ServletQJSP中常常包含中文字W,那么~译使用javacӞJava根据默认的操作pȝ~码作ؓ初始~码。除非特别指定,如在Jbuilder/eclipse中可以指定默认的字符集?/P>
输出途径也有几种Q第一U是JSP面的输出。由于JSP面已经被编译成ServletQ那么在输出Ӟ也将Ҏ操作pȝ的默认编码来选择输出~码Q除非指定输出编码方式;q有输出途径是数据库Q将字符串输出到数据库?/P>
由此看来Q一个J2EEpȝ的输入输出是非常复杂Q而且是动态变化的Q而Java是跨q_q行的,在实际编译和q行中,都可能涉及到不同的操作系l,如果ȝJava自由Ҏ操作pȝ来决定输入输出的~码字符集,q将不可控制地出Cؕ码?/P>
正是׃Java的跨q_Ҏ,使得字符集问题必ȝ具体pȝ来统一解决Q所以在一个Java应用pȝ中,解决中文q的根本办法是明确指定整个应用pȝl一字符集?/P>
指定l一字符集时Q到底是指定ISO8859_1 、GBKq是UTF-8呢?
Q?Q如l一指定为ISO8859_1Q因为目前大多数软g都是西方人编制的Q他们默认的字符集就是ISO8859_1Q包括操作系lLinux和数据库MySQL{。这P如果指定Jivel一~码为ISO8859_1Q那么就有下?个环节必L握:
开发和~译代码时指定字W集为ISO8859_1?/P>
q行操作pȝ的默认编码必LISO8859_1Q如Linux?/P>
在JSP头部声明Q?lt;%@ page contentType="text/html;charset=ISO8859_1" %>?/P>
Q?Q如果统一指定为GBK中文字符集,上述3个环节同样需要做刎ͼ不同的是只能q行在默认编码ؓGBK的操作系l,如中文Windows?/P>
l一~码为ISO8859_1和GBK虽然带来~制代码的方便,但是各自只能在相应的操作pȝ上运行。但是也破坏了Java跨^台运行的优越性,只在一定范围内行得通。例如,Z使得GBK~码在linux上运行,讄Linux~码为GBK?/P>
那么有没有一U除了应用系l以外不需要进行Q何附加设|的中文~码Ҏ解决Ҏ呢?
Java/J2EEpȝ的统一~码定义为UTF-8。UTF-8~码是一U兼Ҏ有语a的编码方式,惟一比较ȝ的就是要扑ֈ应用pȝ的所有出入口Q然后用UTF-8厠Z结扎”它?/P>
一个J2EE应用pȝ需要做下列几步工作Q?/P>
开发和~译代码时指定字W集为UTF-8。JBuilder和Eclipse都可以在目属性中讄?
使用qo器,如果所有请求都l过一个Servlet控制分配器,那么使用Servlet的filter执行语句Q将所有来自浏览器的请求(requestQ{换ؓUTF-8Q因为浏览器发过来的h包根据浏览器所在的操作pȝ~码Q可能是各种形式~码。关键一句:
request.setCharacterEncoding("UTF-8")?BR>|上有此filter的源码,Jdon框架源码中com.jdon.util.SetCharacterEncodingFilter
需要配|web.xml Ȁz该Filter?
在JSP头部声明Q?lt;%@ page contentType="text/html;charset= UTF-8" %>?
在Jsp的html代码中,声明UTF-8:
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
讑֮数据库连接方式是UTF-8。例如连接MYSQL旉|URL如下Q?BR>jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=UTF-8
一般数据库都可以通过理讄讑֮UTF-8
其他和外界交互时能够讑֮~码时就讑֮UTF-8Q例如读取文Ӟ操作XML{?
W者以前在Jsp/Servlet时就采取q个原则Q后来用Struts、Tapestry、EJB、Hibernate、Jdon{框架时Q从未被q困扰q,可以说适合各种架构。希望本Ҏ供更多初学者分享,减少Java/J2EE的第一个拦路虎Q也避免因ؓ采取一些时解x案,D中文问题一直出现在新的技术架构中?
相关J2EE中文问题解决的源码系l可参考:按这?
Ƣ迎q入讨论 也欢q提Z外案?BR>