一、接口
Java 用 implements interface 的模式使用接口。
interface jieKou{ void some_action(); }
class A implements interface { @override void some_action(){/* do some thing*/}; }
一开始还以为 @override 是必须要写的,原来不是,转到 IDEA 后用Java是真的舒服,就是内存要求有点高,几年前的8GB内存,现在已经隐隐不够用了……
接口中定义的方法,可由父类实现,即在扩展类中,用接口去“套”父类中的方法。
使用接口的特性,可以用一致接口将多个不同的实现统合为一。一个典型的列子就是通用的webview接口,比如 webview.evaluateJavascript() ,先定义接口:
public interface UniversalWebviewInterface {
void evaluateJavascript(String jsText, ValueCallback<String> valueCallback);
}
然后,对于原生webview和腾讯公司研发的X5Webview,可以分别这样:
- 原生webview
public class WebViewNative extends WebView implements UniversalWebviewInterface {
// 可以除了构造,啥都不用写
}
- X5Webview
package com.tencent.smtt.sdk;
public void evaluateJavascript(String var1, android.webkit.ValueCallback<String> var2) {
try {
View var3 = this.X5WebView.getView();
Method var4 = ReflectionUtils.a(var3, "evaluateJavascript", String.class, android.webkit.ValueCallback.class);
var4.setAccessible(true);
var4.invoke(this.X5WebView.getView(), var1, var2);
} catch (Exception var7) {
var7.printStackTrace();
this.loadUrl(var1);
}
}
这是“反混淆”解压出后的代码,可以看出已经帮我们实现好了,直接用接口“套”它即可。不过并非所有方法如此,有的方法 X5WebView 使用了自定义类,而不是 android.webkit.* 中的原生类,我对“反混淆”后的代码进行魔改,最终证明是能够兼容的。
接口的方法定义后会占用一个方法数,子类继承父类实现接口,父类被“套”上的方法,不会再额外计入方法数。
如何查看方法数:将文件拖入 android studio 即可。
如何反编译(非 JD-GUI):
java -cp "C:\Program Files\JetBrains\IntelliJ IDEA Community Edition 2019.2.3\plugins\java-decompiler\lib\java-decompiler.jar" org.jetbrains.java.decompiler.main.decompiler.ConsoleDecompiler -dgs=true . src
如何“反混淆”:结合其他资料,手动修改 a b c d e f g。
二、抽象类
abstract class 可以implements多个接口,但不用做任何定义。
abstract class SuperAmazingAbstract implements jiekou1, jiekou2, jiekou3{
// 这里啥都不用写
}
class Activity123 ...{
void HaHa{
SuperAmazingAbstract shiXian = new SuperAmazingAbstract(){
// 实现 jiekou1 中定义的方法
// 实现 jiekou2 中定义的方法
// 实现 jiekou3 中定义的方法
}
}
}
一个典型例子是用一个内部类同时糅和 View.onClickListener、View.onLongClickListener、AdapterView.OnItemClickListener 等监听器,使用起来极为方便。
- 定义
package com.knziha.polymer.widgets;
import android.view.View;
import android.widget.AdapterView;
public abstract class SuperItemListener
implements View.OnClickListener ,
View.OnLongClickListener, AdapterView.OnItemClickListener
{ }
- 使用
SuperItemListener schEngItemLis = new SuperItemListener() {
boolean isLongClicked;
boolean longClick;
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
onClick(view);
}
@Override
public boolean onLongClick(View v) {
isLongClicked=true;
longClick=true;
onClick(v);
return longClick;
}
@Override
public void onClick(View v) {
SearchEnginesItemBinding itemData = (SearchEnginesItemBinding) getTypedTagInAncestors(v, 3, SearchEnginesItemBinding.class);
if(itemData!=null) {
int position = (int) itemData.title.getTag();
int id = v.getId();
switch (id) {
...
}
}
}
最后,展示下最近用此方法实现的,用于浏览器的,搜索引擎列表。自定义修改、排序最为便捷,向左侧滑动打开选项菜单,可以同时打开多个,长按其中的按钮或可进行批量操作。
200k 动图:
\
三、避坑 java.lang.VerifyError
用接口去套父类的方法,若该方法在低版本的安卓平台上不存在,那就悲催, 在构造的时候会抛出 java.lang.VerifyError ,出现类验证错误,还是第一次遇到这个 BUG。
比如,webview 用于打印PDF的接口,API > 21 才有效。
PrintDocumentAdapter createPrintDocumentAdapter(String name);
只好改写,我算是明白 X5Webview 的 createPrintDocumentAdapter 方法为何返回 Object 了。此处连名字都要避讳,真是晦气。
Object initPrintDocumentAdapter(String name);
全文完
网友评论