认识Java反射机制
在正常情况下,必须知道一个类才可以实例化对象,但是在Java中也通过一个对象来找到其所在的类的信息,那么这实际上是Class类的功能。
- package zyz.demo;
- class X{ };
- public class GetClassDemo01{
- public static void main(String args[]){
- X x = new X() ; // 实例化X类的对象
- System.out.println(x.getClass().getName()) ; // 得到对象所在的类的完整名字
- }
- };
- 结果:zyz.demo.X
实例化Class类型对象
实例化Class类型对象的方法有三种:
第一种:通过forName()方法
第二种:类.class
第三种:对象.getClass()
- package zyz.demo;
- class X{
- };
- public class GetClassDemo02{
- public static void main(String args[]){
- Class<?> c1 = null ; // 指定泛型
- Class<?> c2 = null ; // 指定泛型
- Class<?> c3 = null ; // 指定泛型
- try{
- // 以下的操作形式是在开发中最常用的一种形式
- c1 = Class.forName("org.lxh.demo15.getclassdemo.X") ;
- }catch(ClassNotFoundException e){
- e.printStackTrace() ;
- }
- c2 = new X().getClass() ; // 通过Object类中的方法实例化
- c3 = X.class ; // 通过类.class实例化
- System.out.println("类名称:" + c1.getName());// 得到类的名称
- System.out.println("类名称:" + c2.getName());// 得到类的名称
- System.out.println("类名称:" + c3.getName());// 得到类的名称
- }
- };
一旦可以实例化Class类之后,就可以进行反射的进一步操作。
1、实例化对象
- <strong>class Person{
- private String name ; // name属性
- private int age ; // age属性
- public void setName(String name){
- this.name = name ;
- }
- public void setAge(int age){
- this.age = age ;
- }
- public String getName(){
- return this.name ;
- }
- public int getAge(){
- return this.age ;
- }
- public String toString(){ // 覆写toString()方法
- return "姓名:" + this.name + ",年龄:" + this.age ;
- }
- };
- public class Demo01{
- public static void main(String args[]){
- Class<?> c = null ; // 声明Class对象
- try{
- c = Class.forName("org.lxh.demo15.instancedemo.Person") ;
- }catch(ClassNotFoundException e){
- e.printStackTrace() ;
- }
- Person per = null ; // 声明Person对象
- try{
- per = (Person)c.newInstance() ; // 实例化对象
- }catch(Exception e){
- e.printStackTrace() ;
- }
- per.setName("李兴华") ; // 设置姓名
- per.setAge(30) ; // 设置年龄
- System.out.println(per) ; // 内容输出,调用toString()
- }
- };
- </strong>
通过以上的代码,可以发现,即使不使用关键字new对象也可以进行实例化操作,反射的作用。但是,在使用以上操作的时候有一点必须注意,在操作中类中必须存在无参构造方法。否则无法实例化。
所以说,使用以上的方法实际上还是需要类中构造方法的支持,符合于对象的实例化需求。
如果要想调用有参,由必须按照以下的步骤进行:
1、通过Class类中的getConstructors()取得本类中的全部构造方法。
2、向构造方法中传递一个对象数组进去,里面包含了构造方法中所需的各个参数。
3、之后通过Constructor实例化对象
- package org.lxh.demo15.instancedemo ;
- import java.lang.reflect.Constructor ; // 导入反射机制包
- class Person{
- private String name ; // name属性
- private int age ; // age属性
- public Person(String name,int age){
- this.setName(name) ;
- this.setAge(age);
- }
- public void setName(String name){
- this.name = name ;
- }
- public void setAge(int age){
- this.age = age ;
- }
- public String getName(){
- return this.name ;
- }
- public int getAge(){
- return this.age ;
- }
- public String toString(){ // 覆写toString()方法
- return "姓名:" + this.name + ",年龄:" + this.age ;
- }
- };
- public class InstanceDemo03{
- public static void main(String args[]){
- Class<?> c = null ; // 声明Class对象
- try{
- c = Class.forName("org.lxh.demo15.instancedemo.Person") ;
- }catch(ClassNotFoundException e){
- e.printStackTrace() ;
- }
- Person per = null ; // 声明Person对象
- Constructor<?> cons[] = null ;
- cons = c.getConstructors() ;
- try{
- // 第一个数组
- per = (Person)cons[0].newInstance("李兴华",30) ; // 实例化对象
- }catch(Exception e){
- e.printStackTrace() ;
- }
- System.out.println(per) ; // 内容输出,调用toString()
- }
- };
但是,从实际角度看,如果要使用反射进行对象的实例化操作,最好在类中存在无参构造。
2、取得类所实现的全部接口
- package org.lxh.demo15.classinfodemo ;
- public class GetInterfaceDemo{
- public static void main(String args[]){
- Class<?> c1 = null ; // 声明Class对象
- try{
- c1 = Class.forName("org.lxh.demo15.Person") ; // 实例化对象
- }catch(ClassNotFoundException e){
- e.printStackTrace() ;
- }
- Class<?> c[] = c1.getInterfaces() ; // 以数组形式返回实现的全部接口
- for(int i=0;i<c.length;i++){
- System.out.println("实现的接口名称:" + c[i].getName()) ; // 输出接口名称
- }
- }
- };
- 结果:实现的接口名称:org.lxh.demo15.China
3、取得父类
- <strong>package org.lxh.demo15.classinfodemo ;
- public class GetSuperClassDemo{
- public static void main(String args[]){
- Class<?> c1 = null ; // 声明Class对象
- try{
- c1 = Class.forName("org.lxh.demo15.Person") ; // 实例化对象
- }catch(ClassNotFoundException e){
- e.printStackTrace() ;
- }
- Class<?> c2 = c1.getSuperclass() ; // 取得父类
- System.out.println("父类名称:" + c2.getName()) ;
- }
- };
- 结果:父类名称:java.lang.Object
- </strong>
4、取得类中的全部构造方法
- package org.lxh.demo15.classinfodemo ;
- import java.lang.reflect.Constructor ; // 导入构造方法的包
- public class GetConstructorDemo01{
- public static void main(String args[]){
- Class<?> c1 = null ; // 声明Class对象
- try{
- c1 = Class.forName("org.lxh.demo15.Person") ; // 实例化对象
- }catch(ClassNotFoundException e){
- e.printStackTrace() ;
- }
- Constructor<?> con[] = c1.getConstructors() ; // 取得一个类中的全部构造
- for(int i=0;i<con.length;i++){
- System.out.println("构造方法:" + con[i]) ; // 输出构造,直接打印
- }
- }
- };
- 结果:
- 构造方法:public org.lxh.demo15.Person()
- 构造方法:public org.lxh.demo15.Person(java.lang.String)
- 构造方法:public org.lxh.demo15.Person(java.lang.String,int)
以上的操作确实取得了类中的构造方法,但是此时是通过对象直接打印取得的,肯定会调用Constructor类中的toString()方法。
Constructor类中存在了以下的几个方法:
取得修饰符:public int getModifiers()
取得方法名称:public String getName()
取得参数的类型:public Class<?>[] getParameterTypes()
- package org.lxh.demo15.classinfodemo ;
- import java.lang.reflect.Constructor ; // 导入构造方法的包
- public class GetConstructorDemo02{
- public static void main(String args[]){
- Class<?> c1 = null ; // 声明Class对象
- try{
- c1 = Class.forName("org.lxh.demo15.Person") ; // 实例化对象
- }catch(ClassNotFoundException e){
- e.printStackTrace() ;
- }
- Constructor<?> con[] = c1.getConstructors() ; // 取得一个类中的全部构造
- for(int i=0;i<con.length;i++){
- Class<?> p[] = con[i].getParameterTypes() ; // 得到构造方法中的全部参数
- System.out.print("构造方法:" ) ; // 输出构造,直接打印
- System.out.print(con[i].getModifiers() + " ") ; // 得到修饰符
- System.out.print(con[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("){}") ;
- }
- }
- };