Java反射

一、反射概述

其实就是动态加载一个指定的类,并获取该类中的所有的内容。而且将字节码文件封装成对象,并将字节码文件中的内容都封装成对象,这样便于操作这些成员。简单说:反射技术可以对一个类进行解剖。

反射的好处:大大的增强了程序的扩展性。

反射的基本步骤:

    1,获得Class对象,就是获取到指定的名称的字节码文件对象。

    2,实例化对象,获得类的属性、方法或构造函数。

    3,访问属性、调用方法、调用构造函数创建对象。

获取这个Class对象,有三种方式:

    1,通过每个对象都具备的方法getClass来获取。弊端:必须要创建该类对象,才可以调用getClass方法。

    2,每一个数据类型(基本数据类型和引用数据类型)都有一个静态的属性class。弊端:必须要先明确该类。
          前两种方式不利于程序的扩展,因为都需要在程序使用具体的类来完成。

    3,使用的Class类中的方法,静态的forName方法。
          指定什么类名,就获取什么类字节码文件对象,这种方式的扩展性最强,只要将类名的字符串传入即可。

67// 1. 根据给定的类名来获得  用于类加载(被主要使用)  
68String classname = "cn.itcast.reflect.Person";// 来自配置文件  
69Class clazz = Class.forName(classname);// 此对象代表Person.class  
70  
71// 2. 如果拿到了对象,不知道是什么类型   用于获得对象的类型  
72Object obj = new Person();  
73Class clazz1 = obj.getClass();// 获得对象具体的类型  
74  
75// 3. 如果是明确地获得某个类的Class对象  主要用于传参  
76Class clazz2 = Person.class;      

二、反射的应用 

1,调用构造函数:使用反射机制也可以获得类中的构造方法。 Constructor

77package com.leon.demo;  
78  
79import java.lang.reflect.Constructor;  
80class Person  
81{  
82    public Person(){}  
83    public Person(String name){}  
84    public Person(String name,int age){}  
85}  
86public class TestDemo {  
87  
88    public static void main(String[] args) throws ClassNotFoundException   
89    {  
90        Class<?> cls = Class.forName("com.leon.demo.Person");//取得Class对象  
91        Constructor<?>[] cons = cls.getConstructors();//取得全部构造函数  
92          
93        for (int i = 0; i < cons.length; i++)  
94        {  
95            System.out.println(cons[i]);  
96        }  
97    }  
98}  

程序运行结果:

public com.leon.demo.Person()
public com.leon.demo.Person(java.lang.String)
public com.leon.demo.Person(java.lang.String,int)

99package com.leon.demo;  
100  
101//通过反射调用指定参数的构造函数实例化对象  
102import java.lang.reflect.Constructor;  
103class Person  
104{  
105    public Person(){}  
106    public Person(String name,int age)  
107    {  
108        this.name = name;  
109        this.age = age;  
110    }  
111    private String name;  
112    private int age;  
113      
114    @Override  
115    public String toString()  
116    {  
117        return "Person[name="+name+",age="+age+"]";  
118    }  
119}  
120public class TestDemo {  
121  
122    public static void main(String[] args) throws Exception   
123    {  
124        Class<?> cls = Class.forName("com.leon.demo.Person");//取得Class对象  
125          
126        //Object obj1 = cls.newInstance();//无参的构造方法,可以直接实例化。  
127          
128        //取得指定参数类型的构造方法,传递两个参数类型的class对象  
129        Constructor<?> con = cls.getConstructor(String.class,int.class);  
130          
131        Object obj = con.newInstance("张三",22);//为构造方法传递参数  
132          
133        System.out.println(obj);//运行结果:Person[张三,22]  
134    }  
135}  

本程序先通过getConstructor方法取得了一个指定参数类型的构造方法,然后利用Constructor类中的newInstance方法设置了两个参数的内容,这样就相当于调用了类中带有参数的构造方法。

 

