目录
6.多态问题
1.反射的定义
反射的定义:反射是指在运行期,对于任意一个类都能动态的调用信息及获取对象,即知道任意类的属性和方法,调用任意对象的方法和属性。
运行期是指将便后后的文件交给计算机执行,知道执行完毕,也就是将文件从磁盘上读取到内存中的过程。
2.反射的应用
反射主要应用在服务器和中间件程序之间得到广泛应用,而且还应用于各大煮酒框架中。如:在ORM框架的实现中,应用反射机制读取任意一个JavaBean对象的属性,给这些属性赋值。
3.反射的功能
(1)在运行时,判断任意一个对象所属的类。
(2)在运行时,为某个类构造对象。
(3)判断任意一个类的成员变量和方法。
(4)调用任意一个对象的方法。
(5)生成动态代理。
4.Class类
要想知道一个类的属性和方法,必须先获取该类的字节码文件,使用的就是Class类中的对象
classsJVM在执行过程中动态加载的,每读取一中class类型就会将其加载进内存,然后为其创建一个Class实例,并关联起来,每种不同类型的类都有一个Class实例。
4.1获取Class实例的方法:
(1)方式一:通过类名访问class
Class cls1=String.class;
(2)通过实例访问getClass对象
String s="abc";
Class cls2=s.getClass();
(3) 通过Class类的静态方法forName(类名)
Class cls3=Class.forName("java.lang.String");
4.2Class实例获取基本信息
Class cls=String.class;
System.out.println("类、接口的名称:"+cls.getName());
System.out.println("完全限定名:"+cls.getSimpleName());
System.out.println("类型名称:"+cls.getTypeName());
//包
Package p=cls.getPackage();
if(p!=null) {
System.out.println("类所在的包名:"+p);
}
获取父类
Class superClass=String.class.getClass();
System.out.println("父类:"+superClass.getName());
如果该类没有父类则获取的值为null
如果一个类实现了一个接口,它不仅可以实现接口中的抽象方法,还可以继承默认方法
4.3判断类型
Class cls=String.class;
System.out.println("是否为接口:"+cls.isInterface());
System.out.println("是否为数组"+cls.isArray());
System.out.println("是否为枚举类型:"+cls.isEnum());
4.4创建实例对象
Class cls=Class.forName("s07_11.Order");
Object obj1=cls.newInstance();
5.常用方法
5.1获取构造方法
获取所有公有构造方法(包含父类)
Constructor[] constructors=cls.getConstructors();
for(Constructor con:constructors) {
System.out.println(con);
}
获取所有的构造方法(不包含父类)
Constructor[] constructors2=cls.getDeclaredConstructors();
for (Constructor constructor2 : constructors2) {
System.out.println(constructor2);
}
获取一个构造方法
Constructor constructor=cls.getDeclaredConstructor(String.class);
获取有参数的有参构造方法(参数的类型填写顺序必须和有参构造中参数的顺序一致)
Constructor constructor=cls.getDeclaredConstructor(String.class);
调用有参构造方法创建实例
(在调用私有的有参构造方法要设置constructor.setAccessible(true))
Example ex=(Example)constructor.newInstance("aaa");
5.2访问字段(成员变量)
获取公有的字段·
Field [] fields=cls.getFields();
获取所有定义的字段(不包含父类)
Field[] fields=cls.getDeclaredFields();
for(Field f:fields) {
System.out.println("成员变量访问修饰符(int):"+f.getModifiers());
System.out.println("成员变量访问修饰符:"+Modifier.toString(f.getModifiers()));
System.out.println("成员变量类型:"+f.getType());
System.out.println("成员变量名:"+f.getName());
System.out.println();
}
使用反射完成成员变量保存值
Class cls=Book.class;//获取Class类型对象
Object obj=cls.newInstance();//通过反射创建Book类的对象
//按照字段名称,获取指定字段
Field field1=cls.getField("bookName");
//参数1:目标Book对象
//参数2:存入成员变量中的值
field1.set(obj, "平凡的世界");
//bookId是私有的
Field field2=cls.getDeclaredField("bookId");
field2.setAccessible(true);
field2.setInt(obj, 1);
5.3获取所有的方法
获取所有的public方法(包含父类)
Method[] methods=cls.getMethods();
获取所有的方法(不包含父类)
Method[] methods=cls.getDeclaredMethods();
for(Method m:methods) {
System.out.println("方法的修饰符类型:"+Modifier.toString(m.getModifiers()));
System.out.println("方法的返回值类型:"+m.getReturnType());
System.out.println("方法的名称:"+m.getName());
5.4获取参数类型
获取所有参数类型
Class[] parameterTypes=m.getParameterTypes();
获取所有参数对象
Parameter[] paarameter=m.getParameters();
for(Parameter p:paarameter) {
System.out.println(p.getName());
System.out.println(p.getType());
System.out.println("---------------------------");
}
按照方法名称和参数类型获取Method对象
Class cls=Book.class;
Object obj=cls.newInstance();
//Method对象的invoke作用
//以反射的方式执行create方法
Method method=cls.getMethod("dosth",int.class,double.class);
int r=(int)method.invoke(obj, 1,2);
System.out.println(r);
5.5调用静态方法
Class cls=Math.class;
Method method=cls.getMethod("log10", double.class);
int size=Double.valueOf((double)method.invoke(null, 12345)).intValue()+1;
System.out.println(size);
6.多态问题
创建一个Person对象,并定义hello()方法,Student类继承了Person类并重写了hello方法,那么Person.class获取的Method作用于Student调用的是那个类的hello方法呢? 调用的是Student的hello方法
public class Demo05 {
public static void main(String[] args) throws NoSuchMethodException, SecurityException, IllegalAccessException, IllegalArgumentException, InvocationTargetException {
Method m=Person.class.getMethod("hello") ;
m.invoke(new Student());
}
}
class Person{
public void hello() {
System.out.println("Person.hello");
}
}
class Student extends Person{
public void hello() {
System.out.println("Student.hello");
}
}
该代码的执行过程相当于(父类的引用指向子类实例)
Person p=new Student();
p.hello()
通过反射调用方法时任然遵循多态原则。