Java反射

反射基础篇


定义:根据现有对象倒推类的组成

最核心:在JVM中任何一个类都有一个唯一的Class对象 ,此对象记录该类的组成结构,通过该class对象,可以反向查找到这个类的信息,称之为反射;
当类加载时由JVM产生,用户只能取得此对象,无法创建此对象;

1.获取一个类的对应的Class对象 (Class的C是大写)

要想在Java中应用反射,首先取得该类的class对象;有三种方法可以获取:

(1)调用Object提供的getClass方法
class Person {

}
public class Test1 {
    public static void main(String[] args) {
        Person per = new Person();
        System.out.println(per.getClass());
    }
}
(2)类名称 . class
class Person {

}
public class Test1 {
    public static void main(String[] args) throws ClassNotFoundException{
        Class cla = Test1.class;
        System.out.println(cla);
    }
}
(3)调用Class类提供的静态方法:Class . forName(类的全名称)
class Person {

}
public class Test1 {
    public static void main(String[] args) throws ClassNotFoundException{
        //可能产生ClassNotFoundException异常,需要用throws抛出,否则编译不通过
        Class<?> cls = Class.forName("www.bitten.java.Person");   //需用“”括起来,因为参数是String类型
        System.out.println(cls.getName());
    }
}

2.当我们拿到一个类的class对象后,可以做什么呢?

1. 创建该类的新对象

反射与工厂模式

package www.bitten.java;

/**
 * @Author : YangY
 * @Description :   反射与工厂模式
 * @Time : Created in 9:37 2019/3/17
 */
interface Buycomputer {
    void buy();
}
class Lenove implements Buycomputer {
    @Override
    public void buy() {
        System.out.println("买一台联想电脑");
    }
}
class Mac implements Buycomputer {
    @Override
    public void buy() {
        System.out.println("买一台苹果电脑");
    }
}
class ComputerFactory {
    public static Buycomputer getInstance(String computerClass) {
        try {
            Class<?> cls = Class.forName(computerClass);
            Buycomputer computer = (Buycomputer) cls.newInstance();
            return computer;
        }catch (ClassNotFoundException e) {
            e.printStackTrace();
        }catch (IllegalAccessException e){
            e.printStackTrace();
        }catch (InstantiationException e) {
            e.printStackTrace();
        }
        return null;
    }
}

public class Test1 {
    public static void main(String[] args) {
        ComputerFactory.getInstance("www.bitten.java.Lenove").buy();
    }
}

2. 取得包名、父类、父接口信息

interface ILife {

}
interface IAnimal {

}
class Person implements ILife,IAnimal {

}
public class Test1 {
    public static void main(String[] args) throws ClassNotFoundException{
        Class<?> cla = Person.class;
        //打印包名
        System.out.println(cla.getPackage().getName()); 
        //打印它的父类名称
        System.out.println(cla.getSuperclass().getName());
        //用这个类的Class对象生成它的父接口数组
        Class<?>[] clasArr = cla.getInterfaces();  //也可写成Class[] ....
        //输出父接口
        for(Class<?> element: clasArr) {
            System.out.println(element);
        }

    }
}

输出:
www.bitten.java
java.lang.Object
interface www.bitten.java.ILife
interface www.bitten.java.IAnimal

3. 取得构造方法、普通方法、普通属性(⭐)

Constructor :用来描述一个类的构造方法的

(1)取得所有参数构造方法:
  • Class 类提供的getConstructors() :只能取得权限为public的构造方法
  • Class类提供的getDeclaredConstructors():取得所有权限的构造方法
class Person  {
    private String name;
    private int age;
    public Person() {

    }
    Person(String name) {

    }
    private Person(String name, int age) {

    }
}
public class Test1 {
    public static void main(String[] args) throws NoSuchMethodException {
        Class<?> cla = Person.class;
        //只能取得权限为public的构造方法
        Constructor<?>[] constructor = cla.getConstructors();
        //取得所有权限的构造方法
        Constructor<?>[] constructors = cla.getDeclaredConstructors();
        //输出权限为public的所有构造方法
        for (Constructor<?> constructor1 : constructor) {
            System.out.println(constructor1);
        }
        //输出所有权限的构造方法
        System.out.println("--------------------------");
        for (Constructor<?> constructor2 : constructors) {
            System.out.println(constructor2);
        }
    }
}

输出:

public www.bitten.java.Person()

public www.bitten.java.Person()
www.bitten.java.Person(java.lang.String)
private www.bitten.java.Person(java.lang.String,int)

