java反射机制
- 反射机制是java的动态机制,可以在程序"运行期间"再确定实例化对象,方法调用,属性操作等。
- 反射机制可以提高代码的灵活度,但是会带来较多的系统开销和较低的运行效率,因此不能过度依赖。
package reflect;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Scanner;
public class ReflectDemo1 {
public static void main(String[] args) throws ClassNotFoundException {
/*
Class类
Class类称为类的类对象。
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类加载器形式获取
*/
//获取String的类对象
// Class cls = String.class;
// Class cls = ArrayList.class;
// Class cls = Class.forName("java.lang.String");
/*
java.util.ArrayList
java.util.HashMap
java.io.FileInputStream
java.lang.String
*/
Scanner scanner = new Scanner(System.in);
System.out.println("请输入要加载的类的名字:");
String className = scanner.nextLine();
Class cls = Class.forName(className);
String name = cls.getName();//获取完全限定名:包名.类名
System.out.println(name);
name = cls.getSimpleName();//仅获取类名
System.out.println(name);
String packageName = cls.getPackage().getName();
System.out.println("包名:"+packageName);
/*
reflect.Person
*/
//获取String类的所有公开方法(包含从超类继承的方法)
// Method[] methods = cls.getMethods();
//获取本类自己定义的方法(包含私有方法)
Method[] methods = cls.getDeclaredMethods();
for(Method method : methods){
System.out.println(method.getName());
}
}
}
- 使用反射机制实例化对象
package reflect;
import java.util.ArrayList;
import java.util.Scanner;
public class ReflectDemo2 {
public static void main(String[] args) throws ClassNotFoundException, IllegalAccessException, InstantiationException {
ArrayList list = new ArrayList();
System.out.println(list);
//1获取要实例化对象的类的类对象
// Class cls = Class.forName("java.util.ArrayList");
/*
java.util.HashMap
java.util.Date
reflect.Person
*/
Scanner scanner = new Scanner(System.in);
System.out.println("请输入类名:");
String className = scanner.nextLine();
Class cls = Class.forName(className);
//2调用Class的newInstance()来调用无参构造器
Object obj = cls.newInstance();
System.out.println(obj);
}
}
- 使用指定的构造器实例化对象
package reflect;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
public class ReflectDemo3 {
public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
Person p = new Person("李四",33);
System.out.println(p);
//1加载类对象
Class cls = Class.forName("reflect.Person");
//2通过类对象获取指定的有参构造器:Person(String,int)
// Constructor c = cls.getConstructor();//不传参获取的就是无参构造器
Constructor c = cls.getConstructor(String.class,int.class);
Object obj = c.newInstance("王五",66);//new Person("王五",66);
System.out.println(obj);
}
}
- 利用反射机制调用方法
package reflect;
import java.lang.reflect.Method;
import java.util.Scanner;
public class ReflectDemo4 {
public static void main(String[] args) throws Exception {
Person p = new Person();
p.watchTV();
Scanner scanner = new Scanner(System.in);
System.out.println("请输入类名:");
String className = scanner.nextLine();
System.out.println("请输入方法名:");
String methodName = scanner.nextLine();
//1实例化
//1.1加载类对象
// Class cls = Class.forName("reflect.Person");
Class cls = Class.forName(className);
//1.2实例化
Object obj = cls.newInstance();//Object obj = new Person();
//2调用方法
//2.1通过类对象获取要调用的方法
// Method method = cls.getMethod("watchTV");
Method method = cls.getMethod(methodName);
//2.2通过方法对象执行该方法
method.invoke(obj);//obj.watchTV() 前提是obj表示的是一个Person对象
}
}
- 调用有参方法
package reflect;
import java.lang.reflect.Method;
public class ReflectDemo5 {
public static void main(String[] args) throws Exception {
Class cls = Class.forName("reflect.Person");
Object obj = cls.newInstance();
//public void say(String info){
Method method = cls.getMethod("say",String.class);
method.invoke(obj,"你好!");//p.say("你好!");
//public void say(String info,int count){
Method method2 = cls.getMethod("say",String.class,int.class);
method2.invoke(obj,"嘿嘿",5);//p.say("嘿嘿",5)
}
}
私有化强行打开访问权限
package reflect;
import java.lang.reflect.Method;
public class ReflectDemo6 {
public static void main(String[] args)throws Exception {
// Person p = new Person();
// p.hehe();//编译不通过!hehe是私有方法!
Class cls = Class.forName("reflect.Person");
Object obj = cls.newInstance();
/*
Class的方法:
getMethod(),getMethods()都只能获取到类对象表示的类的公开方法
*/
// Method method = cls.getMethod("hehe");
Method method = cls.getDeclaredMethod("hehe");
method.setAccessible(true);//强行打开访问权限
method.invoke(obj);//p.hehe();
method.setAccessible(false);
}
}
isAnnotationPresent用于检查此类中是否存在指定注释类型的注释。该方法返回一个声明相同的布尔值
package ReflectDemo;
import ReflectDemo.annotations.AutoRunClass;
public class ReflectDemo7 {
public static void main(String[] args) throws ClassNotFoundException {
Class cls = Class.forName("ReflectDemo.Person");
//返回一个是否拥有@AutoRunClass的类
boolean flag = cls.isAnnotationPresent(AutoRunClass.class);
if (flag){
System.out.println("被标注了");
}else {
System.out.println("没有被标注");
}
}
}
Demo9
package ReflectDemo;
import ReflectDemo.annotations.AutoRunMethod;
import java.lang.reflect.Method;
public class ReflectDemo8 {
public static void main(String[] args) throws Exception{
Class cls = Class.forName("ReflectDemo.Person");
Method method = cls.getMethod("sayHi");
if (method.isAnnotationPresent(AutoRunMethod.class)){
AutoRunMethod arm = method.getAnnotation(AutoRunMethod.class);
int value = arm.value();//获取@AutoRunMethod里的value
System.out.println(value);
}
}
}
Person类
package reflect;
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);
}
}
private void hehe(){
System.out.println("我是Person的私有方法!!!");
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
通过反射自动调用无参方法
package ReflectDemo;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
public class Test {
public static void main(String[] args) throws Exception {
Class cls = Class.forName("ReflectDemo.Person");
Object obj = cls.newInstance();
Method[] methods = cls.getDeclaredMethods();
for (Method method : methods) {
//判断是否为无参且公开且名中带a的方法
if (method.getName().contains("a")&&method.getParameterCount()==0 && method.getModifiers()== Modifier.PUBLIC) {
System.out.println("自动调用方法:" + method.getName() + "()");
method.invoke(obj);
}
}
}
}
- 自动调用与当前类Test2在通过一个包中所有类中的无参且公开的方法
package ReflectDemo;
import java.io.File;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.net.URISyntaxException;
import java.util.List;
/**
* 自动调用与当前类Test2在通过一个包中所有类中的无参且公开的方法
*/
public class Test2 {
public static void main(String[] args) throws Exception {
//定位当前类所在的包
File dir = new File(Test2.class.getResource(".").toURI());
//遍历所有的类名
File[] subs = dir.listFiles(f->f.getName().endsWith(".class"));
for (File sub : subs) {
//通过每一个class文件的文件名的到类名
String fileName = sub.getName();
String className = fileName.substring(0,fileName.indexOf("."));
//根据Test2这个类的包名来拼接其它同包中的类的完全限定名
className = Test2.class.getPackage().getName()+"."+className;
//加载该类的类对象
Class cls = Class.forName(className);
Object obj = cls.newInstance();//实例化对象
//根据类对象获取该类中所有定义的方法
Method[] methods = cls.getDeclaredMethods();
for (Method method : methods) {
if (method.getParameterCount()==0&&method.getModifiers()== Modifier.PUBLIC){
System.out.println("自动调用方法:" + method.getName() + "()");
method.invoke(obj);
}
}
}
}
}
- 输出与当前类Test3所在同一个包中被@AutoRunClass标注过的类的类名
- isAnnotationPresent 用于检查此类中是否存在指定注释类型的注释。该方法返回一个声明相同的布尔值。
package ReflectDemo;
import ReflectDemo.annotations.AutoRunClass;
import ReflectDemo.annotations.AutoRunMethod;
import java.io.File;
import java.lang.reflect.Method;
import java.net.URISyntaxException;
/**
* 输出与当前类Test3所在同一个包中被@AutoRunClass标注过的类的类名
* isAnnotationPresent 用于检查此类中是否存在指定注释类型的注释。该方法返回一个声明相同的布尔值。
*/
public class Test3 {
public static void main(String[] args) throws Exception {
File dir = new File(Test3.class.getResource(".").toURI());
File[] subs = dir.listFiles(f->f.getName().endsWith(".class"));
for (File sub : subs) {
String fileName = sub.getName();
String className = fileName.substring(0,fileName.indexOf("."));
className = Test3.class.getPackage().getName()+"."+className;
Class cls = Class.forName(className);
//输出该类中被所有被@AutoRunClass标注的方法
if (cls.isAnnotationPresent(AutoRunClass.class)){
System.out.println(cls.getName()+"被@AutoRunClass标注了");
Object obj = cls.newInstance();
//输出该类中被所有被@AutoRunMethod标注的方法
Method[] methods = cls.getDeclaredMethods();
for (Method method : methods) {
if (method.isAnnotationPresent(AutoRunMethod.class)){
System.out.println(method.getName()+"被@AutoRunMethod标注了");
//根据方法里的参数值调用多少次方法
AutoRunMethod arm = method.getAnnotation(AutoRunMethod.class);
int value = arm.value();
for (int i = 0; i < value; i++) {
method.invoke(obj);
}
}
}
}
}
}
}