反射
フレームデザインを反映して、魂であります
負荷クラスの最初に、タイミング
あなたはクラスがまだロードによって、メモリにシステムをロードされていない場合は、クラスを使用したい場合は、このクラスが初期化されて達成するための3つの手順を初期化し、接続します。
- ロード:Classオブジェクトを作成するために、メモリにファイルを読み取るために、クラスを参照し、誰。システムは、Classオブジェクトを構築する際に使用されている任意のクラス。
- 接続:あなたは正しい内部構造や一貫性、および他のクラスを持っていることを確認してください。クラスの静的メンバにメモリを割り当て、デフォルトの初期値を設定する準備を担当します。
- 初期化:ようにメンバ変数を初期化します。
ロード機会
- クラスのインスタンスを作成します。
- アクセスクラスの静的変数や静的変数の代入
- 静的メソッド呼び出しクラス
- クラスのサブクラスを開始
- 反射モードのjava.lang.Class対応するクラスまたはインタフェースオブジェクトの作成を強制的に使用
第二に、クラスローダ
クラスローダクラスローダとは何ですか
ロードのための責任をのためのメモリにファイルを、対応するClassオブジェクトを生成した.class。
私たちは、クラスローディング機構を気に、しかし、このメカニズムを理解していないが、我々はプログラムの理解を実行することができます。
分類クラスローダ
(1)ルート・クラス・ローダ
- また、ブートストラップクラスローダとして知られていると、ロードJavaコアクラスを担当して
- システム、文字列などというようにそのような。JDK、JREのlibディレクトリ下のrt.jarのファイルで
(2)拡張クラスローダ
- ジャーにJRE拡張ディレクトリをロードするための責任。
- libディレクトリの下にJDK extディレクトリにあるJRE
(3)システム・クラス・ローダ
- JVMでjavaコマンドが開始からロードするクラスファイルを担当
- JARパッケージおよびクラスパスは、環境変数のクラスパスを指定しました
第三に、どのような反映されています
三の段階でオブジェクトを作成します
- ステージの.javaソースファイルのファイル
- .classバイトコードのステージ
- オブジェクトのステージに新しいオブジェクト名を作成します。
内観
実行時に取得することができますJavaBeanの間で属性名と取得や方法を設定
反射
- Javaリフレクション機構のために、動作状態にある任意のクラス、すべてのこのクラスのプロパティとメソッドに知らされています。
- 任意のオブジェクトのために、私たちはそのメソッドとプロパティのいずれかを呼び出すことができます。
- この関数の方法及び動的情報は、Java言語の動的取得として知られているオブジェクトの反射機構を呼び出します。
- リフレクションを使用したい、我々はバイトコードファイルを取得するために持っています。
第四に、クラスの反射
クラス名 | 使用 |
---|---|
Classクラス | Javaアプリケーションの実行中のエンティティのクラスを代表してクラスおよびインタフェースを表し |
Fieldクラス | クラスのメンバ変数に代わって(もクラス属性のメンバ変数として知られています) |
メソッドのクラス | この方法は、以下のクラスを表します |
コンストラクタクラス | 代表クラスのコンストラクタ |
(1)クラスクラス
- 関連するクラスのメソッドを取得します
方法 | 使用 |
---|---|
forName(文字列クラス名) | オブジェクトクラス名に応じて、クラスに戻り |
getName() | クラスのフルパス名を取得します。 |
newInstance() | クラスのインスタンスを作成します。 |
getPackage() | クラスのパッケージを取得します。 |
getSimpleName() | 名前は、クラスを派生されます |
getSuperclass() | 現在の名前が派生したクラスは親クラスを継承しています |
でgetInterfaces() | 現在のクラスまたはクラスがインタフェースを実装して取得します |
asSubclass(クラスclazz) | そのサブクラスの代表クラスオブジェクトに渡されたオブジェクト |
キャスト | オブジェクトクラスまたはインタフェースにオブジェクトの代表 |
getClassLoader() | クラスローダを取得します。 |
getClasses() | これは、配列に含まれる配列、クラスのすべてのオブジェクトとインタフェースクラスpublicクラスを返します |
getDeclaredClasses() | これは、アレイに含むすべてのクラスのクラスのオブジェクトの配列とインターフェースクラスを返します |
- 得られたクラスは、関連メソッド属性
方法 | 使用 |
---|---|
getField(文字列名) | パブリックプロパティオブジェクトを取得 |
れるGetFields() | すべてのパブリックプロパティのオブジェクトへのアクセス |
getDeclaredField(文字列名) | Propertyオブジェクトの |
getDeclaredFields() | オブジェクトのすべてのプロパティを取得します。 |
- 関連するクラスのノートを得る方法
方法 | 使用 |
---|---|
getAnnotation(クラスannotationClass) | クラスのパラメータの型のオブジェクトに一致する公開返し注釈 |
getAnnotations() | そのクラスパブリックコメントのすべてのオブジェクトを返します。 |
getDeclaredAnnotation(クラスannotationClass) | パラメータの型と一致するクラスのノートのすべてのオブジェクトを返します。 |
getDeclaredAnnotations() | そのようなオブジェクトのリターンすべてのコメント |
- 関連するクラスのコンストラクタを得る方法
方法 | 使用 |
---|---|
getConstructor(クラス... <?>たparameterTypes) | パブリッククラスのコンストラクタ引数の型マッチングを取得 |
getConstructors() | クラスのすべてのpublicコンストラクタを取得 |
getDeclaredConstructor(クラス... <?>たparameterTypes) | マッチングクラスのコンストラクタのパラメータの型を取得 |
getDeclaredConstructors() | すべてのクラスのコンストラクタを取得します。 |
- 関連するクラスのメソッドを取得
方法 | 使用 |
---|---|
getMethod(文字列名、クラス... <?>たparameterTypes) | こうした公共の道の取得 |
getMethods() | すべてのそのような方法は、公共取得します |
getDeclaredMethod(文字列名、クラス... <?>たparameterTypes) | このような方法を得ます |
getDeclaredMethods() | すべてのメソッドは、クラスを取得します |
- クラスの他の重要なメソッド
方法 | 使用 |
---|---|
isAnnotation() | 注釈型は、trueを返した場合 |
isAnnotationPresent(クラスannotationClass <?注釈拡張します>) | 指定された型の注釈型は、trueを返した場合 |
isAnonymousClass() | 匿名クラスのリターンtrueの場合 |
でIsArray() | クラスがある場合、配列は、trueを返します |
伊仙() | 列挙クラスの戻りtrueの場合 |
でisinstance(オブジェクトobj) | objがクラスのインスタンスである場合はtrueを返します |
isInterface() | インターフェイスクラスはtrueを返す場合 |
isLocalClass() | クラスは、真の部分的復帰の場合 |
isMemberClass() | 内部クラスのリターンtrueの場合 |
(2)フィールドベース
方法 | 使用 |
---|---|
等しい(オブジェクトobj) | 属性は等しいtrueを返し、OBJです |
(オブジェクトobj)を取得 | 対応するプロパティの値OBJを取得 |
集合(オブジェクトobj、Object値) | 设置obj中对应属性值 |
(3)Method类
方法 | 用途 |
---|---|
invoke(Object obj, Object... args) | 传递object对象及参数调用该对象对应的方法 |
(4)Constructor类
方法 | 用途 |
---|---|
newInstance(Object... initargs) | 根据传递的参数创建类的对象 |
五、获取字节码文件
1. Object类的getClass()方法
对象.getClass()
多用于对象的获取字节码的方式
2. 静态属性class
类名.class
多用于参数的传递
3. Class类中静态方法forName()
class.forName("全类名")
多用于配置文件,将类名定义在配置文件中。读取文件,加载类。
注意:在运行期间,一个类,只有一个Class对象产生。
e.g.
class Person {
String name;
Integer age;
Person() {
}
Person(String name, Integer age) {
this.name = name;
this.age = age;
}
}
public class Test {
public static void main(String[] args) throws ClassNotFoundException {
Class clazz1 = Class.forName("Test.Person");
Class clazz2 = Person.class;
Class clazz3 = new Person().getClass();
System.out.println(clazz1 == clazz2); // true
System.out.println(clazz2 == clazz3); // true
System.out.println(clazz1 == clazz3); // true
}
}
六、获取构造器
方法 | 用途 |
---|---|
getConstructor(Class...<?> parameterTypes) | 获得该类中与参数类型匹配的公有构造方法 |
getConstructors() | 获得该类的所有公有构造方法 |
getDeclaredConstructor(Class...<?> parameterTypes) | 获得该类中与参数类型匹配的构造方法 |
getDeclaredConstructors() | 获得该类所有构造方法 |
获取构造器后可执行操作
方法 | 用途 |
---|---|
newInstance(Object... initargs) | 根据传递的参数创建类的对象 |
1. 获取公有的构造器
class Person {
String name;
Integer age;
Person() {
}
private Person(String name) {
super();
this.name = name;
}
public Person(String name, Integer age) {
super();
this.name = name;
this.age = age;
}
@Override
public String toString() {
return "Person [name=" + name + ", age=" + age + "]";
}
}
public class Test {
public static void main(String[] args) throws Exception {
// 1. 获取字节码
Class<?> clazz = Class.forName("Test.Person");
Constructor<?>[] cons = clazz.getConstructors();
for (Constructor<?> con : cons) {
System.out.println(con);
}
System.out.println("--------");
Constructor<?> con = clazz.getConstructor(String.class, Integer.class);
System.out.println(con);
Person p = (Person) con.newInstance("zsy", 20);
System.out.println(p);
}
}
运行结果
public Test.Person(java.lang.String,java.lang.Integer)
--------
public Test.Person(java.lang.String,java.lang.Integer)
Person [name=zs, age=20]
2. 获取私有的构造器
class Person {
String name;
Integer age;
Person() {
}
private Person(String name) {
super();
this.name = name;
}
public Person(String name, Integer age) {
super();
this.name = name;
this.age = age;
}
@Override
public String toString() {
return "Person [name=" + name + ", age=" + age + "]";
}
}
public class Test {
public static void main(String[] args) throws Exception {
// 1. 获取字节码
Class<?> clazz = Class.forName("Test.Person");
Constructor<?>[] cons = clazz.getDeclaredConstructors();
for (Constructor<?> con : cons) {
System.out.println(con);
}
System.out.println("--------");
Constructor<?> con = clazz.getDeclaredConstructor(String.class);
System.out.println(con);
Person p = (Person) con.newInstance("zs");
System.out.println(p);
}
}
运行结果
public Test.Person(java.lang.String,java.lang.Integer)
private Test.Person(java.lang.String)
Test.Person()
--------
private Test.Person(java.lang.String)
抛出java.lang.IllegalAccessException
会发现在使用私有构造器时会报异常
- 使用暴力反射,忽略访问权限修饰符的安全检查
class Person {
String name;
Integer age;
Person() {
}
private Person(String name) {
super();
this.name = name;
}
public Person(String name, Integer age) {
super();
this.name = name;
this.age = age;
}
@Override
public String toString() {
return "Person [name=" + name + ", age=" + age + "]";
}
}
public class Test {
public static void main(String[] args) throws Exception {
// 1. 获取字节码
Class<?> clazz = Class.forName("Test.Person");
Constructor<?>[] cons = clazz.getDeclaredConstructors();
for (Constructor<?> con : cons) {
System.out.println(con);
}
System.out.println("--------");
Constructor<?> con = clazz.getDeclaredConstructor(String.class);
System.out.println(con);
con.setAccessible(true);
Person p = (Person) con.newInstance("zs");
System.out.println(p);
}
}
运行结果
public Test.Person(java.lang.String,java.lang.Integer)
private Test.Person(java.lang.String)
Test.Person()
--------
private Test.Person(java.lang.String)
Person [name=zs, age=null]
3. 获取无参构造器
class Person {
String name;
Integer age;
public Person() {
}
public Person(String name, Integer age) {
super();
this.name = name;
this.age = age;
}
@Override
public String toString() {
return "Person [name=" + name + ", age=" + age + "]";
}
}
public class Test {
public static void main(String[] args) throws Exception {
// 1. 获取字节码
Class<?> clazz = Class.forName("Test.Person");
Constructor<?> con = clazz.getConstructor();
System.out.println(con); // public Test.Person()
Person p = (Person) con.newInstance();
System.out.println(p); // Person [name=null, age=null]
}
}
获取无参构造器时,可以简化为
public class Test {
public static void main(String[] args) throws Exception {
// 1. 获取字节码
Class<?> clazz = Class.forName("Test.Person");
Person p = (Person) clazz.newInstance();
System.out.println(p); // Person [name=null, age=null]
}
}
七、获取字段
方法 | 用途 |
---|---|
getField(String name) | 获得某个公有的属性对象 |
getFields() | 获得所有公有的属性对象 |
getDeclaredField(String name) | 获得某个属性对象 |
getDeclaredFields() | 获得所有属性对象 |
获取字段后可执行操作
方法 | 用途 |
---|---|
get(Object obj) | 获得obj中对应的属性值 |
set(Object obj, Object value) | 设置obj中对应属性值 |
1. 获取公有的字段
直接调用 clazz.getField("字段名称")
class Person {
public String name;
public Integer age;
protected String a;
String b;
private String c;
Person() {
}
Person(String name, Integer age) {
this.name = name;
this.age = age;
}
@Override
public String toString() {
return "Person [name=" + name + ", age=" + age + "]";
}
}
public class Test {
public static void main(String[] args) throws Exception {
// 1. 获取字节码
Class<?> clazz = Class.forName("Test.Person");
Field[] fields = clazz.getFields();
for (Field field : fields) {
System.out.println(field);
}
System.out.println("--------");
Field name = clazz.getField("name");
Field age = clazz.getField("age");
System.out.println(name);
System.out.println(age);
System.out.println("--------");
Person p = (Person) clazz.newInstance();
name.set(p, "zs");
System.out.println(name.get(p));
}
}
运行结果:
public java.lang.String Test.Person.name
public java.lang.Integer Test.Person.age
--------
public java.lang.String Test.Person.name
public java.lang.Integer Test.Person.age
--------
zs
2. 获取私有的字段
class Person {
public String name;
public Integer age;
protected String a;
String b;
private String c;
Person() {
}
Person(String name, Integer age) {
this.name = name;
this.age = age;
}
@Override
public String toString() {
return "Person [name=" + name + ", age=" + age + "]";
}
}
public class Test {
public static void main(String[] args) throws Exception {
// 1. 获取字节码
Class<?> clazz = Class.forName("Test.Person");
Field[] fields = clazz.getDeclaredFields();
for (Field field : fields) {
System.out.println(field);
}
System.out.println("--------");
Field name = clazz.getDeclaredField("name");
Field age = clazz.getDeclaredField("age");
Field a = clazz.getDeclaredField("a");
Field b = clazz.getDeclaredField("b");
Field c = clazz.getDeclaredField("c");
System.out.println(name);
System.out.println(age);
System.out.println(a);
System.out.println(b);
System.out.println(c);
System.out.println("--------");
Person p = (Person) clazz.newInstance();
name.set(p, "zs");
System.out.println(name.get(p));
a.set(p, "a");
System.out.println(a.get(p));
b.set(p, "b");
System.out.println(b.get(p));
c.set(p, "c");
System.out.println(c.get(p));
}
}
运行结果:
public java.lang.String Test.Person.name
public java.lang.Integer Test.Person.age
protected java.lang.String Test.Person.a
java.lang.String Test.Person.b
private java.lang.String Test.Person.c
--------
public java.lang.String Test.Person.name
public java.lang.Integer Test.Person.age
protected java.lang.String Test.Person.a
java.lang.String Test.Person.b
private java.lang.String Test.Person.c
--------
zs
a
b
抛出java.lang.IllegalAccessException
会发现在调用和设置私有字段时会报异常
- 使用暴力反射,忽略访问权限修饰符的安全检查
class Person {
private String c;
Person() {
}
}
public class Test {
public static void main(String[] args) throws Exception {
// 1. 获取字节码
Class<?> clazz = Class.forName("Test.Person");
Field c = clazz.getDeclaredField("c");
System.out.println(c); // private java.lang.String Test.Person.c
Person p = (Person) clazz.newInstance();
c.setAccessible(true);
c.set(p, "c");
System.out.println(c.get(p)); // C
}
}
八、获取方法
方法 | 用途 |
---|---|
getMethod(String name, Class...<?> parameterTypes) | 获得该类某个公有的方法 |
getMethods() | 获得该类所有公有的方法 |
getDeclaredMethod(String name, Class...<?> parameterTypes) | 获得该类某个方法 |
getDeclaredMethods() | 获得该类所有方法 |
获取方法后可执行操作
方法 | 用途 |
---|---|
invoke(Object obj, Object... args) | 传递object对象及参数调用该对象对应的方法 |
1. 获取公有的方法
class Person {
String name;
public void eat(String str) {
System.out.println(name + "在吃" + str);
}
public void work() {
System.out.println(name + "在工作");
}
private void walk() {
System.out.println(name + "在行走");
}
}
public class Test {
public static void main(String[] args) throws Exception {
// 1. 获取字节码
Class<?> clazz = Class.forName("Test.Person");
Person p = (Person) clazz.newInstance();
p.name = "张三";
Method method = clazz.getMethod("work");
method.invoke(p); // 张三在工作
}
}
2. 获取私有的方法
类似的,使用暴力反射,忽略访问权限修饰符的安全检查
class Person {
String name;
public void eat(String str) {
System.out.println(name + "在吃" + str);
}
public void work() {
System.out.println(name + "在工作");
}
private void walk() {
System.out.println(name + "在行走");
}
}
public class Test {
public static void main(String[] args) throws Exception {
// 1. 获取字节码
Class<?> clazz = Class.forName("Test.Person");
Person p = (Person) clazz.newInstance();
p.name = "张三";
Method method = clazz.getDeclaredMethod("walk");
method.setAccessible(true);
method.invoke(p); // 张三在行走
}
}
3. 获取有参的方法
class Person {
String name;
public void eat(String str) {
System.out.println(name + "在吃" + str);
}
}
public class Test {
public static void main(String[] args) throws Exception {
// 1. 获取字节码
Class<?> clazz = Class.forName("Test.Person");
Person p = (Person) clazz.newInstance();
p.name = "张三";
Method method = clazz.getMethod("eat", String.class);
method.invoke(p, "苹果"); // 张三在吃苹果
}
}
九、反射实例
设计一个可以创建任意类的对象,执行此对象中任意方法的框架。
public class Student {
public String name = "zs";
public void study() {
System.out.println(name + "在学习");
}
public void eat(String str) {
System.out.println(name + "在吃" + str);
}
public void parents(String father, String mother) {
System.out.println(name + "的父亲是:" + father);
System.out.println(name + "的母亲是:" + mother);
}
}
public class Test {
public static void main(String[] args) throws Exception {
Properties props = new Properties();
InputStream ins = Test.class.getClassLoader().getResourceAsStream("Test/pro.properties");
props.load(ins);
ins.close();
String className = props.getProperty("className");
String methodName = props.getProperty("methodName");
String methodArgs = props.getProperty("methodArgs");
String[] argList = methodArgs.isEmpty() ? null : methodArgs.split(",");
Class<?> clazz = Class.forName(className);
Object object = clazz.newInstance();
Method[] methods = clazz.getMethods();
for (Method method : methods) {
if(method.getName().equals(methodName)) {
method.invoke(object, argList);
}
}
}
}
className=Test.Student
methodName=parents
methodArgs=ls,ww
加载配置文件
配置文件放置位置
一、通过文件路径加载
该方式必须知道文件的真实路径。
public class Test {
public static void main(String[] args) throws Exception {
String aName = getProperties("a.properties");
String bName = getProperties("src/b.properties");
String cName = getProperties("src/Test/file/c.properties");
System.out.print(aName + "\n" + bName + "\n" + cName);
}
public static String getProperties(String path) throws Exception {
InputStream ins = new FileInputStream(path);
Properties props = new Properties();
props.load(ins);
ins.close();
String className = props.getProperty("className");
return className;
}
}
二、通过getResourceAsStream加载
(1)获取src下的指定资源
Class.getResourceAsStream(String path)
path 不以’/'开头时默认是从此类所在的包下取资源
path 以’/'开头则是从ClassPath根下(即'/'代表src)获取
其只是通过path构造一个绝对路径,最终还是由ClassLoader获取资源。
a.在同级目录下
有类me.class,同时在同级目录下有资源文件 myfile.properties,则应使用:me.class.getResource("myfile.properties");
b.在子目录下
com.x.y 下有类me.class,同时在子目录 com.x.y.file 下有资源文件 myfile.properties,则应使用:me.class.getResource("file/myfile.properties");
c.不在同级目录和子目录下
com.x.y 下有类me.class,同时在 com.x.file 目录下有资源文件 myfile.properties ,则应使用:me.class.getResource("/com/x/file/myfile.properties");
public class Test {
public static void main(String[] args) throws Exception {
//String aName = getProperties("a.properties"); // 这里a不在src下,不能获取
String bName = getProperties("../b.properties"); // 相对路径
String cName = getProperties("/Test/file/c.properties"); // 绝对路径
System.out.print(bName + "\n" + cName);
}
public static String getProperties(String path) throws Exception {
// getResource 获取资源的绝对路径
URL url = Test.class.getResource(path);
System.out.println(url);
// getResourceAsStream 获取资源的字节流
InputStream ins = Test.class.getResourceAsStream(path);
Properties props = new Properties();
props.load(ins);
ins.close();
String className = props.getProperty("className");
return className;
}
}
(2)获取web项目下的指定资源
ServletContext.getResourceAsStream(String path)
默认从WebAPP根目录(即:要发布在服务器下的项目的根目录(与src同级的web文件夹下))下取资源
path是否以’/'开头无所谓。 例:
在web项目的根目录下有myfile.xml文件,则应该使用
getServleContext().getResourceAsStream("myfile.xml");
三、通过类加载的方式进行加载
Class.getClassLoader().getResourceAsStream(String path)
- 默认则是从ClassPath根下获取,path不能以’/'开头,最终是由ClassLoader获取资源。
a.不在同级目录和子目录下
com.x.y 下有类me.class,同时在 com.x.file 目录下有资源文件 myfile.properties ,则应使用:me.class.getClassLoader().getResourceAsStream("com/x/file/myfile.properties");
public class Test {
public static void main(String[] args) throws Exception {
//String aName = getProperties("a.properties"); // 这里a不在src下,不能获取
String bName = getProperties("b.properties");
String cName = getProperties("Test/file/c.properties");
System.out.print(bName + "\n" + cName);
}
public static String getProperties(String path) throws Exception {
// getResource 获取资源的绝对路径
URL url = Test.class.getClassLoader().getResource(path);
System.out.println(url);
// getResourceAsStream 获取资源的字节流
InputStream ins = Test.class.getClassLoader().getResourceAsStream(path);
Properties props = new Properties();
props.load(ins);
ins.close();
String className = props.getProperty("className");
return className;
}
}
四、通过基名
文件必须是 key=value 的properties文件
public class Test {
public static void main(String[] args) throws Exception {
//String aName = getProperties("a"); // 这里a不在src下,不能获取
String bName = getProperties("b");
String cName = getProperties("Test/file/c");
System.out.print(bName + "\n" + cName);
}
public static String getProperties(String path) throws Exception {
ResourceBundle bundle = ResourceBundle.getBundle(path);
String className = bundle.getString("className");
return className;
}
}