java的反射机制

JAVA反射机制是在 运行状态中,对于任意一个 ,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性;这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制。
JAVA反射(放射)机制:“ 程序 运行时,允许改变程序结构或 变量 类型,这种语言称为 动态语言 ”。从这个观点看,Perl,Python,Ruby是 动态语言 ,C++,Java,C#不是动态语言。但是JAVA有着一个非常突出的动态相关机制:Reflection,用在Java身上指的是我们可以于运行时加载、探知、使用编译期间完全未知的classes。换句话说,Java程序可以加载一个运行时才得知名称的class,获悉其完整构造(但不包括methods定义),并生成其对象实体、或对其fields设值、或唤起其methods。
来点代码展现反射形态:
Object obj = new Person("xxc",99);  
//获得Class的实例的三种方式  
//1.通过对象的getClass()方法获得  
Class clazz1 = obj.getClass();  
//2.通过表示类名的字符串来获得,注意:这里的字符串必须是完整路径,否则找不到这个类  
String className = "com.xxc.reflet.Person";  
Class clazz2 = Class.forName(className);  
//3.用类名.class的方式获取  
Class clazz3 = Person.class;  
System.out.println(clazz3);  
System.out.println(clazz1 == clazz3);//true  
System.out.println(clazz1 == clazz2);//true  
System.out.println(clazz3 == clazz2);//true  
//获取基本数据类型的Class对象,void也是一种类型。  
Class intClazz = int.class;  
System.out.println(intClazz);//打印int  
Class voidClazz = void.class;  
System.out.println(voidClazz);//打印void  
/* 
 * 获得类中定义的所有属性 
 * getField(String name)返回一个属性,是这个类或接口当中的公共成员字段   返回类型 Field 
 * getFields()返回这个类或接口中所有公共成员字段  返回类型 Field[] 
 *  
 * getDeclaredField(String name)返回一个已声明的属性,可以是这个类或接口中任意权限的字段   返回类型 Field 
 * getDeclaredFields() 返回这个类或借口中所有已声明的成员字段,任意权限  返回类型 Field[] 
 */  
Class clazz = Person.class;  
Field[] fields = clazz.getDeclaredFields();  
for(Field f: fields){  
    System.out.println("属性名         "+f.getName());  
    System.out.println("类型:   "+f.getType());  
}  
/* 
 * 用反射获取类中的成员字段: 
 * 1.先根据这个属性的名字,拿到这个属性 
 * 2.设置反射的对象在使用时应该取消 Java 语言访问检查,说白了就是不受权限的限制,可以访问private 
 * 3.返回指定对象上此 Field 表示的字段的值。 get(obj)参数的obj表示一个对象。返回obj对象里的字段。 
 */  
Field nameField = clazz.getDeclaredField("name");  
nameField.setAccessible(true);  
Object value = nameField.get(obj);  
System.out.println(value);  
/* 
 * 利用反射来改某个对象里的属性,第一个参数表示要修改哪个对象,第二个表示被修改属性的值。 
 * 至于修改哪个属性,并不是在参数里指定的,调用set方法的那个类就表示哪个属性 
 */  
nameField.set(obj, "xxm");  
System.out.println(obj);  

/* 
 * 获得类中定义的所有方法 
 * getMethod(String name, Class<?>... parameterTypes)  返回这个类或接口中公共的方法  返回类型Method  第一个参数表示哪个对象,第二个参数表示参数类型  int.class 
 *                                                            因为光是指定函数名没用,重载的话就不能明确指出是哪一个方法。 
 * getMethods() 返回这个类或接口中所有公共的方法  返回类型是Method[] 
 *  
 * getDeclaredMethod(String name, Class<?>... parameterTypes)  返回这个类或接口中任意权限的方法  返回类型是Method  
 *  
 * getDeclaredMethods() 返回这个类或接口中任意权限的所有方法 返回类型是Method[] 
 */  
Object obj = new Person("xxc",99);  
Class clazz = obj.getClass();  
Method[] methods = clazz.getDeclaredMethods();  
for(Method m : methods){  
    System.out.println(m.getName());//返回方法名  
    System.out.println(m.getReturnType().getName());//返回方法的返回类型,如果直接是m.getReturnType()则会在返回类型前加class java.lang.String  
    Class[] parameterTypes = m.getParameterTypes();//获取方法中的参数类型,并封装在一个数组中  
    for(Class parameterType : parameterTypes){//遍历参数类型数组  
    System.out.print("参数类型  "+parameterType.getName());//获取参数类型名称  
      }  
}  
Method method = clazz.getDeclaredMethod("run",String.class,int.class,String.class);//获取需要调用的方法对象  第一个参数是方法名字,第二个参数是参数类型  
method.invoke(obj, "xxc",20,"男");//调用方法,第一个参数是具体对象,第二个参数是方法的实参  

