java——反射、反射与类操作

正常处理

public class Test {
   public static void main(String[] args) {
      Date date = new Date() ;
   }
}

以上是我们正常的关于对象的处理流程:根据包名.类名找到类;所谓的"反"指的是根据对象来取得对象的来源信息,而这个"反"的操作核心的处理就在Object类的一个方法:取得Class对象:

public final native Class<?> getClass();

该方法返回的是一个Class类对象,这个Class描述的就是类。

反射机制

public class Test{
    public static void main(String[] args){
        Date date=new Date;
        Class class1=date.getClass();
        System.out.println(class1.getName());
    }
}

三种实例化对象

  1. 任何类的实例化对象可以通过Object类中的getClass()方法取得Class类对象。
  2. “类.class”:直接根据某个具体的类来取得Class类的实例化对象。
  3. 使用Class类提供的方法:public static Class<?> forName(String className) throwsClassNotFoundException。

反射实例化对象

public class Test {
   public static void main(String[] args) 
   throws ClassNotFoundException,
   InstantiationException, IllegalAccessException {
      Class<?> cls = Class.forName("java.util.Date") ;
        // 实例化对象,等价于 new java.util.Date() ;
      Object obj = cls.newInstance() ;
      System.out.println(obj);
   }
}

除了关键字new之外,对于对象的实例化模式有了第二种做法,通过反射进行。
取得了Class对象就意味着取得了一个指定类的操作权。
Class类可以使用newInstance() 实例化对象,同时Class.forName()能够接收类名称。

反射与类操作
反射取得父类信息

  • 取得类的包名称: public Package getPackage()

  • 取得父类的Class对象: public native Class<? super T> getSuperclass();

  • 取得实现的父接口:public Class<?>[] getInterfaces()

    interface IFruit{}
    interface IMessage{}
    class CLS implements IFruit,IMessage{}
    public class Test {
    public static void main(String[] args) {

         Class<?> cls=CLS.class;//取得Class对象
         //取得package名称
         System.out.println(cls.getPackage().getName());
         //取得父类名称
         System.out.println(cls.getSuperclass().getName());
         //取得实现的父类接口
         Class<?>[] iClass=cls.getInterfaces();
         for(Class<?> class1:iClass){
             System.out.println(class1.getName());
         }
    
     }
    

    }

通过反射可以取得类结构上的所有关键信息。

反射调用构造

  • 取得指定参数类型的构造

    public Constructor getConstructor(Class<?>… parameterTypes)
    throws NoSuchMethodException, SecurityException

  • 取得类中的所有构造

    public Constructor<?>[] getConstructors() throws SecurityException

以上两个方法返回的类型都是java.lang.reflect.Constructor类的实例化对象,这个类之中大家只需要关注一个方法.
实例化对象:

public T newInstance(Object ... initargs)
throws InstantiationException, IllegalAccessException, 
IllegalArgumentException, InvocationTargetException 

取得类中的所有构造信息

import java.lang.reflect.Constructor;
class Person1{
    public Person1(){};
    public Person1(String name){};
    public Person1(String name,Integer age){};
}
public class Test {
    public static void main(String[] args) {
        Class<?> cls=Person1.class;
        //取得类中的全部构造
        Constructor<?>[] costructors=cls.getConstructors();
        for(Constructor<?> costructor:costructors){
            System.out.println(costructor);
        }
    }
}

以上的操作是直接利用了Constructor类中的toString()方法取得了构造方法的完整信息(包含方法权限,参数列表),而如果只使用getName()方法,只会返回构造方法的包名.类名。

在定义简单java类的时候一定要保留有一个无参构造
示例:观察Class实例化对象的问题

class Person {
   private String name ; 
   private int age ;
   public Person(String name,int age) { 
      this.name = name ;
      this.age = age ;
   }
@Override
   public String toString() {
      return "Person [name=" + name + ", age=" + age + "]";
   }
}
public class Test {
   public static void main(String[] args)
    throws InstantiationException, IllegalAccessException {
      Class<?> cls = Person.class ; 
      System.out.println(cls.newInstance());
   }
}

Class类通过反射实例化类对象的时候,只能够调用类中的无参构造。如果现在类中没有无参构造则无法使用Class类调用,只能够通过明确的构造调用实例化处理。
示例:通过Constructor类实例化对象

import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
class Person1{
    private String name;
    private int age;
    public Person1(String name,int age){
        this.name=name;
        this.age=age;
    }
    public String toString(){
        return "Person [name=" + name + ", age=" + age + "]";
    }
}
public class Test {
    public static void main(String[] args)
    throws IllegalAccessException,InstantiationException
    ,NoSuchMethodException, SecurityException,
            IllegalArgumentException, InvocationTargetException{
        Class<?> cls=Person1.class;
        //取得指定参数类型的实例化对象
        Constructor<?> cons=cls.getConstructor(String.class,int.class);
        System.out.println(cons.newInstance("zhangsan",22));
    }
}

反射调用普通方法

  • 取得全部普通方法

    public Method[] getMethods() throws SecurityException

  • 取得指定普通方法

    public Method getMethod(String name, Class<?>… parameterTypes)

以上两个方法返回的类型是java.lang.reflect.Method类的对象,在此类中提供有一个调用方法的支持:

public Object invoke(Object obj, Object... args)throws
 IllegalAccessException,
 IllegalArgumentException,InvocationTargetException

