在正常情况下,必须知道一个类的完整路径之后才可以实例对象,但是在java中也允许通过一个对象来找到其所在的类的信息,就是用到class类的功能。
Class类的功能
class X{
} public class Test7 { public static void main(String[] args) { X x=new X(); //得到类所在的位置 System.out.println(x.getClass().getName()); } } |
在Object类中定义了以下的方法,此方法将被所有子类继承:
ü Public final class getClass():此方法返回值类型是一个”class”类,实际上此类是java反射的源头,实际上所谓反射从程序的运行结果来看也很好理解,即:可以通过对象求出类的名称。
正常方式:引入需要的“包.类”名称-------------à同new实例化------------à取得实例化对象
反射机制:实例化对象--------------àgetClass()方法-------------à得到完整的“包.类”类名
Class类:
Class 本身表示了一个类的本身,通过class可以完整的得到一个类中的完整结构,包括此类的方法定义,属性定义等。
Class 没有构造方法,所以此类的构造方法都私有化了。
实例化class类对象有三种方法
第一种:通过forName(完整包名+类名)方法
第二种:类.class
第三种:对象.getClass()
实例化class类对象的三种方式示例代码:
class X{}
public class Test7 { public static void main(String[] args) throws ClassNotFoundException { //用自定义泛型 Class<?> c1=null; Class<?> c2=null; Class<?> c3=null; //方式1:以下的操作形式是开发中最常用的一种反射机制形式Class.forName(String className); c1=Class.forName("X"); //方式2:通过Object类中的方法实例化 c2=new X().getClass(); //方式3:通过类.class实例化 c3=X.class; //得到类的名称 System.out.println(c1.getName()); System.out.println(c2.getName()); System.out.println(c3.getName()); } } |
一旦实例化class类之后,就可以进行反射的进一步操作。
Class主要是反射的源头,不光可以取得对象所在类的信息,也可以直接通过class类的方法进行对象的实例化操作,正常情况下,使用关键字new为对象实例化,如果现在已经实例化好了Class对象,则就可以通过class类中提供的newInstance()方法进行实例化。
使用newInstance()方法示例代码:
class Person { private String name; private int 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; } @Override public String toString() { return "姓名:"+this.name+",年龄:"+this.age; } }
public class Demo1 { public static void main(String[] args) throws Exception { Class<?> c1=null; //使用Class类中的forName(完整类名:包名.类名)方法,此方法返回一个Class对象 c1=c1.forName("com.jeremy.Test.Person"); Person p=null; //当对象已实例化好了,也可以通过对象.newInstance()方法来实例化对象 p=(Person)c1.newInstance(); p.setName("张三"); p.setAge(18); System.out.println(p); } } |
通过以上的代码,可以发现,即使不使用关键字new对象也可以进行实例化操作,反射的作用。
注意:A.在使用以上的操作的时候一定要记住一点,被实例化对象的类中必须存在无参构造方法,如果不存在的话,则肯定是无法实例化的。
B.对于以上的程序也并非没有解决办法,也是可以通过其他的方法进行实例化操作的,只是在操作的时候需要明确的调用类中构造方法,并将参数传递进去之后才可以之后才可以进行实例化操作。
操作步骤:
1. 通过Class类中的getConstructors()取得本类的中全部构造方法。
2. 向构造方法中传递一个对象数组进去,里面包含了构造方法中所需的各个参数。
3. 之后通过Constructor实例化对象。
在constructor类中有一个newInstance(Object…initargs)传递初始化参数,进行对象的实例化操作。
Constructor类使用newInstance(Object…initargs)方法传递参数实例化对象的示例代码:
class Person { private String name; private int age; public Person(String name,int age){ this.name=name; this.age=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; } @Override public String toString() { return "姓名:"+this.name+",年龄:"+this.age; } }
public class Demo1 { public static void main(String[] args) throws Exception { Class<?> c1=null; c1=c1.forName("com.jeremy.Test.Person"); //通过Class类的getConstructors()方法得到类中的所有构造函数,得到一个构造函数类数组 Constructor<?>[] cons=c1.getConstructors(); Person p=null; //拿去某个构造函数类数组内某个构造函数类,用该Constructor类的newInstance()方法创建对象 p=(Person)cons[0].newInstance("张三",18); System.out.println(p); } } |
但是,从实际角度看,如果要使用反射进行对象的实例化操作,最好在类中存在无参构造函数。
总结:
1. 本章的功能是class用的最多的功能,而且在开发中用户会经常使用到的开发模式。
2. 在使用Class实例化对象的时候,必须保证类中存在一个无参构造函数,否则无法使用。
3. 如果想要调用有参构造函数进行对象实例化操作,则必须使用Constructor类完成,此类表示构造函数方法,并通过可变变数传递要求的内容。
反射机制的深入--------取得类的结构
1. 可以使用反射取得实现的全部接口。
2. 可以使用反射取得一个类所继承的父类。
3. 可以使用反射取得一个类的全部构造方法。
4. 可以使用反射取得一个类中的全部方法。
5. 可以使用反射取得一个类中全部属性。
在实际开发中,以上的程序就是反射应用最多的地方,当然,反射机制所提供的功能远不止如此,还可以通过反射得到一个类的完整结构,那么这就要使用到java.lang.reflect包中的一下几个类:
Constructor:表示类中的构造函数。
Field:表示类中的属性。
Method:表示类中的方法。
这三个类都是AccessibleObject类的子类。
-------------------|AccessibleObject类
-----------------------|Constructor表示类中的构造函数
-----------------------|Field表示类中的属性
-----------------------|Method表示类中的方法
如果想要取得一个类所实现的全部接口,则必须使用Class类中的getInterfaces()方法。
此方法定义如下:
PublicClass[] getInterfaces()
此方法返回一个class类的对象数组,之后就可以直接利用class类中的getName()方法输出即可。
Class类中的getInterfaces()方法获得类实现的全部接口:
interface Test1{} interface Test2{} interface Test3{} interface china{ public static final String NATIONAL="china"; public static final String AUTHOR="张三"; public void sayChina(); public String sayHello(String name,String author); } class Person implements china,Test1,Test2,Test3{ private String name; private int age; public Person(String name){ this.name=name; } public Person(){} public Person(String name,int age){ this(name); this.age=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; } @Override public String toString() { return "姓名:"+this.name+",年龄:"+this.age; } @Override public void sayChina() { System.out.println("作者:"+AUTHOR+",国籍:"+NATIONAL);
} @Override public String sayHello(String name, String author) { return name+"你好!我今年"+age+"岁了"; } }
public class Demo1 { public static void main(String[] args) throws Exception { Class<?> c1=null; c1=Class.forName("com.jeremy.Test.Person"); //Class.getInterfaces()方法:获得Class类中实现的全部接口,返回一个Class数组 Class[] interfaces=c1.getInterfaces(); for(int i=0;i<interfaces.length;i++){ System.out.println(interfaces[i].getName()); } } } |
取得父类
一个类可以实现多个接口,但是只能继承一个父类,所以如果要想取得一个类的父类,可以直接使用Class类中的getSuperclass()方法。
此方法定义如下:
PublicClass<? Super T> getSuperclass()
此方法返回的是Class实例,和之前的得到接口一样,可以通过getName()方法取得名称。
示例代码:
class Test4{} interface china{ public static final String NATIONAL="china"; public static final String AUTHOR="张三"; public void sayChina(); public String sayHello(String name,String author); } //继承了Test4为父类 class Person extends Test4 implements china{ private String name; private int age; public Person(String name){ this.name=name; } public Person(){} public Person(String name,int age){ this(name); this.age=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; } @Override public String toString() { return "姓名:"+this.name+",年龄:"+this.age; } @Override public void sayChina() { System.out.println("作者:"+AUTHOR+",国籍:"+NATIONAL);
} @Override public String sayHello(String name, String author) { return name+"你好!我今年"+age+"岁了"; } }
public class Demo1 { public static void main(String[] args) throws Exception { Class<?> c1=null; c1=Class.forName("com.jeremy.Test.Person"); //通过Class对象的方法:getSuperclass()获取对象的父类 Class<?> c2=c1.getSuperclass(); System.out.println(c2.getName()); } } |
取得全部构造方法:
class Test4{} interface china{ public static final String NATIONAL="china"; public static final String AUTHOR="张三"; public void sayChina(); public String sayHello(String name,String author); } class Person extends Test4 implements china{ private String name; private int age; public Person(String name){ this.name=name; } public Person(){} public Person(String name,int age){ this(name); this.age=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; } @Override public String toString() { return "姓名:"+this.name+",年龄:"+this.age; } @Override public void sayChina() { System.out.println("作者:"+AUTHOR+",国籍:"+NATIONAL);
} @Override public String sayHello(String name, String author) { return name+"你好!我今年"+age+"岁了"; } }
public class Demo1 { public static void main(String[] args) throws Exception { Class<?> c1=null; c1=Class.forName("com.jeremy.Test.Person"); Constructor<?>[] cons=c1.getConstructors(); for(int i=0;i<cons.length;i++){ System.out.println(cons[i]); } } } |
以上的操作确实取得了类中的构造方法,但是此时通过对象直接打印取得的,肯定会调用Constructor类中toString()方法
Constructor类中存在了以下的方法:
1. 获取修饰符:public int getModifiers()
2. 获取方法名称:public String getName()
3. 取得参数的类型:public Class<?>[] getParameterTypes()
获取构造函数各个部位的示例代码:
class Test4{} interface china{ public static final String NATIONAL="china"; public static final String AUTHOR="张三"; public void sayChina(); public String sayHello(String name,String author); } class Person extends Test4 implements china{ private String name; private int age; public Person(String name){ this.name=name; } public Person(){} public Person(String name,int age){ this(name); this.age=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; } @Override public String toString() { return "姓名:"+this.name+",年龄:"+this.age; } @Override public void sayChina() { System.out.println("作者:"+AUTHOR+",国籍:"+NATIONAL);
} @Override public String sayHello(String name, String author) { return name+"你好!我今年"+age+"岁了"; } }
public class Demo1 { public static void main(String[] args) throws Exception { Class<?> c1=null; c1=Class.forName("com.jeremy.Test.Person"); Constructor<?>[] cons=c1.getConstructors(); for(int i=0;i<cons.length;i++){ //得到构造方法中的全部参数 Class<?>[] p=cons[i].getParameterTypes(); System.out.println("构造方法:"); //得到构造函数的访问修饰符 System.out.print(cons[i].getModifiers()+" "); //获取构造函数的名字 System.out.print(cons[i].getName()); System.out.print("("); for(int j=0;j<p.length;j++){ System.out.print(p[j].getName()+"arg"+i); if(j<p.length-1){ System.out.print(","); } } System.out.println("){}"); } } } |
执行以上代码,可以成功过取得构造方法的方法名及参数类型,但是在取得权限的时候发现返回的是一个数字而不是public,访问修饰符变为数字,这是因为在整个java中对于方法的修饰符是使用一定的数字表示出来的,而如果要想把这个数字还原成用户可以看懂的关键字,则必须依靠Modifier类完成,此类定义在java.lang.reflect包中。直接使用Modifier类的以下方法即可将修饰符:
Public staticString toString(ing mod);
Intmo=cons[i].getModifiers();
System.out.println(Modifier.toString());
还原访问修饰符
public class Demo1{ public static void main(String[] args)throws Exception{ Class<?> c1=null; c1=Class.forName("com.jeremy.Test.Person"); Constructor<?>[] cons=c1.getConstructors(); for(int i=0;i<cons.length;i++){ Class<?>[] p=cons[i].getParameterTypes(); System.out.print("构造方法:"); //取得构造函数的访问修饰符,返回的是数字 int mo=cons[i].getModifiers(); //通过Modifier类的toString()把数字转换成可以看得懂的访问修饰符 System.out.print(Modifier.toString(mo)+" "); System.out.print(cons[i].getName()); System.out.print("("); for(int j=0;j<p.length;j++){ System.out.print(p[j].getName()+"arg"+i); if(j>p.length-1){ System.out.print(","); } } System.out.println("){}"); } } } |
取得全部方法:
想要取得一个类中的全部方法,可以使用Class类中的getDeclaredMethods()方法,此方法返回一个 Method类的对象数组,而如果要想进一步取得方法的具体信息,例如:方法的参数,抛出的异常声明等等,则要必须依靠Method类
方法:
PublicMethod[] getDeclaredMethods()thows SecuritvException------à输出本类中全部方法
PublicMethod[] getMethods()thorws SecuritvException-----------à输出全部的方法
PublicClass<?> getReturnType()----------à取得全部返回值
PublicClass<?> getParameterTypes()---------à取得全部参数
Public intgetModifiers()----------à取得修饰符
PublicClass<?>[] getExceptionTypes()取得异常信息
Method类的使用:
public class Demo1{ public static void main(String[] args)throws Exception{ Class<?> c1=null; c1=Class.forName("com.jeremy.Test.Person"); //得到类中的所有方法 Method[] m=c1.getMethods(); for(int i=0;i<m.length;i++){ //得到方法的返回值类型 Class<?> r=m[i].getReturnType(); //得到方法的参数类型 Class<?>[] p=m[i].getParameterTypes(); //得到方法的访问修饰符 int xx=m[i].getModifiers(); //调用Modifier.toString(int mo):输出访问修饰符 System.out.print(Modifier.toString(xx)+" "); System.out.print(r+" "); //得到方法的名字 System.out.print(m[i].getName()); System.out.print("("); for(int j=0;j<p.length;j++){ //输入参数的数据类型 System.out.print(p[j].getName()+""+"arg"+j); if(j<p.length-1){ System.out.println(","); } } //返回方法声明抛出的异常 Class<?>[] ex=m[i].getExceptionTypes(); if(ex.length>0){ System.out.print(")throws"); }else{ System.out.print(")"); } for(int j=0;j<ex.length;j++){ //输出异常的名字 System.out.print(ex[j].getName()); if(j<p.length-1){ System.out.print(","); } } System.out.println(); } } } |
在一般的开发工具中经常看见随便提示功能,实际上次功能就是利用以上的程序完成的。
得到实现的接口或父类中的公共属性:public Field[] getFields()throws SecurityException
得到本类中的全部属性:public Field[] getDeclaredFields()throws SecurityException
以上方法返回的都是Field的数组,每个Field对象就表示类中一个属性
示例代码:
public class Demo1{ public static void main(String[] args)throws Exception{ Class<?> c1=null; //通过反射机制,得到类对象 c1=Class.forName("com.jeremy.Test.Person"); //通过Class类对象的getFields()方法得到一个方法类数组 Field[] f=c1.getFields(); for(int i=0;i<f.length;i++){ //得到方法返回值属性类型 Class<?> r=f[i].getType(); //得到访问修饰符 int mo=f[i].getModifiers(); //调用Modifier.toString(mo):方法转换成我们看得懂的访问修饰符 String priv=Modifier.toString(mo); System.out.print("公共属性:"); System.out.print(priv+" "); //输出方法返回值类型 System.out.print(r.getName()); //输出方法名 System.out.print(f[i].getName()); System.out.println(","); } } } |
在正常情况下一个类的对象功能产生之后,就可以直接调用类中的方法了,如果要想调用的话,则肯定必须清楚的知道要调用的方法名称,之后通过Class类中的:public MethodgetMethod(String name,Clsss<?>…parameterTypes)throwsNoSuchMethodException,SecurityException方法,得到一个方法的Method对象,之后通过此Method对象来执行方法,但是在方法调用的时候,因为会牵扯到方法中的参数的问题,所以通过getMethod()取得的时候,必须设置好需要的参数类型。
此方法返回一个Method类,通过此类的public Objectinvoke(Object obj,Object…args)throwsIllegalAccessException,IllegalArgumentException,InvocationTargetException方法执行调用方法。
示例代码:
class Person extends Test4 implements china{ private String name; private int age; public Person(String name){ this.name=name; } public Person(){} public Person(String name,int age){ this(name); this.age=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; } @Override public String toString() { return "姓名:"+this.name+",年龄:"+this.age; } @Override public void sayChina() { System.out.println("作者:"+AUTHOR+",国籍:"+NATIONAL);
} public String sayHello(String name, int age) { return name+"你好!我今年"+age+"岁了"; } @Override public String sayHello(String name, String author) { // TODO Auto-generated method stub return null; } }
public class Demo1{ public static void main(String[] args)throws Exception{ Class<?> c1=null; //通过反射机制得到class对象 c1=Class.forName("com.jeremy.Test.Person"); //通过class对象的getMethod(String methodName,Class<?>…parameterTypes)注意:传递进去的参数类型一定要和方法一样,不然会报NoSuchMethodException异常 Method m1=c1.getMethod("sayHello",String.class,int.class); //调用Method类的invoke(Object obj,Object…args)方法执行方法。 System.out.println(m1.invoke(c1.newInstance(),"张三",18)); } } |
通过反射调用属性
如果现在假设要操作一个类的属性,则可以通过Field完成,而不必麻烦通过setter和getter得到公共属性:
Public Field getField(String name)throws NoSuchFieldException,SecurityException
得到本类属性:
Public Field getDeclaredField(Stringname)throws NoSuchFieldException,SecurityxException
得到属性内容:
Public Object get(Object obj)throwsIllegalArgumentException,IllegalAccessException
示例代码:
class Test4{} interface china{ public static final String NATIONAL="china"; public static final String AUTHOR="张三"; public void sayChina(); public String sayHello(String name,String author); } class Person extends Test4 implements china{ private String name; private int age; public Person(String name){ this.name=name; } public Person(){} public Person(String name,int age){ this(name); this.age=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; } @Override public String toString() { return "姓名:"+this.name+",年龄:"+this.age; } @Override public void sayChina() { System.out.println("作者:"+AUTHOR+",国籍:"+NATIONAL);
} public String sayHello(String name, int age) { return name+"你好!我今年"+age+"岁了"; } @Override public String sayHello(String name, String author) { // TODO Auto-generated method stub return null; } }
public class Demo1{ public static void main(String[] args)throws Exception{ Class<?> c1=null; Object obj=null; c1=Class.forName("com.jeremy.Test.Person"); obj=c1.newInstance(); setter(obj,"name","张三",String.class); setter(obj,"age",30,int.class); System.out.print("姓名:"); getter(obj,"name"); System.out.print("年龄:"); getter(obj,"age"); } public static void setter(Object obj,String att,Object value,Class<?> type)throws Exception{ Method m=obj.getClass().getMethod("set"+initStr(att),type); m.invoke(obj,value); } public static void getter(Object obj,String att)throws Exception{ Method m=obj.getClass().getMethod("get"+initStr(att)); System.out.println(m.invoke(obj)); } public static String initStr(String old){ String str=old.substring(0,1).toUpperCase()+old.toString(); return str; } } |
暴力反射示例代码:
public static void main(String[] args)throws Exception{ Class<?> c1=Class.forName("com.jeremy.Test.Person"); //Field field=c1.getField("age"); //因为age是私有属性,所以通过class.getField拿不到私有属性,此处出现NoSuchFieldException异常 //System.out.println(field); Field field1=c1.getDeclaredField("age"); //Class类中凡是getXXX的方法都是获得公共的成员,如果是Class类中getDeclaredXXX可以获得本类中全部的成员 System.out.println(field1); Object obj=c1.newInstance(); //通过Class类getDeclaredField()方法得到的私有成员,不能对私有成员,进行操作。会出现IllegalArgumentException异常 //可通过Field类父类AccessibleObject中setAccessible(boolean flag)方法:值为 true 则指示反射的对象在使用时应该取消 Java 语言访问检查, //简称暴力反射 field1.setAccessible(true); field1.set(obj, 20); System.out.print(field1.get(obj)); } |