Android SDK中的一些类或方法由于某些原因而被隐藏,导致开发者不能正常的访问这些类和方法,如果访问,导致编译出错。由于SDK中隐藏,而手机环境中的确存在,所以只要我们通过编译,那么在手机上是可以运行的。
看了网上的一些资料,主要的处理方法有两种:
- 在项目中使用重新编译后的,暴露隐藏类和方法的SDK;
- 在项目中利用Java的反射机制来访问隐藏的类和方法;
- 把项目用到的相关类从源码中复制到项目中或者单独导入到一个项目中『后者需要建立目标项目和依赖类所在项目的依赖关系』,保持类所在路径和源码一致,找出并处理掉类中的错误;
说明:
- 方法1:前期准备较多,但后期开发较容易;
- 方法2:需要对Android源码有所了解才能正确编码;
- 方法3:需要的类和一些其它类必然有依赖关系,而真实开发中不需要源码中所有的类,故需要找到并处理掉相关类中的错误;
本文主要想说一下反射操作,并示例中不涉及到Android SDK中相关的隐藏类!
Java反射机制:
JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性;这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制。『百度百科』
和Java反射有关的类有:
- Class;
- Field;
- Method;
- Constructor;
- Array;
获取Class对象的方法有:
- getClass;
- getSuperClass;
- Class.forName;
- 类型.class;
- 基本类型包装类.TYPE;
Class<?> classObject;
// getClass();
String string = new String();
classObject = string.getClass();
// getSuperClass();
Object object = new Object();
classObject = object.getClass().getSuperclass();
// Class.forName();
try {
classObject = Class.forName("package-name" + "class-name");
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
// 类名.class
classObject = String.class;
classObject = Integer.class;
classObject = int.class;
// 基本类型封装类.TYPE
classObject = Integer.TYPE;
classObject = Boolean.TYPE;
对于类中方法和属性的访问,参考下面代码:
package reflect;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
interface Animal {
}
class Person implements Animal {
public String publicString = "this is a public string!";
private String name;
private int age;
public Person() {
System.out.println("Person()" + this.hashCode());
name = "";
age = -1;
}
public Person(String name, int age) {
this.name = name;
this.age = age;
}
public Person(String name) {
this();
this.name = name;
}
public Person(int age) {
this();
this.age = age;
}
public void setName(String name) {
this.name = name;
}
public String getName() {
return name;
}
public void setAge(int age) {
this.age = age;
}
public int getAge() {
return age;
}
public void say(String message) {
System.out.println(message);
}
private void sing(String message) {
System.out.println(message);
}
@Override
public String toString() {
return "{Name:" + name + " Age:" + age + "}";
}
}
public class TestReflect {
public static void main(String[] args) {
try {
Class<?> classPerson = Class.forName("reflect.Person");
Person person = (Person) classPerson.newInstance();
System.out.println("Person:" + person);
person.setName("Tom");
person.setAge(18);
System.out.println("Person:" + person);
Constructor<?>[] constructors = classPerson.getConstructors();
for (int i = 0, length = constructors.length; i < length; i++) {
System.out.println("构造函数:" + constructors[i]);
Class<?>[] parameterTypes = constructors[i].getParameterTypes();
for (int j = 0, lengthPatamter = parameterTypes.length; j < lengthPatamter; j++) {
System.out.println("参数类型:" + parameterTypes[j].getName());
}
}
Class<?>[] interfaces = classPerson.getInterfaces();
for (int i = 0, length = interfaces.length; i < length; i++) {
System.out.println("实现接口:" + interfaces[i].getName());
}
Class<?> superClass = classPerson.getSuperclass();
System.out.println("父类:" + superClass);
Method[] methods = classPerson.getMethods();
for (int i = 0, length = methods.length; i < length; i++) {
Class<?> returnType = methods[i].getReturnType();
System.out.println("方法名称:" + methods[i]);
System.out.println("返回类型:" + returnType);
}
Field[] fields = classPerson.getDeclaredFields();
for (int i = 0, length = fields.length; i < length; i++) {
System.out.println("属性:" + fields[i].getName() + " 类型:" + fields[i].getType());
}
Method methodToString = classPerson.getMethod("toString");
System.out.println("toString:" + methodToString.invoke(classPerson.newInstance()));
Method methodSay = classPerson.getDeclaredMethod("say", String.class);
methodSay.invoke(classPerson.newInstance(), "This is a message to say!:)");
Method methodSing = classPerson.getDeclaredMethod("sing", String.class);
methodSing.setAccessible(true);
Object object = classPerson.newInstance();
methodSing.invoke(object, "This is a song to sing!:)");
Field publicStringField = classPerson.getField("publicString");
System.out.println(publicStringField.get(object).toString());
publicStringField.set(object, ":)");
System.out.println(publicStringField.get(object).toString());
Field nameField = classPerson.getDeclaredField("name");青蛙咬到手
nameField.setAccessible(true);
System.out.println(nameField.get(object).toString());
nameField.set(object, ":)");
System.out.println(nameField.get(object).toString());
} catch (Exception e) {
e.printStackTrace();
}
}
}
说明:为了可以访问私有的方法或属性,需要调用setAccessible方法!
多说一句:在程序员的世界里,问题总有解决的办法!如果暂时没有找到,要么是没有理解问题产生的原因,要么是自己知识欠缺!