一、反射
1.类型信息
Java让我们在运行时识别类和对象的信息,主要有两种方式:一种是传统的RTTI(Run-Time Type Identification),它假定我们在编译期已经知道了所有的类型信息;另一种是反射机制,它允许我们在运行时发现和使用类的信息,使用的前提条件是:必须先得到类的字节码的Class,Class类用于表示.class文件,也就是字节码文件
2.反射概述
Java反射机制是指,在运行状态中,能够知道这个类所有的属性和方法。对于任意一个对象,都能够调用它的任意一个属性和方法,这种动态获取的信息以及动态调用对象的方法的功能叫做Java的反射机制
反射就是把类中的各个成分映射成一个个的对象
3. .class文件的唯一性
拿Student类举例
当我们第一次创建Student类的对象时,JVM会将Student类的字节码文件(Student.class)加载进内存,然后在堆内存开辟空间。
当我们想再次创建Student对象时,JVM会先去内存中寻找是否有Student类的字节码文件(Student.class),如果有,就不会再去加载Student类的字节码文件(Student.class),直接使用。这说明,每个类的字节码文件(.class)再内存的存在都是唯一的。
在一个万物皆对象的Java世界中,我们同样也可以获得类的.class文件的对象,然后通过这个对象去创建对象,这样就可以不通过new创建某个类的对象了
4.与反射有关的类
类名 | 用途 |
---|---|
Class | 代表类的实体,在运行的Java应用程序中表示类和接口 |
Filed | 代表类的成员变量 |
Method | 代表类的方法 |
Constructor | 代表类的构造方法 |
5.获得Class对象的方法
注意:是获得Class对象的方式,不是创建某类对象的方式
以Person类为例
Person person = new Person ();
方式一:
Class class1 = person.getClass();
方式二: 我们一般以这种方式创建Class对象
Class class2 = Class.forName("包名.Person ");
方式三:
Class class3 = Person .class;
方式四:该方法只针对于包装类
Class type = Integer.TYPE;
6.有关Class类的方法
方法 | 用途 |
---|---|
getName() | 获得类的完整路径名字:包名 + 类名 |
getSimpleName() | 获取类名 |
newInstance() | 创建某类对象 |
7.有关Filed类的方法
方法 | 用途 |
---|---|
getFields() | 获得全部public的属性,存在Field[ ]数组中 |
getDeclaredFields() | 获得全部的属性,包括私有,存在Field[ ]数组中 |
getField() | 获得指定public的属性对象,返回的是Field对象 |
getDeclaredField() | 获取指定的属性,包括私有,返回的是Field对象 |
8.有关Method类的方法
方法 | 用途 |
---|---|
getMethods() | 获得当前类和它继承的类的public方法,不包括该类的构造方法 |
getDeclaredMethods() | 获得当前类的所有方法,包括私有,不包括该类的构造方法 |
getMethod(String name, Class…<?> parameterTypes) | 获得该类某个public方法,不包括该类的构造方法 |
getDeclaredMethod(String name, Class…<?> parameterTypes) | 获得该类某个方法,包括私有,不包括该类的构造方法 |
9.有关Constructor类的方法
方法 | 用途 |
---|---|
getConstructors() | 获得该类的所有public构造方法 |
getDeclaredConstructors() | 获得该类所有构造方法,包括私有 |
getConstructor(Class…<?> parameterTypes) | 获得该类中与参数类型匹配的public构造方法 |
getDeclaredConstructor(Class…<?> parameterTypes) | 获得该类中与参数类型匹配的构造方法,包括私有 |
二、反射代码
package czx.xupt.annotation; //注意包名 后面会用到
public class User1 {
private String name;
private int age;
public User1() {
}
public User1(String name, int age) {
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 "User1{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
public class Demo1_Test {
public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
//user 的 Class 对象
Class class1 = Class.forName("czx.xupt.annotation.User1");
System.out.println("===========================================");
System.out.println(class1.getName()); //全类名 包名 + 类名
System.out.println(class1.getSimpleName()); //类名
//获得字段
System.out.println("===========================================");
Field[] fields = class1.getFields(); //只能获得public的属性
System.out.println(fields.length);
Field[] fields2 = class1.getDeclaredFields(); //返回全部的属性,可以获得私有的
System.out.println(fields2.length);
for (Field field : fields2) {
System.out.println("field:\t"+field);
}
Field name = class1.getDeclaredField("name"); //获取指定的字段
System.out.println(name);
//获得方法 : 执行 invoke
System.out.println("===========================================");
Method[] methods = class1.getMethods(); //返回当前类和被继承的类的public方法
System.out.println(methods.length);
for (Method method : methods) {
System.out.println("methods: "+method);
}
Method[] declaredMethods = class1.getDeclaredMethods(); //获得当前类的所有方法
System.out.println(declaredMethods.length);
for (Method method : declaredMethods) {
System.out.println("declaredMethods: "+method);
}
System.out.println("=========================================");
//如果只获得方法的名字就会有问题: 方法有重载(参数类型)
Method setName = class1.getMethod("setName",String.class);
Method setAge = class1.getMethod("setAge",int.class);
System.out.println(setName);
System.out.println(setAge);
//获得构造器 : 创建对象 newInstance()
System.out.println("===========================================");
//获得所有public的构造器
Constructor[] constructors = class1.getConstructors();
System.out.println(constructors.length);
for (Constructor constructor : constructors) {
System.out.println(constructor);
}
//获得所有的构造器
Constructor[] constructors2 = class1.getDeclaredConstructors();
System.out.println(constructors2.length);
for (Constructor constructor : constructors2) {
System.out.println(constructor);
}
System.out.println("========================================");
//获得指定的构造器: 重载,只能通过参数名判断 null
Constructor constructor = class1.getConstructor(null);
Constructor constructor2 = class1.getConstructor(String.class,int.class);
System.out.println(constructor);
System.out.println(constructor2);
}
}
public class Demo2_Test {
public static void main(String[] args) throws Exception {
Class c1 = Class.forName("czx.xupt.annotation.User1");
//创建对象,new
System.out.println("==========================================");
User1 user1 = (User1) c1.newInstance(); //创建对象
System.out.println(user1); //默认调用的是无参构造器
System.out.println("==========================================");
//通过指定构造器创建对象!
Constructor declaredConstructor = c1.getDeclaredConstructor(String.class, int.class );
User1 user2 = (User1) declaredConstructor.newInstance("czx", 23 );
System.out.println(user2);
System.out.println("==========================================");
User1 user3 = (User1) c1.newInstance();
//1. 获得你要操作的方法
Method setName = c1.getDeclaredMethod("setName", String.class);
//2. 通过invoke方法执行方法
//一个class可能存在多个对象, 这个方法需要找到是那个对象使用的,给他赋值;
setName.invoke(user3,"czx1");
System.out.println(user3.getName());
//获得字段
System.out.println("==========================================");
User1 user4 = (User1) c1.newInstance();
Field name = c1.getDeclaredField("name"); //反射无法直接破坏私有的
//显示调用setAccessible为true,则可以访问private方法!
name.setAccessible(true);
name.set(user4,"czx2");
System.out.println(user4.getName());
}
}