2,调用普通方法 Method

136//取得一个类中所定义的所有方法  
137import java.lang.reflect.Constructor;  
138import java.lang.reflect.Method;  
139class Person  
140{  
141    public Person(){}  
142    public Person(String name,int age)  
143    {  
144        this.name = name;  
145        this.age = age;  
146    }  
147    private String name;  
148    private int age;  
149    public String getName()  
150    {  
151        return this.name;  
152    }  
153    public void setName(String name)  
154    {  
155        this.name = name;  
156    }  
157      
158    @Override  
159    public String toString()  
160    {  
161        return "Person[name="+name+",age="+age+"]";  
162    }  
163}  
164public class TestDemo {  
165  
166    public static void main(String[] args) throws Exception   
167    {  
168        Class<?> cls = Class.forName("com.leon.demo.Person");//取得Class对象  
169          
170        Method[] con = cls.getMethods();//获取类中的所有方法  
171          
172        for (int i = 0; i < con.length; i++)  
173        {  
174            System.out.println(con[i]);  
175        }  
176    }  
} 

程序运行结果:

public java.lang.String com.leon.demo.Person.toString()
public java.lang.String com.leon.demo.Person.getName()
public void com.leon.demo.Person.setName(java.lang.String)
public final void java.lang.Object.wait() throws java.lang.InterruptedException
public final void java.lang.Object.wait(long,int) throws java.lang.InterruptedException
public final native void java.lang.Object.wait(long) throws java.lang.InterruptedException
public native int java.lang.Object.hashCode()
public final native java.lang.Class java.lang.Object.getClass()
public boolean java.lang.Object.equals(java.lang.Object)
public final native void java.lang.Object.notify()
public final native void java.lang.Object.notifyAll()

本程序列出了Person类中的所有方法,同时由于Person类本身属于Object类的子类,所以在进行方法列出时会连同继承的方法一起取出。取得Method类对象的最大作用不在于将类中的全部方法列出(方法的列出都在开发工具上使用了),而是取得了Method类对象后可以直接利用反射调用类中的方法。

178//利用反射调用Person类中的setName()、getName()方法  
179public class TestDemo {  
180  
181    public static void main(String[] args) throws Exception   
182    {  
183        Class<?> cls = Class.forName("com.leon.demo.Person");//取得Class对象  
184          
185        Object obj = cls.newInstance();//实例化对象  
186          
187          
188        String attribute = "name";//调用属性名称  
189        Method setMe = cls.getMethod("set"+initCap(attribute), String.class);  
190        Method getMe = cls.getMethod("get"+initCap(attribute));  
191          
192        setMe.invoke(obj, "张三");//等同于:Person对象.setName("张三");  
193        System.out.println(getMe.invoke(obj));//等同于:Person对象.getName();  
194    }  
195      
196    //字符串转换,首字母大写  
197    public static String initCap(String str)  
198    {  
199        return str.substring(0,1).toUpperCase().concat(str.substring(1));  
200    }  
201}  
3,调用成员 Field

202//取得一个类中的全部属性  
203public class TestDemo {  
204  
205    public static void main(String[] args) throws Exception   
206    {  
207        Class<?> cls = Class.forName("com.leon.demo.Person");//取得Class对象  
208          
209        Field[] fil = cls.getDeclaredFields();//取得全部属性,包括私有的  
210          
211        for (int i = 0; i < fil.length; i++)  
212        {  
213            System.out.println(fil[i]);  
214        }  
215    }  
} 

本程序利用反射机制实现了对类中属性的调用,但是不建议使用这样的操作,因为从实际的开发标准来讲,所有的属性应该通过setter()和getter()方法设置和取得。

想要调用类中的私有方法或成员,必须调用Class类中的getDeclared...()方法,并且调用其setAccessible()解除其封装性。但是一般很少用,因为私有就是隐藏起来,所以尽量不要访问。









评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值