naobe @ ウィキ
Java
最終更新:
Bot(ページ名リンク)
-
view
言語に戻る
EJB
JavaEE5
MBean
JMX
JNDI
サーブレット
言語仕様
| 項目 | 説明 |
|---|---|
| transient | 修飾子。Seriariseオブジェクトの保管しないフィールドを修飾する。 |
クラスローダ
目的
- 同じ名前でバージョンの異なるクラスを使用するために使う。クラスローダが異なればバージョンが異なっても良い。自分自身のクラスローダを得るにはgetClassLoader()メソッドを用いる。
- クラスローダには親子関係があり、子クラスローダがクラスをロードするときには、親クラスローダにロードを依頼してロードできなければ、子クラスローダがロードする。
- Class#getClassLoader()は、このクラスをロードしたクラスローダを返す
- クラスローダによってロードされたClassはパーマネント領域に格納される。ClassLoaderがGCされるとGCから解放される。
VMのクラスローダ
ブートストラップクラスローダ
<JAVA_HOME>/lib下のJARファイルに含まれるクラスをロードする。JDK6は、<JAVA_HOME>/jre/lib下? 親はいない
拡張クラスローダ
<JAVA_HOME>/lib/ext下のJARファイルに含まれるクラスをロードする。JDK6は、<JAVA_HOME>/jre/lib/ext下?親はいない
システムクラスローダ
CLASSPATHで指定した位置からクラスをロードする。親は拡張クラスローダ。ブートストラップクラスローダは親子関係なしでも委譲されるということでは? 通常のnew Foo()ではこのクラスローダが使われる。
ブートストラップクラスローダ、拡張クラスローダ、システムクラスローダの順番でクラスをロードする。
コンテキストクラスローダ(JDK6 API Threadより)
コンテキスト ClassLoader は、クラスおよびリソースをロードするときに、このスレッドで実行中のコードが使用するためにスレッドの作成側によって提供されます。コンテキスト ClassLoader が設定されていない場合、デフォルトでは親 Thread の ClassLoader コンテキストになります。通常、親スレッドのコンテキスト ClassLoader は、アプリケーションのロードに使用されるクラスローダーに設定されます。
なので、設定しなければシステムクラスローダがコンテキストクラスローダになる。
コンテキスト・クラスローダを設定・取得するには、java.lang.Thread#setContextClassLoader,getContextClassLoaderメソッドを使う。
なので、設定しなければシステムクラスローダがコンテキストクラスローダになる。
コンテキスト・クラスローダを設定・取得するには、java.lang.Thread#setContextClassLoader,getContextClassLoaderメソッドを使う。
クラスローダ作成
JDK6 APIより
たとえば、アプリケーションはネットワーククラスローダーを作成して、サーバーからクラスファイルをダウンロードできます。コードは次のようになります。
たとえば、アプリケーションはネットワーククラスローダーを作成して、サーバーからクラスファイルをダウンロードできます。コードは次のようになります。
ClassLoader loader = new NetworkClassLoader(host, port);
Object main = loader.loadClass("Main", true).newInstance();
. . .
ネットワーククラスローダーのサブクラスは、ネットワークからクラスをロードするために findClass メソッドと loadClassData メソッドを定義しなければなりません。クラスを作成するバイトを一度ダウンロードしたら、defineClass メソッドを使ってクラスインスタンスを生成する必要があります。実装の例を次に示します。
class NetworkClassLoader extends ClassLoader {
String host;
int port;
public Class findClass(String name) {
byte[] b = loadClassData(name);
return defineClass(name, b, 0, b.length);
}
private byte[] loadClassData(String name) {
// load the class data from the connection
. . .
}
}
特定のディレクトリからクラスをロードするクラスローダを作成してみる。
- MyClassLoaderのmainメソッドで、test.MyClassLoaderTargetをロードしClassを作成する
- MyClassLoaderはClassLoaderを継承したクラスで、loadClassメソッドをオーバライドし、c:/mydoc/tmp/を優先的にロードするディレクトリとしている。c:/mydoc/tmp/にクラスがない場合は、ClassLoaderのloadClassメソッドを実行する
- ClassLoaderのloadClassメソッドでは、キャッシュにあれば、そのクラスを返す。なければ親クラスローダに移譲する。なければシステムクラスローダを使ってクラスをロードする
- Class#newInstance()を実行して、インスタンスを生成する
- MyClassLoaderTarget#execute()を実行し、MyClassLoaderTarget2をnewしてexecute()を実行する
- 実行結果を見ると、MyClassLoaderTarget2のクラスローダは、MyClassLoaderであることがわかる。つまりクラスローダを使ってロードしたクラスから別のクラスをnewするときはそのクラスローダを使うことがわかる。クラスローダを作成すると親クラスローダはシステムクラスローダになる。
- コンテキストクラスローダは明示的に使用しない限り、使われることはなさそう。
package test;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
public class MyClassLoader extends ClassLoader {
private static final int BUFSIZE = 1024;
private byte[] result;
private int last = 0;
@Override
public Class<?> loadClass(String name) throws ClassNotFoundException {
Class<?> c = null;
try {
c = findClass(name);
} catch (ClassNotFoundException e) {
c = super.loadClass(name);
}
return c;
}
private void dbg(String string) {
System.out.println(string);
}
@Override
protected Class<?> findClass(String name) throws ClassNotFoundException {
try {
byte[] b = loadClassData(name);
return defineClass(name, b, 0, b.length);
} catch (Exception e) {
throw new ClassNotFoundException(e.getMessage(), e);
}
}
private byte[] loadClassData(String name) throws IOException {
result = new byte[0];
last = 0;
FileInputStream ins = null;
try {
byte[] buf = new byte[BUFSIZE];
int readSize = 0;
name = name.replace('.','/');
File classFile = new File("c:/mydoc/tmp/" + name + ".class");
ins = new FileInputStream(classFile);
while((readSize = ins.read(buf)) != -1 ) {
moveToResult(readSize, buf);
}
return result;
} finally {
if(ins != null) {
ins.close();
}
}
}
private void moveToResult(int readSize, byte[] buf) {
byte[] tmp = new byte[last + readSize];
// 結果バイト配列をtmp配列の先頭にコピー
System.arraycopy(result, 0, tmp, 0, result.length);
// bufをtmp配列にコピー
System.arraycopy(buf, 0, tmp, last, readSize);
result = tmp;
last += readSize;
}
public static void main(String[] args) {
try {
MyClassLoader loader = new MyClassLoader();
System.out.println("parent:" + loader.getParent().getClass().getName());
Class<?> clazz = loader.loadClass("test.MyClassLoaderTarget");
System.out.println("target class loader name:" + clazz.getClassLoader().getClass().getName());
((Executor)clazz.newInstance()).execute();
} catch (Exception e) {
e.printStackTrace();
}
}
}
package test;
public class MyClassLoaderTarget implements Executor {
@Override
public void execute() {
System.out.println("AAA");
MyClassLoaderTarget2 target2 = new MyClassLoaderTarget2();
target2.execute();
System.out.println("target2 class loader name:" + target2.getClass().getClassLoader().getClass().getName());
}
public static void main(String[] args) {
MyClassLoaderTarget target = new MyClassLoaderTarget();
target.execute();
}
}
package test;
public class MyClassLoaderTarget2 implements Executor {
@Override
public void execute() {
System.out.println("BBB");
}
public static void main(String[] args) {
MyClassLoaderTarget2 target = new MyClassLoaderTarget2();
target.execute();
}
}
package test;
public interface Executor {
public void execute();
}
実行結果
parent:sun.misc.Launcher$AppClassLoader target class loader name:test.MyClassLoader AAA BBB target2 class loader name:test.MyClassLoader
ThreadLocal
スレッドに固有のオブジェクトを保管するために使う(Thread Singleton)。Servletの中で、使用例としてDBに対するConnectionをスレッド毎に保管する場合があげられる。この場合、引数にConnectionを作成すると全てのメソッドにConnectionの引数が必要になり手間がかかる。スレッドにプライベートフィールドを作成して保管できないときに使える。
JDBC
| タイプ | 説明 | 備考 |
| type2 | ベンダのライブラリと共同して、DBと通信。ベンダのクライアントアプリが必要。 | |
| type4 | 直接DBと通信。JDBCドライバサイズが大きい |
バッチ
insert, updateが連続して行われるときにネットワークトラフィックを削減するために使う。PreparedStatementオブジェクトに対して、addBatch(), executeBatch()メソッドを使うと複数のステートメントをまとめてDBサーバ送信する。
言語コード
| コード名 | 説明 |
| Windows-31J | ShiftJISの拡張。NEC特殊コードもサポート。 |
スレッドダンプ
稼働中のスレッドを標準出力にダンプする。
kill -3 プロセス番号
出力例 daemon以外のスレッドを見る。以下の例ではSNMP APIで停止している。
Full thread dump Java HotSpot(TM) Server VM (11.2-b01 mixed mode):
"RMI Scheduler(0)" daemon prio=10 tid=0x0955e000 nid=0x15db waiting on condition [0x30cd1000..0x30cd1fa0]
java.lang.Thread.State: TIMED_WAITING (parking)
at sun.misc.Unsafe.park(Native Method)
- parking to wait for <0x37f243d8> (a java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject)
at java.util.concurrent.locks.LockSupport.parkNanos(LockSupport.java:198)
at java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.awaitNanos(AbstractQueuedSynchronizer.java:1963)
at java.util.concurrent.DelayQueue.take(DelayQueue.java:164)
at java.util.concurrent.ScheduledThreadPoolExecutor$DelayedWorkQueue.take(ScheduledThreadPoolExecutor.java:583)
at java.util.concurrent.ScheduledThreadPoolExecutor$DelayedWorkQueue.take(ScheduledThreadPoolExecutor.java:576)
at java.util.concurrent.ThreadPoolExecutor.getTask(ThreadPoolExecutor.java:947)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:907)
at java.lang.Thread.run(Thread.java:619)
"Thread-7" prio=10 tid=0x0954bc00 nid=0x15bf in Object.wait() [0x30eb7000..0x30eb7ea0]
java.lang.Thread.State: TIMED_WAITING (on object monitor)
at java.lang.Object.wait(Native Method)
- waiting on <0xa89ec300> (a com.adventnet.snmp.snmp2.SnmpCallback)
at com.adventnet.snmp.snmp2.SnmpCallback.sleepUntilNotified(SnmpCallback.java:166)
- locked <0xa89ec300> (a com.adventnet.snmp.snmp2.SnmpCallback)
at com.adventnet.snmp.snmp2.SnmpCallback.run(SnmpCallback.java:152)
アノテーション
注釈。プログラムに影響を与えない。プログラムから読める。コンパイラの動作に影響を与える。
@Override
Overrideアノテーションを付加したメソッドがオーバライドメソッドでなければコンパイルエラーになる。
@SuppressWarning
- Xlintを指定したときに発生する警告メッセージを抑制する。
アプレット
- jarファイルを指定するには、ARCHIVEタグを使う。CLASSPATHはきかない。
セキュリティポリシー
java.policyファイルの構文
grant signedBy "signer_names", codeBase "URL",
principal principal_class_name "principal_name",
principal principal_class_name "principal_name",
...
{
permission permission_class_name "target_name", "action",signedBy "signer_names";
permission permission_class_name "target_name", "action",signedBy "signer_names";
...
};
ここで、"signer_names"、"URL"、principal_class_name、"principal_name"、permission_class_name、"target_name"、"action"、"signer_names"は、変数。
signedBy 、codeBase、、principal は省略可能。
意味は、signer_namesで署名されたURLにあるプログラムが、permission_class_nameで規定されるtarget_nameに対して、actionすることを許可する。target_name, actionについては、permission_class_nameのAPIを参照。
例
permission java.io.FilePermission "\\\\192.168.1.40\\-", "read,write";
192.168.1.40のリモートファイルに対する読み書きを許可する。
Linux firefoxへのJava Plugin インストール
例
# ln -s /usr/java/jdk1.6.0_20/jre/lib/i386/libnpjp2.so /opt/firefox/plugins
インストールの確認
urlにabout:pluginsを設定して開く
Linuxでのplugin コントロールパネル
起動
$JAVA_HOME/bin/ControlPanel を実行
最大メモリ容量の修正
"-XX:MaxPermSize=256m"をJavaタブのアプレットパラメータに追加
その他
スタックトレースをStringに変換する
仕事の都合で、最後の行で改行を削除してタブをスペースに変換している。
private String getStackTraceAsString(Exception e) {
ByteArrayOutputStream ostream = new ByteArrayOutputStream(100);
e.printStackTrace(new PrintStream(ostream));
String sep = System.getProperty("line.separator");
return ostream.toString().replaceAll(sep, "").replace("\t", " ");
}
固定長レコードのファイルを出力
package test;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
public class SingleFille {
private BufferedOutputStream bstream;
/**
* ファイルに書き込むデータ
* 桁数
* 内容
*/
private String[][] data =
{
{"aaa1", "bbb1", "ccc1"},
{"漢字2", "bbb2", "ccc2"},
{"aaa3", "漢字3", "ccc3"},
{"aaa4", "bbb4", "漢字4"},
};
/** 列の桁数 */
private int[] length = {10, 20, 30};
/** ファイルオフセット */
private int offset = 0;
private static final String FILE_PATH = "singleFile.dat";
public static void main(String[] args) {
SingleFille sfile = new SingleFille();
try {
sfile.execute();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
public void execute() throws IOException {
File file = new File(FILE_PATH);
try {
FileOutputStream stream = new FileOutputStream(file);
bstream = new BufferedOutputStream(stream);
for(int i = 0; i < data.length; i++) {
String[] line = data[i];
putFile(line);
}
} catch (IOException e) {
throw e;
} finally {
if(bstream != null) {
try {
bstream.close();
} catch (IOException e) {
throw e;
}
}
}
}
/**
* @param line
* @throws IOException
*/
private void putFile(String[] line) throws IOException {
for(int i = 0; i < line.length; i++) {
//各列を桁数になるように整形
byte[] term = createTerm(line[i], i);
bstream.write(term);
offset += term.length;
}
}
/**
* @param term
* @param index
* @return
* @throws UnsupportedEncodingException
*/
private byte[] createTerm(String term, int index) throws UnsupportedEncodingException {
//項目を格納するバイト
byte[] outterm = new byte[length[index]];
//項目をShift_JISのバイトに変換
byte[] interm = term.getBytes("SJIS");
for(int i = 0; i < outterm.length; i++) {
if( i < interm.length) {
outterm[i] = interm[i];
} else {
//残りはスペース
outterm[i] = 0x20;
}
}
return outterm;
}
}
