反射
57.リフレクションとは何ですか?
リフレクションとは、主に、プログラムが自身の状態または動作にアクセス、検出、および変更する機能を指します。
Javaリフレクション:
Javaランタイム環境では、どのクラスについても、そのクラスがどのような属性とメソッドを持っているかを知ることができますか?任意のオブジェクトについて、そのメソッドのいずれかを呼び出すことができます
Javaリフレクションメカニズムは、主に次の機能を提供します。
-
実行時にオブジェクトが属するクラスを判断します。
-
実行時に任意のクラスのオブジェクトを作成します。
-
実行時に任意のクラスのメンバー変数とメソッドを判断します。
-
実行時に任意のオブジェクトメソッドを呼び出します。
58. Javaシリアル化とは何ですか?どのような状況でシリアル化が必要ですか?
簡単に言うと、さまざまなオブジェクトの状態(つまり、メソッドではなくインスタンス変数)をメモリに保存し、保存されたオブジェクトの状態を読み取ることです。独自のさまざまな方法を使用してオブジェクトの状態を保存できますが、Javaには、独自の方法よりも優れているはずのオブジェクトの状態を保存するためのメカニズム、つまりシリアル化が用意されています。
どのような状況でシリアル化する必要がありますか:
a)オブジェクトの状態をメモリ内のファイルまたはデータベースに保存する場合;
b)ソケットを使用してネットワーク上でオブジェクトを転送する
場合; c)RMIを介してオブジェクトを転送する場合;
59.動的エージェントとは何ですか?アプリケーションは何ですか?
動的プロキシ:
特定のインターフェイスを実装するクラスのメソッドに処理を追加する場合。たとえば、ログの追加、トランザクションの追加などです。このクラスのプロキシを作成できるので、名前が示すように、新しいクラスを作成します。このクラスには、元のクラスメソッドの関数が含まれているだけでなく、元のベースで追加の処理を行う新しいクラスが追加されます。このプロキシクラスは明確に定義されておらず、動的に生成されます。これには、デカップリング、柔軟性、および強力なスケーラビリティという意味があります。
動的エージェントの適用:
-
春のAOP
-
事務を追加します
-
権限を追加する
-
ログを追加
60.動的プロキシを実装する方法は?
まず、インターフェイスを定義し、InvocationHandler(インターフェイスを実装するクラスのオブジェクトを渡す)処理クラスを定義する必要があります。別のツールクラスProxyがあります(彼のnewInstance()を呼び出すとプロキシオブジェクトを生成できるため、プロキシクラスと呼ぶのが通例です。実際、プロキシオブジェクトを生成するのは単なるツールクラスです)。InvocationHandlerを使用して、プロキシクラスのソースコードをスプライシングし、コンパイルしてプロキシクラスのバイナリコードを生成し、ローダーでロードし、インスタンス化してプロキシオブジェクトを生成し、最後に戻ります。
オブジェクトコピー
61.なぜクローンを使用するのですか?
オブジェクトを処理したいが、次の操作のために元のデータを保持したい場合は、クローンを作成する必要があります。Java言語のクローンは、クラスのインスタンス用です。
62.オブジェクトのクローン作成を実装するにはどうすればよいですか?
2つの方法があります:
1)Cloneableインターフェースを実装し、Objectクラスのclone()メソッドを書き直します。
2)Serializableインターフェイスを実現し、オブジェクトのシリアル化と逆シリアル化を通じてクローンを実現します。これにより、実際のディープクローンを実現できます。コードは、次のとおりです。
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
public class MyUtil {
private MyUtil() {
throw new AssertionError();
}
@SuppressWarnings("unchecked")
public static <T extends Serializable> T clone(T obj) throws Exception {
ByteArrayOutputStream bout = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(bout);
oos.writeObject(obj);
ByteArrayInputStream bin = new ByteArrayInputStream(bout.toByteArray());
ObjectInputStream ois = new ObjectInputStream(bin);
return (T) ois.readObject();
// 说明:调用ByteArrayInputStream或ByteArrayOutputStream对象的close方法没有任何意义
// 这两个基于内存的流只要垃圾回收器清理对象就能够释放资源,这一点不同于对外部资源(如文件流)的释放
}
}
テストコードは次のとおりです。
import java.io.Serializable;
/**
* 人类
* @author nnngu
*
*/
class Person implements Serializable {
private static final long serialVersionUID = -9102017020286042305L;
private String name; // 姓名
private int age; // 年龄
private Car car; // 座驾
public Person(String name, int age, Car car) {
this.name = name;
this.age = age;
this.car = car;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public Car getCar() {
return car;
}
public void setCar(Car car) {
this.car = car;
}
@Override
public String toString() {
return "Person [name=" + name + ", age=" + age + ", car=" + car + "]";
}
}
/**
* 小汽车类
* @author nnngu
*
*/
class Car implements Serializable {
private static final long serialVersionUID = -5713945027627603702L;
private String brand; // 品牌
private int maxSpeed; // 最高时速
public Car(String brand, int maxSpeed) {
this.brand = brand;
this.maxSpeed = maxSpeed;
}
public String getBrand() {
return brand;
}
public void setBrand(String brand) {
this.brand = brand;
}
public int getMaxSpeed() {
return maxSpeed;
}
public void setMaxSpeed(int maxSpeed) {
this.maxSpeed = maxSpeed;
}
@Override
public String toString() {
return "Car [brand=" + brand + ", maxSpeed=" + maxSpeed + "]";
}
}
class CloneTest {
public static void main(String[] args) {
try {
Person p1 = new Person("郭靖", 33, new Car("Benz", 300));
Person p2 = MyUtil.clone(p1); // 深度克隆
p2.getCar().setBrand("BYD");
// 修改克隆的Person对象p2关联的汽车对象的品牌属性
// 原来的Person对象p1关联的汽车不会受到任何影响
// 因为在克隆Person对象时其关联的汽车对象也被克隆了
System.out.println(p1);
} catch (Exception e) {
e.printStackTrace();
}
}
}
注:シリアル化と逆シリアル化に基づくクローン作成は、ディープクローン作成であるだけでなく、さらに重要なことに、一般的な制限により、クローン作成するオブジェクトがシリアル化をサポートしているかどうかを確認できます。この確認は、実行時に例外がスローされるのではなく、コンパイラによって実行されます。このソリューションは、Objectクラスのcloneメソッドを使用してオブジェクトのクローンを作成するよりも明らかに優れています。実行時に問題を残すよりも、コンパイル時に問題を公開する方が常に適切です。
63.ディープコピーとシャローコピーの違いは何ですか?
-
シャローコピーはオブジェクトの参照アドレスをコピーするだけで、2つのオブジェクトは同じメモリアドレスを指しているため、いずれかの値が変更されると、それに応じて他の値も変更されます。これはシャローコピーです(例:assign())
-
ディープコピーはオブジェクトと値をコピーすることです。2つのオブジェクトは他の値の値を変更しても変更されません。これはディープコピーです(例:JSON.parse()とJSON.stringify()ですが、このメソッドは関数をコピーできませんの種類)