一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第9天,点击查看活动详情。
啥是反射?
在加载完类后,堆里面产生了应该class对象,我们可以通过这个class对象看到类的源码结构。这个class对象就像一面镜子,透过他可以看到类结构,所以我们把这个叫做反射。
一般情况,我们引入包类名称,然后new得到对象,进行该对象内部属性和方法的操作
反射方式:先实例化对象,然后透过getClass()方法得到该类的全类名(包名.类名)
这么写反射代码?
拿到反射入口
1.通过Class.forName("全类名")
但是这个需要捕获异常
// 1.class.forname(全类名)
try {
Class<?> perClass=Class.forName("reflect.person");
System.out.println(perClass);
} catch (ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
2.通过全类名.class
3.通过对象.class
先对我们要操纵的对象实例化(new),然后对象.getClass
这里我们的实体类是person
person代码
package reflect;
public class person implements{
private int age;
private String name;
public int hhqq;
private void privatemethod() {
System.out.println("私有方法");
}
@Override
public String toString() {
return "person [age=" + age + ", name=" + name + "]";
}
public person(int age, String name) {
super();
this.age = age;
this.name = name;
}
private person( String name) {
super();
this.name = name;
}
public person(int age) {
super();
this.age = age;
}
public person() {
super();
// TODO Auto-generated constructor stub
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
拿到反射入口代码
package reflect;
public class 拿到反射入口 {
public static void main(String[] args) {
// 1.class.forname(全类名)
try {
Class<?> perClass=Class.forName("reflect.person");
System.out.println(perClass);
} catch (ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
// 2. 全类名.class
Class<?> perClass1=reflect.person.class;
System.out.println(perClass1);
// 3.对象.getClass
person p=new person();
Class<?> perClass2=p.getClass();
System.out.println(perClass2);
}
}
上面运行结果是 class 包名.person
反射的相关方法
获取public方法
Method[]method=perClass1.getMethods();
for(Method m:method) {
System.out.println(m);
// 拿到的是全类名,而且还有object里面的方法,重新的接口方法,但是没有私有方法
}
运行结果比如
public java.lang.String reflect.person.getName()
其实等于person类里面的 public String getName()方法
获取全部方法,但是只能是当前类的
Method[]method1=perClass1.**getDeclaredMethods()**;;
for(Method m:method1) {
System.out.println(m);
// 拿到的是全类名,有私有方法 }
获取父类
Class<?> fac=perClass1.getSuperclass();
System.out.println(fac);
获取构造方法
System.out.println("---------------------------------");
Constructor<?>[] meth=perClass1.getConstructors();
for(Constructor c:meth) {
System.out.println(c);
}
拿到公共属性
Field[]md=perClass1.getFields();
for(Field m:md) {
// 拿到的是全类名,而且还有object里面的方法,重新的接口方法,但是没有私有方法
System.out.println(m);
}
拿到所有属性
Field[]md1=perClass1.getDeclaredFields();
for(Field m:md1) {
// 拿到所有方法
System.out.println(m);
}
获取person对象
try {
Object in=perClass1.newInstance();
person pp=(person) in;
pp.systest1();
} catch (InstantiationException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IllegalAccessException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
获取接口
先添加接口类,然后然person继承接口
Class<?>[] inter=perClass1.getInterfaces();
for(Class iq:inter) {
System.out.println(iq);
}
完整代码:
package reflect;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
public class 获取反射方法 {
public static void main(String[] args) {
// 2. 拿到反射入口
Class<?> perClass1=reflect.person.class;
System.out.println(perClass1);
// 拿方法
//1.所有公共方法
Method[]method=perClass1.getMethods();
int i=0;
for(Method m:method) {
System.out.println(m);
i++;
// 拿到的是全类名,而且还有object里面的方法,重新的接口方法,但是没有私有方法
}
System.out.println(i);
System.out.println("=============================================");
// 拿全部方法,只能当前类
Method[]method1=perClass1.getDeclaredMethods();
int j=0;
for(Method m:method1) {
System.out.println(m);
j++;
// 拿到的是全类名,有私有方法
}
System.out.println(j);
System.out.println("---------------------------------");
// 2.获取所有接口
Class<?>[] inter=perClass1.getInterfaces();
for(Class iq:inter) {
System.out.println(iq);
}
System.out.println("---------------------------------");
// 获取父类
Class<?> fac=perClass1.getSuperclass();
System.out.println(fac);
// 获取构造方法
System.out.println("---------------------------------");
Constructor<?>[] meth=perClass1.getConstructors();
for(Constructor c:meth) {
System.out.println(c);
}
System.out.println("---------------------------------");
// 拿到公共属性
Field[]md=perClass1.getFields();
for(Field m:md) {
System.out.println(m);
// 拿到的是全类名,而且还有object里面的方法,重新的接口方法,但是没有私有方法
}
System.out.println("---------------------------------");
// 拿到所有属性
Field[]md1=perClass1.getDeclaredFields();
for(Field m:md1) {
System.out.println(m);
// 拿到的是全类名,而且还有object里面的方法,重新的接口方法,但是没有私有方法
}
System.out.println("---------------------------------");
//获取代表对象
try {
Object in=perClass1.newInstance();
person pp=(person) in;
pp.systest1();
} catch (InstantiationException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IllegalAccessException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
person
package reflect;
public class person implements myinterface,myinterface2{
private int age;
private String name;
public int hhqq;
private void privatemethod() {
System.out.println("私有方法");
}
@Override
public String toString() {
return "person [age=" + age + ", name=" + name + "]";
}
public person(int age, String name) {
super();
this.age = age;
this.name = name;
}
private person( String name) {
super();
this.name = name;
}
public person(int age) {
super();
this.age = age;
}
public person() {
super();
// TODO Auto-generated constructor stub
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public void systest() {
// TODO Auto-generated method stub
System.out.println("test myinterface");
}
@Override
public void systest1() {
// TODO Auto-generated method stub
System.out.println("test myinterface2");
}
}
接口
package reflect;
public interface myinterface {
public void systest();
}
package reflect;
public interface myinterface2 {
public void systest1();
}
通过反射操纵对象
先拿到反射入口,然后拿到反射对象,然后getDeclaredField,对象.方法操作属性
注意因为属性是私有的需要通过setAccessible(true),然反射可以操纵他
getDeclaredField(属性)
set(操作对象,值)
代码
package reflect;
import java.lang.reflect.Field;
public class 通过反射操纵对象 {
public static void demo1() {
Class<?> p1 = reflect.person.class;
// System.out.println(p1);
try {
Object in = p1.newInstance();
person pp = (person) in;
// pp.systest1();
pp.setAge(10);
pp.setName("zs");
System.out.println(pp);
System.out.println("===============");
System.out.println(pp.getAge() + "," + pp.getName());
} catch (InstantiationException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IllegalAccessException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public static void demo2() {
Class<?> p1 = reflect.person.class;
try {
Object in = p1.newInstance();
person pp = (person) in;
访问,person里面age属性
Field f = p1.getDeclaredField("age");
/*
* private 是本类才能,这里不能访问 f.set(pp, 10); System.out.println(pp.getAge());
*/
// 修改属性访问权限
f.setAccessible(true);
给age设置值10,
f.set(pp, 10);
System.out.println(pp.getAge());
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
//同理。给方法,用Method.setAccessible(true);,然后 f.invork();
public static void main(String[] args) {
demo1();
demo2();
}
}
通过反射操作构造方法
package reflect;
import java.lang.reflect.Constructor;
public class 操纵构造方法 {
public static void main(String[] args) {
Class<?> p1=reflect.person.class;
// System.out.println(p1);
try {
// 公共
Constructor<?> con=p1.getConstructor(int.class);
System.out.println(con);
// 私有
Constructor<?> con1=p1.getDeclaredConstructor(String.class);
System.out.println(con1);
//
Constructor<?> con2=p1.getConstructor();
person inst=(person)con2.newInstance();
System.out.println(inst);
//
con1.setAccessible(true);
person inst1=(person)con1.newInstance("zs");
System.out.println(inst1);
} catch (NoSuchMethodException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
面试题目
1. 描述一下JVM加载class文件的原理机制?
答:JVM中类的装载是由ClassLoader和它的子类来实现的,Java ClassLoader 是一个重要的Java运行时系统组件。它负责在运行时查找和装入类文件的类。
2. 利用反射和重载完成以下功能
1)创建Student类,类中有属性name和age并封装属性
2)重载Student的构造函数,一个是无参构造并,另一个是带两个参数的有参构造,要求在构造函数打印提示信息
3)创建带main函数的NewInstanceTest类,利用Class类得到Student对象
4)通过上述获取的Class对象分别调用Student有参函数和无参函数
3. 利用反射的知识完成下面的操作
1)创建Mytxt类,创建myCreate()方法完成创建文件。创建带main方法的NewInstanceTest类,通过Class类获取Mytxt对象,调用myCreat()
4. 利用Annotation和反射知识完成操作
1)自定义一个有效的Annotation注释名为MyAnnotation,其中有属性myname创建Student类并重写toString(),toString()要求使用三个基本的Annotation和自定义的MyAnnotation注释
2)创建TestGetAnno类,打印出Student类的toString方法的所有注释
5. 利用通过反射修改私有成员变量
1. 定义PrivateTest类,有私有name属性,并且属性值为hellokitty,只提供name的getName的公有方法
2. 创建带有main方法ReflectTest的类,利用Class类得到私有的name属性
3. 修改私有的name属性值,并调用getName()的方法打印name属性值
6. 利用反射和File完成以下功能
1. 利用Class类的forName方法得到File类
2. 在控制台打印File类的所有构造器
3. 通过newInstance的方法创建File对象