1、反射的两个作用
A、获取类的信息
B、动态调用对象成员
2、类加载到内存后,JVM会为该类创建一个Class对象,用于保存类中的信息:
- 所在的包
- 父类
- 接口
- 成员变量
- 成员方法
- 构造方法
通过反射,可以读取类中的全部信息(除了方法体)
3、Class c = Class.forName() : 将类加载到内存,但是不实例化
如果要实现化,调用c.newInstance()来完成实例化工作
创建对象的两种方法:
方法一:
String s = new String("韬睿"); //将String类加载到内存,然后实例化
方法二:
Class c = Class.forName("java.lang.String");
Object s = c.newInstance();
4、案例:Java中创建对象的几种方法
public class Student implements Cloneable{
private int sid;
private String name;
public Student() {
System.out.println("构造方法");
}
public Student(int sid, String name) {
super();
this.sid = sid;
this.name = name;
System.out.println("构造方法");
}
@Override
public String toString() {
return "Student [sid=" + sid + ", name=" + name + "]";
}
@Override
public Object clone() throws CloneNotSupportedException {
return super.clone();
}
}
public class ObjectDemo {
public static void main(String[] args) throws Exception {
//通过new关键字
Student s1 = new Student(1, "张三");
System.out.println(s1);
//通过反射
Class c = Class.forName("com.tr.ref.Student");
Object s2 = c.newInstance();
System.out.println(s2);
//采用克隆技术
Object s3 = s1.clone();
System.out.println(s3);
System.out.println(s1 == s3);
}
}
5、获得Class对象的几种方法
A、通过字符串
Class c = Class.forName("java.lang.String");
B、通过类的class属性
Class c = Date.class;
C、通过对象的getClass()方法
Class c = new Date().getClass();
D、基本类型
Class c = int.class;
6、通过Class可以获取其他数据
所在的包
Package pck = c.getPackage();
父类
Class superClass = c.getSuperClass();
接口
Class[] interfaces = c.getInterfaces();
成员变量
Field[] fields = c.getFields();//public
Field[] fields = c.getDeclaredFields();//all
成员方法
Method[] methods = c.getMethods();//public、父类
Method[] methods = c.getDeclaredMethods();//all
构造方法
Constructor[] cons = c.getConstructors();
7、反射提供了一种操作对象成员的另一种方式
8、通过反射访问对象的成员变量
A、获得成员变量Field对象
Field f = c.getDeclaredField("name");
B、Field的set()方法用于给成员变量赋值
C、Field的get()方法用于获取成员变量的值
此方法的作用等同于:
Student s = new Student(); //创建对象
s.name = "张三";//给属性赋值
String name = s.name;//取出属性的值
完成属性的访问操作需要对象、属性名和属性值
反射实现:
Class c = Class.forName("com.tr.ref.Student");//加载类
Object stu = c.newInstance();//创建对象
Field name = c.getField("name");
name.set(stu, "张三");
Object n= name.get(stu);
使用反射可以增强程序的可配置性和扩展性
9、通过反射访问对象的成员方法
A、获取Method对象
Method method = c.getDeclaredMethod("方法名", A.class, B.class);
比如:
Method play = c.getDeclaredMethod("play", int.class, int.class, String.class);
B、通过Method.invoke(Object obj, 参数值列表)来调用方法
play.invoke(stu, 1, 2, "小猫");
传统做法:
Student stu = new Student();
stu.play(1, 2, "小猫");
反射做法:
Class c = Class.forName("com.tr.ref.Student");//加载类
Object stu = c.newInstance();//创建对象
//获得方法对象
Method play = c.getDeclaredMethod("play", int.class, int.class, String.class);
//调用方法
play.invoke(stu, 1, 2, "小猫");
10、练习
定义一个员工类,有姓名和出生日期两个属性,有上班的方法(参数为小时)
public class Employee{
public String name;
public Date birthday;
public void doWork(int hour){
Sysout.out.println("工作了" + hour + "小时";
}
}
请使用反射完成下面的功能:
A)给员工对象的name和birthday属性赋值并打印出来
B)调用doWork方法