java的反射是属于javase的部分,但是建议是在对javaweb学习的时候再学习一下反射。
反射也可以叫做反射机制。是一种机制,只要获得类的Class对象,它就可以动态的获得这个类里面的信息,获取到后就可以创建对象,就可以对这个对象中的属性和方法进行调用
反射
在之前的时候,我们是如何创建使用对象的?
1、设计类(这种就是在哪用就在那new出一个对象来用)
类只是一个感念,里面会定义一些抽象的属性
在用的时候我们就要new一个构造方法(构造方法的名字是和类的名字一样的)
2、IO的反序列化
将对象通过输出流输出到一个文件当中,再把文件中的信息读入进来,于是在内存中就还原出现了一个对象。
3、加载MySQL的驱动时,本质上就是创建出了一个Driver类的这么一个对象
Class.forName(com.mysql.cj.jdbc.Driver);
4、在javaweb中将servlet配置到web.xml文件Tomcar启动时,就会读取配置,然后就会创建出了一个servlet对象(这其实就是反射机制)。
<sevlet-class>com.demo.demoweb.servlet.DemoServlet</servlet-class>
但是现在就是有了一个实际问题,如果我们事先还没有这么一个类,但是现在就要体现调用出这么一个类的对象存在(就比如上面的web和MySQL配置,在服务器运行的时候就会对这个配置的信息进行读取,根据这个类的地址,去反向找到类的字节码文件的地址,然后动态的去创建类的对象)
什么是反射?
反射就是在仅仅知道一个类的类名,动态的得到类的定义信息,包括这个得到类的方法和属性。
Java反射的感念
java反射机制就是在运行的状态中,对于任意一个类,仅仅在只通过类的地址就能够知道这个类的所有属性和方法;
还可以通过此类的对象,能够调用它的任意一个方法和属性;
这种动态获取信息以及动态调用对象的方法的功能我们就称为java的反射机制。
反射的厉害之处就在于,只用写一套代码,就可以获得任意类的信息,并为其创建出对象。
java反射的作用
动态获取类的信息,进一步实现需要的功能。
怎么实现反射机制?
java反射的相关API
java反射相关的类主要就是包括以下这四个类:
● Class 类型
● Constructor 构造方法
● Method 方法
● Field 属性
▲ 除了Class外,其他的类都是位于java.long.reflect包中
就由此可以看出,从反射的API不难看出,是将类的类型,方法,属性都封装成了类,其中最重要的类就是Class类,可以说,一切的反射都是从Class开始的。
在API中主要有以下几点:
1、获得构造方法。
2、获得属性。
3、获得父类、接口。
4、获得注解标签。
Class类
Class类的类表示正在运行的Java应用程序中的类和接口。 枚举是一种类,一个注释是一种界面。 每个数组也属于一个反映为类对象的类,该对象由具有相同元素类型和维数的所有数组共享。 原始Java类型( boolean , byte , char , short , int , long , float和double ),和关键字void也表示为类对象。
——来自jdk1.8的api(机译)
可以理解为Class类的对象表示正在运行的Java应用程序中的类和接口
一旦Class文件被加载到内存中,就会为其创建一个Class对象,任何类被使用的时候都会创建一个Class对象的。
Class类是Java反射机制的基础,通过Class类,可以得到一个类的基本信息。
如何获得一个类的Class对象?
获得方式有三种:
1、类名.class
2、对象名.getClass()
3、Class.forName(“类的地址”)(这里也发生了类加载)
package com.demo.reflect;
public class Car {
public String name;
private String color;
public Car() {
System.out.println("这是一个无参构造");
}
public Car(String name, String color) {
System.out.println("这是一个有参构造");
this.name = name;
this.color = color;
}
public void run() {
System.out.println("车能跑");
}
public void run(int speed) {
System.out.println("车跑的速度是" + speed);
}
}
package com.demo.reflect;
public class Test1 {
public static void main(String[] args) {
//反射机制是在运行时获得类的信息,并创建出对象
//前提是要获得类对应的Class对象。
//获得方式一:
Class car1 = Car.class;
System.out.println(car1);
System.out.println("-------------------");
//方式二: public final native(调用的是本地方法 C++) Class<?> getClass();
Class car2 = new Car().getClass();//getClass指的是Car对象对应的Class类的对象
System.out.println(car2);
System.out.println(car1 == car2);//true 获得的是同一个类的Class对象
System.out.println("-------------------");
//方式三: 经常使用的
String classpath = "com.demo.reflect.Car";
try {
Class car3 = Class.forName(classpath);//根据类的地址将类信息加载到内存中,并创建类的Class对象
//需要抛出一个异常
System.out.println(car3);
} catch (ClassNotFoundException e) { //类找不到异常
e.printStackTrace();
}
}
}
方式三是一种动态获取的方式,所以在动态的创建一个此类的对象
package com.demo.reflect;
public class Test1 {
public static void main(String[] args) {
//反射机制是在运行时获得类的信息,并创建出对象
//前提是要获得类对应的Class对象。
//方式三: 动态获取,动态操作
String classpath = "com.demo.reflect.Car";
try {
Class car3 = Class.forName(classpath);//根据类的地址将类信息加载到内存中,并创建类的Class对象
//需要抛出一个异常
System.out.println(car3);
try {
//反射创建对象的方式一:
Car t = (Car) car3.newInstance();//表示此类对象 表示的类的 新实例 采用了一个向下转型的模式
// 就是由Class car3表示的com.demo.reflect.Car这个类的对象
} catch (InstantiationException e) {//实例化异常
e.printStackTrace();
} catch (IllegalAccessException e) {//非法访问就是类型不匹配异常
e.printStackTrace();
}
} catch (ClassNotFoundException e) { //类找不到异常
e.printStackTrace();
}
}
}
● 一旦class文件被加载到内存中,就会为其创建一个Class对象。任何类被使用时都会创建一个Class的对象。
● Class类是Java反射机制的基础,通过Class类,可以得到一个类的基本信息。
Constructor类(创建构造方法)
Constructor提供了一个类的单个构造函数的信息和访问。Constructor允许在将实际参数与newInstance()与底层构造函数的形式参数进行匹配时进行扩展转换,但如果发生缩小转换,则抛出IllegalArgumentException 。
——来自jdk1.8的api(机译)
Constructor类的对象表示一个构造方法信息
Constructor类是可以通过getXXX的方法获得构造方法的基本信息。(构造方法是可以初始化我们的一个对象)
例如:
● getName:返回构造方法的名字
除了获得构造方法的基本信息,还可以创建实例
● newInstance(Object…initargs):创建一个实例
如何获得Constructor类的实例?
● Constructor实例通过Class实例获得,Class类中定义 了如下方法:
Constructor getConstructor(Class… parameterTypes) :通过指定参数类型,返回构造方法实例。
创建对象 constructor.newInstance(“zhangsan", 20);
● getConstructor()获得指定的公共构造方法
● getDeclaredConstructor()获得任意(包含私有的)指定的构造方法
● getConstructors() 返回所有公共的构造方法,返回值是数组
● getDeclaredConstructors() 获得所有的构造方法,返回值是数组
package com.demo.reflect;
public class Car {
public String name;
private String color;
private int price;
public Car() {
System.out.println("这是一个无参构造");
}
public Car(String name, String color) {
System.out.println("这是一个String,String的公共的有参构造");
this.name = name;
this.color = color;
}
private Car(String name, int price) {
System.out.println("这是一个String,int的私有的有参构造");
this.name = name;
this.price = price;
}
public void run() {
System.out.println("车能跑");
}
public void run(int speed) {
System.out.println("车跑的速度是" + speed);
}
@Override
public String toString() {
return "Car{" +
"name='" + name + '\'' +
", color='" + color + '\'' +
", price=" + price +
'}';
}
}
package com.demo.reflect;
import java.lang.annotation.Annotation;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
public class Test1 {
public static void main(String[] args) throws ClassNotFoundException, IllegalAccessException, InstantiationException, InvocationTargetException {
String classpath = "com.demo.reflect.Car";
Class aClass = Class.forName(classpath);//根据类的地址将类信息加载到内存中,并创建类的Class对象
System.out.println(aClass);
System.out.println("---------------------------");
//反射创建对象的方式一:
Car car = (Car) aClass.newInstance();//表示此类对象 表示的类的 新实例 采用了一个向下转型的模式
// 就是由Class car3表示的com.demo.reflect.Car这个类的对象
System.out.println(car);
System.out.println("---------------------------");
//获得类的构造方法信息
try {
//反射创建对象的方式二:
//getConstructor()获得指定的公共构造方法,需要传参的时候,传递的是参数的类型,只是意为拿到的意思
Constructor constructor = aClass.getConstructor();//获得无参的构造方法
// 就是将无参的构造方法信息封装到一个Construct的对象中去
Car car1 = (Car) constructor.newInstance();
//通过Constructor类中的newInstance()创建对应类的对象
System.out.println(car1);
System.out.println("---------------------------");
Constructor constructor1 = aClass.getConstructor(String.class, String.class);
//获得有参的构造方法,它里面传的也应该是参数的class的对象
Car car2 = (Car) constructor1.newInstance("五菱", "五彩斑斓");
//这里创建对象时,必须写入参数,不然它意为调用的是一个无参的构造方法,会报错的
// 且它获得不了私有的构造方法
System.out.println(car2);
System.out.println("---------------------------");
//反射创建对象的方式三:
//getDeclaredConstructor()获得任意(包含私有的)指定的构造方法
Constructor constructor2 = aClass.getDeclaredConstructor(String.class, int.class);
constructor2.setAccessible(true);//手动设置可以允许操作私有权限,不设置的话会报错不能创建私有的构造方法
Car car3 = (Car) constructor2.newInstance("五菱", 20000);
System.out.println(car3);
System.out.println("---------------------------");
//反射创建对象的方式四:
//getConstructors() 返回所有公共的构造方法,返回值是数组
Constructor[] constructors = aClass.getConstructors();//返回所有公共的构造方法,返回值是数组
//反射创建对象的方式四:
//getDeclaredConstructors() 获得所有的构造方法,返回值是数组
Constructor[] declaredConstructors = aClass.getDeclaredConstructors();
for (Constructor con : declaredConstructors) {
System.out.println(con.getName());
System.out.println(con.getParameterCount());//获得构造方法传入的参数数量
System.out.println("--------------");
}
System.out.println("---------------------------");
} catch (NoSuchMethodException e) {
e.printStackTrace();
/*没有这种方法例外,异常意思就是说,可能没有这个构造方法
* 为什么会没有呢?有一点就是在创建了一个有参的构造方法,那么无参的构造方法就没有了
* 所以一般情况下,当我们在写有有参的构造方法时,会将无参的构造方法再次书写一遍*/
}
}
}
Field 属性
Field类是将类的属性进行封装,可以获得属性的基本信息、属性的值,也可以对属性进行赋值。
● getName:返回属性的名字
● Set:设置属性值
获得Field实例
想要获得Field实例,都是通过Class中的方法实现
● public Field getField(String name)
● 通过指定Field名字,返回Field实例
● 注意Field的访问权限
package com.demo.reflect;
public class Car {
public String name;
private String color;
private int price;
public Car() {
System.out.println("这是一个无参构造");
}
@Override
public String toString() {
return "Car{" +
"name='" + name + '\'' +
", color='" + color + '\'' +
", price=" + price +
'}';
}
}
package com.demo.reflect;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
public class Test {
public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException, NoSuchFieldException {
Class<?> aClass = Class.forName("com.demo.reflect.Car");
Constructor<?> constructor = aClass.getConstructor();
Object o = constructor.newInstance();//创建出一个对象来
Field name = aClass.getField("name");
//拿到类中name的这个属性,封装到Field name的这个对象中
name.set(o, "五菱");//给Car这个类中的name属性赋一个值
Field[] fields = aClass.getFields();
//拿到类中name的所有(公共)的属性,封装到Field name的这个对象中
Field[] declaredFields = aClass.getDeclaredFields();
//拿到类中name的所有的属性,封装到Field name的这个对象中
for (Field field : declaredFields) {
field.setAccessible(true);//设置为true就可以设置私有可操作性
if (field.getName().equals("name")) {//这里的name就相当于数据库当中的列名
field.set(o, "极狐");//拿到了属性,给set到所选择对应的属性中去
}
if (field.getName().equals("color")) {
field.set(o, "银色");
}
if (field.getName().equals("price")) {
field.set(o, 12300);
}
}
System.out.println(o);
}
}
Method 方法
Method类将类中的方法进行封装,可以动态获得方法的信息。
例如:
● getName:获得方法名字
● getParameterTypes:获得方法参数类型
除了动态获得方法信息外,Method还能动态调用某一个对象的 具体方法
● invoke(Object obj, Object… args) :使用obj调用该方法,参数为args
如何获得Method实例?
Method实例都是通过Class类的方法获得
● Method getMethod(String name, Class… parameterTypes) :通过指定方法名,参数类型,返回一个 Method实例
package com.demo.reflect;
public class Car {
public String name;
private String color;
private int price;
public Car() {
System.out.println("这是一个无参构造");
}
public void run() {
System.out.println("车能跑");
}
public void run(int speed) {
System.out.println("车跑的速度是" + speed);
}
public String getName() {
System.out.println("这是属性值的get方法(getName方法)");
return name;
}
public void setName(String name) {
this.name = name;
}
public String getColor() {
System.out.println("这是属性值的get方法(getColor方法)");
;
return color;
}
public void setColor(String color) {
this.color = color;
}
public int getPrice() {
System.out.println("这是属性值的get方法(getPrice方法)");
;
return price;
}
public void setPrice(int price) {
this.price = price;
}
}
package com.demo.reflect;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
public class Test {
public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException, NoSuchFieldException {
Class<?> aClass = Class.forName("com.demo.reflect.Car");
//Constructor<?> constructor = aClass.getConstructor();
Object o = aClass.newInstance();//创建出一个对象来
Method met = aClass.getMethod("run");//这里获得找到的是一个无参的成员方法
met.invoke(o); //调用方法
//方法都是成员方法,是属于对象的,所以在调用方法时,都需要绑定在Class对象上
System.out.println("-----------------------------");
Method met1 = aClass.getMethod("run", int.class);
//这里获得的是一个有参的成员方法,要注明参数的类型,且类型也是要拿到对应的class对象中的
met1.invoke(o, 80);
System.out.println("-----------------------------");
Field[] fields = aClass.getDeclaredFields();//获得到类中的所有属性
for (Field field : fields) {
Method method = aClass.getMethod("get" + field.getName().substring(0, 1).toUpperCase() + field.getName().substring(1));
//field.getName().substring(0,1).toUpperCase()获得name中的第一个字母,并将其大写,
// 就这样通过知道属性名,就能拼成了一个私有属性获得数据的方法名,所以起名也是应该注意的一个东西
method.invoke(o);
System.out.println("------------");
}
System.out.println("-----------------------------");
}
}
反射机制多用于框架部分,框架为我们封装好,我们只需要写我们的业务代码,就产生看许多的类,框架就是通过反射来对我们创建的类进行管理