java反射reflection
/**
* reflection反射
* 初次创建某一个类的对象时,JVM会先通过类加载器ClassLoader将类文件xxx.class从磁盘中加载到内存(io操作)
* 在方法区中将类生成一个类对象Class<xxx>对象,类对象/Class对象中有类文件的所有信息,每个类的Class对象只生成一个,用来创建类的所有对象
* 通过这个类的唯一的Class对象创建类的对象,当第二次及以后创建对象时,同样使用这个Class对象创建,不再重复加载类文件
*/
public class TestReflection1 implements Serializable {
//创建一个类
String name;
public int age;
public TestReflection1(String name, int age) {
this.name = name;
this.age = age;
}
private TestReflection1(String name) {
this.name = name;
}
//私有构造器
public TestReflection1(int age) {
this.age = age;
}
public TestReflection1() {
}
@Override
public String toString() {
return "TestReflection1{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
private void printAge(){
System.out.println(age);
}
//私有方法
public boolean setAge(int a){
age = a;
return true;
}
}
class GetClass{
public static void main(String[] args) {
TestReflection1 t1 = new TestReflection1("quan",20);
//Class对象在方法区,新的对象在堆heep,变量t1在栈stack中main栈帧中
Class<? extends TestReflection1> tClass = t1.getClass();
//通过实例化的对象.getClass()得到对象所属的类的Class对象,返回类型为Class<? extends 类名>,Class对象只有一份,所有实例化对象调用.getClass()会返回同一个Class对象
//每个实例化对象都是由这一个Class对象创建的
System.out.println(tClass);
//Class对象.toString() 返回“class 包名.类名”
System.out.println(tClass.getName());
//.getName()返回"包名.类名"
Class<GetClass> getClassClass = GetClass.class;
//通过类的静态属性.class得到Class对象,每个类都有class静态属性,当内存中没有该Class对象时JVM会去磁盘中加载
try {
Class<?> aClass = Class.forName("java.lang.String");
//通过Class类的静态方法.forName(String className)得到Class对象,字符串必须是完整的"包名.类名",返回类型为Class<?>因为编译时没有解析字符串只能用通配符
System.out.println(aClass);
} catch (ClassNotFoundException e) {
throw new RuntimeException(e);
}
Constructor<?>[] declaredConstructors = tClass.getDeclaredConstructors();
//Class对象.getDeclaredConstructors()方法返回构造器类数组Constructor[],declared声明的,返回的是这个类中的所有构造器类的对象,包括private等四种访问控制符修饰的所有构造器对象
for (Constructor<?> c :
declaredConstructors) {
System.out.println(c);
}
/*结果
public TestReflection1()
public TestReflection1(int)
private TestReflection1(java.lang.String)
public TestReflection1(java.lang.String,int)
*/
Constructor<?>[] constructors = tClass.getConstructors();
//不加declared的get只返回public的构造器
System.out.println(Arrays.toString(constructors));
//结果:[public TestReflection1(), public TestReflection1(int), public TestReflection1(java.lang.String,int)]
try {
Constructor<? extends TestReflection1> declaredConstructor = tClass.getDeclaredConstructor(int.class);
//不加s的get返回单个构造器,需要传入Class<?>...p可变参数对应构造器的形参类型,这里传入的是int.class即int的Class对象,返回只传一个int参数的构造器
System.out.println(declaredConstructor);
//结果:public TestReflection1(int)
// System.out.println(tClass.getConstructor(String.class));
//不加declared不加s,只查找public的构造器,但TestReflection1(String name)是private的,所以找不到传参为String的构造器,抛出异常java.lang.NoSuchMethodException: TestReflection1.<init>(java.lang.String)
System.out.println(tClass.getConstructor(null));
//只传null对应无参构造器,结果为:public TestReflection1() ,idea提示将null改为(Class<?>)null
// System.out.println(tClass.getConstructor(int.class,String.class));
//参数顺序和构造器形参顺序不同也会报错,形参顺序不同可以构成重载
Constructor<? extends TestReflection1> constructor = tClass.getConstructor(String.class, int.class);
TestReflection1 yang = constructor.newInstance("yang", 20);
//构造器对象.newInstance(Object...args)方法会生成新的对象,要求传入的参数和构造器的形参类型一致
} catch (NoSuchMethodException | InstantiationException | IllegalAccessException | InvocationTargetException e) {
throw new RuntimeException(e);
}
Field[] fields = tClass.getFields();
//.getFields()方法返回public的属性Field[]数组,和构造器对象一样,属性也是对象,这里的Field指成员变量,属于对象,不包含属于类的静态变量
System.out.println(Arrays.toString(fields));
//结果为:[public int TestReflection1.age]
for (Field declaredField : tClass.getDeclaredFields()) {
//加Declared忽略访问控制符,返回所有Field
System.out.print(declaredField.getName()+"\t");
//.getName()返回属性的名字,结果:name age
}
try {
Field age = tClass.getField("age");
//不加s返回单个,查找和传参的字符串名字一致的属性,public的属性
System.out.println(age);
//结果:public int TestReflection1.age
System.out.println(tClass.getDeclaredField("name"));
//加declared忽略访问控制符
TestReflection1 t2 = tClass.newInstance();
//通过Class对象.newInstance()创建无参的实例
age.set(t2,23);
//Field对象.set(类的对象,值) 用于设定指定类的对象的成员变量的值,上面通过.getField("age")得到了age属性的Field对象,引用变量为age
//通过Field对象age.set对指定t2的属性age的值进行设定,设定的值的类型同样需要小于等于属性的类型
System.out.println(age.get(t2));
//Field对象.get(类的对象)返回指定对象的成员变量的值,使用age.get()会返回age属性的值,传参t2会返回t2对象的age属性的值,返回值类型为Object
age.setInt(t2,24);
int i = age.getInt(t2);
//使用指定具体类型的set、get,setInt要求参数为int类型,getInt返回int类型参数而不是Object
//对于属性的使用和正常通过对象调用一样,受访问控制符的限制,在类外不能查改private属性(除非关闭安全检查)
} catch (NoSuchFieldException | IllegalAccessException | InstantiationException e) {
throw new RuntimeException(e);
}
Method[] methods = tClass.getMethods();
//.getMethods()返回所有public修饰的普通方法对象数组Method[]
for (Method m :
methods) {
System.out.println(m);
}
//继承的public方法也会返回,比如继承Object类的public final void java.lang.Object.wait(long,int) throws java.lang.InterruptedException
System.out.println(Arrays.toString(tClass.getDeclaredMethods()));
//返回类内声明的所有方法,declared声明,通过继承得到的但是类内没有声明的方法不会返回
// 结果为:[public java.lang.String TestReflection1.toString(), private void TestReflection1.printAge(), public boolean TestReflection1.setAge(int)]
// 返回内容中有toString是因为重写了toString方法
try {
Method method1 = tClass.getMethod("setAge", int.class);
//.getMethod(String name,Class<?>...types)和getConstructor()方法类似,需要指定方法名和形参列表,只能查找public修饰的方法
System.out.println(method1.getName());
//.getName()返回方法名,结果:setAge
System.out.println(tClass.getDeclaredMethod("printAge"));
//加declared忽略访问控制符,无参方法只传方法名
TestReflection1 t3 = tClass.newInstance();
Method setAge = tClass.getDeclaredMethod("setAge",int.class);
Method printAge = tClass.getDeclaredMethod("printAge");
Object a = setAge.invoke(t3, 23);
//Method方法对象.invoke(类的对象,对应形参的参数值),调用哪个方法对哪个对象。invoke调用,返回的是方法的返回值,setAge()方法返回boolean,向上转换为Object返回
System.out.println(a);
//结果:true
// Object pr = printAge.invoke(t3);
//对t3调用printAge方法,无参数,方法声明void时invoke()返回null,但由于printAge()方法为private,调用时抛异常java.lang.IllegalAccessException: Class GetClass can not access a member of class TestReflection1 with modifiers "private"
printAge.setAccessible(true);
//通过.setAccessible(true)关闭安全检查,设为true后JVM不再对该对象的调用检查访问控制符
Object pr = printAge.invoke(t3);
//不再报错,accessible可使用的,默认setAccessible(false)开启安全检查,受到访问控制符修饰的属性、方法、构造器等对象均可以通过setAccessible(true)关闭安全检查
} catch (NoSuchMethodException | IllegalAccessException | InstantiationException | InvocationTargetException e) {
throw new RuntimeException(e);
}
String n = tClass.getName();
//.getName()返回 包名.类名
Package aPackage = String.class.getPackage();
//.getPackage()返回包对象
System.out.println(aPackage);
//结果:package java.lang, Java Platform API Specification, version 1.8
System.out.println(aPackage.getName());
//结果:java.lang
System.out.println(tClass.getSimpleName());
//.getSimpleName()返回不含包名的类名
Class<?> superclass = tClass.getSuperclass();
//.getSuperclass()返回父类
System.out.println(superclass);
//结果为:class java.lang.Object
Class<?>[] interfaces = tClass.getInterfaces();
//.getInterfaces()返回当前类所实现的所有接口的Class对象数组
System.out.println(Arrays.toString(interfaces));
//结果为:[interface java.io.Serializable]
}
}