反射的认识
反射:就是 加载类(),并允许以编程的方式,解剖类中的各种成分(成员变量、成员方法、构造器等)
有什么作用?
获取类的信息、操作他们
反射具体怎么用?
获取Class对象的三种方法:
public class Main { public static void main(String[] args) throws ClassNotFoundException { //类名.class Class c1 = Objecter.class; System.out.println(c1);//全类名 = 包名 + 类名 System.out.println(c1.getSimpleName());//简单的就是类名 //Class的静态方法forName() Class c2 = Class.forName("com.yym.test.Objecter"); System.out.println(c2); System.out.println(c1 == c2);//比较地址 //实例对象.getClass() Objecter objecter = new Objecter(); Class c3 = objecter.getClass(); System.out.println(c3); System.out.println(c3 == c2); } }
获取类的构造器并对其进行操作:
import java.lang.reflect.Constructor; public class Main { //获取Objecter的全部构造器 public static void main(String[] args) throws Exception { //1. 反射第一步:必须先得到这个类的Class对象 Class c = Objecter.class; //2. 获取类的全部构造器 // Constructor[] constructors = c.getConstructors();//只能获取public的构造器 Constructor[] constructors = c.getDeclaredConstructors();//获取全部权限的构造器 //3. 遍历数组中每个构造器对象 for (Constructor constructor : constructors) { //构造器名称 + 构造器参数个数 System.out.println(constructor.getName() + "---->" + constructor.getParameterCount()); //构造器名称 + 构造器参数类型(后面的方法返回的是类型的数组,因此用Arrays.toString,Arrays中的toString方法已经被重写了) // System.out.println(constructor.getName() + "---->" + Arrays.toString(constructor.getParameterTypes())); } //4. 获取无参构造器 //Constructor constructor = c.getConstructor();//只能获取public修饰的无参构造器 Constructor constructor = c.getDeclaredConstructor();//获取全部权限的构造器 System.out.println(constructor.getName() + "----->" + constructor.getParameterCount()); //5. 获取有参构造器(这里的参数:.class代表类型【相当于一种变量】,如果只有类型,那么参数列表的结构不对了【类型 变量】) Constructor constructor1 = c.getDeclaredConstructor(int.class,String.class); System.out.println(constructor1.getName() + "----->" + constructor1.getParameterCount()); } }
获取类构造器的作用(初始化对象返回):
//类 public class Objecter { private int age; private String name; public Objecter(int age, String name) { this.age = age; this.name = name; System.out.println("有参构造器启动!!!"); } public Objecter() { System.out.println("无参构造器启动!!!"); } 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 "Objecter{" + "age=" + age + ", name='" + name + '\'' + '}'; } } //Test import java.lang.reflect.Constructor; public class Main { //获取Objecter的全部构造器 public static void main(String[] args) throws Exception { //1. 反射第一步:必须先得到这个类的Class对象 Class c = Objecter.class; //2. 获取无参构造器 Constructor constructor = c.getDeclaredConstructor();//获取全部权限的构造器 //3. 获取无参构造器怎么初始化并返回对象? Objecter object1 = (Objecter)constructor.newInstance(); System.out.println(object1); //4. 获取有参构造器(这里的参数:.class代表类型【相当于一种变量】,如果只有类型,那么参数列表的结构不对了【类型 变量】) Constructor constructor1 = c.getDeclaredConstructor(int.class,String.class); //5. 获取有参构造器并返回对象 Objecter object2 = (Objecter) constructor1.newInstance(9,"hello"); System.out.println(object2); } }
注意:
看下面的图,这里有个 setAccessible()方法,设置为true后,就算构造器为private修饰也可以访问,破环了类的封装性
获取到类的成员变量、对成员变量操作(赋值、取值)
获取到类的成员方法
(作用:执行)
反射的作用、应用场景(简单了解)
基本作用:
可以得到一个类的全部成分然后操作
可以破环封装性
适合做框架,基本主流框架都会基于反射设计一些通用的功能
### 使用反射做一个简易版的框架
需求:
实现步骤:
1. 定义一个方法,可以接收任意对象。
2. 每收到一个对象后,使用反射获取该对象的Class对象,然后获取全部的成员变量
3. 遍历成员变量,然后提取成员变量在该对象中的具体值
4. 把成员变量名、该变量的值、写出到文件中去;
```java
package TestFrame;
public class Student {
private String name;
private int age;
private char sex;
private double height;
private String hobby;
public Student() {
}
public Student(String name, int age, char sex, double height, String hobby) {
this.name = name;
this.age = age;
this.sex = sex;
this.height = height;
this.hobby = hobby;
}
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;
}
public char getSex() {
return sex;
}
public void setSex(char sex) {
this.sex = sex;
}
public double getHeight() {
return height;
}
public void setHeight(double height) {
this.height = height;
}
public String getHobby() {
return hobby;
}
public void setHobby(String hobby) {
this.hobby = hobby;
}
}
```
```java
package TestFrame;
public class Teacher {
private String name;
private double salary;
public Teacher() {
}
public Teacher(String name, double salary) {
this.name = name;
this.salary = salary;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public double getSalary() {
return salary;
}
public void setSalary(double salary) {
this.salary = salary;
}
}
```
```java
package TestFrame;
import java.io.FileOutputStream;
import java.io.PrintStream;
import java.lang.reflect.Field;
public class ObjectFrame {
//目标:保存任意对象的字段和其数据到文件中去
public static void saveObject(Object obj) throws Exception {
PrintStream ps = new PrintStream((new FileOutputStream("D:\\javacode\\newtest\\heimatest\\src\\TestFrame\\TestSave.txt",true)));
//obj是任意对象,到底有多少字段需要保存?---反射获取全部成分
Class c = obj.getClass();
String cName = c.getSimpleName();//拿到对象的简名就是类名
ps.println("-----------" + cName + "------------");
//从这个类中提取它的全部成员变量
Field[] fields = c.getDeclaredFields();
//遍历每个成员变量
for (Field field : fields){
field.setAccessible(true);//禁止检查访问控制
//拿到成员变量的名字
String name = field.getName();
//拿到这个成员变量在对象中的数据
String value = field.get(obj) + "";//基本数据类型不能直接进行强制类型转换为 String,使用(String)转换会报错
//向文件中保存(打印流)
ps.println(name + "=" + value);
}
ps.close();
}
}
```
```java
package TestFrame;
import org.junit.Test;
public class TestFrame {
@Test
public void save() throws Exception {
Student s1 = new Student("张三",22,'男',180.6,"篮球、游泳");
Teacher t1 = new Teacher("王博",1000.0);
//需求:把任意对象的字段和其对应的值,保存到文件中去。
ObjectFrame.saveObject(s1);
ObjectFrame.saveObject(t1);
}
}
```
```java
结果:
-----------Student------------
name=张三
age=22
sex=男
height=180.6
hobby=篮球、游泳
-----------Teacher------------
name=王博
salary=1000.0
```