如果想要通过读取配置文件re.properties :
classfullpath=com.edu.Cat method=hi
创建Cat的对象并运行方法,用传统的new方法是不可实现的
//Cat类 /** * @author mtl121 * @version 1.0 */ public class Cat { private String name = "招财猫"; public int age = 2; public Cat() { } public Cat(int age) { this.age = age; } public Cat(String name, int age) { this.name = name; this.age = age; } public void hi() {//常用方法 System.out.println("hi" + name); } }
package com.edu.reflection.question; import com.edu.Cat; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.IOException; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.util.Properties; /** * @author mtl121 * @version 1.0 */ public class ReflectionQuestion { public static void main(String[] args) throws IOException, ClassNotFoundException, IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException { //根据配置文件 re.properties 指定信息, 创建 Cat 对象并调用方法 hi Cat cat = new Cat(); cat.hi(); //1. 使用 Properties 类, 可以读写配置文件 Properties properties = new Properties(); properties.load(new FileInputStream("src/re.properties")); String classpath = properties.getProperty("classfullpath"); String method = properties.getProperty("method"); System.out.println("classpath = " + classpath);//com.edu.Cat 类地址 System.out.println("method = " + method); //2.想通过配置文件中的类路径创建对象,只能通过反射机制解决 // (1)加载类,返回Class类型的对象cls forName传入参数为全限定类名【就是类的完整地址,包+类名】的String Class cls = Class.forName(classpath); //(2) 通过cls 得到你加载的类 com.edu.Cat 的对象实例 Object o = cls.newInstance(); System.out.println("o的运行类型 = " + o.getClass()); //(3) 通过 cls 得到你加载的类 com.hspedu.Cat 的 methodName"hi" 的方法对象 Method method1 = cls.getMethod(method); //(4) 通过 method1 调用方法: 即通过方法对象来实现调用方法 method1.invoke(o);//传统方法 对象.方法() , 反射机制 方法.invoke(对象) } }
反射机制:
1.反射机制允许程序在执行期间借助于Reflection API获取任何类的内部信息(比如成员变量,构造器,成员方法等等),并能操作对象的属性及方法。
2.加载完类之后,在堆中就产生了一个Class类型的对象(一个类只有一个Class对象),该对象包含了类的完整结构信息,通过该对象就可以获得类的结构。
反射相关的主要类:
package com.edu.reflection; import com.edu.Cat; import java.io.FileInputStream; import java.io.IOException; import java.lang.reflect.Constructor; import java.lang.reflect.Field; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.util.Properties; /** * @author mtl121 * @version 1.0 */ public class Reflection01 { public static void main(String[] args) throws IOException, ClassNotFoundException, IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException, NoSuchFieldException { //根据配置文件 re.properties 指定信息, 创建 Cat 对象并调用方法 hi Cat cat = new Cat(); cat.hi(); //1. 使用 Properties 类, 可以读写配置文件 Properties properties = new Properties(); properties.load(new FileInputStream("src/re.properties")); String classpath = properties.getProperty("classfullpath"); String method = properties.getProperty("method"); System.out.println("classpath = " + classpath);//com.edu.Cat 类地址 System.out.println("method = " + method); //2.想通过配置文件中的类路径创建对象,只能通过反射机制解决 // (1)加载类,返回Class类型的对象cls forName传入参数为全限定类名【就是类的完整地址,包+类名】的String Class cls = Class.forName(classpath); //(2) 通过cls 得到你加载的类 com.edu.Cat 的对象实例 Object o = cls.newInstance(); System.out.println("o的运行类型 = " + o.getClass()); //(3) 通过 cls 得到你加载的类 com.hspedu.Cat 的 methodName"hi" 的方法对象 Method method1 = cls.getMethod(method); //(4) 通过 method1 调用方法: 即通过方法对象来实现调用方法 method1.invoke(o);//传统方法 对象.方法() , 反射机制 方法.invoke(对象) //java.lang.reflect.Field: 代表类的成员变量, Field 对象表示某个类的成员变量 //得到name字段 //getField不能得到私有的属性 Field age = cls.getField("age"); System.out.println(age.get(o));//传统写法 对象.成员变量 , 反射 : 成员变量对象.get(对象) //java.lang.reflect.Constructor: 代表类的构造方法, Constructor 对象表示构造器 Constructor constructor = cls.getConstructor();//()中可以指定构造器参数类型, 返回无参构造器 System.out.println("constructor = " + constructor); //传入类的class对象作为参数,获得有参构造,Cat类的一个构造器为public Cat(int age),可以传入 int.class或者Integer.TYPE[只有包装类的可以用TYPE] //Integer.class和Integer.TYPE区别?Interger.TYPE和int.class区别? Constructor constructor1 = cls.getConstructor(Integer.TYPE); //再举个例子, cat中 有个构造器public Cat(String name, int age) Constructor constructor2 = cls.getConstructor(String.class, int.class); System.out.println("constructor1 = " + constructor1); } }
反射的缺点:
使用反射是解释执行,对执行速度有影响,但是可以通过关闭访问检查来优化
1.Method,Field和Constructor对象中都有setAccessible()方法
2.setAccessible()的作用是启用和关闭访问安全检查的开关
3.参数值为true则表示,反射的对象在使用时取消访问检查,提高反射的效率,
细节:
1.Class也是类,因此也继承Object类
2.Class类对象不是new出来的,而是系统创建出来的
3.对于某个类的Class类对象,在内存中只有一份,因为类只加载一次
4.每个类的实例都会记得自己是由哪个Class实例所生成的
5.通过Class对象可以完整地得到一个类的完整结构,通过一系列API
6.Class对象是存放在堆的
7.类的字节码二进制数据,放在方法区,有的地方称为类的元数据(包括,方法代码,变量名,方法名,访问权限等等)
package com.edu.reflection.class_; import com.edu.Car; import java.lang.reflect.Field; /** * @author mtl121 * @version 1.0 */ public class Class02 { public static void main(String[] args) throws ClassNotFoundException, IllegalAccessException, InstantiationException, NoSuchFieldException { String classfullpath = "com.edu.Car"; //1 . 获取到 Car 类 对应的 Class 对象 // <?> 表示不确定的 Java 类型 Class cls = Class.forName(classfullpath); //输出cls,cls不是一个Car类,他是Class类的实例,不可以强制转换成(Car) System.out.println(cls);//显示 cls 对象, 是哪个类的 Class 对象 com.edu.Car System.out.println(cls.getClass());//输出cls运行类型java.lang.Class //3.获取Class对象cls对应的类所在的包名 System.out.println(cls.getPackage()); //4.得到类名 System.out.println(cls.getName()); //5.通过cls创建对象实例 Car car = (Car)cls.newInstance(); System.out.println(car); //6. 通过反射获取属性 Field brand = cls.getField("brand"); System.out.println(brand.get(car));//宝马 // 7. 通过反射给属性赋值 brand.set(car, "奔驰"); System.out.println(brand.get(car));//奔驰 // 8 我希望大家可以得到所有的属性(字段) System.out.println("=======所有的字段属性===="); Field[] fields = cls.getFields(); for (Field f: fields) { System.out.println(f.getName()); } } }