(2)取得指定参数的构造方法
  • Class类提供的getConstructor(参数) : 只能取得权限为public的构造方法
  • Class类提供的getDeclaredConstructor(参数) : 可以取得类中所有构造方法,与权限无关

例码:

class Person  {
    private String name;
    private int age;
    public Person() {

    }
    public Person(String name) {

    }
    public Person(String name, int age) {

    }
}
public class Test1 {
    public static void main(String[] args)throws NoSuchMethodException{
        Class<?> cla = Person.class;
        //注意:getConstructor这个方法只能取得权限为public的构造方法
        Constructor constructor = cla.getConstructor(String.class,int.class);
        System.out.println(constructor.getName());
    }
}

输出:
www.bitten.java.Person

(3)创建新对象

利用反射创建新对象有两种方法:

  • 通过Class类的newInstance()方法 ,此方法只能调用无参构造来产生实例化对象;
  • 通过Constructor的newInstance方法获取指定参数构造方法实例化的对象;
(1):通过Class类的newInstance()方法
class Person  {
    private String name;
    private int age;
    public Person() {

    }
    public Person(String name) {

    }
    public Person(String name, int age) {

    }
    public void fun() {
        System.out.println("hello");
    }
}
public class Test1 {
    public static void main(String[] args)throws InstantiationException,IllegalAccessException{
        Class<?> cla = Person.class;
        //Class类的newInstance方法只能获取无参构造实例化的对象
        Person per =(Person) cla.newInstance();
        System.out.println(per);
        per.fun();
    }
}

输出:
www.bitten.java.Person@154617c
hello

结论:我们在编写Java程序时要养成保留无参构造的习惯 (⭐)

(2)通过Constructor的newInstance方法获取指定参数构造方法实例化的对象
class Person  {
        private String name;
        private int age;
        public Person() {

        }
        public Person(String name) {
            this.name = name;
        }
        public Person(String name, int age) {

        }
        public void fun() {
            System.out.println("hello");
        }
        public String getName() {
            return name;
        }

    }
    public class Test1 {
        public static void main(String[] args)throws NoSuchMethodException,InstantiationException
                ,IllegalAccessException,InvocationTargetException {
            Class<?> cla = Person.class;
            Constructor constructor = cla.getConstructor(String.class);
            Person per =(Person) constructor.newInstance("yy");
            System.out.println(per);
            System.out.println(per.getName());
        }
}
(4)取得普通方法和调用普通方法

Class类中提供了获取所有普通方法和获取指定参数普通方法的方法;

1.获取所有普通方法(返回值类型都为Method[ ])
  • (1):getMethods(),该方法返回对应的所有普通方法(不能返回private修饰的方法) ,它还返回父类,包括Object类的相关方法,也能返回所实现接口的普通方法;

  • (2):getDeclaredMethods(),该方法返回对应的所有普通方法,包括private修饰的普通方法,它不会返回父类的方法,但它能返回所实现接口中的方法;

最大区别:(1)方法能返回所继承父类的方法,而(2)不能;⭐

2.获取指定参数的普通方法
public Method getMethod(String name, Class<?>... parameterTypes)
class PP {
  public void funfun() {

  }
}
class Person extends PP{
  private String name;
  public Person() {
  }

  public String getName() {
      return name;
  }
  public void fun() {

  }

  public void setName(String name) {
      this.name = name;
  }

}
public class Test1 {
  public static void main(String[] args) throws Exception{
      Class cla = Person.class;
      Person per = (Person)cla.newInstance();
      //通过class对象的getDeclaredMethods()方法获取所有普通方法;
      Method[] arrMethod = cla.getDeclaredMethods();
      for(Method method:arrMethod) {
          System.out.println(method);
      }
      Method method1 = cla.getMethod("setName", String.class);
      Method method2 = cla.getMethod("getName");  //该方法需要抛出NoSuchMethodException;
      //要调用普通方法,必须得先创建它的实例化对象,per则是实例化
      method1.invoke(per,"yy");
      System.out.println(method2.invoke(per));   //输出yy
  }
}

输出:
public void www.bitten.java.Person.fun()
public java.lang.String www.bitten.java.Person.getName()
public void www.bitten.java.Person.setName(java.lang.String)
yy

可见getDeclaredMethod方法没有返回父类的方法;

(5)取得属性

前提:类中的所有属性一定在类对象实例化之后才会进行空间分配,所以此时如果要想调用类的属性,必须保证有实例化对象。通过反射的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<?

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

  1. 设置属性内容 : public void set(Object obj, Object value) throws IllegalArgumentException,
    IllegalAccessException
  2. 取得属性内容 : public Object get(Object obj) throws IllegalArgumentException,
    IllegalAccessException
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值