新建测试类:
public class Dog implements Animal {
private String name;
String color;
@Override
public void say() {
System.out.println("dog..say..");
}
public void run(){
System.out.println("dog..run..");
}
public void eat(String S){
System.out.println("dog..eat.."+S);
}
//....
public Dog() {
}
public Dog(String name, String color) {
this.name = name;
this.color = color;
}
}
第一步:理解class类
1.Class是一个类,封装了当前对象所对应的类的信息
2.一个类中有属性,方法,构造器等,比如说有一个Person类,一个Order类,这些都是不同的类,现在需要一个类,用来描述类,这就是Class,
它应该有类名,属性,方法,构造器等。Class是用来描述类的类。
3.对于每个类而言,JRE 都为其保留一个不变的 Class 类型的对象。
4.Class 对象只能由系统建立对象,一个类(而不是一个对象)在 JVM 中只会有一个Class实例。
@Test
public void test5(){
Class clazz1=Dog.class;
Class clazz2=Dog.class;
System.out.println(clazz1);
System.out.println(clazz2);
System.out.println(clazz1==clazz2);//true
}
获取Class对象的三种方式:
1.通过类名获取 类名.class
Class clazz=Dog.class;
2.通过对象获取 对象名.getClass()
Dog dog=new Dog();
Class clazz=dog.getClass();
3.通过全类名获取 Class.forName(全类名)
Class clazz=Class.forName("com.utils.Dog");
Class类的常用方法:
第二步:ClassLoader
类装载器是用来把类(class)装载进 JVM 的。JVM 规范定义了两种类型的类装载器:启动类装载器(bootstrap)和用户自定义装载器(user-defined class loader)。 JVM在运行时会产生3个类加载器组成的初始化加载器层次结构。
第三步:反射概述
Reflection(反射)是Java被视为动态语言的关键,反射机制允许程序在执行期借助于Reflection API取得任何类的內部信息,并能直接操作任意对象的内部属性及方法。
Java反射机制主要提供了以下功能:
在运行时构造任意一个类的对象
在运行时获取任意一个类所具有的成员变量和方法
在运行时调用任意一个对象的方法(属性)
生成动态代理
1.获取对象中的method
public void test() throws Exception {
//获取Dog.class的对象
Class dogClass=Dog.class;
//获取Dog.class所有的方法,包括父类方法,不包括私有方法
//Method[] methods=dogClass.getDeclaredMethods();
//获取Dog.class所有的方法,包括私有方法,不包括父类方法
Method[] methods=dogClass.getDeclaredMethods();
for(Method method:methods){
System.out.println(method.getName());
}
//返回该Class对象的一个实例
Object objects= dogClass.newInstance();
//获取无参方法 say( )
Method method=dogClass.getDeclaredMethod("say");
//第一个参数表示执行哪个对象的方法,剩下的参数是执行方法时需要传入的参数
method.invoke(objects,null);
//获取带参方法 eat( ),参数类型为String.class
method=dogClass.getDeclaredMethod("eat",String.class);
method.invoke(objects,"骨头");
}
2.获取对象中的field
public void test() throws Exception{
Class clazz=Dog.class;
//获取所有字段属性,包括私有,不包括继承
Field fields[]= clazz.getDeclaredFields();
for (Field field:fields){
System.out.println(field.getName()+"---"+field.getType());
}
//获取所有继承字段属性
fields = clazz.getFields();
for (Field field:fields){
System.out.println(field.getName()+"---"+field.getType());
}
//获取非私有字段属性
Field field=clazz.getDeclaredField("color");
Object object=new Dog();
//设置字段属性值
field.set(object,"red");
System.out.println("field.get(object)="+field.get(object));
//获取私有字段属性
field=clazz.getDeclaredField("name");
object=new Dog();
field.setAccessible(true);
//设置字段属性值
field.set(object,"tom");
System.out.println("field.get(object)="+field.get(object));
}
3.获取对象的构造方法
public void test() throws Exception{
Class clazz=Dog.class;
//获取所有构造函数
Constructor[] constructors= clazz.getConstructors();
for (Constructor constructor:constructors){
System.out.println(constructor);
}
//获取无参构造方法
Constructor constructor= clazz.getConstructor(new Class[]{});
System.out.println("无参构造 "+constructor);
constructor=clazz.getConstructor(new Class[]{String.class,String.class});
System.out.println("带参构造 "+constructor);
}
5.看到这里,我们自己动手设计一个工具方法。
//自定义反射方法 类对象和类方法名作为参数,执行方法
public Object myInvoke(Class object,String methodName,Object...args) throws Exception, InstantiationException {
//把参数转化为对应的class对象
Class[] argsClass=new Class[args.length];
for (int i=0;i<args.length;i++){
argsClass[i]=args[i].getClass();
System.out.println(argsClass[i]);
}
//获取方法
Method method=object.getDeclaredMethod(methodName,argsClass);
//执行方法
return method.invoke(object.newInstance(),args);
}
测试:
public void test() throws Exception {
Object args[]=new Object[]{};
Object result= myInvoke(Dog.class,"say",args);
System.out.println("result="+result);
}
6.我们再设计一个工具方法,不但能访问当前类的私有方法,还要能访问父类的私有方法
一般使用getDeclaredMethod获取方法(因为此方法可以获取类的私有方法,但是不能获取父类方法),如何获取父类方法呢?
public Method getMethodForClass(Class clazz,String methodName,Class[] parameterTypes) throws NoSuchMethodException {
for(;clazz != Object.class; clazz = clazz.getSuperclass()){
try {
Method method = clazz.getDeclaredMethod(methodName, parameterTypes);
if(method==null){
continue;
}
return method;
} catch (Exception e) {
System.out.println(e);
}
}
return clazz.getDeclaredMethod(methodName, parameterTypes);
}
第四步:文章小结
1. Class: 是一个类; 一个描述类的类.封装了描述方法的 Method,描述字段的 Filed,描述构造器的 Constructor 等属性.
2. 如何得到 Class 对象:
2.1 Person.class
2.2 person.getClass()
2.3 Class.forName("com.atguigu.javase.Person")
3. 关于 Method:
3.1 如何获取 Method:
1). getDeclaredMethods: 得到 Method 的数组.
2). getDeclaredMethod(String methondName, Class ... parameterTypes)
3.2 如何调用 Method
1). 如果方法是 private 修饰的, 需要先调用 Method 的 setAccessible(true), 使其变为可访问
2). method.invoke(obj, Object ... args);
4. 关于 Field:
4.1 如何获取 Field: getField(String fieldName)
4.2 如何获取 Field 的值:
1). 如果Field是 private 修饰的, 需要先调用 Field 的 setAccessible(true),setAccessible(true)
2). field.get(Object obj)
4.3 如何设置 Field 的值:
field.set(Obejct obj, Object val)
5. 了解 Constructor