JAVA学习(反射reflection)

举例说明

1. 实例类
class Person {
	private String name = "liming";
	public int age = 2;
	
	public Person(){	
	}
	public Person(int age, String name){
		this.age = age;
		this.name = name;
	}
	
	public void sayHello(){
		System.out.println("hi!....");
	}
	public int getAgeDay(int a)	
		return a * 365;
	}
	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;
	}
}
2. 创建实例类的对象

方式一:new + 构造器
方式二:要创建Xxx类的对象,可以考虑:Xxx、Xxxs、XxxFactory、XxxBuilder类中查看是否有静态方法的存在。可以调用其静态方法,创建Xxx对象。
方式三:通过反射

  • 实例
//方式一:①Class对象调用newInstance()方法
	Class<Person> clazz = Person.class;
	Person obj = clazz.newInstance();
	System.out.println(obj);

//方式二:②通过反射获取到构造器之后,构造器通过newInstance()方法就可以生成初始化的类对象
	Constructor constructors = null;
		//获取构造器
		try {
			constructors = clazz2.getConstructor(new Class[]{int.class,String.class});
		} catch (SecurityException e) {
			e.printStackTrace();
		} catch (NoSuchMethodException e) {
			e.printStackTrace();
		}
		
		//获取类对象
		try {
			Person person3 = (Person) constructors.newInstance(10,"ahong");			
			System.out.println("我"+person3.age + "岁了!我叫" + person3.getName()+ "");
		} catch (IllegalArgumentException e) {
			// 参数不合法异常
			e.printStackTrace();
		} catch (InstantiationException e) {
			// 没有这个构造器,实例化异常
			e.printStackTrace();
		} catch (IllegalAccessException e) {
			// 类型转换异常
			e.printStackTrace();
		} catch (InvocationTargetException e) {
			// 当被调用的方法的内部抛出了异常而没有被捕获时,将由此异常接收
			e.printStackTrace();
	}
  • 说明
  1. newInstance():调用此方法,创建对应的运行时类的对象。内部调用了运行时类的空参的构造器。

  2. 要想此方法正常的创建运行时类的对象,要求:
    2.1运行时类必须提供空参的构造器
    2.2空参的构造器的访问权限得够。通常,设置为public。

  3. 在javabean中要求提供一个public的空参构造器。原因:
    3.1便于通过反射,创建运行时类的对象
    3.2便于子类继承此运行时类时,默认调用super()时,保证父类此构造器

1. 不用反射
  1. 调用实例类
