动态语言是指程序在运行时,可以改变程序结构或变量的类型。典型的有Python、JavaScipt等。例如下面的JS代码:
function test(){
var s = "var a = 3; var b = 5; alert(a + b);";
eval(s);
}
JS可执行位于字符串里面的源码。也就是说,外部传入的字符串是什么内容,JS就执行什么。这样,在执行的时候就完全改变了源码结构。这种动态特性,让程序更灵活,更开放。
Java虽然有动态性,但不是动态语言,可以利用反射机制或者字节码操作获得类似动态语言的特性。
Java反射机制让我们在程序运行状态中,对于任意一个类,都能知道该类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法。这种动态获取以及动态调用对象方法的功能就是“Java的反射机制”
来看下面这个代码
public class Study{
public static void main(String[] args) {
Person person = new Person("xxx");
}
static class Person{
String name;
public Person(String name){
this.name = name;
}
}
}
分析内存结构:
Java在加载任何一个类时都会在方法区建立这个类对应的Class对象,由于Class对象包含了这个类的整个信息结构,所以可以通过这个Class对象来操作这个类。
在使用一个类之前要先加载它,在加载完类后,会在对内存中产生一个Class类型的对象(一个类只有一个Class对象),这个对象包含了完整的类的结构信息,可以通过这个对象知道类的结构。这个对象如图一面镜子,透过它可以看到类的结构,因此被称为反射。“Class对象”是反射机制的核心。获得了Class对象,就相当于获得了类结构。通过“Class对象”可以调用该类的所有属性、方法和构造器,中依旧可以动态加载和运行相关的类。
java.lang.Class类是实现反射(Reflection)的根源。针对任何想动态加载、运行的类,只有先获得相对于的Class对象。java.lang.Class类用于表示Java中的类型(class,interface,enum,annotation,primitive type,void)本身。
Class对象可用以下方法获取
1)getClass()方法
2).class语法
3)运行Class.forName(),这个最常用
示例如下:
package blog.Study;
public class Study{
public static void main(String[] args) throws Exception{
Person person = new Person("xxx");
Class c1 = person.getClass();
Class c2 = Person.class;
Class c3 = Class.forName("blog.Study.Person");
System.out.println(c1);
System.out.println(c2);
System.out.println(c3);
System.out.println(c1.equals(c2));
System.out.println(c1.equals(c3));
System.out.println(c1.getName());
System.out.println(c1.getSimpleName());
}
}
class Person{
String name;
public Person(String name){
this.name = name;
}
}
//输出如下
class blog.Study.Person
class blog.Study.Person
class blog.Study.Person
true
true
blog.Study.Person
Person
1)动态加载类、动态获取类的信息
2)动态构造对象
3)动态调用类和对象的任意方法
4)动态调用和处理属性
5)获取泛型信息
6)处理注解
常用类如下
首先定义Person类:
package blog.Study;
public class Person{
private String name;
private int age;
public Person(String name, int age){
this.name = name;
this.age = age;
}
public Person(String name){
this.name = name;
}
public Person(){
}
public void print() {
System.out.println("Person{" + "name='" + name + '\'' + ", age=" + age + '}');
}
public String getName(){
return this.name;
}
public int getAge(){
return this.age;
}
public void setName(String name){
this.name = name;
}
public void setAge(int age){
this.age = age;
}
}
import blog.Study.Person;
import java.lang.reflect.Constructor;
public class study {
public static void main(String[] args) throws Exception{
String path = "blog.Study.Person";
Class c = Class.forName(path);
Constructor[] constructors = c.getDeclaredConstructors();
for(Constructor temp : constructors)
System.out.println(temp);
System.out.println(c.getDeclaredConstructor(null));
System.out.println(c.getDeclaredConstructor(String.class));
System.out.println(c.getDeclaredConstructor(String.class, int.class));
Person person = (Person)c.newInstance();
Person person1 = (Person)c.getDeclaredConstructor(null).newInstance();
Person person2 = (Person)c.getDeclaredConstructor(String.class).newInstance("XXX");
Person person3 = (Person)c.getDeclaredConstructor(String.class,int.class).newInstance("xxx", 18);
person.print();
person1.print();
person2.print();
person3.print();
}
}//输出如下
public blog.Study.Person(java.lang.String,int)
public blog.Study.Person()
public blog.Study.Person(java.lang.String)
public blog.Study.Person()
public blog.Study.Person(java.lang.String)
public blog.Study.Person(java.lang.String,int)
Person{
name='null', age=0}
Person{
name='null', age=0}
Person{
name='XXX', age=0}
Person{
name='xxx', age=18}
import blog.Study.Person;
import java.lang.reflect.Field;
public class study {
public static void main(String[] args) throws Exception{
String path = "blog.Study.Person";
Class c = Class.forName(path);
Field[] fields = c.getDeclaredFields();
for(Field temp : fields)
System.out.println("属性->" + temp);
Field field = c.getDeclaredField("name");
System.out.println(field);
Person person = (Person)c.newInstance();
Field field1 = c.getDeclaredField("age");
field.setAccessible(true);//跳过安全检查,直接访问私有属性和方法
field1.setAccessible(true);
field.set(person, " xxx ");
field1.set(person, 18);
person.print();
}
}//输出如下
属性->private java.lang.String blog.Study.Person.name
属性->private int blog.Study.Person.age
private java.lang.String blog.Study.Person.name
Person{
name=' xxx ', age=18}
import blog.Study.Person;
import java.lang.reflect.Method;
public class study {
public static void main(String[] args) throws Exception{
String path = "blog.Study.Person";
Class c = Class.forName(path);
Method[] methods = c.getDeclaredMethods();
for(Method temp : methods)
System.out.println("方法->" + temp);
Method method = c.getDeclaredMethod("setName", String.class);
Method method1 = c.getDeclaredMethod("setAge", int.class);
Method method2 = c.getDeclaredMethod("print", null);
Person person = (Person) c.newInstance();
method.invoke(person, "xxx");
method1.invoke(person, 18);
method2.invoke(person, null);
}
}//输出如下
方法->public java.lang.String blog.Study.Person.getName()
方法->public void blog.Study.Person.setName(java.lang.String)
方法->public void blog.Study.Person.print()
方法->public void blog.Study.Person.setAge(int)
方法->public int blog.Study.Person.getAge()
Person{
name='xxx', age=18}
测试代码如下:
import blog.Study.Person;
import java.lang.reflect.Constructor;
public class study {
public static void main(String[] args) throws Exception{
String path = "blog.Study.Person";
Class c = Class.forName(path);
long RTimeStart = System.currentTimeMillis();
Person person1;
Constructor constructor = c.getDeclaredConstructor(String.class, int.class);
for(int i = 0; i < 999999; i++)
person1 = (Person) constructor.newInstance("xxx", 18);
long RTimeEnd = System.currentTimeMillis();
Person person2;
for(int i = 0; i < 999999; i++)
person2 = new Person("xxx", 18);
long UTmieEnd = System.currentTimeMillis();
System.out.println("反射时间:" + (RTimeEnd - RTimeStart) + "ms");
System.out.println("普通时间:" + (UTmieEnd - RTimeEnd) + "ms");
}
}//输出如下
反射时间:58ms
普通时间:4ms
采用反射机制的Java程序要经过字节码解析过程,将内存中的对象进行解析,包括了一些动态类型,而JVM无法对这些代码进行优化,因此,反射机制的效率比那些非反射操作效率低得多。