反射
大家好呀!我是小笙!本节我和大家分享一下反射的基础知识!我们也将结束javaSe基础1.0版本的学习总结
反射
反射机制
什么是反射?
反射就是Reflection,Java的反射是指程序在运行期可以拿到一个对象的所有信息。这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制
反射就是把java类中的各种成分(成员变量,方法,构造器等等类的成员)映射成一个个的Java对象
反射的优缺点
优点:可以动态的创建和使用对象,使用灵活(框架底层核心)
缺点:使用反射基本是解释执行,对执行的效率有很大的影响
class类
Class类的实例表示java应用运行时的类或接口(每个java类运行时都在JVM里表现为一个class对象,可通过类名.class、类型.getClass()、Class.forName(“类名”)等方法获取class对象
// 总结
// 1.注意Class类和class关键字的区别
// 2.私有构造函数,只有 Java 虚拟机会创建 Class 对象
// 3.每个通过关键字class标识的类,在内存中有且只有一个与之对应的Class对象来描述其类型信息,无论创建多少个实例对象,其依据的都是用一个Class对象
public final class Class<T> implements java.io.Serializable,
GenericDeclaration,
Type,
AnnotatedElement,
TypeDescriptor.OfField<Class<?>>,
Constable {
private static final int ANNOTATION= 0x00002000;
private static final int ENUM = 0x00004000;
private static final int SYNTHETIC = 0x00001000;
private static final ClassDesc[] EMPTY_CLASS_DESC_ARRAY = new ClassDesc[0];
private static native void registerNatives();
static {
registerNatives();
}
/*
* Private constructor. Only the Java Virtual Machine creates Class objects.
* This constructor is not used and prevents the default constructor being
* generated.
* 私有构造函数,只有 Java 虚拟机会创建 Class 对象。不使用此构造函数并阻止生成默认构造函数。
*/
private Class(ClassLoader loader, Class<?> arrayComponentType) {
// Initialize final field for classLoader. The initialization value of non-null
// prevents future JIT optimizations from assuming this final field is null.
classLoader = loader;
componentType = arrayComponentType;
}
类加载阶段
// 代码示例
class Cat{
private String name;
public Cat(){}
public void hi(){}
}
类加载的生命周期
类加载的过程包括了加载
、验证
、准备
、解析
、初始化
五个阶段
注意:加载
、验证
、准备
、初始化
四个阶段的开始顺序是依次如此,但是在运行中会交叉运行程序(如:相互调用);解析阶段可能会出现在初始化之后(为了支持动态绑定)
类的加载示例(图片)
反射的使用
Class类的对象获取
- 根据类名:类名.class
- 根据对象:对象.getClass()
- 根据全限定类名:Class.forName(全限定类名)
public class Reflection01 {
public static void main(String[] args) throws ClassNotFoundException, IllegalAccessException, InstantiationException {
// 测试用例
// 1.forName()
// (1)获取Class对象的一个引用,但引用的类还没有加载(该类的第一个对象没有生成)就加载了这个类。
// (2)为了产生Class引用,forName()立即就进行了初始化。
System.out.println("forName: "+Class.forName("com.Al_tair.reflection.Cat")); // forName: class com.Al_tair.reflection.Cat
// 2.Object-getClass() 获取Class对象的一个引用,返回表示该对象的实际类型的Class引用。
System.out.println("getClass: "+new Cat().getClass()); // getClass: class com.Al_tair.reflection.Cat
// 3.getName() 取全限定的类名(包括包名),即类的完整名字。
System.out.println("getName: "+com.Al_tair.reflection.Cat.class); // getName: class com.Al_tair.reflection.Cat
// 4.getSimpleName() 获取类名(不包括包名)
System.out.println("getSimpleName: "+ new Cat().getClass().getSimpleName()); // getSimpleName: Cat
// 5.getCanonicalName() 获取全限定的类名(包括包名)
System.out.println("getCanonicalName: "+ new Cat().getClass().getCanonicalName()); // getCanonicalName: com.Al_tair.reflection.Cat
// 6.isInterface() 判断Class对象是否是表示一个接口
System.out.println("isInterface: "+ new Cat().getClass().isInterface()); // isInterface: false
System.out.println("isInterface: "+ Fly.class.isInterface()); // isInterface: true
// 7.getInterfaces() 返回Class对象数组,表示Class对象所引用的类所实现的所有接口。
for (Class list:new Cat().getClass().getInterfaces()){
System.out.println(list); // interface com.Al_tair.reflection.Fly
}
// 8.getSuperclass() 返回Class对象,表示Class对象所引用的类所继承的直接基类。应用该方法可在运行时发现一个对象完整的继承结构。
System.out.println("getSuperclass"+new Cat().getClass().getSuperclass()); // getSuperclassclass com.Al_tair.reflection.Animal
// 9. getFields() 获得某个类的所有的公共(public)的字段,包括继承自父类的所有公共字段。 类似的还有getMethods和getConstructors。
// getDeclaredFields 获得某个类的自己声明的字段,即包括public、private和proteced,默认但是不包括父类声明的任何字段
Cat cat = Cat.class.newInstance();
for (Field f: cat.getClass().getFields()) {
System.out.print(f.getName()+" "); // name color age
}
}
}
interface Fly{
}
class Animal{
public int age;
}
class Cat extends Animal implements Fly {
public String name = "";
public String color;
public Cat() {
}
public Cat(String name, String color, int age) {
this.name = name;
this.color = color;
this.age = age;
}
@Override
public String toString() {
return "cat{" +
"name='" + name + '\'' +
", color='" + color + '\'' +
", age=" + age +
'}';
}
}
Constructor类及其用法
Class类与Constructor相关的主要方法如下:
关于Constructor类本身一些常用方法如下(仅部分,其他可查API)
我在这里就不大篇幅的讲述Constructor类的大量方法,用代码举例一些常用方法如下
public class Constructor01 {
public static void main(String[] args) throws IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException {
Class cls = new Person().getClass();
Person p = (Person)cls.newInstance(); // 调用无参构造器
System.out.println(p); // User{age=18, name='lns'}
// 调用public修饰的有参构造器
Constructor con = cls.getConstructor(String.class);
Person p2 = (Person)con.newInstance("zlr");
System.out.println(p2); // User{age=18, name='zlr'}
// 调用非public修饰的有参构造器
Constructor decCon = cls.getDeclaredConstructor(int.class,String.class);
decCon.setAccessible(true); // 设置爆破,突破访问权限
Person p3 = (Person)decCon.newInstance(12,"zlr");
System.out.println(p3); // User{age=12, name='zlr'}
}
}
class Person {
private int age = 18;
private String name = "lns";
public Person() {
super();
}
public Person(String name) {
super();
this.name = name;
}
private Person(int age, String name) {
super();
this.age = age;
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "User{" +
"age=" + age +
", name='" + name + '\'' +
'}';
}
}
Field类及其用法
Class类与Field对象相关方法如下:
关于Field类还有其他常用的方法如下:
我在这里就不大篇幅的讲述Field类的大量方法,用代码举例一些常用方法如下
public class Field01 {
public static void main(String[] args) throws ClassNotFoundException, IllegalAccessException, InstantiationException, NoSuchFieldException {
Class<?> cls = Class.forName("com.Al_tair.reflection.Student");
Student s = (Student)cls.newInstance();
Field age = cls.getField("age");
// 设置age属性值(public修饰)
age.set(s,12);
System.out.println(s.toString()); // Student{age=12, name='lns'}
Field name = cls.getDeclaredField("name");
name.setAccessible(true); // 爆破私有属性
// 设置name属性(私有属性)
name.set(s,"zlr");
System.out.println(s.toString()); // Student{age=12, name='zlr'}
}
}
class Student {
public int age = 18;
private String name = "lns";
@Override
public String toString() {
return "Student{" +
"age=" + age +
", name='" + name + '\'' +
'}';
}
}
Method类及其用法
Class类获取Method对象相关的方法:
常用方法如下:
我在这里就不大篇幅的讲述Method类的大量方法,用代码举例一些常用方法如下
public class Method01 {
public static void main(String[] args) throws ClassNotFoundException, IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException {
// method.setAccessible(true) 私有方法爆破
// 访问: method.invoke(object,实参列表) 注意:静态方法的话object对象可以填写成null
Class<?> cls = Class.forName("com.Al_tair.reflection.car");
car c = (car)cls.newInstance();
System.out.println(c.toString()); // car{OilPer=0.6, name='玛莎拉蒂'}
// 获取的方法的名字和形参类型
Method name = cls.getMethod("setName", String.class);
// 传入形参(该方法是公有方法)
name.invoke(c, "红旗");
System.out.println(c.toString()); // car{OilPer=0.6, name='红旗'}
// getDeclaredMethod 可以是公有的方法也可以是私有的方法
Method addOil = cls.getDeclaredMethod("addOil", double.class);
// 私有方法爆破
addOil.setAccessible(true);
// 传入形参(该方法是公有方法)
addOil.invoke(c,1.0);
System.out.println(c.toString()); // car{OilPer=1.0, name='红旗'}
}
}
class car{
private double OilPer = 0.6; // 油量60%
private String name = "玛莎拉蒂";
private void addOil(double oilPer){
this.OilPer = oilPer;
}
public void setName(String name){
this.name = name;
}
@Override
public String toString() {
return "car{" +
"OilPer=" + OilPer +
", name='" + name + '\'' +
'}';
}
}
相关面试题
1. Java反射在实际项目中有哪些应用场景?
- 使用JDBC时,如果要创建数据库的连接,则需要先通过反射机制加载数据库的驱动程序;
- 多数框架都支持注解/XML配置,从配置中解析出来的类是字符串,需要利用反射机制实例化;
- 面向切面编程(AOP)的实现方案,是在程序运行时创建目标对象的代理类,这必须由反射机制来实现。