什么是反射
Java中提供的一套类库,通过这套类库
- 运行时动态获取类中的信息
- 运行时动态调用构造函数创建对象
- 运行时动态访问(调用)对象的方法和属性
这种运行期间动态获取类中的信息(属性,方法,包.注解(@Test)等),以及动态调用对象的方法和属性的功能称之为Java语言的>反射机制,通俗理解,在运行期间对类的内容进行操作
Class类
想要使用反射,就要获取到类中的所有信息(属性方法等)
在Java中有一个特殊的类类型叫做:Class
此类型的对象存储的是某个类中的信息
比如
Class clazz1=Class.forName("cn.tedu.Student");
clazz1是一个对象,此对象中存储的都是数据,这些数据都是Student中的属性和方法
属性:访问修饰符,类型,属性名
方法:访问修饰符,返回值类型,方法名(参数列表);
Class clazz2=Class.forName("cn.tedu.User");
clazz2是一个对象,对象中存储的是User类中的属性和方法
Class类是Java提供的,这个Class类可以表达一个类的信息(属性方法等类中的信息)
-
每个类加载后(方法区),系统都会为该类生成一个对应的Class类类型的对象
这个对象是存储在堆区中,通过该Class对象可以访问方法区中的类的信息 -
一旦获取了某个类Class类型的对象之后,程序员可以写程序调用Class对象中的API方法
获取该Class对象中的类的信息
如何获取Class类型的对象
- 对象.getClass();
比如:
User user=new User();
Class clazz1=user,getClass();
- 类名.class
比如:
User user=new User();
Class clazz1=User.Class();
- Class.forName(“包名.类名”);
比如
Class clazz=Class.forName("包名.类名");
此种情况分为两步
1. 加载类User ,进入方法区,创建Class类型的对象
2. 返回Class类型的对象
用以上的三种方式可以获取到Class类型的对象
User类:
public class User {
private String userName;
private String userPassword;
String userAddress;
protected int age;
public String desc;
public User(){}
public User(String userName, String userPassword, String userAddress, int age, String desc) {
this.userName = userName;
this.userPassword = userPassword;
this.userAddress = userAddress;
this.age = age;
this.desc = desc;
}
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
public String getUserPassword() {
return userPassword;
}
public void setUserPassword(String userPassword) {
this.userPassword = userPassword;
}
public String getUserAddress() {
return userAddress;
}
public void setUserAddress(String userAddress) {
this.userAddress = userAddress;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getDesc() {
return desc;
}
public void setDesc(String desc) {
this.desc = desc;
}
private float xxx(int a,float b){
return 0;
}
protected void yyy(String a,double b){
}
String zzz (String a, Date date){
return null;
}
}
测试类
public class TestReflectClass {
@Test
public void testMethod1(){
User user=new User();
user.setUserName("zhangsan");
user.setUserPassword("123");
System.out.println(user.getUserName()+" "+user.getUserPassword());
}
/**
* 反射的做法,首要要得到Class类型的对象
* 此对象,在类加载后自动有jvm创建,并把对象放在堆中
* 程序员只是通过api获取Class对象
*/
@Test
public void testMethod2() throws Exception{
//方式一
User user=new User();
Class clazz1=user.getClass();
//方式二
Class clazz2=User.class;
//方式三
Class clazz3=Class.forName("day20.jdk.reflect.User");
//输出hashCode,hashCode值一样,证明此Class的对象只有一个
System.out.println(clazz1);
System.out.println(clazz2);
System.out.println(clazz3);
System.out.println(ArrayList.class.hashCode());
}
@Test
public void testMethod3() throws Exception{
Class clazz=Class.forName("day20.jdk.reflect.User");
}
}
通过Class类型的对象获取如下:
- Filed类;代表的是成员变量,即属性
- Method类:代表的是方法
- Constructor类:代表的是构造函数
- Annotation类:代表的是注解
通过以上的类的api获取对应的信息
- 可以获取Filed中的信息,获取类的属性,属性的修饰符,属性的类型,属性的名称
- 可以获取Method中的信息,获取该类的方法,修饰符,返回值类型,方法名,参数列表
- 可以获取Constructor中的你想逆袭,获取类的构造函数,修饰符,构造函数的参数列表
- 可以获取Annotation中的信息,获取类的注解,注解的名称,朱恩杰的属性值
结论
在运行期间通过Class对象调用反射的api可以反射实例化对象
可以反射访问属性,和反射调用方法
总之编译期间能写的代码,用反射也能实现