反射
为了测试反射,编写一个 Cat 的测试类;
public class Cat {
public static int a;
public static final String COUNTRY = "中国";
private String name;
private int age;
public Cat() {
System.out.println("调用无参构造器!!!");
}
public Cat(String name, int age) {
System.out.println("调用有参构造器!!!");
this.name = name;
this.age = age;
}
private void eat(){
System.out.println("爱吃猫粮~~~");
}
private String eat(String name){
return "爱吃" + name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
@Override
public String toString() {
return "Cat{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
反射获得构造器对象
@Test
public void testGetConstructor() throws Exception{
//得到这个类的Class对象
Class c = Cat.class;
//获取全部的构造器
Constructor[] constructors = c.getDeclaredConstructors();
for (Constructor constructor : constructors) {
System.out.println(constructor);
}
//获取某个类的构造器。无参构造器
Constructor constructor = c.getDeclaredConstructor();
System.out.println(constructor.getName() + "--->" + constructor.getParameterCount());
//禁止检查访问权限
constructor.setAccessible(true);
//调用构造器对象表示的构造器,并传入参数,完成对对象的初始化
Cat cat = (Cat) constructor.newInstance();
System.out.println(cat);
//获得有参数的构造器
Constructor constructor1 = c.getDeclaredConstructor(String.class, int.class);
System.out.println(constructor1.getName() + "--->" + constructor1.getParameterCount());
constructor1.setAccessible(true);
Cat cat1 = (Cat) constructor1.newInstance("加菲猫", 3);
System.out.println(cat1);
}
反射获得成员变量
@Test
public void testGetFields() throws Exception {
//获得类的Class对象
Class c = Cat.class;
//获取类的全部从成员变量
Field[] fields = c.getDeclaredFields();
for (Field field : fields) {
System.out.println(field.getName() + "--->" + field.getType());
}
//定位某个成员变量
Field fname = c.getDeclaredField("name");
System.out.println(fname.getName() + "-->" + fname.getType());
Field fage = c.getDeclaredField("age");
System.out.println(fage.getName() + "-->" + fage.getType());
//为某个成员变量赋值
fname.setAccessible(true);
fage.setAccessible(true);
Cat cat = new Cat();
fname.set(cat,"加菲猫");
fage.set(cat,18);
System.out.println(cat);
System.out.println(fname.get(cat));
System.out.println(fage.get(cat));
}
反射获得成员方法
@Test
public void testGetMethod() throws Exception {
//获得类的Class对象
Class c = Cat.class;
//获取全部方法
Method[] methods = c.getDeclaredMethods();
for (Method method : methods) {
System.out.println(method.getName() + "-->"
+ method.getParameterCount() + "--->"
+ method.getReturnType());
}
//获取单个方法
Method eat = c.getDeclaredMethod("eat");
System.out.println(eat.getName() + "-->"
+ eat.getParameterCount() + "--->"
+ eat.getReturnType());
Method eat1 = c.getDeclaredMethod("eat",String.class);
System.out.println(eat1.getName() + "-->"
+ eat1.getParameterCount() + "--->"
+ eat1.getReturnType());
//触发获得的方法
Cat cat = new Cat();
eat.setAccessible(true);
eat1.setAccessible(true);
Object invoke = eat.invoke(cat);
System.out.println(invoke);
String invoke1 = (String) eat1.invoke(c, "草鱼");
System.out.println(invoke1);
}
注解
注解本质就是一个接口,java中所有注解都继承 Annotation 接口;
@注解(…):其实就是一个实现类对象,实现了该注解以及Annotation接口。
编写注解类
public @interface MyTest {
String a();
//默认为true
boolean b() default true;
String[] c();
//特殊属性(若只有他一个属性,可以不写value直接写值)
String value();
}
使用注解
//这里其实就是在创建一个实现类对象
@MyTest(a = "孙行者",c = {"java1","java2"},value = "2")
public class AnnotationTest01 {
@MyTest(a = "无忌",c = {"java1","java2"},value = "3")
public void test1(){
}
public static void main(String[] args) {}
}
使用工具进行反编译
import java.lang.annotation.Annotation;
public interface MyTest
extends Annotation
{
public abstract String a();
public abstract boolean b();
public abstract String[] c();
public abstract String value();
}
元注解
修饰注解的注解;
-
@Target 作用:声明被修饰的注解只能在哪些位置使用
@Target(ElementType.TYPE)TYPE,类,接口
FIELD,成员变量
METHOD,成员方法PARAMETER,方法参数
CONSTRUCTOR,构造器
LOCAL_VARIABLE,局部变量
-
@Retention作用:声明注解的保留周期。
@Retention(RetentionPolicy.RUNTIME)
SOURCE 只作用在源码阶段,字节码文件中不存在。
CLASS(默认值) 保留到字节码文件阶段,运行阶段不存在。
RUNTIME(开发常用) 一直保留到运行阶段。
注解的解析
- 解析类上的注解
@Test
public void parseClass() throws Exception {
//得到class对象
Class c = AnnotationTest01.class;
//解析类上的注解
//判断类上是否包含了某个注解
if (c.isAnnotationPresent(MyTest.class)) {
MyTest my = (MyTest) c.getDeclaredAnnotation(MyTest.class);
System.out.println(my.a());
System.out.println(my.b());
System.out.println(Arrays.toString(my.c()));
System.out.println(my.value());
}
}
- 解析方法上的注解
@Test
public void parseMethod() throws Exception{
//得到class对象
Class c = AnnotationTest01.class;
Method m = c.getDeclaredMethod("test1");
//解析方法上的注解
//判断方法上是否包含了某个注解
if (m.isAnnotationPresent(MyTest.class)){
MyTest my = m.getDeclaredAnnotation(MyTest.class);
System.out.println(my.a());
System.out.println(my.b());
System.out.println(Arrays.toString(my.c()));
System.out.println(my.value());
}
}
模拟junit
加注解的方法执行,不加的不执行。
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
public class AnnotationTest02 {
public void test1(){
System.out.println("*******test1*******");
}
@JunitTest
public void test2(){
System.out.println("*******test2*******");
}
public void test3(){
System.out.println("*******test3*******");
}
@JunitTest
public void test4(){
System.out.println("*******test4*******");
}
public static void main(String[] args) throws Exception {
AnnotationTest02 a = new AnnotationTest02();
//得到类的class对象
Class c = AnnotationTest02.class;
//提取这个类中全部的成员方法
Method[] methods = c.getDeclaredMethods();
//遍历数组中的每个方法,查看是否又@JunitTest注解
for (Method method : methods) {
if (method.isAnnotationPresent(JunitTest.class)){
method.invoke(a);
}
}
}
}