取得一个类中的全部普通方法

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
class Person1 {
    private String name ;
    private int age ;
    public Person1() {}
    public Person1(String name,int age) {
        this.name = name ;
        this.age = age ;
    }
    @Override
    public String toString() {
        return "Person [name=" + name + ", 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;
    }
}
public class Test {
    public static void main(String[] args) throws Exception {
        //Class<?> cls = Person.class ;
        //Method[] methods = cls.getMethods() ;
        //for (Method method : methods) {
            //System.out.println(method);
        //}
        Class<?> cls = Class.forName("www.bit.java.testthread.Person") ;
        // 任何时候调用类中的普通方法都必须有实例化对象
        Object obj = cls.newInstance() ;
        // 取得setName这个方法的实例化对象,设置方法名称与参数类型
        Method setMethod = cls.getMethod("setName", String.class) ;
     // 随后需要通过Method类对象调用指定的方法,调用方法需要有实例化对象
     // 同时传入参数
        setMethod.invoke(obj, "yuisama") ; // 相当于Person1对象.setName("yuisama") ;
        Method getMethod = cls.getMethod("getName") ;
        Object result  = getMethod.invoke(obj) ;  // 相当于Person1对象.getName() ; System.out.println(result) ;
    }
}

之前程序编写的简单java类中的getter、setter方法采用的都是明确的对象调用。现在有了反射机制处理之后,即使没有明确的Person类型对象(依然需要实例化对象,Object对象描述,所有的普通方法必须在有实例化对象之后才可以进行调用)。就可以通过反射调用。

反射调用类中的属性
前提:类中的所有属性一定在类对象实例化之后才会进行空间分配,所以此时如果要想调用类的属性,必须保证有实 例化对象。通过反射的newInstance()可以直接取得实例化对象(Object类型)。
在Class类中提供有两组取得属性的方法:

  1. 第一组(父类中)-取得类中全部属性: public Field[] getFields() throws SecurityException
  2. 第一组(父类中)-取得类中指定名称属性: public Field getField(String name) throws
    NoSuchFieldException, SecurityException
  3. 第二组(本类中)-取得类中全部属性: public Field[] getDeclaredFields() throws SecurityException
  4. 第二组(□本类中)-取得类中指定名称属性 : public Method getDeclaredMethod(String name, Class<?

    … parameterTypes) throws NoSuchMethodException, SecurityException

取得类中的全部属性

import java.lang.reflect.Field;
class Person1 {
    public String name ;
    public int age ;
}
class Student extends Person1{
    private String school ;
}
public class Test {
    public static void main(String[] args) throws Exception {
        Class<?> cls = Class.forName("www.bit.java.testthread.Student");
        { // 普通代码块
            // 第一组-取得类中全部属性
            Field[] fields = cls.getFields();
            for (Field field : fields) {
                System.out.println(field);
            }
        }
        System.out.println("   ");
        {
            // 第二组-取得类中全部属性
            Field[] fields = cls.getDeclaredFields();
            for (Field field : fields) {
                System.out.println(field);
            }
        }
    }
}

我们需要关注属性的核心描述类:java.lang.reflect.Field,在这个类之中有两个重要方法:

  1. 设置属性内容 : public void set(Object obj, Object value) throws IllegalArgumentException, IllegalAccessException
  2. 取得属性内容 : public Object get(Object obj) throws IllegalArgumentException, IllegalAccessException

通过反射操作属性

import java.lang.reflect.Field;
class Person1{
    private String name;
}
public class Test{
    public static void main(String[] args)throws Exception {
        Class<?> cls = Class.forName("www.bit.java.test.Person1") ;
        // 实例化本类对象
        Object obj = cls.newInstance() ;
        // 操作name属性
        Field nameField = cls.getDeclaredField("name") ;
        nameField.set(obj, "zhangsan") ; // 相当于对象.name = "zhangsan" System.out.println(nameField.get(obj)); // 取得属性
    }
}

在AccessibleObject类中提供有一个方法:
动态设置封装:

public void setAccessible(boolean flag) throws SecurityException

示例:

import java.lang.reflect.Field;
class Person {
   private String name ;
}
public class Test {
   public static void main(String[] args) throws Exception {
      Class<?> cls = Class.forName("www.bit.java.testthread.Person") ;
      // 实例化本类对象
      Object obj = cls.newInstance() ;
     // 操作name属性
     Field nameField = cls.getDeclaredField("name") ;
     // 取消封装
     nameField.setAccessible(true) ;
    // ----------------------------
     nameField.set(obj, "zhangsan") ; // 相当于对象.name = "zhangsan" System.out.println(nameField.get(obj)); // 取得属性
   }
}

在Field类之中有一个特别有用的方法:
取得属性类型:

public Class<?> getType()

取得属性类型

import java.lang.reflect.Field;
 class Person {
   private String name ;
}
public class Test {
   public static void main(String[] args) throws Exception {
      Class<?> cls = Class.forName("www.bit.java.testthread.Person") ;
      // 实例化本类对象
      Object obj = cls.newInstance() ;
     // 操作name属性
     Field nameField = cls.getDeclaredField("name") ;
      // 包.类
      System.out.println(nameField.getType().getName()) ;
      // 类名称
      System.out.println(nameField.getType().getSimpleName()) ;
   }
}

猜你喜欢

转载自blog.csdn.net/qq_44149554/article/details/89414029