反射是Java的动态机制,可以在 [ 程序运行期间 ] 再确定如:对象实例化,方法调用,属性操作等
Class cls = String.class;
Class cls = int.class;
注意:基本类型仅有上述这种方式可以获取
Class cls = Class.forName("java.lang.String");
Class cls = Class.forName("java.util.ArrayList");
Class cls = o.getClass() //o可以是任意对象,比如o是String实例,那么就可以获取String的类对象
Class cls =Class.forName("java.lang.String");
Object obj = cls.newInstance();//必须有无参构造器
Class cls = Class.forName("reflect.Person");
//Person()
Constructor c = cls.getConstructor(); //获取无参构造器
c.newInstance(); //new Person();
//Person(String)
Constructor c = cls.getConstructor(String.class);
Object obj = c.newInstance("王五");
System.out.println(obj);
//Person(String,int)
Constructor c2 = cls.getConstructor(String.class,int.class);
Object obj2 = c2.newInstance("赵六", 20);
System.out.println(obj2);
JDK5之后Java提供了的特性
package reflect;
/**
* JDK5之后Java提供了一个特性:变长参数
*/
public class ArgsDemo {
public static void main(String[] args) {
/*
doSome(1, new String[]{});
doSome(1, new String[]{"one"});
doSome(1, new String[]{"one", "two"});
doSome(1, new String[]{"one", "two", "three"});
doSome(1, new String[]{"one", "two", "three", "four"});
doSome(1, new String[]{"one", "two", "three", "four", "five"});
*/
doSome(1);
doSome(1, "one");
doSome(1, "one", "two");
doSome(1, "one", "two", "three");
doSome(1, "one", "two", "three", "four");
doSome(1, "one", "two", "three", "four", "five");
}
// public static void doSome(int a, String[] args) {
public static void doSome(int a, String... args) {
System.out.println(args.length);
}
}
Method类:反射对象之一,它的每一个实例用于表示一个类中的某个方法通过Method对象可以反应出该方法的相关信息:
Class cls = Class.forName("reflect.Person");
Method method = cls.getMethod("say",String.class,int.class);
Method method = cls.getDeclaredMethod("hehe"); //私有方法
Class cls = Class.forName("reflect.Person");
Method[] methods = cls.getMethods();
Class cls = Class.forName("reflect.Person");
Method[] methods = cls.getDeclaredMethods();
方法 | 作用 |
---|---|
String getName() | 获取方法名 |
int getModifiers | 获取方法的修饰符 |
int getParameterCount() | 获取方法参数个数 |
Class getReturnType | 获取方法返回值类型 |
Class[ ] getParamerTypes() | 获取方法的参数列表 |
Object invoke(Object obj,Object… args) | 执行该方法并获取返回值(如果有) |
public class ReflectDemo6 {
public static void main(String[] args) throws Exception {
//查看Person类中say(String,int)的相关信息
Class cls = Class.forName("reflect.Person");
Object obj = cls.newInstance();
Method method = cls.getMethod("say",String.class,int.class);
//获取方法名
String name = method.getName();
System.out.println("方法名:"+name);
//获取参数列表
Class[] parametersTypes = method.getParameterTypes();
for(Class pt : parametersTypes){
System.out.println("参数:"+pt);
}
//获取参数的个数
int parameterCounter = method.getParameterCount();
System.out.println("参数的个数:"+parameterCounter);
//获取返回值类型
Class returnType = method.getReturnType();
System.out.println("返回值类型:"+returnType);
//获取访问修饰符
int modifiers = method.getModifiers();
switch (modifiers){
case Modifier.PUBLIC:
System.out.println("访问修饰符:"+"public");
break;
case Modifier.PRIVATE:
System.out.println("访问修饰符:"+"private");
break;
case Modifier.PROTECTED:
System.out.println("访问修饰符:"+"protected");
break;
default:
System.out.println("访问修饰符:"+"default");
break;
}
//执行该方法
method.invoke(obj,"hello",3);
}
}
Field也是反射对象之一,用于表示类中的某个属性,很少会直接操作属性,因为属性建议都是私有的
public static void main(String[] args) throws Exception{
Teacher t = new Teacher();
t.name = "李老师";
System.out.println(t.name);
Class cls = Class.forName("reflect.Teacher");
Object obj = cls.newInstance();
/*
Filed也是反射对象之一,Field的每一个实例表示的是一个属性的信息
*/
Field field =cls.getField("name"); //获取Teacher中的name属性
field.set(obj,"王老师"); //obj.name = "王老师"
System.out.println(obj);
System.out.println(field.get(obj)); //System.out.println(obj.name)
}
像Field,Constructor,Method都提供了一个方法:setAccessible()。
该方法如果传入true,可以强行打开访问权限,用于访问本不可访问的内容。比如私有方法是不能在类的外部访问的,但是通过调用对应的Method对象的setAccessible方法可以强制打开访问权限
public static void main(String[] args) throws Exception {
String a = "abc"; //字面量创建的字符串对象会缓存在常量池
String b = "abc"; //重用a对象
System.out.println("a:"+a); //a:abc
System.out.println("b:"+b); //b:abc
Class cls = String.class; //Class cls = Class.forName("java.lang.String")
//获取对象a内部的value属性重新赋值
Field field = cls.getDeclaredField("value");
//打开访问权限的同时也破除了final的限制
field.setAccessible(true); //暴力反射,打开访问权限
field.set(a,new char[]{'h','e','l','l','o'}); //a.value = new char[]{'h','e','l','l','o'};
System.out.println("a:"+a); //a:hello
System.out.println("b:"+b); //b:hello
String c = "abc"; //依然重用常量池中a对象
System.out.println("c:"+c); //c:hello
}
注解(Annotation)是一种元数据(metadata)机制,可以使用注解来为代码中的各个部分添加额外
的信息,以帮助程序的编译、运行或者其他处理过程
// 关键字 注解名
public @interface AutoRunClass {}
注解可以在类的各个组成部分上使用,常见的位置:
@Target:用于标注当前注解可以被应用的位置.它的值对应枚举类:ElementType
@Retention:表示当前注解的保留级别,可选项是使用枚举RetentionPolicy表示的
@Target({ElementType.TYPE,ElementType.PACKAGE})
@Retention(RetentionPolicy.RUNTIME)
public @interface AutoRunClass {
}
注:在反射机制使用时必须是RUNTIME级别
所有反射对象都提供了一个方法: isAnnotationPresent(Class cls)用于判断反射对象表示的内容是否被指定的注解标注,参数为一个类对象,表示指定的注解的类对象
//获取Person的类对象
Class cls = Class.forName("reflect.Person");
//通过类对象判断是否被特定注解标注
boolean mark = cls.isAnnotationPresent(AutoRunClass.class);
System.out.println(mark?"被标注了":"没有被标注");
常见的反射对象:
注解可以指定参数,格式:类型 参数名() [DEFAULT 默认值]
使用注解传递参数时,使用的格式为: 参数名=参数值
当使用注解时,传参方式:
@AutoRunMethod(参数1名=参数1值,参数2名=参数2值,…)
注意:参数的顺序可以与定义时不一致
//以两个参数为例:
public @interface AutoRunMethod {
int num();
String name();
}
//实际使用时,传参可以:
@AutoRunMethod(num=1,name="张三")
@AutoRunMethod(name="张三",num=1)
有默认值时
public @interface AutoRunMethod {
int num() default 1;
String name();
}
//实际使用时可以忽略有默认值的参数,此时该参数使用默认值,传参可以:
@AutoRunMethod(name="张三")
当注解只有一个参数时(或者其他参数都有默认值时),参数名使用 value ,那么使用时可以忽略参数名
public @interface AutoRunMethod {
int value();
}
//实际使用时,传参可以:
@AutoRunMethod(1) //使用时可以忽略参数名
Annotation getAnnotation(Class cls)
@AutoRunMethod(5)
public void sayHello() {
System.out.println(name + ":hello!");
}
//获取Person类中sayHello()方法上的注解@AutoRunMethod中的value参数的参数值
public static void main(String[] args) throws Exception {
Class cls = Class.forName("reflect.Person");
Method method = cls.getMethod("sayHello");
if(method.isAnnotationPresent(AutoRunMethod.class)){
AutoRunMethod arm = method.getAnnotation(AutoRunMethod.class);
int value = arm.value();
System.out.println("参数value的值为:"+value);
}
}