1.Java反射机制是什么?
Java反射机制是指在运行状态中而不是编译状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意方法和属性;这种动态获取信息以及动态调用对象方法的功能称为Java语言的反射机制。在Java尤其是J2ee中经常会使用反射,其原因是因为反射机制有很多好处,动态的反射来创建对象和调用方法可以帮助我们减少每个类之间的耦合度,也就是解耦。
不使用反射机制,直接在代码中new出自己需要的类,这种静态编译的方法会在编译的时候绑定对象,虽然这样运行起来比反射机制快,但是如果一旦在项目中修改某个类,那么可能造成很多地方需要修改一遍,而且这个类的方法和属性也有可能要涉及修改。这会造成不必要的麻烦。
使用反射机制,相比较静态编译,反射机制是动态编译,在运行的时候确定类并且实例化、调用方法。反射发挥了Java编程的灵活性,如果此时类需要修改,那么只需要修改反射类的那一句话即可,或者如果你喜欢,甚至可以把关于反射的内容单独作为一个配置文件用xml写出来,如果需要修改,直接在配置文件中修改反射的类名即可。
Java中分反射方法集中在java.lang.Class这个类和java.lang.reflect包中。java.lang.Class是反射的基础,而且这个类中包括了很多我们所需要的反射方法。其中参数T是由Class对象建模的类型,例如,如果String.class那么这个T就是String,如果并不能确定被建模的类,那么就用Class
2.Java反射机制的主要作用?
a.获取类名
> public class test {
public test() throws ClassNotFoundException {
}
public static void main (String[] args) throws ClassNotFoundException {
Date d = new Date();
Class <?> c1 = d.getClass();//获取运行时类名。是Object方法,不是Class的方法。
Class <?> c2 = int.class;
Class <?> c3 = Class.forName("java.util.Date");//返回与给定字符串相关联的Class对象名。
System.out.println(c1.getName());
System.out.println(c2.getName());
System.out.println(c3.getName());
}
}
java.util.Date
int
java.util.Date
b.获取所有父类和接口
getSuperclass()返回表示此Class所表示的实体(类、接口、基本类型或void)的超类的Class。如果此Class表示Object类、一个接口、一个基本类型或void,则返回null。(因为这些没有超类)
class gogo{
}
interface gg{
}
interface coco{
}
public class test extends gogo implements gg,coco {
public static void main(String[] args){
String t1 = test.class.getSuperclass().getName();//获取父类名
//Type t2 = test.class.getGenericSuperclass();获取父类名,若果父类是泛型类,获取其类型参数
Class<?> t3[] = test.class.getInterfaces();//获取所有接口存入数组
System.out.println(t1);
for (Class<?> t : t3){
System.out.println(t.getName());
}
}
}
gogo
gg
coco
c.创建对象
创建此Class对象所表示的类的一个新实例。如同一个带有一个空参数列表的new表达式实例化该类。
test ts = test.class.newInstance();
d.获取构造器
获取所有的构造器,将其存入一个Constructor<?>数组中。代码示例如下:
> public class test extends gogo implements gg,coco {
public int i;
public test(){}
public test(int i){
}
public static void main(String[] args) throws IllegalAccessException, InstantiationException {
Constructor<?>[] cons = test.class.getDeclaredConstructors();
System.out.println(cons[0]);
System.out.println(cons[1]);
}
}
输出结果:
public test()
public test(int)
由给出的参数和参数顺序获取特定的构造器,将其存入一个Constructor<?>中。代码示例如下:
class gogo{
public int x;
public gogo(int x){
}
}
interface gg{
}
interface coco{
}
public class test extends gogo implements gg,coco {
public int i;
public test(int x) {
super(x);
}
public static void main(String[] args) throws IllegalAccessException, InstantiationException, ClassNotFoundException, NoSuchMethodException {
Constructor<?> cons = Class.forName(test.class.getSuperclass().getName()).getDeclaredConstructor(int.class);//获取test类的父类的特定构造器方法
System.out.println(cons);
}
}
输出结果:
public gogo(int)
Constructor类
getDeclaringClass()方法:获取这个Constructor对象中构造器表示的那个类,即构造器所属的原来的类。
Class<?> thisClass = con.getDeclaringClass();//thisClass是构造器所属的类名
getParameterTypes()方法:获取这个Constructor对象中的所有形参类型的class对象,存入Class<?>[]数组中。
Constructor<?> cons = Class.forName(test.class.getSuperclass().getName()).getDeclaredConstructor(int.class);
Class<?>[] para = cons.getParameterTypes();
for (Class<?>pa : para){
System.out.println(pa.getSimpleName());//输出形参类型
}
输出结果:
int
toGenericString()方法:和toString方法差不多,都是返回完整的构造器字符串,但是如果有类型参数,也会包含在内输出。
Constructor<?> cons = Class.forName(test.class.getSuperclass().getName()).getDeclaredConstructor(int.class);
System.out.println(cons.toGenericString());
输出结果:
public gogo(int)
e.获取属性
获取所有的类的属性,将其存入一个field[]数组中。
Field[] fies = test.class.getDeclareFields();
由给出的参数和参数顺序获得特定构造器,将其存入一个Constructor<?>中。
Field fie = test.class.getDeclareField("a");
Field类
setAccessible()方法:setAccessible方法并不是Field类中的方法,但是却极为常用,作用是修改安全检查,使得我们可以访问Field对象中的属性,即使他是private来修饰的。
fie.setAccessible(true);//fie中的属性即使为private,我们现在也可访问
get()和set()方法:get方法可以获取Field对象中的属性的值,参数为那个被获取的属性所属的类的一个实例。而set方法可以设置Field对象的属性的值,第一个参数为那个属性所属的那个类的一个实例,第二个参数为要修改为的值。
Field fie = test.class.getDeclaredField("a");//fie中的属性为test类中名为a的属性
System.out.println(fie.get(test.class.newInstance()));//获取了fie中属性的默认值
test<String, Date> ca=null;//声明一个test类对象ca
fie.set(ca=ClassA.class.newInstance(), 10);//设置ca中a的值为10
System.out.println(fie.get(ca));//输出a的值,显然输出应该是10
getModifiers()和Modifier.toString()方法:Field类中有一个getModifiers方法以整数的形式返回Field对象中属性的修饰符,而Modifier类中的toString方法则可以将整数解码,返回字符串形式的修饰符。
System.out.println(Modifier.toString(fie.getModifiers()));
以下的方法和Constructor类中相同。
isSynthetic()方法
toGenericString()方法
getDeclaringClass()方法
f. 获取方法
获取所有的方法,将其存入一个Method[]数组中。
Method[] mths = test.class.getDeclaredMethods();
由给出的参数和参数顺序获取特定的方法,将其存入一个Method对象中。
Method mth =test.class.getDeclaredMethod("setObject",Object.class);
//如果参数是泛型参数则用Object.class,原因是虚拟机擦除
System.out.println(mth.toGenericString());
//输出:
//public void Reflect.test.setObject(T)
Method类
getReturnType()方法:获取Method对象中方法的正式返回类型。
System.out.println(mth.getReturnType()); //输出: void
isBridge() 方法:如果这个方法是桥方法,则返回true。
System.out.println(mth.isBridge());//如果是桥方法返回true,不是桥方法,返回false
invoke(Object obj,Object…args)方法:第一个参数是从中调用方法的对象,后面的参数是用于方法调用的参数(可为数组)。如果底层方法是静态的,那么可以忽略指定的 obj 参数。该参数可以为 null。 如果底层方法所需的形参数为 0,则所提供的 args 数组长度可以为 0 或 null。 如果底层方法是静态的,并且尚未初始化声明此方法的类,则会将其初始化。 如果方法正常完成,则将该方法返回的值返回给调用者;如果该值为基本类型,则首先适当地将其包装在对象中。但是,如果该值的类型为一组基本类型,则数组元素不 被包装在对象中;换句话说,将返回基本类型的数组。如果底层方法返回类型为 void,则该调用返回 null。
Method mth =test.class.getDeclaredMethod("setObject",Object.class);
mth.invoke(test.class.newInstance(),"a");
//调用并执行了test中的setObject方法
Method mth2 =test.class.getDeclaredMethod("getObject");
System.out.println(mth2.invoke(test.class.newInstance()));
//调用了无参数的getObject方法,并且将返回值显示出来
以下的方法和Constructor类中相同。
getParameterTypes()方法
isSynthetic()方法
toGenericString()方法
getDeclaringClass()方法