clone
| 日本語 | 複製、コピー、クローン |
| 英語 | clone |
| ふりがな | くろーん |
| フリガナ | クローン |
Objectクラスのclone()メソッド。
インスタンスを複製するためのメソッド。
このメソッドには複雑なルールがある。
まず、Objectクラスのclone()メソッドはprotectedメソッドのため、外のクラスから直接呼び出すことはできない。このメソッドはオーバーライドするか、またはオーバーライドしたclone()メソッド内で呼び出す。
サブクラスからObjectクラスのclone()メソッドを呼び出すことで、そのサブクラスの複製を作成することができる。サブクラスのインスタンスが作られ、フィールドの値が全てコピーされてから、Objectクラスのclone()メソッドの戻り値としてインスタンスの参照が返される。
ただし、Objectクラスのclone()メソッドは、サブクラスがCloneableインターフェイスの実装クラスでない場合、CloneNotSupportedException例外を投げる。つまりObjectクラスのclone()メソッドは、このメソッドが呼ばれることを証明するために、サブクラスにCloneableインターフェイスの実装を強制する。
Objectクラスのclone()メソッドによる複製は、フィールドの値をそのままコピーする。フィールドが参照型変数の場合、その参照値がそのままコピーされるため、参照先のインスタンスは複製されない。これを「浅いコピー」(シャローコピー)という。
インスタンスも複製する「深いコピー」(ディープコピー)を行う場合には、オーバーライドしたclone()メソッド内で各フィールドの参照型変数が参照するインスタンスの複製を作り、セットする必要がある。
clone()メソッドによる複製は面倒だが、Javaではクラスを参照を通してのみ管理することができ、参照の複製のみではインスタンスは複製されない以上、必須のシステムである。
Javaのクラスとインスタンス、参照を理解した上で、適切に実装できることが望まれる。
インスタンスを複製するためのメソッド。
このメソッドには複雑なルールがある。
まず、Objectクラスのclone()メソッドはprotectedメソッドのため、外のクラスから直接呼び出すことはできない。このメソッドはオーバーライドするか、またはオーバーライドしたclone()メソッド内で呼び出す。
サブクラスからObjectクラスのclone()メソッドを呼び出すことで、そのサブクラスの複製を作成することができる。サブクラスのインスタンスが作られ、フィールドの値が全てコピーされてから、Objectクラスのclone()メソッドの戻り値としてインスタンスの参照が返される。
ただし、Objectクラスのclone()メソッドは、サブクラスがCloneableインターフェイスの実装クラスでない場合、CloneNotSupportedException例外を投げる。つまりObjectクラスのclone()メソッドは、このメソッドが呼ばれることを証明するために、サブクラスにCloneableインターフェイスの実装を強制する。
Objectクラスのclone()メソッドによる複製は、フィールドの値をそのままコピーする。フィールドが参照型変数の場合、その参照値がそのままコピーされるため、参照先のインスタンスは複製されない。これを「浅いコピー」(シャローコピー)という。
インスタンスも複製する「深いコピー」(ディープコピー)を行う場合には、オーバーライドしたclone()メソッド内で各フィールドの参照型変数が参照するインスタンスの複製を作り、セットする必要がある。
clone()メソッドによる複製は面倒だが、Javaではクラスを参照を通してのみ管理することができ、参照の複製のみではインスタンスは複製されない以上、必須のシステムである。
Javaのクラスとインスタンス、参照を理解した上で、適切に実装できることが望まれる。
// Sample.java
public class Sample
{
public static void main( String[] args )
{
try
{
// DataNotUseSuperクラスの使用例。
// 元インスタンスを作ります。
DataNotUseSuper data = new DataNotUseSuper();
data.setData( 100 );
System.out.println( data.getData() );
// 100
// clone()メソッドで複製を作ります。
DataNotUseSuper dataCloned = (DataNotUseSuper)data.clone();
// 出力します。
System.out.println( dataCloned.getData() );
// 100
}
catch( CloneNotSupportedException e )
{
e.printStackTrace();
}
try
{
// DataUseSuperクラスの使用例。
// 元インスタンスを作ります。
DataUseSuper data = new DataUseSuper();
data.setData( 200 );
System.out.println( data.getData() );
// 200
// clone()メソッドで複製を作ります。
DataUseSuper dataCloned = (DataUseSuper)data.clone();
// 出力します。
System.out.println( dataCloned.getData() );
// 200
}
catch( CloneNotSupportedException e )
{
e.printStackTrace();
}
try
{
// DataNotCloneableImplementedクラスの使用例。
// 元インスタンスを作ります。
DataNotCloneableImplemented data = new DataNotCloneableImplemented();
data.setData( 300 );
System.out.println( data.getData() );
// 300
// clone()メソッドで複製を作ります。
DataNotCloneableImplemented dataCloned = (DataNotCloneableImplemented)data.clone();
}
catch( CloneNotSupportedException e )
{
// DataNotCloneableImplementedクラスは、Cloneableインターフェイス
// の実装クラスじゃないのに、Objectクラスのclone()メソッドで
// 複製を作ろうとしたので、CloneNotSupportedException例外が投げられます。
e.printStackTrace();
// java.lang.CloneNotSupportedException: DataNotCloneableImplemented
// at java.lang.Object.clone(Native Method)
// at DataNotCloneableImplemented.clone(Sample.java:170)
// at Sample.main(Sample.java:61)
}
// Objectクラスのclone()メソッドはprotectedなので、
// オーバーライドしないと呼び出せません。
DataNotCloneOverride data = new DataNotCloneOverride();
// data.clone();
// コンパイルエラー:
// メソッド clone() は型 Object で不可視です。
}
}
/**
* Objectクラスのclone()メソッドをオーバーライドして、
* 手作業でインスタンスを作りフィールドをコピーする例。
*/
class DataNotUseSuper
{
private int data;
public void setData( int i )
{
data = i;
}
public int getData()
{
return data;
}
/**
* Objectクラスのclone()メソッドをオーバーライドします。
*/
protected Object clone() throws CloneNotSupportedException
{
// 自クラスのインスタンスを作り、フィールドをコピーします。
// (自クラスなので、privateフィールドもアクセスできます)
DataNotUseSuper newData = new DataNotUseSuper();
newData.data = this.data;
return newData;
}
}
/**
* Objectクラスのclone()メソッドをオーバーライドして、
* Objectクラスのclone()メソッドを使用して複製を作ります。
*/
class DataUseSuper implements Cloneable
{
private int data;
public void setData( int i )
{
data = i;
}
public int getData()
{
return data;
}
/**
* Objectクラスのclone()メソッドをオーバーライドします。
*/
protected Object clone() throws CloneNotSupportedException
{
// Objectクラスのclone()メソッドで複製を作ります。
// Cloneableインターフェイスの実装クラスでないと
// CloneNotSupportedException例外が投げられます。
return super.clone();
}
}
/**
* Objectクラスのclone()メソッドをオーバーライドして、
* Objectクラスのclone()メソッドを使用して複製を作ります。
* ただし、Cloneableインターフェイスの実装クラスでは
* ありません(つまり間違った例です)。
*/
class DataNotCloneableImplemented
{
private int data;
public void setData( int i )
{
data = i;
}
public int getData()
{
return data;
}
/**
* Objectクラスのclone()メソッドをオーバーライドします。
*/
protected Object clone() throws CloneNotSupportedException
{
// Objectクラスのclone()メソッドで複製を作ります。
// でも、Cloneableインターフェイスの実装クラスではないので
// CloneNotSupportedException例外が投げられます。
return super.clone();
}
}
/**
* Objectクラスのclone()メソッドをオーバーライドしていいないクラス。
* これも間違った例です。
*/
class DataNotCloneOverride
{
private int data;
public void setData( int i )
{
data = i;
}
public int getData()
{
return data;
}
}
public class Sample
{
public static void main( String[] args )
{
try
{
// DataNotUseSuperクラスの使用例。
// 元インスタンスを作ります。
DataNotUseSuper data = new DataNotUseSuper();
data.setData( 100 );
System.out.println( data.getData() );
// 100
// clone()メソッドで複製を作ります。
DataNotUseSuper dataCloned = (DataNotUseSuper)data.clone();
// 出力します。
System.out.println( dataCloned.getData() );
// 100
}
catch( CloneNotSupportedException e )
{
e.printStackTrace();
}
try
{
// DataUseSuperクラスの使用例。
// 元インスタンスを作ります。
DataUseSuper data = new DataUseSuper();
data.setData( 200 );
System.out.println( data.getData() );
// 200
// clone()メソッドで複製を作ります。
DataUseSuper dataCloned = (DataUseSuper)data.clone();
// 出力します。
System.out.println( dataCloned.getData() );
// 200
}
catch( CloneNotSupportedException e )
{
e.printStackTrace();
}
try
{
// DataNotCloneableImplementedクラスの使用例。
// 元インスタンスを作ります。
DataNotCloneableImplemented data = new DataNotCloneableImplemented();
data.setData( 300 );
System.out.println( data.getData() );
// 300
// clone()メソッドで複製を作ります。
DataNotCloneableImplemented dataCloned = (DataNotCloneableImplemented)data.clone();
}
catch( CloneNotSupportedException e )
{
// DataNotCloneableImplementedクラスは、Cloneableインターフェイス
// の実装クラスじゃないのに、Objectクラスのclone()メソッドで
// 複製を作ろうとしたので、CloneNotSupportedException例外が投げられます。
e.printStackTrace();
// java.lang.CloneNotSupportedException: DataNotCloneableImplemented
// at java.lang.Object.clone(Native Method)
// at DataNotCloneableImplemented.clone(Sample.java:170)
// at Sample.main(Sample.java:61)
}
// Objectクラスのclone()メソッドはprotectedなので、
// オーバーライドしないと呼び出せません。
DataNotCloneOverride data = new DataNotCloneOverride();
// data.clone();
// コンパイルエラー:
// メソッド clone() は型 Object で不可視です。
}
}
/**
* Objectクラスのclone()メソッドをオーバーライドして、
* 手作業でインスタンスを作りフィールドをコピーする例。
*/
class DataNotUseSuper
{
private int data;
public void setData( int i )
{
data = i;
}
public int getData()
{
return data;
}
/**
* Objectクラスのclone()メソッドをオーバーライドします。
*/
protected Object clone() throws CloneNotSupportedException
{
// 自クラスのインスタンスを作り、フィールドをコピーします。
// (自クラスなので、privateフィールドもアクセスできます)
DataNotUseSuper newData = new DataNotUseSuper();
newData.data = this.data;
return newData;
}
}
/**
* Objectクラスのclone()メソッドをオーバーライドして、
* Objectクラスのclone()メソッドを使用して複製を作ります。
*/
class DataUseSuper implements Cloneable
{
private int data;
public void setData( int i )
{
data = i;
}
public int getData()
{
return data;
}
/**
* Objectクラスのclone()メソッドをオーバーライドします。
*/
protected Object clone() throws CloneNotSupportedException
{
// Objectクラスのclone()メソッドで複製を作ります。
// Cloneableインターフェイスの実装クラスでないと
// CloneNotSupportedException例外が投げられます。
return super.clone();
}
}
/**
* Objectクラスのclone()メソッドをオーバーライドして、
* Objectクラスのclone()メソッドを使用して複製を作ります。
* ただし、Cloneableインターフェイスの実装クラスでは
* ありません(つまり間違った例です)。
*/
class DataNotCloneableImplemented
{
private int data;
public void setData( int i )
{
data = i;
}
public int getData()
{
return data;
}
/**
* Objectクラスのclone()メソッドをオーバーライドします。
*/
protected Object clone() throws CloneNotSupportedException
{
// Objectクラスのclone()メソッドで複製を作ります。
// でも、Cloneableインターフェイスの実装クラスではないので
// CloneNotSupportedException例外が投げられます。
return super.clone();
}
}
/**
* Objectクラスのclone()メソッドをオーバーライドしていいないクラス。
* これも間違った例です。
*/
class DataNotCloneOverride
{
private int data;
public void setData( int i )
{
data = i;
}
public int getData()
{
return data;
}
}
// Sample.java
public class Sample
{
public static void main( String[] args )
{
try
{
// DataNotUseSuperクラスの使用例。
// 元インスタンスを作ります。
DataNotUseSuper data = new DataNotUseSuper();
data.setData( 100 );
System.out.println( data.getData() );
// 100
// clone()メソッドで複製を作ります。
DataNotUseSuper dataCloned = (DataNotUseSuper)data.clone();
// 出力します。
System.out.println( dataCloned.getData() );
// 100
}
catch( CloneNotSupportedException e )
{
e.printStackTrace();
}
try
{
// DataUseSuperクラスの使用例。
// 元インスタンスを作ります。
DataUseSuper data = new DataUseSuper();
data.setData( 200 );
System.out.println( data.getData() );
// 200
// clone()メソッドで複製を作ります。
DataUseSuper dataCloned = (DataUseSuper)data.clone();
// 出力します。
System.out.println( dataCloned.getData() );
// 200
}
catch( CloneNotSupportedException e )
{
e.printStackTrace();
}
try
{
// DataNotCloneableImplementedクラスの使用例。
// 元インスタンスを作ります。
DataNotCloneableImplemented data = new DataNotCloneableImplemented();
data.setData( 300 );
System.out.println( data.getData() );
// 300
// clone()メソッドで複製を作ります。
DataNotCloneableImplemented dataCloned = (DataNotCloneableImplemented)data.clone();
}
catch( CloneNotSupportedException e )
{
// DataNotCloneableImplementedクラスは、Cloneableインターフェイス
// の実装クラスじゃないのに、Objectクラスのclone()メソッドで
// 複製を作ろうとしたので、CloneNotSupportedException例外が投げられます。
e.printStackTrace();
// java.lang.CloneNotSupportedException: DataNotCloneableImplemented
// at java.lang.Object.clone(Native Method)
// at DataNotCloneableImplemented.clone(Sample.java:170)
// at Sample.main(Sample.java:61)
}
// Objectクラスのclone()メソッドはprotectedなので、
// オーバーライドしないと呼び出せません。
DataNotCloneOverride data = new DataNotCloneOverride();
// data.clone();
// コンパイルエラー:
// メソッド clone() は型 Object で不可視です。
}
}
/**
* Objectクラスのclone()メソッドをオーバーライドして、
* 手作業でインスタンスを作りフィールドをコピーする例。
*/
class DataNotUseSuper
{
private int data;
public void setData( int i )
{
data = i;
}
public int getData()
{
return data;
}
/**
* Objectクラスのclone()メソッドをオーバーライドします。
*/
protected Object clone() throws CloneNotSupportedException
{
// 自クラスのインスタンスを作り、フィールドをコピーします。
// (自クラスなので、privateフィールドもアクセスできます)
DataNotUseSuper newData = new DataNotUseSuper();
newData.data = this.data;
return newData;
}
}
/**
* Objectクラスのclone()メソッドをオーバーライドして、
* Objectクラスのclone()メソッドを使用して複製を作ります。
*/
class DataUseSuper implements Cloneable
{
private int data;
public void setData( int i )
{
data = i;
}
public int getData()
{
return data;
}
/**
* Objectクラスのclone()メソッドをオーバーライドします。
*/
protected Object clone() throws CloneNotSupportedException
{
// Objectクラスのclone()メソッドで複製を作ります。
// Cloneableインターフェイスの実装クラスでないと
// CloneNotSupportedException例外が投げられます。
return super.clone();
}
}
/**
* Objectクラスのclone()メソッドをオーバーライドして、
* Objectクラスのclone()メソッドを使用して複製を作ります。
* ただし、Cloneableインターフェイスの実装クラスでは
* ありません(つまり間違った例です)。
*/
class DataNotCloneableImplemented
{
private int data;
public void setData( int i )
{
data = i;
}
public int getData()
{
return data;
}
/**
* Objectクラスのclone()メソッドをオーバーライドします。
*/
protected Object clone() throws CloneNotSupportedException
{
// Objectクラスのclone()メソッドで複製を作ります。
// でも、Cloneableインターフェイスの実装クラスではないので
// CloneNotSupportedException例外が投げられます。
return super.clone();
}
}
/**
* Objectクラスのclone()メソッドをオーバーライドしていいないクラス。
* これも間違った例です。
*/
class DataNotCloneOverride
{
private int data;
public void setData( int i )
{
data = i;
}
public int getData()
{
return data;
}
}




