反射是java的动态机制,它允许我们在程序【运行期间】再确定要实例化的对象,调用的方法或操作的属性。该机制可以大大提高代码的灵活性和可拓展性,但是也随之带来了较低的程序运行效率和更多的系统开销,因此程序不应当过度利用反射机制。
import java.lang.reflect.Method;
import java.util.Scanner;
/**
* Java反射机制:
* 反射是java的动态机制,它允许我们在程序【运行期间】再确定要实例化的对象,
* 调用的方法或操作的属性。该机制可以大大提高代码的灵活性和可拓展性,
* 但是也随之带来了较低的程序运行效率和更多的系统开销,因此程序不应当过度利用反射机制。
*/
public class ReflectDemo {
public static void main(String[] args) throws ClassNotFoundException {
/**
* 获取要操作的类对象
* class类的实例:
* 该实例用于表示JVM加载的类,当JVM加载一个类时,就会实例化一个class对象与之对应,
* 并且每个被加载的类有且仅有一个class的实例与之绑定,通过该class实例我们可以了解到
* 其表示的类的一切信息(类名,多少个方法,多少个构造器,多少个属性等)
*
* 获取一个类对象的方式:
* 1.类名.class
* Class cls = String.class
* Class cls = int.class
* 注意:基本类型获取类对象仅有上述方式
*
* 2. Class.forName(String className)
* 基于类的完全限定名(包名.类名)加载一个类
* Class cls = Class.forName("java.lang.String");
*
* 3:ClassLoader类加载器形式
*/
// Class cls = String.class;
System.out.println("请输入类的完全限定名:");
Scanner scanner = new Scanner(System.in);
Class cls = Class.forName(scanner.nextLine());
System.out.println(cls.getName()); //获取类对象表示的类的完全限定名 java.lang.String
System.out.println(cls.getSimpleName()); //仅获取类名 String
/**
* Method类的实例用于表示某个类上的一个方法,
* 通过方法对象可以得知该方法的一切信息(访问修饰符,返回值类型,方法名,参数列表等)
* 还可以通过方法对象类调用该方法
*/
Method[] methods = cls.getMethods(); //获取类对象所表示的类的所有公开方法(包含从超类继承的)
for (Method m:methods) {
System.out.println(m.getName());
}
}
}
Person类
/**
* 使用当前类测试反射机制
*/
public class Person {
private String name = "张三";
private int age = 22;
public Person() {
}
public Person(String name, int age) {
this.name = name;
this.age = age;
}
public void sayHello() {
System.out.println(name + ":hello!");
}
public void sayHi() {
System.out.println(name + ":hi!");
}
public void dance() {
System.out.println(name + "正在跳舞");
}
public void sing() {
System.out.println(name + "正在唱歌");
}
public void watchTV() {
System.out.println(name + "正在看电视");
}
public void playGame() {
System.out.println(name + "正在打游戏");
}
public void say(String info) {
System.out.println(name + "说:" + info);
}
public void say(String info, int count) {
for (int i = 0; i < count; i++) {
System.out.println(name + "说:" + info);
}
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
import java.util.Scanner;
/**
* 利用反射机制实例化对象
*/
public class ReflectDemo02 {
public static void main(String[] args) throws Exception {
Person person = new Person(); //无参构造
System.out.println(person);
/**
* 加载需要实例化对象的类的类
*/
// Class cls = Class.forName("com.example.reflect.Person");
System.out.println("请输入类的完全限定名:");
Scanner scanner = new Scanner(System.in);
Class cls = Class.forName(scanner.nextLine());
/**
* 类对象提供了方法:newInstance()
* 可以利用其表示的类的公开的无参构造器实例化
*/
Object o = cls.newInstance();
System.out.println(o);
}
}
import java.lang.reflect.Constructor;
/**
* 使用指定构造器实例化对象
*/
public class ReflectDemo03 {
public static void main(String[] args) throws Exception {
Person person = new Person("李四", 66);
System.out.println(person);
Class cls = Class.forName("com.example.reflect.Person");
/**
* 通过类对象获取其表示的类的某个指定的构造器
* cls.getConstructor()
*
* Constructor类的每一项实例用于表示某个类上的某一个构造器
*/
Constructor constructor = cls.getConstructor(String.class, int.class);
Object obj = constructor.newInstance("张三",28);
System.out.println(obj);
}
}
import java.util.Arrays;
/**
* JDK5之后推出了一个新特性:变长参数
*/
public class ArgsDemo {
public static void main(String[] args) {
/**
* 变长参数是编译器认可的,最终会被编译器改为数组
* 传参时改为:
* dosome(new String[]{"a", "b", "c", "d", "e"})
*/
dosome("red");
dosome("a", "b");
dosome("a", "b", "c", "d", "e");
}
/**
* 变长参数在一个方法中必须是最后一个参数
*/
public static void dosome(String... strings) {
System.out.print(strings.length + " ");
System.out.println(Arrays.toString(strings));
}
}
import java.lang.reflect.Method;
import java.util.Scanner;
/**
* 使用反射机制调用方法
*/
public class ReflectDemo04 {
public static void main(String[] args) throws Exception {
Person person = new Person();
person.dance();
reflecttest1();
}
private static void reflecttest1() throws Exception {
Scanner sc = new Scanner(System.in);
System.out.println("请输入类的完全限定名:");
Class cls = Class.forName(sc.nextLine());
Object o = cls.newInstance();
System.out.println("请输入需要调用的方法:");
Method method = cls.getMethod(sc.nextLine());
method.invoke(o);
}
private static void extracted() throws Exception {
//实例化
Class cls = Class.forName("com.example.reflect.Person");
Object o = cls.newInstance(); //Person o = new Person();
/*
* 调用方法
*/
//通过类对象获取要调用方法的方法对象(Method对象)
Method method = cls.getMethod("dance"); //dance方法
//通过方法对象来调用该方法
method.invoke(o); //person.dance();
}
}
import java.lang.reflect.Method;
/**
* 使用反射机制调用方法
*/
public class ReflectDemo05 {
public static void main(String[] args) throws Exception {
Person person = new Person();
person.say("work");
person.say("red",1);
Class<?> cls = Class.forName("com.example.reflect.Person");
Object o = cls.newInstance();
Method method1 = cls.getMethod("say", String.class);
method1.invoke(o,"test_method");
Method method2 = cls.getMethod("say", String.class, int.class);
method2.invoke(o,"张三",2);
}
}
import java.lang.reflect.Method;
import java.util.Arrays;
/**
* 利用反射机制访问私有方法
*/
public class ReflectDemo06 {
public static void main(String[] args) throws Exception {
/**
* getMethods()和getMethod()
* 可以获取类对象所表示的类的所有公开方法(包含从超类继承的),无法访问私有的
*
* getDeclaredMethod()和getDeclaredMethods()
* 可以获取被类定义的方法(包含私有方法),无法获取超类继承的方法
*/
Class cls = Class.forName("com.example.reflect.Person");
Object o = cls.newInstance();
System.out.println(Arrays.toString(cls.getDeclaredMethods()));
Method method = cls.getDeclaredMethod("privat");
method.setAccessible(true); //强行打开访问权限
method.invoke(o);
method.setAccessible(false); //用后应及时关闭访问权限
}
}
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
/**
* 利用反射机制调用Person类中所有无参方法
* Method上定义了 int getParameterCount()方法,
* 该方法可以获取当前Method表示的方法中有多少个参数
*/
public class Test {
public static void main(String[] args) throws Exception {
Class<?> cls = Class.forName("com.example.reflect.Person");
Object o = cls.newInstance();
Method[] methods = cls.getDeclaredMethods();
for (Method m : methods) {
/**
* m.getModifiers() == Modifier.PUBLIC
* 判断方法是否为public类型
*/
if (m.getParameterCount() == 0 && m.getModifiers() == Modifier.PUBLIC) {
m.invoke(o);
}
}
}
}
import java.io.File;
/**
* 实例化与当前类在同一个包中的所有类
*/
public class Test2 {
public static void main(String[] args) throws Exception {
File file = new File(
Test2.class.getResource(".").toURI() //获取当前类所在包的路径
);
String fqn = Test2.class.getPackage().getName(); //获取当前类的完全限定名
File[] files = file.listFiles();
for (int i = 0; i < files.length; i++) {
String name = files[i].getName();
String type = name.split("\\.")[1];
String filename = name.split("\\.")[0];
if ("class".equals(type)) {
Class cls = Class.forName(fqn + "." + filename);
Object o = cls.newInstance();
System.out.println(o);
}
}
}
}
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* 注解 JDK8后引入的一个新特性,我们可以利用注解辅助反射机制。
* 注解使用前需要先定义.
* Java中有几个内置的注解是来为我们自定义的注解添加某些特性的:
*
* @Target() 用于说明我们定义的注解所能标注的位置
* ElementType.TYPE 类上
* ElementType.METHOD 方法上
* ElementType.FIELD 属性上
*
* @Retention() 用于说明当前注解的保留级别(有3个可选值)
* RetentionPolicy.RUNTIME 注解会被保留在字节码文件中,且可以被反射机制访问
* RetentionPolicy.CLASS 注解会被保留在字节码文件中,但是不可被反射机制访问。这些也是注解的默认保留级别
* RetentionPolicy.SOURCE 注解仅保留在源码文件中
*/
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface AutoRunClass {
}
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface AutoRunMethod {
/**
* 注解中可以添加参数,添加格式为:
* 参数类型 参数名() [default 默认值]
* default可以为参数设定默认值,在使用注解不传递参数时采取默认值。
*
* 当注解只有一个参数时,参数名称建议选取"value",这样在使用注解时便于传递参数,
* 这时调用注解例如:@AutoRunMethod(3)
*
* 正常使用注解时,参数传递格式为:@AutoRunMethod(参数名 = 参数值),
* 例如:@AutoRunMethod(value = 1),参数顺序可以与定义时不一致
*/
int value() default 1;
}
/**
* 反射中的注解操作
*/
public class ReflectDemo07 {
public static void main(String[] args) throws Exception {
Class<?> cls = Class.forName("com.example.reflect.Person");
/**
* 判断当前cls所表示的类是否被注解AutoRunClass标注
*/
if (cls.isAnnotationPresent(AutoRunClass.class)){
System.out.println("被标注了");
}else {
System.out.println("没被标注");
}
}
}
import com.example.reflect.annotations.AutoRunMethod;
import java.lang.reflect.Method;
/**
* 获取注解参数
*/
public class ReflectDemo08 {
public static void main(String[] args) throws Exception {
Class<?> cls = Class.forName("com.example.reflect.Person");
Method method = cls.getDeclaredMethod("playGame");
if (method.isAnnotationPresent(AutoRunMethod.class)){
//获取该方法对象所表示的方法上的特定注解
AutoRunMethod annotation = method.getAnnotation(AutoRunMethod.class);
//通过注解对象获取参数value的值
int value = annotation.value();
System.out.println(value);
}
}
}
import com.example.reflect.annotations.AutoRunClass;
import java.io.File;
/**
* 实例化与当前类在同一个包下被@AutoRunClass标注类
*/
public class Test3 {
public static void main(String[] args) throws Exception {
File file = new File(
Test3.class.getResource(".").toURI() //获取当前文件的路径
);
String fqn = Test3.class.getPackage().getName(); //获取当前文件的完全限定名
/**
* 添加过滤器获取该目录中的所有字节码文件
* 返回出.class文件
*/
File[] files = file.listFiles((File f) -> {
return f.getName().endsWith(".class");
});
for (File f : files) {
String fileName = f.getName(); //获取文件名
String className = fileName.substring(0, fileName.indexOf(".")); //获取类名
Class<?> cls = Class.forName(fqn + "." + className);
/**
* 判断当前类是否被注解AutoRunClass标注
*/
if (cls.isAnnotationPresent(AutoRunClass.class)) {
Object o = cls.newInstance();
System.out.println(o);
}
}
}
}
import com.example.reflect.annotations.AutoRunClass;
import com.example.reflect.annotations.AutoRunMethod;
import java.io.File;
import java.lang.reflect.Method;
/**
* 自动调用与当前类在同一个包下被注解@AutoRunClass标注的类里面,
* 被注解@AutoRunMethod标注的方法
*/
public class Test4 {
public static void main(String[] args) throws Exception {
File file = new File(
Test4.class.getResource(".").toURI() //获取当前文件路径
);
String fqname = Test4.class.getPackage().getName(); //获取当前文件的完全限定名
/**
* 添加过滤器获取该目录中的所有字节码文件
* 返回出.class文件
*/
File[] files = file.listFiles((File f) -> {
return f.getName().endsWith(".class");
});
for (File f : files) {
String filename = f.getName(); //获取当前文件文件名
String classname = filename.substring(0, filename.indexOf("."));
Class cls = Class.forName(fqname + "." + classname);
/**
* 判断类是否被注解@AutoRunClass标注
*/
if (cls.isAnnotationPresent(AutoRunClass.class)) {
Object o = cls.newInstance();
System.out.println(o);
Method[] methods = cls.getDeclaredMethods();
for (Method m : methods) {
/**
* 判断方法是否被注解@AutoRunMethod标注
*/
if (m.isAnnotationPresent(AutoRunMethod.class)) {
m.invoke(o);
}
}
}
}
}
}