Skip to content

Commit dd22267

Browse files
committed
Update Reflect Doc & Refactor Formatter Logic for JSON
1 parent 8ff8cd8 commit dd22267

File tree

4 files changed

+226
-134
lines changed

4 files changed

+226
-134
lines changed

app/build.gradle

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,6 @@ dependencies {
3333
implementation "com.jakewharton:butterknife:$butterknife_version"
3434
kapt "com.jakewharton:butterknife-compiler:$butterknife_version"
3535

36-
// implementation project(':utils')
37-
implementation 'com.github.yjfnypeu:EasyAndroid:1.0.9'
36+
implementation project(':utils')
37+
// implementation 'com.github.yjfnypeu:EasyAndroid:1.0.9'
3838
}

app/src/main/java/com/haoge/sample/easyandroid/activities/EasyReflectActivity.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -149,7 +149,7 @@ class Test private constructor(private val name:String){
149149
}
150150

151151
fun withVararg(perfix:Int, vararg name:String) {
152-
EasyLog.DEFAULT.d("perfix = $perfix + name = $name")
152+
EasyLog.DEFAULT.d("perfix = $perfix + name = ${name.easyFormat()}")
153153
}
154154

155155
companion object {

docs/EasyReflect.md

Lines changed: 162 additions & 113 deletions
Original file line numberDiff line numberDiff line change
@@ -6,195 +6,244 @@ EasyReflect对常规的反射操作进行封装。让使用反射操作变得简
66

77
## 用法
88

9-
### 使用EasyReflect
10-
11-
EasyReflect操作类包装了两部分数据:
9+
### 1. 初识EasyReflect
1210

1311
```
14-
// 1. clazz:类的Class数据。总是存在
15-
// 2. instance:具体的对象实例。可能不存在。当进行的操作会需要使用此数据时。会自动匹配默认构造器进行创建
1612
class EasyReflect private constructor(val clazz: Class<*>, var instance:Any?)
1713
```
1814

19-
#### 创建EasyReflect实例的几种方式:
15+
可以看到:EasyReflect本身持有两部分数据:`clazz``instance`.
2016

21-
1. 通过指定class创建实例。此种方式创建数据**不存在**具体的instance实例
17+
- clazz: 此实例所绑定操作的clazz实例。永不为null
18+
- instance: 此实例所绑定的instance实例,为clazz类型的具体实例。可能为null。
2219

23-
```
24-
var reflect = EasyReflect.create(clazz:Class<*>)
25-
```
20+
**请注意:对于instance数据来说,当执行操作过程中需要使用此instance实例时(比如读取某个成员变量),若此时instance为null,则将触发使用默认的空构造器进行instance创建。**
2621

27-
2. 通过具体数据对象创建实例:此种方式创建数据**存在**具体的instance实例
22+
### 2. 创建EasyReflect的几种姿势
23+
24+
1. **只使用Class进行创建**:创建后只含有clazz数据
2825

2926
```
30-
var reflect = EasyReflect.create(any:Any)
27+
val reflect = EasyReflect.create(Test::class.java)
3128
```
3229

33-
3. 通过完整的对象名与ClassLoader创建实例:此种方式创建数据**不存在**具体的instance实例
30+
2. **使用类全名进行创建(可指定ClassLoader)**:创建后只含有clazz数据
3431

3532
```
36-
var reflect = EasyReflect.create(name:String, loader:ClassLoader?)
33+
val reflect = EasyReflect.create("com.haoge.sample.Test")
34+
// 也可指定ClassLoader进行加载
35+
val reflect = EasyReflect.create(className, classLoader)
3736
```
3837

39-
4. 通过具体的构造器进行实例创建:此种方式创建数据**存在**具体的instance实例
38+
3. **直接通过指定实例进行创建**:创建后clazz与instance均存在, clazz为instance.javaClass数据
4039

4140
```
42-
// 可变参数args需要与具体的构造器匹配
43-
var reflect = EasyReflect.create(clazz).instance(varage args:Any?)
41+
val reflect = EasyReflect.create(any)
4442
```
4543

46-
#### 对字段进行取值/赋值
44+
了解了EasyReflect的几种创建方式与其区别后。我们就可以正式进行使用了
45+
46+
### 3. 调用指定构造器进行实例创建
4747

4848
```
49-
var reflect = ...
50-
// 取值
51-
reflect.getFieldValue(name:String)
52-
// 赋值
53-
reflect.setField(name:String, value:Any?)
49+
val reflect:EasyReflect = createReflect()
50+
// 通过默认空构造器进行对象创建
51+
val instance1 = EasyReflect.instance().instance
52+
// 通过与可变参数类型匹配的构造器进行对象创建
53+
val instance2 = EasyReflect.instance(arg0, arg1...argN).instance
5454
```
5555

56-
#### 对方法进行调用
56+
### 4. 字段的赋值与取值
5757

58-
```
59-
var reflect = ...
60-
// 仅调用:name为方法名。args为所需参数数据
61-
reflect.call(name:String, varage args:Any?)
62-
// 调用并使用方法返回值构建新的EasyReflect实例并返回.
63-
var newReflect = reflect.callWithReturn(name:String, varage args:Any?)
64-
```
58+
EasyReflect对字段的操作,不用再去考虑它是否是`静态的`或者还是`final修饰的`。更不用去操心字段是否是`private`不可见的。我们只需要指定字段名即可。这大大增强了便利性!
6559

66-
### 使用ConstructorReflect操作构造器
60+
- 访问指定字段的值:
6761

6862
```
69-
// 此实例同样包裹两部分数据:
70-
// 1. constructor:此实例操作所使用的构造器
71-
// 2. 上级对象。
72-
class ConstructorReflect(val constructor: Constructor<*>, val upper:EasyReflect)
63+
val value = reflect.getFieldValue(fieldName)
7364
```
7465

75-
#### 获取实例
66+
- 为指定字段赋值:
7667

7768
```
78-
// 仍然是首先创建EasyReflect实例
79-
val reflect = ...
80-
// 1. 读取此类所有的构造器:
81-
val list:List<ConstructorReflect> = reflect.getConsturctors()
82-
// 2. 根据参数类型匹配指定的构造器
83-
val constructor:ConstructorReflect = reflect.getConstructor(varage types:Class<*>)
69+
reflect.setField(fieldName, newValue)
8470
```
8571

86-
#### 使用
72+
- 获取指定字段的EasyReflect实例进行使用
8773

8874
```
89-
val constructorReflect = ...
90-
// 使用指定构造器创建新的EasyReflect实例
91-
val newReflect:EasyReflect = constructorReflect.newInstance(varage args:Any?)
75+
val newReflect = reflect.getField(fieldName).transform()
9276
```
9377

94-
### 使用FieldReflect操作变量
78+
### 5. 方法调用
79+
80+
与字段操作类似,我们也不用去担心方法的可见性问题。需要的只有`此方法存在`即可
81+
82+
- 调用指定方法
9583

9684
```
97-
class FieldReflect(val field:Field, val upper:EasyReflect)
85+
// 调用指定方法,不含参数
86+
reflect.call(methodName)
87+
// 调用指定方法,含指定参数
88+
reflect.call(methodName, arg0, arg1...argN)
9889
```
9990

100-
#### 获取实例
91+
- 调用指定方法并获取返回值
10192

10293
```
103-
// 仍然是首先创建EasyReflect实例
104-
val reflect = ...
105-
// 1. 读取此类所有的成员变量:
106-
val fields:List<FieldReflect> = reflect.getFields()
107-
// 2. 根据参数类型匹配指定的构造器
108-
val field:FieldReflect = reflect.getField(name:String)
94+
val value = reflect.callWithReturn(methodName, arg0, arg1...argN).instance
10995
```
11096

111-
#### 使用
97+
### 6. 传参包括可变参数时的调用方式
11298

113-
```
114-
val fieldReflect = ...
99+
可变参数会在编译时。替换为数组的形式。所以使用反射进行可变参数的传参时,需要使用数组的形式对参数进行构建:
115100

116-
// 1. 获取此变量的具体值
117-
val value = fieldReflect.getValue()
118-
// 2. 为此变量设置值
119-
fieldReflect.setValue(value:Any?)
120-
// 使用此变量的数据创建新的EasyReflect实例提供使用
121-
val newReflect:EasyReflect = fieldReflect.transform()
101+
以下方的两个方法为例:
102+
103+
```
104+
class Method{
105+
fun onlyVararg(vararg names:String)
106+
fun withVararg(preffix:Int, vararg names:String)
107+
}
122108
```
123109

124-
### 使用MethodReflect
110+
此类中的两个方法均为带有可变参数的方法,在反射环境下。就应该将其中的可变参数看作为是对应的数组进行使用,所以这个时候。我们需要使用如下方式进行参数传递:
125111

126112
```
127-
class MethodReflect(val method:Method, val upper:EasyReflect)
113+
// 1. 调用只含有可变参数的方法
114+
reflect.call("onlyVararg", arrayOf("Hello", "World"))
115+
// 2. 调用包含其他参数的可变参数方法
116+
reflect.call("withVararg", 1, arrayOf("Hello", "World"))
128117
```
129118

130-
#### 获取实例
119+
在这里要特别提醒一下:由于java与kotlin的差异性,在java中调用**只含有可变参数**的方法时。需要对参数进行特殊处理(外层包裹一层`Object[]`):
131120

132121
```
133-
// 仍然是首先创建EasyReflect实例
134-
val reflect = ...
135-
// 1. 读取此类所有的方法
136-
val methods:List<MethodReflect> = reflect.getMethods()
137-
// 2. 根据指定方法名name与参数类型types匹配对应的方法
138-
val method:MethodReflect = reflect.getMethod(name:Stirng, varage types:Class<*>)
122+
EasyReflect reflect = EasyReflect.create(Method.class)
123+
reflect.call("onlyVararg", new Object[]{new String[]{"Hello", "World"}})
139124
```
140125

141-
#### 使用
126+
而对于`withVararg`这种带有非可变参数的方法则不用进行此特殊处理:
142127

143128
```
144-
val methodReflect = ..
145-
146-
// 1. 执行此方法:
147-
methodReflect.call(varage args:Any?)
148-
// 2. 执行此方法。并将返回值作为数据。创建出新的EasyReflect实例返回
149-
val newReflect = methodReflect.callWithReturn(varage args:Any?)
129+
reflect.call("withVararg", 1, new String[]{"Hello", "World"})
150130
```
151131

152-
### 使用动态代理进行托管访问
132+
这是因为在java中。若实参为一个数组时。这个时候将会对此数组进行解构平铺,所以我们需要在外层再单独套一层Object数组。才能对参数类型做到正确匹配。而在kotlin中不存在此类问题。
133+
134+
### 7. 使用动态代理进行托管
153135

154136
当你需要对某个类进行访问,但是又不想通过写死名字的方式去调用时,可以使用此特性:
155137

156-
假设我们有以下的类,需要进行访问:
138+
**通过动态代理的方式,创建一个代理类来对反射操作进行托管**
157139

158-
```
159-
class Test private constructor(private val name:String){
160-
constructor():this("默认名字")
140+
还是通过举例来说明:
161141

162-
fun invoked(name:String){
163-
...
164-
}
165-
166-
companion object {
167-
@JvmStatic
168-
private fun print(message:String) {
169-
...
170-
}
171-
}
142+
```
143+
class Test {
144+
private fun function0(name:String)
172145
}
173146
```
174147

175-
然后我们想通过代理接管的方式来进行方法调用、访问:
148+
对于上面所举例的类来说。要通过反射调用它的function0方法,那么需要这样写:
149+
150+
```
151+
val reflect = EasyReflect.create(Test::class.java)
152+
reflect.call("function0", "This is name")
153+
```
176154

177-
- 配置代理接口
155+
而若使用托管的方式。配置先创建代理接口,然后通过代理接口进行方法访问
178156

179157
```
180-
interface Proxy {
181-
fun invoked(name:String)// 托管到Test.invoked方法
182-
fun print(message:String) // 托管到Test.print方法
183-
fun getName():String // 获取成员变量name的值
184-
fun get(name:String):String // 获取成员变量name的值
185-
fun setName(value:String) // 为变量name赋值为value
186-
fun set(name:String, value:String)// 为变量name赋值为value
158+
// 创建代理接口
159+
interface ITestProxy {
160+
fun function0(name:String)
187161
}
162+
163+
val reflect = EasyReflect.create(Test::class.java)
164+
// 创建托管代理实例:
165+
val proxy:ITestProxy = reflect.proxy(ITestProxy::class.java)
166+
// 然后直接通过代理类进行操作:
167+
proxy.function0("proxy name")
188168
```
189169

190-
注册托管代理并直接使用
170+
当然,如果只能对方法进行托管那这功能就有点太弱逼了。托管方案也同时支持了对变量的操作
191171

192172
```
173+
class Test {
174+
// 添加一个字段
175+
private val user:User
176+
private fun function0(name:String)
177+
}
178+
179+
// 创建代理接口
180+
interface ITestProxy {
181+
fun function0(name:String)
182+
183+
//==== 对user字段进行赋值
184+
// 方式一:使用setXXX方法进行赋值
185+
fun setUser(user:User)
186+
// 方式二:使用set(name, value)方法进行赋值
187+
fun set(fieldName:String, value:String)
188+
189+
//==== 对user进行取值
190+
// 方式一:使用getXXX方法进行取值
191+
fun getUser()
192+
// 方式二:使用get(name)方法进行取值
193+
fun get(fieldName:String)
194+
}
195+
193196
val reflect = EasyReflect.create(Test::class.java)
194-
// 注册托管代理
195-
val proxy:Proxy = reflect.proxy(Proxy::class.java)
196-
// 使用托管代理直接调用执行
197-
proxy.invoked("invoked")// 等同调用Test.invoked("invoked")
198-
proxy.print("message") // 等同调用Test.print("message")
199-
val name = proxy.getName() // 等同调用Test.name
200-
```
197+
// 创建托管代理实例:
198+
val proxy:ITestProxy = reflect.proxy(ITestProxy::class.java)
199+
// 然后直接通过代理类进行操作:
200+
proxy.setUser(user)// 方式一赋值
201+
proxy.set("user", user)// 方式二赋值
202+
203+
proxy.getUser() // 方式一取值
204+
proxy.get("user")// 方式二取值
205+
```
206+
207+
从某种程度上来说:代理托管方案会比一般的直接反射操作要繁琐一点。但是带来的便利也是显而易见的:
208+
209+
首当其冲的优点就是:托管方式写的代码比直接进行反射操作更加优雅~
210+
211+
其次,在某些使用环境下,比如在团队协作中:可以将对外不方便直接提供实例的通过托管代理实例进行提供。
212+
213+
最后,贴上proxy方法代码,希望能对理解托管代理方法的执行原理起到一定的帮助:
214+
215+
```
216+
fun <T> proxy(proxy:Class<T>):T {
217+
@Suppress("UNCHECKED_CAST")
218+
return Proxy.newProxyInstance(proxy.classLoader, arrayOf(proxy), {_, method, args ->
219+
try {
220+
// 优先匹配存在的方法
221+
return@newProxyInstance this@EasyReflect.callWithReturn(method.name, *args).get()
222+
} catch (e:Exception) {
223+
// 不能匹配到已存在的方法,则匹配set/get方法进行字段托管
224+
try {
225+
val methodName = method.name
226+
if (methodName == "get" && args.size == 1 && args[0] is String) {
227+
return@newProxyInstance getFieldValue(args[0] as String)
228+
} else if (methodName == "set" && args.size == 2 && args[0] is String) {
229+
setField(args[0] as String, args[1])
230+
} else if (methodName.startsWith("get") && method.returnType != Void::class.java) {
231+
val name = methodName.substring(3,4).toLowerCase() + methodName.substring(4)
232+
return@newProxyInstance getFieldValue(name)
233+
} else if (methodName.startsWith("set") && args.size == 1) {
234+
val name = methodName.substring(3,4).toLowerCase() + methodName.substring(4)
235+
setField(name, args[0])
236+
}
237+
} catch (e:Exception) {
238+
// ignore
239+
}
240+
// 最后,兼容不存在的方法,提供默认值的返回值。
241+
return@newProxyInstance when (method.returnType.name) {
242+
"int", "byte", "char", "long", "double", "float", "short" -> 0
243+
"boolean" -> false
244+
else -> method.defaultValue
245+
}
246+
}
247+
}) as T
248+
}
249+
```

0 commit comments

Comments
 (0)