1.反射的概念
- 在运行状态中,对于任意一个类都能够知道这个类所有的属性和方法; 并且对于任意一个对象,都能够调用它的任意一个方法;这种动态获取信息以及动态调用对象方 法的功能成为 Java 语言的反射机制。
2.反射的使用
2.1 获取Class对象
方式一:通过对象的getClass()方法获取 。如果类中有定义静态块则会运行它
public class ReflectTest {
public static void main(String[] args) {
ReflectTest reflectTest = new ReflectTest();
Class clazz = reflectTest.getClass();
System.out.println(clazz);
}
}
方式二:通过类的classs属性获取。如果类中有定义静态块则会运行它
public class ReflectTest {
public static void main(String[] args) {
Class clazz = ReflectTest.class;
System.out.println(clazz);
}
}
方式三:通过Class的forName静态方法,forName有两个重载方法,className参数方法在创建Class对象时默认执行类中定义的静态代码块。另外一个forName方法通过参数控制是否需要运行静态代码块,并指定类加载器。
public class ReflectTest {
static {
System.out.println("静态代码块");
}
public static void main(String[] args) {
try {
//会执行静态代码块
Class clazz = Class.forName("com.javabase.reflect.ReflectTest");
System.out.println(clazz);
//通过false指定不执行静态代码块
Class clazzFalse =Class.forName("com.javabase.reflect.ReflectTest",false,ClassLoader.getSystemClassLoader());
System.out.println(clazzFalse);
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
}
//这里通过true表明需要执行静态代码块
@CallerSensitive
public static Class<?> forName(String className)
throws ClassNotFoundException {
Class<?> caller = Reflection.getCallerClass();
return forName0(className, true, ClassLoader.getClassLoader(caller), caller);
}
2.2 获取Class对象的方法集合
- java.lang.Class#getMethod(String name, Class<?>… parameterTypes):获取指定名称的public方法,包含继承的父类方法。
- java.lang.Class#getMethods:获取所有public类型的方法,包括继承类的公共方法
- java.lang.Class#getDeclaredMethods:获取类或接口声明的所有方法,包括公共、保护、默认(包)访问和私有方法,但不包括继承的方法
public class ReflectTest extends ParentReflect {
static {
System.out.println("静态代码块");
}
private String name;
public static final int age = 0;
public String address;
private String getName() {
return name;
}
protected void setName(String name) {
this.name = name;
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
public static void main(String[] args) {
try {
Class clazz = Class.forName("com.javabase.reflect.ReflectTest");
//通过指定方法名获取方法,只能获取public类型的方法,包括继承类的公共方法
Method methodByName = clazz.getMethod("getParentName");
System.out.println(methodByName);
//获取所有public类型的方法,包括继承类的公共方法
Method[] methods = clazz.getMethods();
for (Method method : methods) {
System.out.println(method);
}
//获取类或接口声明的所有方法,包括公共、保护、默认(包)访问和私有方法,但不包括继承的方法
Method[] methodAll = clazz.getDeclaredMethods();
for (Method method : methodAll) {
System.out.println(method);
}
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (NoSuchMethodException e) {
e.printStackTrace();
}
}
}
2.3 获取构造方法
public class ReflectTest extends ParentReflect {
static {
System.out.println("静态代码块");
}
public ReflectTest() {
}
private ReflectTest(String name, String address) {
this.name = name;
this.address = address;
}
private String name;
public static final int age = 0;
public String address;
private String getName() {
return name;
}
protected void setName(String name) {
this.name = name;
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
public static void main(String[] args) {
try {
Class clazz = Class.forName("com.javabase.reflect.ReflectTest");
//获取当前类的公共构造函数
Constructor[] constructors = clazz.getConstructors();
for (Constructor constructor : constructors) {
System.out.println(constructor);
}
//获取指定参数的公共构造函数
Constructor constructor =clazz.getConstructor();
System.out.println(constructor);
//获取类或接口声明的所有构造函数,包括公共、保护、默认(包)访问和私有方法
Constructor[] constructorAll = clazz.getDeclaredConstructors();
for (Constructor cons : constructorAll) {
System.out.println(cons);
}
} catch (ClassNotFoundException e) {
e.printStackTrace();
}catch (NoSuchMethodException e){
e.printStackTrace();
}
}
}
2.4获取成员变量
- getFiled:访问公有的成员变量
- getDeclaredField:所有已声明的成员变量,但不能得到其父类的成员变量
2.5创建对象的两种方法
- java.lang.Class#newInstance:
clazz.newInstance()
- java.lang.reflect.Constructor#newInstance:
constructor.newInstance()
2.6 反射机制的优缺点
- 优点:可以动态执行,在运行期间根据业务功能动态执行方法、访问属性,最大限度发挥了java的灵活性。
- 缺点:反射的效率很低,而且会破坏封装,通过反射可以访问类的私有方法,不安全。