JavaSE阶段配置文件解析、反射以及注解综合小练习
练习要求
先创建一个项目wzry,在项目中创建一个resource源文件夹,在该文件夹下,有一个
web.properties配置文件。该配置文件内容如下:
package=cn #package是key,值是cn指的是包
annotantion=HeroType #HeroType是值,是一个英雄类型注解
请解析这个配置文件,然后将package作为扫描【遍历硬盘上cn目录下的所有文件夹、文件】的目录包,
扫描包下所有java类,将所有HeroType注解的值是"力量型"英雄的类,调用beGoodAt()方法。
通过分析题意,我们将本题分为三个部分
1.解析配置文件,获得包名及注解名
2.获得注解类对应的字节码文件
3.通过反射找出符合题意的类,并调用方法
首先在main方法中解析properties类型的配置文件
此处采用的是类加载器的方式,通过当前类的加载器获取
另外也可以通过当前线程获取,方法很多,不再赘述了
public class HeroTest2 {
public static Class hero = null;
public static void main(String[] args) throws Exception {
// 解析配置文件,获得包名和注解名
Properties p = new Properties();
ClassLoader classLoader = HeroTest2.class.getClassLoader();//获取当前类加载器
String pa = null;// 声明包名
String ann = null;// 声明注解名
try(
/*
* 2. 通过类加载器的方式
1.同当前类的加载器获取
1.当前类.class.getClassLoader();// 获取当前类加载器
2.classLoader.getResourceAsStream("文件路径/文件名");//通过类加载器获取流对象,如果是源文件夹,直接文件名
*/
InputStream is = classLoader.getResourceAsStream("web.properties");//获取当前类加载器并获取流
BufferedInputStream bis = new BufferedInputStream(is);
){
p.load(bis);// load方法解析配置文件
pa = p.getProperty("package");// 获得包名cn
ann = p.getProperty("annotantion");// 获取注解名HeroType
} catch (FileNotFoundException e) {
System.out.println("文件没有找到异常!");
e.printStackTrace();
} catch (IOException e) {
System.out.println("IO异常!");
e.printStackTrace();
}
// 获得项目的绝对路径
File file = new File(pa);
String paPath = file.getAbsolutePath();
// System.out.println(paPath);
//E:\Java_software\eclipse-jee-neon-2\eclipse_workspace\wzry\cn
String path = paPath.substring(0, (paPath.length()-pa.length()-1));
// System.out.println(path);
//E:\Java_software\eclipse-jee-neon-2\eclipse_workspace\wzry
File dir = new File(path);
getHero(dir,pa,ann);//调用获取注解对象字节码文件方法
getStrengthHero(dir,pa);//调用获取对象方法
}
获取到配置文件中的包名及注解名之后,便可以实现对对应的包进行遍历,查找符合题意的java文件
其中获取注解类字节码文件的代码如下:
public static Class getHero(File dir,String pa,String ann) throws Exception {
if (dir.isFile() && dir.getName().equals(ann + ".java") && dir.getAbsolutePath().contains(pa)) {
String path = dir.getAbsolutePath();
// System.out.println(path);
// // E:\Java_software\eclipse-jee-neon-2\eclipse_workspace\wzry\src\cn\itsource\hero\HeroType.java
path = path.substring(path.indexOf(pa));
// System.out.println(path);
// // cn\itsource\hero\HeroType.java
path = path.replace("\\",".").replaceAll(".java", "");
// System.err.println(path);
// // cn.itsource.hero.HeroType
hero = Class.forName(path);
} else if (dir.isDirectory()) {
File[] listFiles = dir.listFiles();
for (File file : listFiles) {
getHero(file,pa,ann);
}
}
return null;
}
通过递归方法遍历文件夹,找到符合配置文件中注解名的类并获取到其字节码文件。
接下来只剩通过class.getAnnotation()方法获取到每个java文件的注解内容,再将其与题目中的所需类型进行比对即可。
public static void getStrengthHero(File dir,String pa) throws Exception {
if (dir.isFile() && dir.getName().endsWith(".java") && !dir.getName().contains("HeroType") && dir.getAbsolutePath().contains(pa)) {
String path = dir.getAbsolutePath();
// System.out.println(path);
path = path.substring(path.indexOf(pa)).replace("\\",".").replaceAll(".java", "");
// System.err.println(path);
// 通过文件名获取每一个对应的字节码对象
Class c = Class.forName(path);
if (c.getAnnotation(hero) != null) {
String annString = c.getAnnotation(hero).toString();
// System.out.println(annString);
/*
* @cn.itsource.hero.HeroType(type=智力型)
@cn.itsource.hero.HeroType(type=敏捷型)
@cn.itsource.hero.HeroType(type=力量型)
*/
if (annString.contains("力量型")) {
// 通过当前匹配上的字节码对象去获取对象中的普通方法 beGoodAt()
Method method = c.getMethod("beGoodAt");
// 执行非static修饰的beGoodAt()方法, 是通过当前method对象调用执行方法 invoke()
// Object invoke(Object obj, Object... args) //非static需要对象
// 3.先通过字节码对象获取一个构造方法对象,再去用newInstance()创建对象
method.invoke(c.getConstructor().newInstance());
}
}
} else if (dir.isDirectory()) {
File[] listFiles = dir.listFiles();
for (File file : listFiles) {
getStrengthHero(file,pa);
}
}
}
通过反射的方式获取类中的方法、构造方法,并创建对象调用方法即可完成题目要求。
附上题目已给的几个已知类:
Hero类
/**
* 英雄类
* 抽象基类
*/
public abstract class Hero {
/**
* 擅长的能力
*/
public abstract void beGoodAt();
}
注解类
/**
* 英雄类型
*/
@Target(ElementType.TYPE)//只有一个值,且属性的名字是value可以省略
@Retention(RetentionPolicy.RUNTIME)
public @interface HeroType {
String type();
}
@HeroType(type="智力型")
public class Master extends Hero {
@Override
public void beGoodAt() {
System.out.println("烧死你.....");
}
}
@HeroType(type="敏捷型")
public class Shooter extends Hero {
@Override
public void beGoodAt() {
System.out.println("射你.....");
}
}
@HeroType(type="力量型")
public class Warrior extends Hero {
@Override
public void beGoodAt() {
System.out.println("砍死你.....");
}
}
以上即为JavaSE初学阶段关于注解、反射以及配置文件解析的综合小练习,仅供参考。