Class和class
回顾java的数据类型,基本数据类型和引用数据类型,int,long,float,double,boolean,Object(?)
除了使用java定义的基本数据类型,自定义的类(或者接口)也是一种类型-- Class,每个类都有一个对应的Class实例
//如
Class class = new Class();
以String类为例,当JVM加载String类时,它首先读取String.class文件到内存,然后,为String类创建一个Class实例并关联起来:
Class cls = new Class(String);
而这个class实例是jvm在第一次加载某个类的时候自动创建的,注意我们用户并不能创建Class,代码层面解释的话就是Class类的构造方法是private类型的,这个Class实例保存了这个类的字段,方法,继承结构等等的信息,通过这个Class实例获取对应类(class)信息的方式,就叫反射
获取Class实例
//1.
Class c1= String.class;
//2.
String s = new String();
Class c2= s.getClass();
//3.
Class c3= Class.forName("java.lang.String");
获取字段信息
Field f1 = c2.getField("length");//根据字段名获取某个public的field(包括父类)(注意是public限制符)
Field f2 = c2.getDeclaredField("length");//根据字段名获取当前类的某个field(不包括父类)(没有限制符的限制)
Field[] f3 = c2.getFields();//同上
Field[] f4 = c2.getDeclaredFields();
//获取字段值
Object value = f.get(s);
System.out.println(value);
//修改值
f.set(s,"sth");
获取成员方法信息
Method getMethod(name, Class...)//方法参数的Class实例,方法的意义同上
Method getDeclaredMethod(name, Class...)
Method[] getMethod()
Method[] getDeclaredMethod()
//public方法调用
invoke(Instance , Object...)//实例,方法入参
//静态方法调用
invoke(null, Object...)//静态方法与实例对象没有联系,所以传入的第一个参数永远为null(经过试验,调用静态方法第一个参数不影响调用)
//非公共方法调用同上公共方法,但是可能会调用失败,抛出IllegalAccessException
setAccessible(true);
//通过调用这个方法允许其调用,不过也可能会失败,jvm为了保护自己的核心类库会不允许
构造方法
有Class实例后可以使用Class实例创建新的实例对象0
String s= = String.class.newInstance();
这种创建方式的局限是只能调用该类的public无参构造方法,如果构造方法带有参数,或者不是public,就无法直接通过Class.newInstance()来调用
同样,java反射api也有构造方法的操作类,基本和Method一样,但是构造方法返回的结果就是一个实例,因为它是构造方法
Constructor cons = String.class.getConstructor(parameterTypes...);//无参可以传null
获取父类的Class
Class n = s.getSuperclass();
获取实现的接口
Class[] is = s.getInterfaces();
JDK动态代理
学习spring的过程中了解到的一个用法,我认为jdk的动态代理有一个最大的局限就是只能代理接口
先定义了接口Hello,但是并不去编写实现类,而是直接通过JDK提供的一个 Proxy.newProxyInstance() 创建了一个Hello接口对象。这种没有实现类但是在运行期动态创建了一个接口对象的方式,称为动态代码。JDK提供的动态创建接口对象的方式,就叫动态代理。
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
public class Main {
public static void main(String[] args) {
InvocationHandler handler = new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println(method);
if (method.getName().equals("morning")) {
System.out.println("Good morning, " + args[0]);
}
return null;
}
};
Hello hello = (Hello) Proxy.newProxyInstance(
Hello.class.getClassLoader(), // 传入ClassLoader
new Class[] { Hello.class }, // 传入要实现的接口
handler); // 传入处理调用方法的InvocationHandler
hello.morning("Bob");
}
}
interface Hello {
void morning(String name);
}