------- android培训、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;
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}
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}
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 }
- }
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}
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
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 }
- }
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()解除其封装性。但是一般很少用,因为私有就是隐藏起来,所以尽量不要访问。