/*通过反射获取构造函数,以及其中的参数类型,构造函数名称,用构造函数创建对象。 
 *getConstructors() 获取某一个类中所有的公共权限构造函数 
 *getConstructor(Class<?>... parameterTypes) 获取某一个类中指定参数类型的公共权限构造函数  
 * 
 *getDeclaredConstructors() 获取某一个类中所有的任意权限的构造函数 
 *getDeclaredConstructor(Class<?>... parameterTypes) 获取某一个类中指定参数类型的任意权限的构造函数 
 */  
Object obj = new Person("xxc",99);  
Class clazz = obj.getClass();  
Constructor[] constructors = clazz.getDeclaredConstructors();  
for(Constructor constructor : constructors){  
    System.out.println("构造函数名字"+constructor.getName());  
    System.out.println("构造函数的参数类型:");  
    Class[] parametersTypes = constructor.getParameterTypes();  
    for(Class parametersType : parametersTypes){  
        System.out.print(parametersType.getName());  
        System.out.println();  
    }  
}  
//调用有参构造函数,创建对象  
/* 
 * 下面这句话的第二个参数能写数组的原因是因为在1.5前,这里的第二个参数就是数组类型。 
 * 它和可变参数最主要的区别就是,当调用的函数是没有参数的,那么可变参数的可以不用写,而用数组类型表示的需要写null 
 */  
Constructor constructor = clazz.getDeclaredConstructor(String.class,int.class);  
//Constructor constructor = clazz.getDeclaredConstructor(new Class[]{String.class,int.class});JDK1.5之前用的  
Person person = (Person)constructor.newInstance("xxx",99);//使用反射获取的有参构造函数创建对象  
System.out.println(person);  
persion类
public class Person {  
    private String name;  
    private int age;  
      
    Person(String name,int age){  
        this.name = name;  
        this.age = age;  
    }  
  
    public String toString() {  
        return "Person [name=" + name + ", age=" + age + "]";  
    }  
      
    public void run(String str,int age,String sex){  
        System.out.println(str+"  "+age+"  "+sex);  
    }  
}  

获取类或方法前的修饰:
Package pack = clazz.getPackage();//获取某个类的包名  
System.out.println("包名--->"+pack.getName());  
          
          
int num = clazz.getModifiers();//可以获取类的修饰内容  
/* 
 * 以下这个方法这样用有局限性,因为一个类既有public修饰,又有abstract修饰 
 * Modifier.PUBLIC=1 
 * Modifier.abstract=1024 
 * 那么此时有两个修饰就是1025,所以再用Modifier.PUBLIC就不能正确判断了。 
 * 这时可以用Modifier.isPublic(num)来进行判断。 
 */  
if(num == Modifier.PUBLIC){  
    System.out.println("这个类的修饰符是PUBLIC");  
}  
if(Modifier.isPublic(num)){  
    System.out.println("这个类的修饰符是PUBLIC");  
}  
Method run = clazz.getDeclaredMethod("run",String.class,int.class,String.class);  
if(Modifier.isPublic(run.getModifiers())){//函数中也有获取修饰符类型的方法  
    System.out.println("Run方法是PUBLIC修饰的");

练习:通过反射,做一个面向接口的,能计算任何形状面积的方法。

创建接口(此接口中有计算面积的抽象方法):

package com.xxc.reflet.test;  
  
public interface InterfaceTest {  
    double getArea();  
}     

实现接口的类(圆)

package com.xxc.reflet.test;  
  
public class ChangFangXing implements InterfaceTest{  
    private double height;  
    private double width;  
    public double getArea() {  
        return height*width;  
    }  
      
}  

实现接口的类(长方形)

package com.xxc.reflet.test;  
  
public class ChangFangXing implements InterfaceTest{  
    private double height;  
    private double width;  
    public double getArea() {  
        return height*width;  
    }  
      
}  

测试:

package com.xxc.reflet.test;  
  
import java.io.BufferedReader;  
import java.io.InputStreamReader;  
import java.lang.reflect.Field;  
  
public class RefletTest {  
    public static void main(String[] args) throws Exception {  
        System.out.println("请输入要计算的图形名称");  
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));  
        String name = br.readLine();  
        Class clazz;  
        try {  
            clazz = Class.forName("com.xxc.reflet.test."+name);  
        } catch (Exception e) {  
            System.out.println("不存在这样的图形");  
            return;  
        }  
        InterfaceTest ift = (InterfaceTest)clazz.newInstance();  
        Field[] parameterType = clazz.getDeclaredFields();//获得所有的数据域  
        for(Field f : parameterType){  
            System.out.println("请输入:"+f.getName());  
            double num = Double.parseDouble(br.readLine());  
            f.setAccessible(true);//将所有的域设置为可访问的。  
            f.setDouble(ift, num);  
        }  
        double area = ift.getArea();  
        System.out.println("图形面积是:"+area);  
    }  
}  






评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值