reflect : 反射,映射
类加载到内存中:将类的信息读取到内存中去(class文件读到内存中去)
(一)创建对象的两个不同时机:
(1)编译时创建对象:new Person(""); (弊端:对象改变时需要不断修改源代码)
(2)运行时创建对象:首先要获取class文件的信息 ,java中提供了一个类Class类
(二)Class类获得对象三种方法:
(1)
Class clazz1=Class.forName("");
注:引号""里面放的是包名.类名(通过对应java文件下的文件右键copyQualifiedName得到)
(2)
Class clazz2=类名.class;
(3)
Class clazz3=对象名.getClass();
注:上述clazz1 clazz2 clazz3对象都是同一个对象(因为读取的都是同一个类的相同的class文件)
(三)Class类的对象获取构造方法:
Class对象名.getConstructors():只能得public修饰的所有构造方法
Class对象名.getDelcaredConstructors():得到所有构造方法
Class对象名.getConstructors():只能得到public修饰的一个构造方法 Class对象名.getDelcaredConstructors():得到一个构造方法
(四)通过构造方法(有参或无参)可以创建其相对应的对象实例。
Object obj=构造方法对象名.newInstance();
(五)Class类的对象获取普通方法(同构造方法):
Class对象名.getMethods():只能得public修饰的所有方法
Class对象名.getDelcaredMethods():得到所有方法
Class对象名.getMethod():能得到public修饰的一个方法
Class对象名.getDeclaredMethod():得到一个方法
(六)Class类的对象获取属性(同构造方法),但一般实体类的属性都为私有变量,且多为一次取一个,故getDeclaredField(Field field)最为常用。
(七)以reflect包下的拥有姓名和年龄属性的Person实体类为例,
例1:
运行时(加载类文件的方式)创建Person对象
Class clazz=Class.forName("reflect.Person");//创建Class类对象
Constructor c=clazz.getConstructor();//创建无参构造变量
Object obj=c.newInstance();//用该无参构造变量创建Person对象实例
例2:
Class clazz=Class.forName("reflect.Person");//创建Class类对象
Constructor c=clazz.getConstructor(String.class,int.class);//创建有参构造对象
Object obj=c.newInstance("张三",20);
//用该有参构造对象创建Person对象实例
例3:
运行时(加载类文件的方式)通过无参构造创建Person对象并调用其display方法(公有无参方法),设定姓名属性name为”张三”(私有属性)
Class clazz=Class.forName("reflect.Person");//创建Class类对象
Constructor c=clazz.getConstructor();//创建无参构造对象
Object obj=c.newInstance();//用该无参构造对象创建Person对象实例
Method m=clazz.getMethod("display", null);//创建方法对象
m.invoke(obj);//执行方法
Field field=clazz.getDeclaredField("name");//创建私有变量对象
field.setAccessible(true);//私有变量设定取出或方法执行时需要得到权限,setAccessible(true);使其得到权限。
field.set(obj, "张三");//设定这个属性
(八)练习
1.写一个方法,此方法可将obj对象中名为propertyName的属性的值设置为value
class Person {
private String name;
private int age;
public Person() {
}
public Person(String name, int age) {
super();
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
@Override
public String toString() {
return "Person [name=" + name + ", age=" + age + "]";
}
}
public class ReflectTest {
public static void setProperty(Object obj, String propertyName, Object value) throws Exception{
Class clazz=obj.getClass();
Field fName=clazz.getDeclaredField(propertyName);
fName.setAccessible(true);
fName.set(obj, value);
}
public static void main(String[] args) throws Exception{
Person p=new Person();
setProperty(p, "name", "范冰冰");
setProperty(p, "age", 23);
System.out.println(p);
}
}
2.用键盘输入一个字符串,该字符串就是类的全名,使用反射机制创建该类的对象,并调用该对象中的方法showString
public class ReflectTest {
public static void main(String[] args) throws Exception{
System.out.println("请输入类的全名:");
Scanner input=new Scanner(System.in);
String s=input.next();
Class clazz=Class.forName(s);
Constructor c=clazz.getDeclaredConstructor();
Object obj=c.newInstance();
Method m=clazz.getDeclaredMethod("showString");
m.setAccessible(true);
m.invoke(obj);
}
}
3.(1)写一个config.properties命名的配置文件,内容为类的完整名称(reflect.Person),放置在src下
(src路径:E:\Users\Administrator\workspace\Learning\src)
(2) 写一个程序,读取这个Properties配置文件,获得类的完整名称并加载这个类
(3)用反射 的方式运行display方法
public class ReflectTest3 {
//读取并返回指定路径文件内容
public static String getFileProperties(String path) throws IOException{
FileInputStream fi=new FileInputStream(path);
int len;
StringBuffer sb=new StringBuffer();
while((len=fi.read())!=-1){
sb.append((char)len);
}
fi.close();
return sb.toString();
}
public static void main(String[] args) throws Exception {
String property=getFileProperties("E:\\Users\\Administrator\\workspace\\Learning\\src\\config.properties");//获取src下配置文件的完整内容(类的全名)
Class clazz=Class.forName(property);
Constructor c=clazz.getDeclaredConstructor();
Object obj=c.newInstance();
Method m=clazz.getDeclaredMethod("display");
m.setAccessible(true);
m.invoke(obj);
}
//IO流读取文件方法可参考以下链接:
【java基础】输入输出流及练习