反射的好处
- 反射不仅可以让我们获得隐藏的方法和属性,还可以让对象的实例化从编译时转化为运行时,因为我们可以通过Class.forName(“cc.abto.demo.Book”).newInstance()的方法来生成新的实例
反射的弊端
- 反射带来的两大弊端可能就是安全和性能问题
类类型,类的动态加载
package com.zhangyu;
public class ClassTest {
public static void main(String[] args) {
//Test的实例对象如何表示
Test test1 = new Test();//test1就表示出来了
//Test这个类也是一个实例对象,Class类的实例对象
//任何一个类都是Class的实例对象,这个实例对象有三种表示方法
//方式1,任何一个类都有一个隐含的静态成员变量
Class c1 = Test.class;
//方式2,已知该类的对象通过getClass方法
Class c2 = test1.getClass();
//c1,c2表示了Test类的类类型class type
System.out.println(c1 == c2);//true
//方式3,动态加载类(编译时刻加载类是静态加载,运行时刻加载类是动态加载)
Class c3 = null;
try {
c3 = Class.forName("com.zhangyu.Test");
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
System.out.println(c2 == c3);//true
//可以通过类的类类型来创建该类的对象实例。通过c1,c2,c3创建Test的实例
try {
Test test = (Test) c1.newInstance();
test.print();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
}
class Test {
void print(){
System.out.println("test");
}
}
获取方法信息、成员变量信息、构造方法信息
package com.zhangyu;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
public class ClassUtil {
public static void main(String[] args) {
String s = "hello";
printMethodInfo(s);
printFieldInfo(s);
printConstructorInfo(1);
}
/**
* 获取成员函数信息 public
*
* @param object
*/
public static void printMethodInfo(Object object) {
//首先获取类类型
Class<?> clazz = object.getClass();
//获取类的名称
System.out.println("类的名称是:" + clazz.getName());
/**
* 获取类中的方法
* 每一个方法成员就是一个Method对象
* getMethods()获取所有public方法,包括父类继承来的
* getDeclaredMethods()获取的是该类中所有自己声明的方法(pulic、private、protect)(不包括父类继承来的)
*/
//getMethods获取所有public方法
Method[] methods = clazz.getMethods();
for (int i = 0; i < methods.length; i++) {
Method method = methods[i];
System.out.println("-----------");
//得到方法名称
String methodName = method.getName();
System.out.println("方法名:" + methodName);
//得到方法的返回值类型
Class<?> returnType = method.getReturnType();
System.out.println("返回值类型:" + returnType.getName());
//获取参数类型
Class<?>[] parameterTypes = method.getParameterTypes();
System.out.print("参数类型:");
for (int j = 0; j < parameterTypes.length; j++) {
Class<?> parameterType = parameterTypes[j];
System.out.print(parameterType.getName() + " ");
}
System.out.println("");
}
}
/**
* 获取成员变量信息
* 成员变量也是对象
* java.lang.reflect.Field
* Field封装了关于成员变量的操作
* getFields()方法获取的是所有的public的成员变量的信息
* getDeclaredField()获取的是该类自己声明的成员变量的信息
*/
public static void printFieldInfo(Object object) {
Class<?> clazz = object.getClass();
Field[] fields = clazz.getDeclaredFields();
System.out.println("-----------");
for (int i = 0; i < fields.length; i++) {
Field field = fields[i];
//得到成员变量的类类型
Class<?> classType = field.getType();
String typeName = classType.getName();
//得到成员变量名称、
String fieldName = field.getName();
System.out.println(typeName + " " + fieldName);
}
}
/**
* 获取构造方法的信息
* getConstructors()
* getDeclaredConstructors()
*
* @param object
*/
public static void printConstructorInfo(Object object) {
Class<?> clazz = object.getClass();
Constructor<?>[] constructors = clazz.getDeclaredConstructors();
System.out.println("-----------");
for (int i = 0; i < constructors.length; i++) {
Constructor<?> constructor = constructors[i];
System.out.print(constructor.getName() + "(");
Class<?>[] parameterTypes = constructor.getParameterTypes();
for (int j = 0; j < parameterTypes.length; j++) {
Class<?> parameterType = parameterTypes[j];
System.out.print(parameterType.getName()+",");
}
System.out.println(")");
}
}
}
类的名称是:java.lang.String
-----------
方法名:equals
返回值类型:boolean
参数类型:java.lang.Object
-----------
方法名:length
返回值类型:int
参数类型:
-----------
方法名:toString
返回值类型:java.lang.String
参数类型:
-----------
方法名:hashCode
返回值类型:int
参数类型:
-----------
[B value
byte coder
int hash
boolean hashIsZero
long serialVersionUID
boolean COMPACT_STRINGS
[Ljava.io.ObjectStreamField; serialPersistentFields
java.util.Comparator CASE_INSENSITIVE_ORDER
byte LATIN1
byte UTF16
-----------
java.lang.Integer(java.lang.String,)
java.lang.Integer(int,)
方法的反射
- 如何获取某个方法?
方法的名称和方法的参数列表才能唯一决定某个方法 - 方法的反射如何操作?
method.invoke(参数列表)
package com.zhangyu;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
public class MethodTest {
public static void main(String[] args) {
//获取A类中的print方法
//print(int a, int b)
//获取A的类类型
A a1 = new A();
Class<? extends A> clazz = a1.getClass();
//获取类的信息
//Method method = clazz.getMethod("print", new Class[]{int.class, int.class});
try {
System.out.println("-----------");
Method method = clazz.getMethod("print", int.class, int.class);
//方法的反射操作,用method对象来进行方法的调用,和a1.print的效果相同
Object invoke = method.invoke(a1,1, 2);
System.out.println("-----------");
method = clazz.getMethod("print", String.class, String.class);
//方法的反射操作,用method对象来进行方法的调用,和a1.print的效果相同
invoke = method.invoke(a1,"hello", "world");
} catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException e) {
e.printStackTrace();
}
}
}
class A {
public void print(int a, int b) {
System.out.println(a + b);
}
public void print(String a, String b) {
System.out.println(a.toUpperCase() + "," + b.toUpperCase());
}
}
-----------
3
-----------
HELLO,WORLD
通过反射了解Java泛型的本质
package com.zhangyu;
import java.lang.reflect.Method;
import java.util.ArrayList;
public class GenericsTest {
public static void main(String[] args) {
ArrayList list1 = new ArrayList();
ArrayList<String> list2 = new ArrayList<>();
list2.add("hello");
// list2.add(1);//错误,因为限定了String类型
//得到两个类类型
Class c1 = list1.getClass();
Class c2 = list2.getClass();
System.out.println(c1 == c2);//两个类类型相同,true
//反射的操作都是在编译之后进行的
//c1==c2结果返回true说明编译后是去泛型化的
//Java中集合的泛型,是防止错误输入的,只在编译阶段有效
//我们可以用通过方法的反射来向list2中加入int类型
Method add = null;
try {
add = c2.getMethod("add", Object.class);
add.invoke(list2,"hello");
add.invoke(list2,100);
System.out.println(list2);
} catch (Exception e) {
e.printStackTrace();
}
}
}
true
[hello, hello, 100]