声明一个对象,但是此对象需要实例化之后才能使用。
3.1 认识反射:
正常情况下,一个类要想使用,必须先找到这个类,然后才能创建对象,必须要先有类 再有对象。
public finalClass<?> getClass();此可以方法返回一个class,通过class就可以完成反射的操作。
3.2.认识class类:
在反射机制中,class 是一个源头,所有的反射操作从此类展开,实例化Class类,可以通过下面的三种方式:
通过Object类中的getClass()方法
通过类.Class的形式
通过Class.forName();//推荐使用的方式
3.3通过Class类实例化对象:
在class的使用中,实例化对象,是最常用的一种操作。而且日后所有框架的实现原理都是依靠Class来完成的。
3.3.1.实例化无参构造的类(最重要):
package org.lxh.demo.classdemo02;
public class Person {
public StringtoString(){
return"hello World";
}
}
通常是通过关键字new来实例化对象,但是现在通过Class来完成。按照以下的步骤。
1.根据包.类名称实例化class对象。
2.通过Class类中的以下方法
public TnewInstance()
throws InstantiationException,
IllegalAccessException
packageorg.lxh.demo.classdemo02;
public classInstanceDemo01 {
public static void main(String[]args) {
Class<?>c = null ;
try {
c =Class.forName("org.lxh.demo.classdemo02.Person");
} catch(ClassNotFoundException e) {
//TODO Auto-generated catch block
e.printStackTrace();
}
try {
Personp = (Person)c.newInstance();
System.out.println(p);
} catch(InstantiationException e) {
//TODO Auto-generated catch block
e.printStackTrace();
} catch(IllegalAccessException e) {
//TODO Auto-generated catch block
e.printStackTrace();
}
}
}
以上程序能正常实例化一个对象。
packageorg.lxh.demo.classdemo03;
public class Person{
private String name;
private int age;
public Person(String name ,intage){
this.setName(name);
this.setAge(age);
}
public String toString(){
return "helloWorld";
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
具有有参构造方法,这个程序因为没有无参构造方法,所以会报错
Exception in thread"main" java.lang.ClassCastException: org.lxh.demo.classdemo02.Person
atorg.lxh.demo.classdemo03.InstanceDemo02.main(InstanceDemo02.java:14)
3.3.2实例化指定构造的类
以上的的操作中,必须存在一个无参的构造方法,而如果现在没有无参构造方法。则必须通过调用指定的构造方法,并向其传递参数,才可以实例化操作。
public Constructor<?>[] getConstructors()--------------->获取一个类的所有的构造方法,以Constructor对象数组的形式返回。Constructor类的定义,Constructor类是在
java.lang.reflect包中,所以是属于反射的操作包。取得一个构造方法后,可以通过Constructor的以下方法进行实例化:
public T newInstance(Object...initargs)
throws InstantiationException,
IllegalAccessException,
IllegalArgumentException,
InvocationTargetException
例:调用有两个参数的构造方法(略),比较复杂
为了开发的方便,一定要在类中定义无参构造方法。
3.4通过class取得完整结构:(了解)
通过class类中的很多方法可以轻易取得一个类中定义的全部构造方法,普通方法,常量、变量等等。现在假设有如下的类。
packageorg.lxh.demo.classdemo04;
interface Info{
public static final String AUTHOR= "MLDN" ;
public String getInfo();
public String say(Stringname,String content);
public void sayHello();
}
public class Personimplements Info{
private String name;
private int age;
public Person(){
}
public Person(String name){
this.setName(name);
}
public Person(String name ,intage){
this(name);
this.setAge(age);
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String toString(){
return "姓名:" + this.name + "年龄:" +this.age;
}
public String getInfo() {
return "hellworld";
}
public String say(String name,String content) {
return "说了:" + content;
}
public void sayHello() {
System.out.println("hello-------->"+ AUTHOR) ;
}
}
下面通过一系列的反射,完成操作。
3.4.1 取得继承的父类
public Class<?super T> getSuperclass()
public classGetSuperClassDemo {
public static void main(String[]args) throws ClassNotFoundException {
Class<?> c=Class.forName("org.lxh.classDemo04.Person");
Class<?> sc =c.getSuperclass();
System.out.println(sc.getName());
}
}
3.4.1 取得继承的父类
publicstaticvoid main(String[] args) throws Exception {
Class<?> c = Class.forName("org.lxh.demo.classdemo04.Person");
Class<?> sc = c.getSuperclass() ;
System.out.println(sc.getName());
}
}
3.4.2 取得实现的全部接口
一个类可以实现多个接口,故有下列方法:
public Class<?>[] getInterfaces()
接口本身是一个特殊的类:所以会以Class的对象数组形式返回。
package org.lxh.demo.classdemo04;
publicclass GetInterfacesDemo {
publicstaticvoid main(String[] args) throws Exception {
Class<?> c = Class.forName("org.lxh.demo.classdemo04.Person");
Class<?> Inter[] = c.getInterfaces() ;
for(int i=0 ;i<Inter.length;i++){
System.out.println(Inter[i].getName());
}
}
}
3.4.3 取得类的全部构造方法
package org.lxh.demo.classdemo04;
import java.lang.reflect.Constructor;
publicclass GetConstructorDemo01 {
publicstaticvoid main(String[] args) throws Exception {
Class<?> c = Class.forName("org.lxh.demo.classdemo04.Person");
Constructor<?>con[] = c.getConstructors(); // 得到全部构造
for (int i = 0; i < con.length; i++) {
System.out.println(con[i].getName()); // 输出内容
}
}
}
以上确实得到了全部的构造方法,但是程序有一个弊病,如果用.getName()来取得,只能取得构造方法的名字,而访问的修饰符和参数全都不见了。
如果现在想手工拼凑出一个构造方法,还需要下面几个方法的支持。
1. 得到访问权限(修饰符)public int getModifiers()
2. 得到全部的参数。public Class<?>[] getParameterTypes()
从结果中发现,访问修饰符是数字,而不是之前看到的public,在程序开放中,访问权限基本上是以数字来表示的。如果要想正确还原一个方法的访问修饰符,则要用到Modifier类。
进行还原。public static String toString(int mod)
3.4.4 取得类的全部方法
public Method[] getMethods()
throws SecurityException
Class<?> c = Class.forName("org.lxh.demo.classdemo04.Person");
Method m[] = c.getMethods(); // 取得全部的方法
for (int i = 0; i < m.length; i++) {
System.out.println(m[i]); // 输出内容
以上是取得一个类中全部方法最简单的操作,但是与构造方法一样,可以通过反射机制慢慢取得,此时需要以下方法的支持。
1.取得一个方法的返回值类型,public Class<?> getReturnType()
2.取得方法的全部参数 public Class<?>[] getParameterTypes()
3.取得抛出的异常的类型。public Class<?>[] getExceptionTypes()
3.4.5 取得类的全部属性
1.得到继承而来的公共属性:public Field[] getFields()
throws SecurityException
2.得到自定义的属性:public Method[] getDeclaredMethods()
throws SecurityException
开发工具的核心原理就是反射。但是此种操作,一般不用。
3.5反射的进一步应用(理解)
3.5.1通过反射调用类中的方法
正常情况下,都是通过对象.方法完成类中指定方法的调用,那么实际上可以通过反射机制完成类中方法的调用。
在Class类中用如下方法来取得要调用方法的method对象:public Method getMethod(String name,
Class<?>... parameterTypes)
throws NoSuchMethodException,
SecurityException
之所以要传递可变参数,主要是因为一个方法在使用的时候可能存在多个调用的参数,所以在此处必须指定好参数的类型。
取得method对象之后,通过如下方法 进行调用:
public Object invoke(Object obj,
Object... args)
throws IllegalAccessException,
IllegalArgumentException,
InvocationTargetException
以上方法表示在程序中真正要执行的方法。
3.5.2通过反射直接操作类中的setter和getter
3.5.3通过反射直接操作属性