反射

     

使用场景 : 在于 `框架 & 工具类` 底层代码的实现.

作用 : 在程序运行阶段, 动态创建对象. 完成程序代码的通用性.

创建对象:

1. new  类名();

缺点 : 编译阶段确定了创建的对象. 如果不修改源代码, 就无法实现更换对象.

优点 : 代码简单, 阅读性强.

2.反射创建对象;

反射创建对象的优点 : 实现了对象的灵活性. 根据配置文件的信息, 动态创建对应的字符串表示的对象.

  1. 获取指定 `字符串` 的Class对象.   字符串表示的是一个'全限定类名'.
  2. 使用获取的Class 对象调用 newInstance() 方法创建一个字符串表示的实例对象.
public static void main(String[] args) throws Exception {

		//1.创建properties对象
		Properties prop = new Properties();

		//2.将配置文件加载到properties对象     配置文件key=value;
		prop.load(new FileReader("obj.properties"));

		//3.使用getProperty(key)方法获取value,即通过key拿到value即'包名+类名'也就是全限定类名
		String className = prop.getProperty("obj");
		System.out.println(className);

		//4.通过className也就是权限类名  使用class.forName()方法拿到class对象;
		Class<?> cls = Class.forName(className);

		//5.使用class对象调用newInstance(),创建一个字符串表示的实例对象
		Object obj = cls.newInstance();

		System.out.println(obj);

	}

静态代码块加载配置文件:

特点:

1.时间早,在类被加载的时候执行

2.静态代码块仅被执行一次

public class ReflectionTest2 {

	// 定义一个Properties对象
	private static Properties prop = null;

	// 定义一个静态代码块儿
	static {
		// 初始化Properties对象
		prop = new Properties();
		try {
		// 加载配置文件到Peoperties对象中
			prop.load(new FileReader("obj.properties"));
		} catch (IOException e) {
			e.printStackTrace();
		}
	}



	public static void main(String[] args) throws Exception {
		method1();
		method2();
	}

	public static void method1() throws Exception {
		String className = prop.getProperty("obj1");
		Class<?> cls = Class.forName(className);
		Object obj = cls.newInstance();
		System.out.println(obj);
	}

	public static void method2() throws Exception {
		String className = prop.getProperty("obj2");
		Class<?> cls2 = Class.forName(className);
		Object obj = cls2.newInstance();
		System.out.println(obj);
	}

}

获取Class对象的三种方式:

  1. 通过 Class.forName(全限定类名);使用场景 : 配置文件

  2. 通过 类名.class 属性;使用场景 : 调用方法时的形参类型确定.

  3. 通过 对象.getClass() 方法.使用场景 : 方法内部确定传入参数对象的具体类型.

public class TestClass {
	public static void main(String[] args) throws Exception {
		
		/*
		 * ClassNotFoundException	类找不到异常 
		 * InstantiationException	实例化异常 (创建对象异常) 
		 * IllegalAccessException	非法访问异常
		 */
		
		// 1. Class.forName(全限定类名);
		
		Class<?> cls = Class.forName("reflection.Student");
		Object obj = cls.newInstance();
		System.out.println(obj);
		
		// 2. 类名.class 属性
		// 确定一个唯一的方法   `方法名 + 参数列表`    
		// introduce(String, int, char)
		// introduce(String.class, int.class, char.class)    所用类型都拥有 class 属性.
		// int.class, float.class, char.class, boolean.class
		Class<?> cls2 = Student.class;
		System.out.println(cls2);
		Object obj2 = cls2.newInstance();
		System.out.println(obj2);
		
		System.out.println(cls == cls2);//ture
		
		// 3. 对象名.getClass() 方法
		Student stu = new Student();
		show(stu);
	}
	
	public static void show(Object obj) throws Exception {
		
		Class<?> cls = obj.getClass();
		System.out.println(cls);
		
		Object o = cls.newInstance();
		System.out.println(o);
	}
}

反射构造方法:

public class TestConstructor {
	public static void main(String[] args) throws Exception {
		
		// 公开无参(public)
		Class<?> cls = Class.forName("reflection.Student");
		Object obj = cls.newInstance();
		System.out.println(obj);
		
		// 私有有参(private)
		// 1. 获取私有构造方法对象
		// Constructor<T> getDeclaredConstructor(Class<?>... parameterTypes)
		// 参数列表 : Class 类型的可变参数, 可变参数底层就是数组.
		Class<?>[] parameterTypes = new Class<?>[]{String.class, int.class};
		Constructor<?> constructor = cls.getDeclaredConstructor(parameterTypes);
		// 2. 设置私有构造方法的暴力访问
		constructor.setAccessible(true);
		// 3. 创建对象
		// newInstance(Object ... initargs)		需要的是一个 Object 类型的可变参数
		Object[] initargs = new Object[]{"Lucy", 18};
		Object obj2 = constructor.newInstance(initargs);
		System.out.println(obj2);
	}
}

反射调用方法:

public class TestMethod {
	// args -> arguments 实参		parameter 形参
	public static void main(String[] args) throws Exception {
		
		/*
		// public
		stu.setName("Lucy");
		stu.setAge(18);
		
		// private 
		stu.show(10086);
		*/
		
		// 1. 反射创建一个对象
		// Object obj = Class.forName("reflection.Student").newInstance();
		Class<?> cls = Class.forName("reflection.Student");
		Object obj = cls.newInstance();
		
		// 2. 获取方法对象   (public)    setName:方法名
		Class<?>[] parameterTypes = new Class<?>[]{String.class};
		Method method1 = cls.getMethod("setName", parameterTypes);
		Object[] arguments = new Object[]{"Lucy"};
		method1.invoke(obj, arguments);
		
		System.out.println(obj);
		
		// 3. 调用私有方法   show:方法名
		Method method2 = cls.getDeclaredMethod("show", int.class);
		// 4. 暴力访问
		method2.setAccessible(true);
		// 5. 调用方法
		method2.invoke(obj, 10086);
	}
}

反射设置并获取属性:

public class TestField {
	public static void main(String[] args) throws Exception {
		
		// 1. 反射创建一个对象
		Class<?> cls = Class.forName("reflection.Student");
		Object obj = cls.newInstance();
		
		// 2. 获取属性对象    desc:公开属性
		Field field1 = cls.getField("desc");
		// 3. 设置属性
		field1.set(obj, "学霸");
		
		System.out.println(obj);
		
		
		// 获取私有属性对象        name:私有属性
		Field field2 = cls.getDeclaredField("name");
		// 暴力访问
		field2.setAccessible(true);
		// 设置属性
		field2.set(obj, "Lucy");
		
		System.out.println(obj);
	}
}

类加载器:

Class 类的对象是 `类加载器` 为我们创建的.

Class 对象在程序中是无法直接创建的.

Class 类的构造方法是私有的. 该构造方法接收一个参数. 类型为 `ClassLoader` 类加载器. 只有Java虚拟机可以创建Class对象.

Java 虚拟机类加载器的类型 :

  1. 引导类加载器:      加载运行 `JRE` 中所有以 lib 结尾的包.
  2. 扩展类加载器:      加载运行时 `JRE` 中所有以 ext 结尾的包. (extension)          Ext 包中的类是给 JRE 运行环境提供辅助和扩展
  3. 应用类加载器:      加载程序员编写的 `类`.     第三方框架和工具类.

        三者之间的关系 : 应用类加载器     继承     扩展类加载器             继承              引导类加载器

 

 

 

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值