巧读 反射的秘密

反射

反射概述

JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性;这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制。

获取Class对象

如何找到对应的Class<?>模型对象 一共有三种方法

  • 1.通过类名
  • 2.通过对象名
  • 3.通过全路径
public static void main(String[] args) throws Exception {
		//1. 对象名.getClass();
		Person p = new Person();
		Class clazz = p.getClass();
		
		//2.  p.load(类名.class.getClassLoader().getResourceAsStream("config.properties");
		//类名.class
		Class clazz2 = Person.class;
		
		//3. Class.forName(全类名);
		Class clazz3 = Class.forName("reflect.Person");
		
		System.out.println(clazz == clazz2);//同一个类的Class对象只有一个
		System.out.println(clazz2 == clazz3);
		}

反射获取构造方法

public Constructor[] getConstructors(); 获取所有用public修饰的构造方法

public Constructor getConstructor(Class…args); 获取单个的用public修饰构造方法

public Constructor[] getDeclaredConstructors (); 获取所有的构造方法

public Constructor getDeclaredConstructor (Class…args); 获取单个构造方法

/**
 *  反射获取构造方法
 */
public class ReflectDemo2 {
	public static void main(String[] args) {
		try {
			//1. 得到Class对象
			Class clazz  = Class.forName("reflect.Person");
			//2. 获取构造方法
			//只能获取用public修饰的构造方法
			Constructor[] cs = clazz.getConstructors();
			for (Constructor c : cs) {
				System.out.println(c);
			}
			System.out.println("--------");
			Constructor[] ds = clazz.getDeclaredConstructors();
			for (Constructor c : ds) {
				System.out.println(c);
			}
			System.out.println("--------");
			//得到单个的构造方法:
			Constructor c1 = clazz.getConstructor(String.class,int.class);
			System.out.println(c1);
			System.out.println("--------");
			//得到单个的构造方法:
			Constructor c2 = clazz.getConstructor();//null, 无参
			System.out.println(c2);
			System.out.println("--------");
			//得到单个的构造方法: 用public修饰
//			Constructor c3 = clazz.getConstructor(String.class);//java.lang.NoSuchMethodException: 
//			System.out.println(c3);
			Constructor c4 =clazz.getDeclaredConstructor(String.class);
			System.out.println(c4);
			System.out.println("----");
			Constructor c5 =clazz.getDeclaredConstructor(int.class);
			
			//构造方法创建对象
			Object o = c1.newInstance("Jack",45);
			System.out.println(o);
			Object o2 = c4.newInstance("Rose");
			System.out.println(o2);
			
			//默认无法访问私有构造方法,如果非要访问,需要暴力破解
			c5.setAccessible(true);
			Object o3 = c5.newInstance(14);//Class 
			System.out.println(o3);
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
}

反射获取成员变量

Field[] fs getFields

Field[] fs getDeclaredFields

Field getField

Field getDeclaredField

/**
 * 反射获取成员变量
 */
public class ReflectDemo3 {

	public static void main(String[] args) {
		try {
			//1. Class
			Class clazz = Class.forName("reflect.Person");
			//2. 获取变量:
			//只能获取用public修饰的变量, 包括父类的
			Field[] fs = clazz.getFields();
			for (Field f : fs) {
				System.out.println(f);
			}
			System.out.println("------");
			Field[] dfs = clazz.getDeclaredFields();//得到所有
			for (Field f : dfs) {
				System.out.println(f);
			}
			//得到单个的变量
			Field f1 = clazz.getField("name");//public
			//Field f2 = clazz.getField("age");//不是public
			
			Field f3 = clazz.getDeclaredField("age");
			Field f4 = clazz.getDeclaredField("gender");
			
			//给对象中的变量赋值: p.name = "zhaangsan"
			//创建对象
			Object o = clazz.newInstance();//调用无参构造,保证类中有无参构造
			f1.set(o, "张三");// 把o对象中的名字设置为张三	 o.name="张三"
			//私有默认访问不了,暴力破解
			f3.setAccessible(true);
			f3.set(o, 18);
			f4.set(o, '男');
			
			//给静态属性赋值
			Field f5 = clazz.getDeclaredField("a");
			f5.set(null, 123);//把 a变量设置成了123
			System.out.println(o);
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
}

反射获取成员方法

Method[] getMethods

Method [] getDeclaredMethods

Method getMethod

Method getDeclaredMethod

/**
 * 使用反射获取方法
 */
public class ReflectDemo4 {

	public static void main(String[] args) {
		try {
			//1. Class
			Class clazz = Class.forName("reflect.Person");
			Method[] ms = clazz.getMethods();// 得到用public修饰的方法(自己类中和父类中)
			for (Method m : ms) {
				System.out.println(m);
			}
			//本类中所有的方法,不包含父类中的方法
			Method[] ds = clazz.getDeclaredMethods();
			System.out.println("-----");
			for (Method d : ds) {
				System.out.println(d);
			}
			//获取单个"
			Method m = clazz.getMethod("test1",null);
			System.out.println(m);
			
			Method m2 = clazz.getDeclaredMethod("test2", null);
			
			//调用方法,需要有一个对象
			Object o = clazz.newInstance();
			Object re = m.invoke(o, null);
			m2.setAccessible(true);
			m2.invoke(o, null);
			
			//调用一个有参数有返回值的方法
			Method m3 = clazz.getDeclaredMethod("getSum", int.class,int.class);
			Object sum = m3.invoke(o, 100,200);
			System.out.println(sum);
			
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
}

反射练习

ArrayList的一个对象,我想在这个集合中添加一个整型数据,如何实现呢?

/**
 * 	ArrayList<String>的一个对象,我想在这个集合中添加一个整型数据,如何实现呢?
 */
public class ReflectTest {
	public static void main(String[] args) {
		try {
			ArrayList<String> list = new ArrayList<>();
			list.add("abc");
			//填整数: 泛型只在编译时期有效
			//1. 先获取Class对象: ArrayList 的对象
			Class clazz = list.getClass();
			
			//2. 获取add方法   Object
			Method m = clazz.getMethod("add", Object.class);
			
			//3. 调用add方法,用哪个对象调用? list调用
			m.invoke(list, 12);
			m.invoke(list, 12.5);
			
			System.out.println(list);
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
}

反射解耦合

程序的耦合

  • 耦合:程序间的依赖关系
    • 包括:
      • 类之间的依赖
      • 方法间的依赖
  • 解耦:降低程序间的依赖关系
  • 实际开发中应该做到:
    • 编译期不依赖,运行时才依赖
  • 解耦的思路:
    • 第一步:通过读取配置文件来获取要创建的对象全限定类名
    • 第二步:使用反射来创建对象,而避免使用new关键字
public interface Teachable {

	public void teach();
}
public class Teacher implements Teachable {

	@Override
	public void teach() {
		System.out.println("教的挺水........");
	}

}

public class SuperTeacher implements Teachable{
	@Override
	public void teach() {
		System.out.println("教的贼6......");
	}
}

public class TeacherTest {

	public static void main(String[] args) {
		/*Teachable t = new Teacher();
		t.teach();*/
		try {
			Properties p = new Properties();
			p.load(TeacherTest.class.getClassLoader().getResourceAsStream("config.properties"));
			String value = p.getProperty("class.name");//全类名
			Class clazz = Class.forName(value);
			Object o = clazz.newInstance();
			
			Teachable tt = (Teachable)o;//
			tt.teach();
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值