创建一个Person类
package com.qianfeng.test;
public class Person {
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Person() {
super();
}
public Person(String name) {
super();
this.name = name;
}
@Override
public String toString() {
return "Person [name=" + name + "]";
}
//非静态无参
public void play(){
System.out.println("play");
}
//非静态有参
public void run(String number){
System.out.println("run:"+number);
}
//静态有参
public static void show(String apple,int age){
System.out.println("show:"+apple+" age:"+age);
}
}
获取字节码文件对象的3种方式
package com.qianfeng.test;
/*
* 反射:动态的获取类的字节码文件对象,并对其成员进行抽象。
*
* 想做的:就是通过字节码文件将对象直接创建普通的对象。
*
* 1.获取字节码文件对象
* 2.>通过字节码文件对象获取具体的实例对象
* >获取具体的构造方法(通过从构造方法中抽象出来的类Constructor)
* 3.获取具体的属性并给属性赋值(通过从属性中抽象出来的类Field实现)
* 4.获取具体的方法,并调用方法(通过从方法中抽象出来的类Method实现)
*
*
* 首先:1.获取字节码文件对象
* a:通过Object提供的getClass方法得到字节码文件对象
* 缺点:首先要有一个对象 XXXXX
* b:每种数据类型都有一个class属性,通过他也可以获取当前的字节码文件对象
* 缺点:首先要知道这个类的名字 XXXX
* c:Class提供的方法forName(字符串) 字符串的构成:包名+类名
* 优点:只需要提供一个当前类的字符串形式
*
* 注意:字符串表示的类在工作的时候必须保证对应的是一个真正的类,否则报异常ClassNotFoundException
*
*/
public class Demo1 {
public static void main(String[] args) throws Exception{
// * a:通过Object提供的getClass方法得到字节码文件对象
fun1();
// * b:每种数据类型都有一个class属性,通过他也可以获取当前的字节码文件对象
fun2();
// * c:Class提供的方法forName(字符串) 字符串的构成:包名+类名
fun3();
}
// * a:通过Object提供的getClass方法得到字节码文件对象
public static void fun1(){
Person person = new Person("bingbing");
Class class1 = person.getClass();
Person person1 = new Person("bingbing");
Class class2 = person.getClass();
System.out.println(class1 == class2);//说明一个类只对应一个字节码文件对象
}
// * b:每种数据类型都有一个class属性,通过他也可以获取当前的字节码文件对象
public static void fun2(){
Class class1 = Person.class;
System.out.println(class1);
}
// * c:Class提供的方法forName(字符串) 字符串的构成:包名+类名
public static void fun3() throws ClassNotFoundException{
Class class1 = Class.forName("com.qianfeng.test.Person");
System.out.println(class1);
}
}
获取具体的实例对象和构造方法
package com.qianfeng.test;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
/*
* 2.>通过字节码文件对象获取具体的实例对象
* >获取具体的构造方法(通过从构造方法中抽象出来的类Constructor)
*/
public class Demo2 {
public static void main(String[] args) throws ClassNotFoundException, InstantiationException, IllegalAccessException, NoSuchMethodException, SecurityException, IllegalArgumentException, InvocationTargetException {
//通过普通的方式创建对象
Person person = new Person("bingbing");
//通过反射--绕过new
Class class1 = Class.forName("com.qianfeng.test.Person");
//通过无参的构造方法
fun1(class1);
//通过有参的构造方法
fun2(class1);
}
//通过无参的构造方法
public static void fun1(Class class1) throws InstantiationException, IllegalAccessException{
//创建实例对象
//相当于在newInstance方法的内部调用了无参的构造方法
Object person = class1.newInstance();
//向下转型
Person person2 = (Person)person;
person2.setName("bingbing");
System.out.println(person2.getName());
}
//通过有参的构造方法
public static void fun2(Class class1) throws NoSuchMethodException, SecurityException, InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException{
//这里的参数是实际的构造方法的参数字节码文件对象
Constructor constructor = class1.getConstructor(String.class);
//调用方法
Object person = constructor.newInstance("bingbing");//给定的实际参数
System.out.println(person);
}
}
获取具体的属性并赋值
package com.qianfeng.test;
import java.lang.reflect.Field;
/*
* 3.获取具体的属性并给属性赋值(通过从属性中抽象出来的类Field实现)
*/
public class Demo3 {
public static void main(String[] args) throws Exception {
//通过普通的方式
// Person person = new Person();
// person.setName("bingbing");
//通过反射
//1.获取字节码对象
Class class1 = Class.forName("com.qianfeng.test.Person");
//2.调用Field的方法得到对应的属性
//参数就是那个实际属性
//注意:getField方法在获取属性的时候,必须保证属性存在,还要保证name的权限够大--public
//Field field1 = class1.getField("name");
//当属性是私有的,可以通过下面的设置临时更改属性的权限,完成属性的获取。
Field field1 = class1.getDeclaredField("name");
field1.setAccessible(true);
//3.给当前的属性指定一个具体的实例对象
Object person1 = class1.newInstance();
//4.将field指定给person1
//第一个参数是field1对应的具体的实例对象,第二个参数是赋的具体的值
field1.set(person1, "bingbing");//person.name="bingbing"
System.out.println(field1.get(person1));
//再次进行实例对象的创建并绑定属性并赋值
//3.给当前的属性指定一个具体的实例对象
Object person2 = class1.newInstance();
//4.将field指定给person1
//第一个参数是field1对应的具体的实例对象,第二个参数是赋的具体的值
field1.set(person2, "chenchen");//person.name="bingbing"
System.out.println(field1.get(person2));
}
}
获取具体的方法
package com.qianfeng.test;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
/*
* 4.获取具体的方法,并调用方法(通过从方法中抽象出来的类Method实现)
*/
public class Demo4 {
public static void main(String[] args) throws Exception {
//调用普通的方法
// Person person = new Person();
// person.run("123");
//使用反射
//1.获取字节码对象
Class class1 = Class.forName("com.qianfeng.test.Person");
//2.调用非静态的无参方法
fun1(class1);
//3.调用非静态的有参方法
fun2(class1);
//4.调用静态的有参方法
fun3(class1);
}
//2.调用非静态的无参方法
public static void fun1(Class class1) throws Exception{
//第一个参数:对应的方法的具体名字 第二个参数:具体方法参数的字节码文件对象
Method method = class1.getMethod("play");
//创建实例对象
Constructor constructor = class1.getConstructor(String.class);
Object person = constructor.newInstance("bingbing");
//调用方法
//第一个参数:给当前的指定的具体对象 第二个参数:方法的具体参数
method.invoke(person);
}
//3.调用非静态的有参方法
public static void fun2(Class class1) throws Exception{
//第一个参数:对应的方法的具体名字 第二个参数:具体方法参数的字节码文件对象
Method method = class1.getMethod("run",String.class);
//创建实例对象
Constructor constructor = class1.getConstructor(String.class);
Object person = constructor.newInstance("bingbing");
//调用方法
//第一个参数:给当前的指定的具体对象 第二个参数:方法的具体参数
method.invoke(person,"123");
}
//4.调用静态的有参方法
public static void fun3(Class class1) throws Exception{
//第一个参数:对应的方法的具体名字 第二个参数:具体方法参数的字节码文件对象
//注意:所有数据类型都有自己的字节码文件对象
Method method = class1.getMethod("show",String.class,int.class);
//调用方法
//第一个参数:给当前的指定的具体对象 第二个参数:方法的具体参数
method.invoke(null,"苹果",222);
}
}