Java反射机制
1.反射简述
2.Class是什么?
3.通过反射获得Field,Constructor,Method
4.反射的应用
====================== 华丽丽的分割线 ======================
1.反射简述
类用于描述一类具有相同属性和方法的东西,那么,Java中的类又能否有相应的类去描述?
答案是肯定的,反射(reflect)就是用来把Java类中的各种成分映射成各种相应的Java类.
Java反射涉及的类分别为:Field、Constructor、Method、Class。
Field 类:提供有关类或接口的属性的信息,以及对它的动态访问权限。反射的字段可能是一个类(静态)属性或实例属性,简单的理解可以把它看成一个封装反射类的属性的类。
Constructor 类:提供关于类的单个构造方法的信息以及对它的访问权限。这个类和 Field 类不同,Field 类封装了反射类的属性,而 Constructor 类则封装了反射类的构造方法。
Method 类:提供关于类或接口上单独某个方法的信息。所反映的方法可能是类方法或实例方法。这个类不难理解,它是用来封装反射类方法的一个类。
Class 类:类的实例表示正在运行的 Java 应用程序中的类和接口。枚举是一种类,注释是一种接口。每个数组属于被映射为 Class 对象的一个类,所有具有相同元素类型和维数的数组都共享该 Class 对象。
====================== 华丽丽的分割线 ======================
2.Class是什么?
Class:简单而言,就是用来描述Java类(与接口)的类.它的实例用来表示正在运行的Java应用程序中的类和接口。
如何获得字节码?
Class cls = Xxx.class;
Class cls = xx.getClass();
Class.forname(类名);  // 返回字节码:若内存中有加载该类,则他找到该类的字节码并返回,若无,则找到该类的路径,加载后返回.
要区别一个概念,这里获得的是类的字节码,与具体的对象无关。
View Code 
1 public class ClassTest {
2
3 public static void main(String[] args){
4 String str1 = "abc";
5 String str2 = "123";
6 System.out.println("str1.getClass() 等于 str2.getClass()? " + (str1.getClass() == str2.getClass());
7 }
8 }
9 /* Output:
10 * str1.getClass()等于str2.getClass()? true
11 */
如前所说,他是用来描述正在运行的Java类。这里这里的getClass()获得的是String类型的字节码,故当然相等.
====================== 华丽丽的分割线 ======================
3.通过反射获得Field,Constructor,Method
通过反射获得类得各种成分
View Code 
1 public class ReflectTest{
2
3 public int a = 47;
4
5 private String str = "hello";
6
7 public ReflectTest(){}
8
9 public ReflectTest(String str){
10 this.str = str;
11 }
12
13 public String getStr(String str){
14 return this.str + "," + str;
15 }
16
17 public String getStr(){
18 return str;
19 }
20
21 public static void main(String[] args){
22 System.out.println("This is GenericsTest" + args[1]);
23 }
24
25 }
这里有一个类,用于待会通过反射来获得它的成分,这个类中有属性(公有与私有,基础类型与非基础类型),两个构造方法,两个方法(多态)。
3.1. 通过反射获得Field:
View Code 
1 import java.lang.reflect.Field;
2
3 public class ReflectField {
4
5 public static void main(String[] args) throws Exception {
6 Class clazz = Class.forName("ReflectTest");
7 System.out.println(clazz.getName());
8
9 // method two:
10 // Class clazz1 = GenericsTest.class;
11
12 // method three:
13 // GenericsTest gt = new GenericsTest();
14 // Class clazz2 = gt.getClass();
15
16 Field fieldA = clazz.getField("a");
17 // Can not:Field fieldA = clazz.getField("str");
18 // Because str's modifiers is private.
19 System.out.println("属性名:" + fieldA.getName() + "; 类型:"
20 + fieldA.getType() + "; 权限修饰符:"
21 + fieldA.getGenericType() + "; 值:" + fieldA.get(new ReflectTest()));
22
23 // 既然反射是将类的各种成分映射成相应的类,那么私有的属性理应也可获取(暴力反射):
24 ReflectTest rt = new ReflectTest();
25 Field fieldStr = clazz.getDeclaredField("str");
26 fieldStr.setAccessible(true);
27 System.out.println(fieldStr.get(rt));
28 fieldStr.set(rt, "abc");
29 System.out.println(fieldStr.get(rt));
30 }
31
32 }
在这个类中,演示了如何获得属性,要注意的是,私有属性的获得是需要通过暴力反射。
3.2. 通过反射获得构造方法:
View Code 
1 import java.lang.reflect.Constructor;
2
3
4 public class ReflectConstructor {
5
6 public static void main(String[] args) throws Exception {
7 Class clazz = Class.forName("ReflectTest");
8
9 // 获取无参的构造方法
10 Constructor<ReflectTest> constructor = clazz.getConstructor();
11 ReflectTest rt = constructor.newInstance();
12 System.out.println(rt.getStr());
13
14 // 获取有参的构造方法,需指明参数类型
15 constructor = clazz.getConstructor(String.class);
16 rt = constructor.newInstance("world");
17 System.out.println(rt.getStr());
18
19 // 可以看出,先通过获取ReflectTest的字节码,然后得到它的构造方法,再调用该构造方法生成对象
20 // 对于无参的构造方法,Class类中提供一个方法可以直接生成该类的对象
21 rt = (ReflectTest)clazz.newInstance();
22 System.out.println(rt.getStr());
23 }
24
25 }
3.3. 通过反射获得方法:
View Code 
1 import java.lang.reflect.Method;
2
3
4 public class ReflectMethod {
5
6 public static void main(String[] args) throws Exception{
7 ReflectTest rt = new ReflectTest();
8 ReflectTest rt2 = new ReflectTest();
9 Method method = ReflectTest.class.getMethod("getStr",String.class);
10 String message = (String)method.invoke(rt,"world!");
11 System.out.println(message);
12 }
13 }
要补充的是,对于无参的方法,不用写参数;而对于静态方法时,则为:method.invoke(null,参数名...);
因为静态方法是不需要对象的。。。
====================== 华丽丽的分割线 ======================
4.反射的应用
反射的应用:框架。就好比建筑一样,我们先建好框架,等待门窗安进来,而在建房时无需知道门与窗长得什么样。
下面通过一个常用的实例来模拟一个小框架,即通过获取properties文件中的类名,来创建对象(框架的基本原理)
#config.properties
className=ReflectTest
在properties中,由于我做这个实例的时候直接丢到默认包,所以路径就直接写,蛋若有包名,则需写全
View Code 
1 import java.io.InputStream;
2 import java.util.Properties;
3
4
5 public class ReflectApp {
6
7 public static void main(String[] args) throws Exception {
8 // 从当前类所对应的包中找到config.properties文件.若在前面加上 "/",则从项目的根目录开始.
9 InputStream inStream = ReflectApp.class.getResourceAsStream("config.properties");
10
11 // method two:
12 // 该方法需从根目录开始,也就是得指明包,这里是默认包,所以直接写
13 // InputStream inStream = ReflectApp.class.getClassLoader().getResourceAsStream("config.properties");
14 Properties props = new Properties();
15 props.load(inStream);
16 inStream.close();
17 String className = props.getProperty("className");
18 System.out.println("创建一个对象: " + Class.forName(className).newInstance());
19 }
20
21 }
这就是反射的基本应用,其实在做‘有个饭桶’的时候就用到了,只是当时知其然而不知其所以然。。。现在学框架,懂了这个后回头看,便清晰容易多了。。。
                    
                
                
            
        
浙公网安备 33010602011771号