目录
动态语言和静态语言
Java不是动态语言,但可以称为“准动态语言”,即有一定的动态性,可利用反射机制或字节码操作等获得类似动态语言的特性。
动态语言
动态语言在运行时可以改变其结构,例如新的函数对象甚至代码都可以被引进,已有的函数可以被删除等等。
在运行时代码可以根据某些条件改变自身结构。
主要动态语言:Objective-C,c#,JavaScript,PHP,Python,Erlang
静态语言
运行时结构不可变的语言就是静态语言,如Java,C,C++;
反射概述
- 反射是java被视为动态语言的关键,反射机制允许程序在执行期借助于Reflection API取得任何类的内部信息,并能直接操作任意对象的内部属性及方法。
- 加载完类之后。堆内存的方法区中就会产生一个Class类的对象(一个类只有一个对象)
- 该对象包含了完整的类的结构信息,故称其为反射。
基本操作
实现一个普通的类
首先实现一个普通的person类,其中name为私有属性,该类有一个私有构造类和一个私有的show方法。
class Person{
private String name;
public int age;
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
public Person(String name, int age) {
this.name = name;
this.age = age;
}
private Person(int age){
this.age=age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
private int getAge() {
return age;
}
private void setAge(int age) {
this.age = age;
}
public void show(){
System.out.println("hahahaha");
}
private String showNation(String nation){
System.out.println("国籍为"+nation);
return nation;
}
}
用反射对类进行基本操作
public static void main(String[] args) throws IOException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException, NoSuchFieldException {
//创建Class类
Class cl1 = Person.class;
//得到构造器
Constructor cons1 = cl1.getConstructor(String.class,int.class);
//创建类的对象 其本质为person
Object obj = cons1.newInstance("Tom", 12);
Person p = (Person) obj;
//调用对象指定的属性
Field age = cl1.getDeclaredField("age");
//给p对象改属性
age.set(p,10);
//调用对象指定的方法
Method show = cl1.getDeclaredMethod("show");
show.invoke(p);
}
反射调用类的私有结构
public static void main(String[] args) throws IOException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException, NoSuchFieldException {
//创建Class类
Class cl1 = Person.class;
//通过反射,可以调用Person类的私有结构,比如私有的构造器 方法 属性 等
//Person有一个私有构造方法,只需传入age参数 故构建此构造器
Constructor cons2 = cl1.getDeclaredConstructor(int.class);
cons2.setAccessible(true);
//创建对象
Person p1 = (Person) cons2.newInstance(20);
//Person{name='null', age=20}
System.out.println(p1);
//调用其私有的name属性
Field name = cl1.getDeclaredField("name");
name.setAccessible(true);
name.set(p1,"Jack");
//Person{name='Jack', age=20}
System.out.println(p1);
//调用其私有方法
Method showNation = cl1.getDeclaredMethod("showNation", String.class);
showNation.setAccessible(true);
//国籍为中国
String nation = (String) showNation.invoke(p1, "中国");
//中国
System.out.println(nation);
}
反射对类内部结构的获取
获取运行时类的属性结构
Class cl1 = Person.class;
//获取其属性结构 只能出来当前类及其父类的public属性
Field[] fields = cl1.getFields();
for(Field f:fields){
System.out.println(f);
}
//获取当前类自己定义的所有属性 不包含父类属性
Field[] declaredFields = cl1.getDeclaredFields();
for(Field f:declaredFields){
System.out.println(f);
}
//获取当前类自己定义的所有属性 不包含父类属性
for(Field f:declaredFields){
//获取权限修饰符
int modifiers = f.getModifiers();
//0:default 1:public 2:private
System.out.println(modifiers);
//或者直接打印
System.out.println(Modifier.toString(modifiers));
//获取数据类型
Class type = f.getType();
//获取属性名
String fname = f.getName();
}
获取运行时类的方法结构
Class cl1 = Person.class;
//获取其所有方法结构 只能出来当前类及其父类的public方法
Method[] fields = cl1.getMethods();
for(Method m:fields){
System.out.println(m);
}
//获取当前类自己定义的所有方法 不包含父类方法
Method[] declaredMethods = cl1.getDeclaredMethods();
for(Method m:declaredMethods){
System.out.println(m);
}
获取运行时类方法的内部结构
public static void main(String[] args) throws Exception {
Class cl1 = Person.class;
Method[] declaredMethods = cl1.getDeclaredMethods();
for(Method m:declaredMethods){
//获取方法声明的注解
Annotation[] annotations = m.getAnnotations();
for (Annotation an:annotations){
System.out.println(an);
}
//获取权限修饰符
System.out.println(Modifier.toString(m.getModifiers()));
//获取返回值类型
System.out.println(m.getReturnType().getName());
//获取方法名
System.out.println(m.getName());
//获取形参列表
Class[] parameterTypes = m.getParameterTypes();
//没有形参的情况下
if(!(parameterTypes == null && parameterTypes.length==0)){
for(Class p:parameterTypes){
System.out.println(p.getName());
}
}
//获取抛出的异常
Class[] exceptionTypes = m.getExceptionTypes();
if(!(exceptionTypes == null && exceptionTypes.length==0)){
for (Class p:exceptionTypes){
System.out.println(p.getName());
}
}
}
}
获取运行时类的构造器的结构
Class cl1 = Person.class;
//获取当前运行时中声明为public的构造器
Constructor[] constructors = cl1.getConstructors();
for (Constructor c:constructors){
System.out.println(c);
}
//获取当前运行时类中声明的所有构造器
Constructor[] declaredConstructors = cl1.getDeclaredConstructors();
for (Constructor c:declaredConstructors){
System.out.println(c);
}
获取运行时类的父类以及父类的泛型
Class cl1 = Person.class;
//获取运行时类的父类
Class superclass = cl1.getSuperclass();
//获取运行时类的带泛型的父类
Type generSuperClass = cl1.getGenericSuperclass();
System.out.println(generSuperClass);
获取运行时类的接口 所在包 注解
Class cl1 = Person.class;
//获取接口
Class[] interfaces = cl1.getInterfaces();
//获取类的包
Package aPackage = cl1.getPackage();
调用类中的指定属性
Class cl1 = Person.class;
//创建一个对象
Person p = (Person) cl1.newInstance();
//获取指定属性
Field name = cl1.getDeclaredField("name");
//保证当前属性是可访问的
name.setAccessible(true);
//设置这个值
name.set(p,"zhang");
//获取值
String name1 = (String) name.get(p);
调用类中的指定方法
Class cl1 = Person.class;
//创建一个对象
Person p = (Person) cl1.newInstance();
//获取指定的方法 需要指定形参类
Method show = cl1.getDeclaredMethod("show", String.class);
show.setAccessible(true);
//指定调用者和实参
show.invoke(p,"CHN");
//如果要调静态方法
Method showNation = cl1.getDeclaredMethod("showNation");
showNation.setAccessible(true);
//传入当前运行类
showNation.invoke(Person.class);