一,Java的反射框架主要提供以下功能:
1.在运行时判断任意一个对象所属的类;
2.在运行时构造任意一个类的对象;
3.在运行时判断任意一个类所具有的成员变量和方法(通过反射甚至可以调用私有方法);
4.在运行时调用任意一个对象的方法
二,主要用途:
如图1所示,反射最重要的用途就是开发各种通用框架。
三,基本反射功能的实现(反射相关的类一般都在java.lang.relfect包里):
1,获得类对象
使用类类的forName静态方法,直接获取某一个对象的类,调用某个对象的getClass()方法
2,判断是否为某个类的实例
用的instanceof关键字来判断是否为某个类的实例
3,创建实例
使用类对象的的newInstance()方法来创建类对象对应类的实例。
先通过类对象获取指定的构造对象,再调用构造对象的的newInstance()方法来创建实例。
4,获取方法
getDeclaredMethods()
5,获取构造器信息
getDeclaredMethods()
的getMethods()
getMethod()
6,获取类的成员变量(字段)信息
getFiled:访问公有的成员变量
getDeclaredField:所有已声明的成员变量但不能得到其父类的成员变量
getFileds和getDeclaredFields用法
7,调用方法
调用()
8,利用反射创建数组
Array.newInstance()
Java的机制反射的英文一个非常强大的功能,在很多大型项目比如春天,MyBatis的都可以看见反射的身影。通过反射机制我们可以在运行期间获取对象的类型信息,利用这一特性我们可以实现工厂模式和代理等模式设计模式,同时也可以解决的Java泛型擦除等令人苦恼的问题。本文我们就从实际应用的角度出发,来应用一下的Java的反射机制。
反射基础
在应用反射机制之前,首先我们先来看一下如何获取一个对象对应的反射类Class
,在Java的中我们有三种方法可以获取一个对象的反射类。
通过的getClass方法
在的Java中,一个每Object
都有一个getClass
方法,通过的getClass方法我们可以获取到这个对象对应的反射类:
String s = "ziwenxie";
Class<?> c = s.getClass();
通过的forName方法
也。我们可以调用Class
类的静态方法forName
:
Class<?> c = Class.forName("java.lang.String");
使用的.class
或者我们也可以直接使用.class
:
Class<?> c = String.class;
获取类型信息
在文章开头我们就提到反射的一大好处就是可以允许我们在运行期间获取对象的类型信息,下面我们通过一个例子来具体看一下。
我们首先在typeinfo.interfacea
包下面新建一个接口A
:
package typeinfo.interfacea;
public interface A { void f(); }
我们接着在typeinfo.packageaccess
包下面新建一个接口C
,接口C
继承自接口A
,并且我们还另外创建了几个用于测试的方法,注意下面几个方法的权限都是不同的。
package typeinfo.packageaccess;
import typeinfo.interfacea.A;
class C implements A {
public void f() { System.out.println("public C.f()"); }
public void g() { System.out.println("public C.g()"); }
protected void v () { System.out.println("protected C.v()"); }
void u() { System.out.println("package C.u()"); }
private void w() { System.out.println("private C.w()"); }
}
public class HiddenC {
public static A makeA() { return new C(); }
}
在callHiddenMethod()
方法中我们用到了几个新的API,其中getDeclaredMethod()
根据方法名用于电子杂志类类指代对象的某个方法,我们然后通过调用invoke()
方法传入实际的对象就可以触发对象的相关方法:
package typeinfo;
import typeinfo.interfacea.A;
import typeinfo.packageaccess.HiddenC;
import java.lang.reflect.Method;
public class HiddenImplementation {
public static void main(String[] args) throws Exception {
A a = HiddenC.makeA();
a.f();
System.out.println(a.getClass().getName());
// Oops! Reflection still allows us to call g():
callHiddenMethod(a, "g");
// And even methods that are less accessible!
callHiddenMethod(a, "u");
callHiddenMethod(a, "v");
callHiddenMethod(a, "w");
}
static void callHiddenMethod(Object a, String methodName) throws Exception {
Method g = a.getClass().getDeclaredMethod(methodName);
g.setAccessible(true);
g.invoke(a);
}
}
从输出结果我们可以看出来,不管是public
,default
,protect
还是pricate
方法,通过反射类我们都可以自由调用。当然这里我们只是为了显示反射的强大威力,在实际开发中这种技巧还是不提倡。
public C.f()
typeinfo.packageaccess.C
public C.g()
package C.u()
protected C.v()
private C.w()
应用实践
我们有下面这样一个业务场景,我们有一个泛型集合类List<Class<? extends Pet>>
,需要我们出统计集合这个类中每种具体的Pet
有多少个。由于Java的的泛型擦除,类似注意List<? extends Pet>
的做法肯定的英文不行的,因为编译器做了静态类型检查之后,到了运行期间JVM会将集合中的对象都视为Pet
,但是并知道不会Pet
代表的究竟的英文Cat
还是Dog
,所以到了运行期间对象的类型信息其实全部丢失了。
为了实现我们上面的例子,我们先来定义几个类:
public class Pet extends Individual {
public Pet(String name) { super(name); }
public Pet() { super(); }
}
public class Cat extends Pet {
public Cat(String name) { super(name); }
public Cat() { super(); }
}
public class Dog extends Pet {
public Dog(String name) { super(name); }
public Dog() { super(); }
}
public class EgyptianMau extends Cat {
public EgyptianMau(String name) { super(name); }
public EgyptianMau() { super(); }
}
public class Mutt extends Dog {
public Mutt(String name) { super(name); }
public Mutt() { super(); }
}
上面的Pet
类继承自Individual
,Individual
类的的实现稍微复杂一点,我们实现了Comparable
接口,重新自定义了类的比较规则,如果不是很明白的话,也没有关系,我们已经将它抽象出来了,所以不理解实现原理也没有关系。
public class Individual implements Comparable<Individual> {
private static long counter = 0;
private final long id = counter++;
private String name; // name is optional
public Individual(String name) { this.name = name; }
public Individual() {}
public String toString() {
return getClass().getSimpleName() + (name == null ? "" : " " + name);
}
public long id() { return id; }
public boolean equals(Object o) {
return o instanceof Individual && id == ((Individual)o).id;
}
public int hashCode() {
int result = 17;
if (name != null) {
result = 37 * result + name.hashCode();
}
result = 37 * result + (int) id;
return result;
}
public int compareTo(Individual arg) {
// Compare by class name first:
String first = getClass().getSimpleName();
String argFirst = arg.getClass().getSimpleName();
int firstCompare = first.compareTo(argFirst);
if (firstCompare != 0) {
return firstCompare;
}
if (name != null && arg.name != null) {
int secendCompare = name.compareTo(arg.name);
if (secendCompare != 0) {
return secendCompare;
}
}
return (arg.id < id ? -1 : (arg.id == id ? 0 : 1));
}
}
下面创建了一个抽象类PetCreator
,以后我们通过调用arrayList()
方法便可以直接电子杂志相关Pet
类的集合。这里使用到了我们上面没有提及的newInstance()
方法,它会返回类类所真正指代的类的实例,这是什么意思呢?声明比如说new Dog().getClass().newInstance()
状语从句:直接new Dog()
的英文等价的。
public abstract class PetCreator {
private Random rand = new Random(47);
// The List of the different getTypes of Pet to create:
public abstract List<Class<? extends Pet>> getTypes();
public Pet randomPet() {
// Create one random Pet
int n = rand.nextInt(getTypes().size());
try {
return getTypes().get(n).newInstance();
} catch (InstantiationException e) {
throw new RuntimeException(e);
} catch (IllegalAccessException e) {
throw new RuntimeException(e);
}
}
public Pet[] createArray(int size) {
Pet[] result = new Pet[size];
for (int i = 0; i < size; i++) {
result[i] = randomPet();
}
return result;
}
public ArrayList<Pet> arrayList(int size) {
ArrayList<Pet> result = new ArrayList<Pet>();
Collections.addAll(result, createArray(size));
return result;
}
}
接下来我们来实现上面这一个抽象类,解释一下下面的代码,在下面的代码中,我们声明了两个集合类,allTypes
和types
,其中allTypes
中所有游戏了我们呢上面所声明的所有类,但是我们具体的实际上类型只有两种即Mutt
状语从句:EgypianMau
,我们所以需要真正new
出来的宠物只是types
中所所有游戏的类型,我们以后通过调用getTypes()
便可以得到types
中所所有游戏的所哟类型。
public class LiteralPetCreator extends PetCreator {
@SuppressWarnings("unchecked")
public static final List<Class<? extends Pet>> allTypes = Collections.unmodifiableList(
Arrays.asList(Pet.class, Dog.class, Cat.class, Mutt.class, EgyptianMau.class));
private static final List<Class<? extends Pet>> types = allTypes.subList(
allTypes.indexOf(Mutt.class), allTypes.size());
public List<Class<? extends Pet>> getTypes() {
return types;
}
}
总体的逻辑已经完成了,我们求最后实现用来统计集合中相关Pet
类个数的TypeCounter
类。一下解释isAssignalbeFrom()
方法,它可以判断一个反射类是某个反射类的子类或者间接子类。而getSuperclass()
顾名思义就是得到某个反射类的父类了。
public class TypeCounter extends HashMap<Class<?>, Integer> {
private Class<?> baseType;
public TypeCounter(Class<?> baseType) {
this.baseType = baseType;
}
public void count(Object obj) {
Class<?> type = obj.getClass();
if (!baseType.isAssignableFrom(type)) {
throw new RuntimeException(
obj + " incorrect type " + type + ", should be type or subtype of " + baseType);
}
countClass(type);
}
private void countClass(Class<?> type) {
Integer quantity = get(type);
put(type, quantity == null ? 1 : quantity + 1);
Class<?> superClass = type.getSuperclass();
if (superClass != null && baseType.isAssignableFrom(superClass)) {
countClass(superClass);
}
}
@Override
public String toString() {
StringBuilder result = new StringBuilder("{");
for (Map.Entry<Class<?>, Integer> pair : entrySet()) {
result.append(pair.getKey().getSimpleName());
result.append("=");
result.append(pair.getValue());
result.append(", ");
}
result.delete(result.length() - 2, result.length());
result.append("} ");
return result.toString();
}
}