public class TestReflection {
	public static void main(String[] args) {
		
		//方法一:常规调用
		Person person = new Person();
		int myAge = person.age;
		String myNameString = person.getName();
		int day = person.getAgeDay(myAge);
		System.out.println("我是" + myNameString + myAge + "岁" + "出生" + day +"天了!");
		person.sayHello();
		System.out.println("-------------------------------------------");
	}
}
2. 使用反射
  • 我们可以通过反射,获取对应的运行时类中所有的属性、方法、构造器、父类、接口、父类的泛型、包、注解、异常等。。。。
  • setAccessible(true)方法,这是针对私有变量而言,public和protected等都不需要。这个方法是允许通过反射访问类的私有结构。
  1. 获取Class对象
		//方式一;调用运行时类的属性:.class 
		Class<Person> clazz1 = Person.class;
		
		//方式二:通过运行时类的对象,调用getClass()
		Class clazz2 = person.getClass();
		
		//方式三:调用Class的静态方法:forName(String classPath)
		try {
			Class clazz3 = Class.forName("Person");
		} catch (ClassNotFoundException e) {
			e.printStackTrace();
		}
		
		//方式四:使用类的加载器:ClassLoader  (了解)
		ClassLoader classLoader = TestiBATIS.class.getClassLoader();
		
		//在非static的方法下可以用ClassLoader classLoader = this.getClass().getClassLoader();得到加载器
		try {
			Class clazz4 = classLoader.loadClass("Person");
		} catch (ClassNotFoundException e) {
			e.printStackTrace();
		}
  1. 获取运行时类的父类,使用Class对象调用getSuperclass()方法
		Class superClass = clazz1.getSuperclass();
		System.out.println(superClass); 
  1. 获取接口,使用Class对象调用getInterfaces()方法
		//一个类可以实现多个接口,所以getInterfaces()方法返回的是Class[]数组getInterfaces()只返回指定类实现的接口,不会返父类实现的接口。
		Class[] interfaceClasss = clazz1.getInterfaces();
  1. 调用指定的属性
		//1.getDeclaredField(String fieldName):获取运行时类中指定变量名的属性
		Person per = clazz1.newInstance();
		Field name = clazz1.getDeclaredField("name");
		//2.保证当前属性是可访问的
		name.setAccessible(true);
		//3.获取、设置指定对象的此属性值
		name.set(per, "Li");
		System.out.println(name.get(per));
  1. 调用指定的构造器
    1.获取指定的构造器 getDeclaredConstructor():参数:指明构造器的参数列表
    
    Constructor constructor = clazz.getDeclaredConstructor(int.class, String.class);

    //2.保证此构造器是可访问的
    constructor.setAccessible(true);
    
    //3.调用此构造器创建运行时类的对象
    Person per = (Person) constructor.newInstance("Tom");
    System.out.println(per);
  1. 调用指定的方法
  • invoke()方法
  1. java反射提供invoke()方法,在运行时根据业务需要调用相应的方法,这种情况在运行时非常常见,只要通过反射获取到方法名之后,就可以调用对应的方法
  2. invoke方法有两个参数,第一个参数是要调用方法的对象,第二个参数是调用方法要传入的参数。如果有多个参数,则用数组。如果调用的是static方法,invoke()方法第一个参数就用null代替
		//1.获取指定的某个方法getDeclaredMethod():参数1 :指明获取的方法的名称  参数2:指明获取的方法的形参列表
		
		Method dayMethod = clazz.getDeclaredMethod("day", int.class);
		
		//2.保证当前方法是可访问的
		dayMethod.setAccessible(true);
		
		//①获取方法参数
		Class[] parameterTypes = dayMethod.getParameterTypes();
		//②获取方法返回类型
		Class returnType = dayMethod.getReturnType();
		
		//3. 调用方法的invoke():参数1:方法的调用者  参数2:给方法形参赋值的实参
        //invoke()的返回值即为对应类中调用的方法的返回值。
		//执行此方法
		int day1 = (Integer)dayMethod.invoke(per, 1);
		System.out.println(day1);

精简版

		//二.带参无返回值
		Method sayNameAgeMehtod = clazz.getDeclaredMethod("sayNameAge", int.class, String.class);
		
		sayNameAgeMehtod.setAccessible(true);
		
		System.out.println(sayNameAgeMehtod.invoke(per, 2, "kkkk"));
3. 反射的应用
  1. 使用反射可以在运行时检查和调用类声明的成员方法,可以用来检测某个类是否有getter和setter方法。getter和setter是java bean必须有的方法。 getter和setter方法有下面的一些规律: getter方法以get为前缀,无参,有返回值 setter方法以set为前缀,有一个参数,返回值可有可无, 下面的代码提供了检测一个类是否有getter和setter方法
public static void printGettersSetters(Class aClass){
  Method[] methods = aClass.getMethods();

  for(Method method : methods){
    if(isGetter(method)) System.out.println("getter: " + method);
    if(isSetter(method)) System.out.println("setter: " + method);
  }
}

public static boolean isGetter(Method method){
  if(!method.getName().startsWith("get"))      return false;
  if(method.getParameterTypes().length != 0)   return false;  
  if(void.class.equals(method.getReturnType()) return false;
  return true;
}

public static boolean isSetter(Method method){
  if(!method.getName().startsWith("set")) return false;
  if(method.getParameterTypes().length != 1) return false;
  return true;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值