Java反射01-反射机制和Class对象
反射机制介绍
是啥?
1在运行状态中,对于任意一个类都能够知道这个类所有的属性和方法
2对于任意一个对象,都能够调用它的任意一个方法
这种动态获取信息以及动态调用对象方法的功能就是Java 语言的反射机制。
怎么做到的?
把类的各个组成部分封装为对象(如把成员变量封装为Filed对象,成员方法封装为Method对象,构造方法封装为Constructor方法)
为了更深入的了解,我们先看下java类的加载过程。
1硬盘中的java源文件(xx.java)先编译为字节码文件(xx.class,还在硬盘中)。
2 类加载进内存:类加载器将class文件读入jvm的方法区(堆中),并创建一个java.lang.class对象,表示这个类的运行时元数据。
3 类中的所有属性又封装进 Field对象中,所有方法封装进 Method对象中,
所有构造方法封装进Constructor当中。
这样一个硬盘中的类文件,就读入了内存中,变成了某些特定的对象(Class,Field,Method),通过调用这些对象便能获取类的信息和调用类中的方法,后面会详细讲解如何调用这些对象。
有啥用?
1可以在程序运行中,操作反射生成的method,Filed,constructor对象,访问对象的属性,方法。
2 IDE开发工具的代码提示(对象或类后输入. 会自动提示其所有的方法和属性)
3生成动态代理,帮助我们创建框架。 比如spring框架的IOC容器,我们只在配置文件中提供类的信息,spring便可通过反射来动态创建bean对象。
Class对象
获取Class对象的三种方式
以下三种方式获取的Class对象是同一个对象,类的字节码文件(.class)在类的运行过程中只会被加载一次(内存堆中只有一个该类的class对象)
//创建一个类对应的Class对象的三种方式
//1类还未加载进内存时:通过Class类的forName方法把类加载进内存并生成Class对象
//多用于读取配置文件,加载类
Class<?> class01 = Class.forName("cn.yy.TestClassObject");
//2类已经加载,但是还没有创建实例对象:可以使用类的class属性获取class对象
//多用于调用方法时传递参数
Class<TestClassObject> class02 = TestClassObject.class;
//3类已经加载,且有实例对象:可通过实例对象的getClass方法来获取class对象
//多用于获取某个对象的字节码文件
TestClassObject testClassObject = new TestClassObject();
Class<? extends TestClassObject> class03 = testClassObject.getClass();
//经过比较三种方式获取的Class对象是同一个对象。
//可得出结论:类的字节码文件(.class)在类的运行过程中只会被加载一次(内存堆中只有一个该类的class对象)
System.out.println(class01 == class02);//true
System.out.println(class02 == class03);//true
//也可反向观察不同类对应的Class对象不同
Class<?> classReflection = Class.forName("cn.yy.Reflection01");
System.out.println(class01 == classReflection);//false
Class对象常用方法
(1)forName–根据类名返回类对象
Class<Game> gameClass = (Class<Game>) Class.forName("cn.yy.testClassObject.Game");
(2)getName()–获取类完整路径名
Class<Game> gameClass = (Class<Game>) Class.forName("cn.yy.testClassObject.Game");
String path = gameClass.getName();//获取类全路径名:cn.yy.testClassObject.Game
(3)cast()–类型转化
下面是几个测试的类,Game是游戏接口,ComputerGames 和MobileGames是Game的两个实现类。
public interface Game {
String Name = "game";
//展示游戏名
String printGameName();
//展示游戏类型
String GameType();
}
public class ComputerGames implements Game {
@Override
public String printGameName() {
return "I am Computer Games";
}
@Override
public String GameType() {
return "My Type is Computer Games";
}
}
public class MobileGames implements Game {
@Override
public String printGameName() {
return "I am Mobile Games";
}
@Override
public String GameType() {
return "My Type is Mobile Games";
}
}
下面是cast方法测试
//cast方法:(强制)类型转化
//获取Game类的Class对象
Class<Game> gameClass = (Class<Game>) Class.forName("cn.yy.testClassObject.Game");
MobileGames mobileGames = new MobileGames();
//调用cast方法,将mobileGames转为了Game类型
Game cast = gameClass.cast(mobileGames); //类型转化成功
//若被转化对象不是Game的子类,则报错
Car car = new Car();
Game cast1 = gameClass.cast(car); //因为car不是Game的实现类,所以报错:
//java.lang.ClassCastException: Cannot cast cn.yy.testClassObject.Car to cn.yy.testClassObject.Game
可以看下cast的源码:先调用isInstance判断能否被强制转换
public T cast(Object obj) {
if (obj != null && !isInstance(obj))
throw new ClassCastException(cannotCastMsg(obj));
return (T) obj;
}
class.inInstance(obj)情况分析:
1一个对象是本身类的一个对象
2.一个对象能被转化为本身类所继承类(父类的父类等)和实现的接口(接口的父接口)强转
3.所有对象都能被Object的强转
4.凡是null有关的都是false class.inInstance(null)
(4)获取Field 属性对象
1 Declared的暴力获取所有Field,Method或者Constructor,无视权限修饰符
2 结尾带s的获取所有Field,Method或者Constructor,返回结果是数组。
3 结尾不带s的根据名称获取Field,Method,根据参数类型获取Constructor,返回结果是一个Field/Method/Constructor对象
测试类
public class Car {
//四种不同权限修饰符的属性
public String publicProperty="publicProperty";
protected String protectedProperty="protectedProperty";
String defaultProperty="defaultProperty";
private String privateProperty="privateProperty";
//四种不同权限修饰符的方法
public void showPublicMethod(){
System.out.println("This is a Public Method");
}
protected void showProtectedMethod(){
System.out.println("This is a Protected Method");
}
void showDefaultMethod(){
System.out.println("This is a Default Method");
}
private void showPrivateMethod(){
System.out.println("This is a Private Method");
}
}
方法代码
Class<Car> carClass = (Class<Car>) Class.forName("cn.yy.testClassObject.Car");
//获取car类中所有权限修饰符为public的属性对应的Field对象
Field[] fields = carClass.getFields();
//获取car类中所有权限修饰符的属性对应的Field对象
Field[] declaredFields = carClass.getDeclaredFields();
//获取car类中指定名称的属性对应的Field对象
Field declaredField = carClass.getDeclaredField("protectedProperty");
Debug结果,可以看到declaredFields可以获取所有属性
(5)获取Method对象
1 Declared的暴力获取所有Field,Method或者Constructor,无视权限修饰符
2 结尾带s的获取所有Field,Method或者Constructor,返回结果是数组。
3 结尾不带s的根据名称获取Field,Method,根据参数类型获取Constructor,返回结果是一个Field/Method/Constructor对象
Class<Car> carClass = (Class<Car>) Class.forName("cn.yy.testClassObject.Car");
//根据方法名获取Method对象
Method showDefaultMethod = carClass.getMethod("showPublicMethod");
//获取car类中所有public的方法对应的Method对象
Method[] methods = carClass.getMethods();
//获取car获取car类中所有方法对应的Method对象
Method[] declaredMethods = carClass.getDeclaredMethods();
可以看到,getMethods(),方法除了获取car类本身的public方法,还获取了继承自Object类的方法。
(6)获取Constructor对象
测试代码
Class<Car> carClass = (Class<Car>) Class.forName("cn.yy.testClassObject.Car");
Constructor<?>[] constructors = carClass.getConstructors();
Constructor<?>[] declaredConstructors = carClass.getDeclaredConstructors();
//因为构造函数时重载的,名称一样,因此通过参数类型 来获取指定的Constructor对象
Constructor<Car> stringParameterConstructor = carClass.getDeclaredConstructor(String.class);
Field,Method和Constructor对象会在反射的后续文章中介绍。
![aa](https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1595917045997&di=5e84ceab98c2ae21074ca736894e8bf3&imgtype=0&src=http%3A%2F%2Fm.cqwanqu.com%2Fupfiles%2Fimage%2F20190402%2F20190402145929_5355.jpg)
Java萌新,如有错误,请指正
创作不易,对您有帮助的话,劳烦您点赞支持啦~~