第十四天,主要强化一下反射的用法
18周 JAVA从入门到入土
一、反射
反射可以近似理解为 通过获取编译后的字节码来反射一个未知类的各种成员。
反射的权限很大,在编程过程中一定要谨慎使用。
1.1 获取字节码
可以通过三种方式来获取字节码:
- 类名.class
- 对象.getClass()
- Class.forName(“包名.类名”)
1.2 获取成员字段
有了字节码以后,可以通过 getDeclared…() 方法来获取该类的所有成员:
- 变量 getDeclaredFields()
- 方法 getDeclaredMethods()
- 注解 getDeclaredAnnotations()
每个方法都有对应的获取单个成员的方法,那些方法需要传入对应成员名的字符串。
1.3 创建对象
有了一个类的字节码以后,可以通过 newInstance() 方法来创建其对象。
1.4 调用方法
获得一个类的方法以后,可以通过 invoke() 方法来调用,括号里需要传入一个该类的对象。
public class ClassA {
public void methodA(String str) {
System.out.println("run-ClassA-methodA-" + str);
}
}
public static void main(String[] args) {
try {
Method method = ClassA.class.getDeclaredMethod("methodA", String.class);
method.invoke(ClassA.class.newInstance(), "HelloWord");
} catch (Exception e) {
e.printStackTrace();
}
}
运行结果:
Object... args
这句表示括号内可以无限传参,这里的 args 等效于一个 Object 数组。
Method method = ClassA.class.getDeclaredMethod("methodA", String.class);
method.invoke(ClassA.class.newInstance(), "HelloWord");
当获取的方法需要参数时,需要将参数放在 invoke() 方法 obj 参数的后面,同时在获取 method 的时候,要将对应参数的类型的字节码传入。
二、自定义注解
2.1 注解的创建
注解的创建与类的创建类似:
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@Retention(RetentionPolicy.RUNTIME)
public @interface Ann {
}
注解创建完成以后,就可以标记在任意的类和方法上了。
@Retention(RetentionPolicy.RUNTIME)
这句注解用于标记一个注解,让自定义的注解可以被反射。
2.2 注解的属性
注解也可以添加属性:
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@Retention(RetentionPolicy.RUNTIME)
public @interface Ann {
public String remark();
}
调用注解的属性:
@Ann(remark = "TestA的Ann注解的remark标识")
public class TestA {
}
public class TestB {
public static void main(String[] args) {
Ann ann = TestA.class.getDeclaredAnnotation(Ann.class);
System.out.println(ann.remark());
}
}
运行结果:
三、文件操作
文件操作需要用到 File 文件类,其格式:
File file = new File("文件地址");
3.1 常用 API
API | 功能 | 输出类型 |
---|---|---|
listFiles() | 获取当前文件夹下的所有文件 | File[] |
isFile() | 判断是否为文件 | boolean |
isDirectory() | 判断是否为文件夹 | boolean |
3.2 递归遍历文件夹
递归遍历 D 盘下的 File 文件夹:
import java.io.File;
public class ReadFiles {
public static void main(String[] args) {
readFiles(new File("D:/File"));
}
public static void readFiles(File file) {
File[] fileArr = file.listFiles();
for (File f : fileArr) {
if (f.isFile()) {
System.out.println(f.toString());
} else {
readFiles(f);
}
}
}
}
运行结果:
四、练习
利用注解来切换创建不同的子类对象:
public interface Father {
public void method();
}
@RunThis
public class SonA implements Father {
@Override
public void method() {
System.out.println("Run-SonA-method.");
}
}
//@RunThis
public class SonB implements Father {
@Override
public void method() {
System.out.println("Run-SonB-method.");
}
}
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@Retention(RetentionPolicy.RUNTIME)
public @interface RunThis {
//
}
import java.io.File;
public class Main {
public static void main(String[] args) {
try {
Father obj = null;
File f = new File("D:/JAVA/workspace/Project/src/com/test/demo");
File[] fileArr = f.listFiles();
for (File file : fileArr) {
String name = "com.test.demo." + file.getName().split("\\.")[0];
RunThis r = Class.forName(name).getDeclaredAnnotation(RunThis.class);
if (r != null) {
obj = (Father) Class.forName(name).newInstance();
}
}
obj.method();
} catch (Exception e) {
e.printStackTrace();
}
}
}
运行结果: