知识点
1. 写出获取Class实例的三种常见方式
(1)类名.class
(2)对象名.getClass
(3)Class.forName
2. 谈谈你对Class类的理解
每个Java类都有一个对应的Class对象,这个对象代表了该类的类型信息。
Class对象在类加载到JVM时由类加载器自动创建。
练习一:我有一个ArrayList<Integer>集合,现在我在这个集合中添加一个字符串数据,如何实现?
public class ReflectionDemo4 {
public static void main(String[] args) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
ArrayList<Integer> arrays = new ArrayList<>();
Class<? extends ArrayList> class1 = arrays.getClass();
Method m = class1.getMethod("add", Object.class);
m.invoke(arrays,"hello");
m.invoke(arrays,"world");
m.invoke(arrays,"java");
System.out.println(arrays);
}
}
练习二:通过配置文件运行类中的方法(反射)
创建学生类和教师类
//学生类
package reflectiondemo2;
public class Student {
public void study(){
System.out.println("好好学习天天向上");
}
}
//教师类
package reflectiondemo2;
public class Teacher {
public void teach(){
System.out.println("用爱成就学员");
}
}
创建一个class.text配置文件
内容为
className=reflectiondemo2.Student
methodName=study
测试类
package reflectiondemo2;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Properties;
//通过配置文件运行类中的方法
public class Test {
public static void main(String[] args) throws IOException, ClassNotFoundException, NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException {
/* Student s = new Student();
s.study();*/
/* Teacher t = new Teacher();
t.teach();*/
/*
* class.txt
* className=xxx
* methodName=xxx
创建一个class.txt文件
内容为:className=reflectiondemo2.Student
methodName=study
* */
//加载数据
Properties prop = new Properties();
FileReader fr = new FileReader("JavaReflectionProject\\class.txt");
prop.load(fr);
fr.close();
//className=reflectiondemo2.Student
//methodName=study
String className = prop.getProperty("className");
String methodName = prop.getProperty("methodName");
Class<?> c = Class.forName(className);
Constructor<?> con = c.getConstructor();
Object o = con.newInstance();
Method m = c.getMethod(methodName);
m.invoke(o);
}
}
优点:灵活性高,便于修改内容(更改时只需改配置文件就可)
练习三:利用反射和重载完成以下功能
1)创建Student类,类中有属性name和age并封装属性
2)重载Student的构造函数,一个是无参构造并,另一个是带两个参数的有参构造,要求在构造函数打印提示信息
3)创建带main函数的NewInstanceTest类,利用Class类得到Student对象
4)通过上述获取的Class对象分别调用Student有参函数和无参函数
//属性类
package reflectiondemo3;
public class Student {
private String name;
private Integer age;
public Student() {
System.out.println("调用的是无参构造");
}
public Student(String name, Integer age) {
this.name = name;
this.age = age;
System.out.println("调用有参构造函数 "+"姓名:"+name+" ," +"年龄:"+age);
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
//测试类
package reflectiondemo3;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
public class Test1 {
public static void main(String[] args) throws NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException {
Class<Student> class1 = Student.class;
Constructor<Student> con = class1.getConstructor();
Object s = con.newInstance();
Constructor<Student> con1 = class1.getConstructor(String.class, Integer.class);
Object s1 = con1.newInstance("张三",18);
}
}
练习四: 利用通过反射修改私有成员变量
1. 定义PrivateTest类,有私有name属性,并且属性值为hellokitty,只提供name的getName的公有方法
2. 创建带有main方法ReflectTest的类,利用Class类得到私有的name属性
3. 修改私有的name属性值,并调用getName()的方法打印name属性值
//属性类
package reflectiondemo3;
public class PrivateTest {
private String name="helloKitty";
public String getName() {
return name;
}
}
//测试类
package reflectiondemo3;
import java.lang.reflect.Field;
public class ReflectTest {
public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException, InstantiationException, IllegalAccessException {
Class<?> c = Class.forName("reflectiondemo3.PrivateTest");
Object o = c.newInstance();
Field f = c.getDeclaredField("name");
f.setAccessible(true);
System.out.println(f.get(o));
}
}
练习五: 利用反射和File完成以下功能
1. 利用Class类的forName方法得到File类
2. 在控制台打印File类的所有构造器
3. 通过newInstance的方法创建File对象,并创建D:\mynew.txt文件
Class<?> fileClass = null;
try {
fileClass = Class.forName("java.io.File");
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
if (fileClass != null) {
Constructor<?>[] constructors = fileClass.getConstructors();
System.out.println("File类的所有构造器:");
for (Constructor<?> constructor : constructors) {
System.out.println(constructor);
}
}
import java.io.File;
import java.io.IOException;
public class ReflectFileTest {
public static void main(String[] args) {
try {
// 1. 利用Class类的forName方法得到File类
Class<?> fileClass = Class.forName("java.io.File");
// 2. 在控制台打印File类的所有构造器
Constructor<?>[] constructors = fileClass.getConstructors();
System.out.println("File类的所有构造器:");
for (Constructor<?> constructor : constructors) {
System.out.println(constructor);
}
// 3. 通过newInstance的方法创建File对象
// 由于File类没有默认构造器,我们使用路径字符串构造器
Class<?>[] paramTypes1 = new Class<?>[]{String.class};
Constructor<?> constructor = fileClass.getConstructor(paramTypes1);
Object fileObject = constructor.newInstance("D:\\mynew.txt");
// 将fileObject转换为File类型,以便使用File类的方法
File file = (File) fileObject;
// 创建D:\mynew.txt文件
if (!file.exists()) {
file.createNewFile();
System.out.println("文件创建成功");
} else {
System.out.println("文件已存在");
}
} catch (Exception e) {
e.printStackTrace();
}
}
}