java学习之路 之 反射机制-练习题

反射机制练习题

前面我们对反射机制的理论知识进行了学习,现在我们来实际应用,从而更加了解它。首先我们先创建Person类,和Teacher类继承Person类(包含注解),供我们反射使用,具体如下:

package com.atguigu.javase.reflect;

import java.io.Serializable;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;

import org.junit.Test;

@Retention(RetentionPolicy.RUNTIME) // 保持在运行时,才可以通过反射获取
@interface MyAnn {
	String name() default "张三";
	int age() default 30;
}

// 创建Person类,为完成反射提供一个简单的类
class Person {
	
	public String gender;
	public int height;
	public double weight;
	
	private void privateTest() {
		System.out.println("Person.privateTest()");
	}
}

// 创建Teacher类继承Person类
@MyAnn
public class Teacher extends Person implements Serializable, Comparable {
	
	private static int counter = 100;
	
	public static void test() {
		System.out.println("static test()");
	}
	
	public String name;
	private int age;
	private double salary;
	
	public Teacher() {
	}
	
	private Teacher(String name, int age, double salary) {
		super();
		this.name = name;
		this.age = age;
		this.salary = salary;
	}

	public void eat(String something) {
		System.out.println("老师在吃" + something);
	}
	
	public void eat(String something, int time) {
		System.out.println("老师在吃" + something + "吃了" + time + "小时");
	}
	
	@MyAnn(name="李四", age=40)
	private static final String concat(int i, double d, char c, boolean b) {
		return "" + i + d + c + b;
	}

	@Override
	public String toString() {
		return "Teacher [name=" + name + ", age=" + age + ", salary=" + salary + "]";
	}

	@Override
	public int compareTo(Object o) {
		return 0;
	}
	
}
现在我们就可以测试反射创建对象、调用属性、方法等和正常情况创建有什么区别?

package com.atguigu.javase.reflect;

import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.PrintStream;
import java.lang.annotation.Annotation;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Properties;
import java.util.Set;

import org.junit.Test;


public class ReflectTest {		
	// 正常方式创建对象,调用方法
	@Test
	public void test1() {
		/*
		Teacher t1 = new Teacher(); // 由JVM自动 加载类, 再创建对象.
		t1.name = "小明";
		t1.age = 20;
		t1.salary = 1000;
		System.out.println(t1.name);
		System.out.println(t1.age);
		System.out.println(t1.salary);
		t1.eat("回锅肉");
		System.out.println(t1);
		*/
	}

	// 通过反射获取类的属性,以及私有属性的获取
	@Test
	public void test2() {
		try {
			Class clazz = Class.forName("com.atguigu.javase.reflect.Teacher");// 根据类的全限定名称加载类并创建类模板对象,
			//加载类的过程就是由类加载器读取Teacher.class二进制文件,由类加载器生成Class对象
			// 类模板对象中包含了类中的属性的定义(Field对象)和方法的代码(Method对象)
			Object object = clazz.newInstance(); // 对象的创建由方法来完成, 调用类的无参构造器创建对象
			System.out.println(object);
			
			//((Teacher)object).name = "小红";
			//Field ageField = clazz.getField("age"); // 只能获取公共的属性
			Field ageField = clazz.getDeclaredField("age"); // 只在在本类中声明了的属性, 就可以获取到!!!, 不受访问控制修饰
			ageField.setAccessible(true);
			ageField.set(object, 40);// 相当于object.age = 40;
			System.out.println(ageField.get(object)); // System.out.println(object.age);
			
			Field salaryField = clazz.getDeclaredField("salary");
			System.out.println(salaryField);
			salaryField.setAccessible(true); // 突破封装,实现私有成员的访问
			salaryField.set(object, 5000);
			System.out.println(salaryField.get(object));
			
			Field nameField = clazz.getDeclaredField("name");
			nameField.setAccessible(true); // 突破封装,实现私有成员的访问
			nameField.set(object, "小红");
			
			System.out.println(object);
			
		} catch (ClassNotFoundException e) { // 类名不正确, 根据类名找到.class文件
			e.printStackTrace();
		} catch (InstantiationException e) { // 构造器调用错误!!
			e.printStackTrace();
		} catch (IllegalAccessException e) { // 构造器封装
			e.printStackTrace();
		} catch (NoSuchFieldException e) {
			e.printStackTrace();
		} catch (SecurityException e) {
			e.printStackTrace();
		} 
	}

 	// 通过反射获取类实现了哪些接口
	@Test
	public void test3() {
		try {
			Class clazz = Class.forName("com.atguigu.javase.reflect.Teacher");
			Class superClazz = clazz.getSuperclass();
			System.out.println(superClazz);
			Class[] interfaceArr = clazz.getInterfaces();
			for (int i = 0; i < interfaceArr.length; i++) {
				System.out.println("实现接口:" + interfaceArr[i]);
			}
		} catch (ClassNotFoundException e) {
			e.printStackTrace();
		}
	}

	//  创建对象的4种方法
	@Test
	public void test4() {
		try {
			//1) 常规使用, 软编码
			Class clazz1 = Class.forName("com.atguigu.javase.reflect.Teacher");
			
			//2) 最简单, 硬编码
			Class clazz2 = Teacher.class;
			
			System.out.println(clazz1 == clazz2);
			
			//3) 比较灵活, 硬编码
			Class clazz3 = new Teacher().getClass();
			System.out.println(clazz2 == clazz3);
			
			//4) 比较复杂, 先获取到类加载器对象,再手工加载类, 软编码
			ClassLoader classLoader = this.getClass().getClassLoader();
			Class clazz4 = classLoader.loadClass("com.atguigu.javase.reflect.Teacher");
			System.out.println(clazz3 == clazz4);
			
		} catch (ClassNotFoundException e) {
			e.printStackTrace();
		}
	}
	
	// 通过反射获取类加载器
	@Test
	public void test5() {
		ClassLoader appClassLoader = ClassLoader.getSystemClassLoader();
		System.out.println(appClassLoader);
		
		ClassLoader extClassLoader = appClassLoader.getParent();
		System.out.println(extClassLoader);
		
		ClassLoader bootstapClassLoader = extClassLoader.getParent();
		System.out.println(bootstapClassLoader);
		
		System.out.println("" + Object.class.getClassLoader());// 引导类加载器加载核心类
		System.out.println("" + Person.class.getClassLoader());
	}

	@Test
	public void test6() throws IOException {
		// 通类加载器读取的资源文件的当前目录不是项目目录, 而是src目录
		// src目录就是项目的classpath中的
		// 可以直接从jar包中读取资源文件
		//InputStream is = this.getClass().getClassLoader().getResourceAsStream("resource.properties");
		InputStream is = this.getClass().getClassLoader().getResourceAsStream("com/sun/corba/se/impl/logging/LogStrings.properties");
		Properties properties = new Properties();
		properties.load(is);
		System.out.println(properties.getProperty("IOR.nullPoa"));
	}

	// 通过反射获取类的方法,并实现方法
	@Test
	public void test7() {
		try {
			Class clazz = Class.forName("com.atguigu.javase.reflect.Teacher");
			Object object = clazz.newInstance();
			
			Field nameField = clazz.getDeclaredField("name");
			nameField.setAccessible(true);
			nameField.set(object, "小明");
			
			System.out.println(object);
			
			// 调用方法
			// 1) 从类模板对象中获取方法对象, getMethod会获取本类或者从父类继承的所有公共方式
			Method eatMethod1 = clazz.getMethod("eat", String.class);
			// 2) 通过方法对象间接调用自己
			Object retValue = eatMethod1.invoke(object, "肉包子"); // object.eat("肉包子");
			System.out.println("方法返回值:" + retValue);
			
			Method eatMethod2 = clazz.getMethod("eat", String.class, int.class);
			eatMethod2.invoke(object, "紫菜包饭", 5);
			
			Method toStringMethod = clazz.getMethod("toString");
			Object retValue2 = toStringMethod.invoke(object);
			System.out.println(retValue2);
			
			Method hashCodeMethod = clazz.getMethod("hashCode");
			Object retValue3 = hashCodeMethod.invoke(object);
			System.out.println(retValue3);
			
			// 可以获取本类所有方法,包括私有方法
			Method concatMethod = clazz.getDeclaredMethod("concat", int.class, double.class, char.class, boolean.class);
			concatMethod.setAccessible(true);
			Object retValue4 = concatMethod.invoke(object, 100, 3.14, '你', true);
			System.out.println(retValue4);
			
			System.out.println("修饰符:" + Modifier.toString(concatMethod.getModifiers()));
			Annotation annotation = concatMethod.getAnnotation(Test.class); // 获取注解
			System.out.println(annotation);
			
			// getDeclaredMethod, 只能获取本类中声明的方法,从父类继承的无法拿到
			//Method getClassMethod = clazz.getDeclaredMethod("getClass");
			//System.out.println(getClassMethod);
			
			// 获取父类的私有方法,并通过子类对象来调用, 也是可以成功的, 说明子类继承父类的所有成员!!
			Method method = clazz.getSuperclass().getDeclaredMethod("privateTest");
			method.setAccessible(true);
			method.invoke(object);
			
		} catch (ClassNotFoundException e) {
			e.printStackTrace();
		} catch (InstantiationException e) {
			e.printStackTrace();
		} catch (IllegalAccessException e) {
			e.printStackTrace();
		} catch (NoSuchFieldException e) {
			e.printStackTrace();
		} catch (SecurityException e) {
			e.printStackTrace();
		} catch (NoSuchMethodException e) {
			e.printStackTrace();
		} catch (IllegalArgumentException e) {
			e.printStackTrace();
		} catch (InvocationTargetException e) {
			e.printStackTrace();
		}
	}

	// 通过反射获取构造器对象,从而完成对象的创建
	@Test
	public void test8() {
		try {
			Class clazz = Class.forName("com.atguigu.javase.reflect.Teacher");
			// 使用其他构造器创建对象
			// 1) 先获取到构造器对象
			//Constructor constructor = clazz.getConstructor(String.class, int.class, double.class);
			Constructor constructor = clazz.getDeclaredConstructor(String.class, int.class, double.class);
			int modifiers = constructor.getModifiers(); // 获取修饰符
			Class[] typesClasses = constructor.getParameterTypes();
			for (int i = 0; i < typesClasses.length; i++) {
				System.out.println("构造器参数:" + typesClasses[i]);
			}
			System.out.println(Modifier.toString(modifiers));
			
			constructor.setAccessible(true);
			// 2) 间接调用构造器完成对象创建
			Object object = constructor.newInstance("立超", 19, 10000);
			System.out.println(object);
			
			Constructor runtimeConstructor = Runtime.class.getDeclaredConstructor();
			System.out.println(runtimeConstructor);
			runtimeConstructor.setAccessible(true);
			Object object2 = runtimeConstructor.newInstance();
			System.out.println(object2);
			System.out.println(Runtime.getRuntime());
			
			System.out.println(Object.class.getSuperclass());
			
		} catch (ClassNotFoundException e) {
			e.printStackTrace();
		} catch (NoSuchMethodException e) {
			e.printStackTrace();
		} catch (SecurityException e) {
			e.printStackTrace();
		} catch (InstantiationException e) {
			e.printStackTrace();
		} catch (IllegalAccessException e) {
			e.printStackTrace();
		} catch (IllegalArgumentException e) {
			e.printStackTrace();
		} catch (InvocationTargetException e) {
			e.printStackTrace();
		}
	}

	// 通过反射获取私有方法,注解
	@Test
	public void test9() {
		try {
			Class clazz = Class.forName("com.atguigu.javase.reflect.Teacher");
			Annotation classannotation = clazz.getAnnotation(MyAnn.class);
			System.out.println(classannotation);
			
			// 可以获取本类所有方法,包括私有方法
			Method concatMethod = clazz.getDeclaredMethod("concat", int.class, double.class, char.class, boolean.class);
			System.out.println("修饰符:" + Modifier.toString(concatMethod.getModifiers()));
			Annotation annotation = concatMethod.getAnnotation(MyAnn.class); // 获取注解
			System.out.println(annotation);
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	// 通过反射获取一个类的构造器,属性,方法
	@Test
	public void test10() throws Exception {
		String className = "java.util.HashMap";
		Class clazz = Class.forName(className);
		Constructor[] allConstructors = clazz.getDeclaredConstructors(); // 本类中声明的所有构造器
		for (int i = 0; i < allConstructors.length; i++) {
			System.out.println(allConstructors[i]);
		}
		System.out.println("----------------------");
		Field[] allFields = clazz.getDeclaredFields(); // 本类中声明的所有的属性
		for (int i = 0; i < allFields.length; i++) {
			System.out.println(allFields[i]);
		}
		Field[] allPublicFields = clazz.getFields(); // 获取本类及从父类继承的所有公共属性
		for (int i = 0; i < allPublicFields.length; i++) {
			System.out.println(allPublicFields[i]);
		}
		System.out.println("-----------------------------");
		Method[] allMethods = clazz.getDeclaredMethods(); // 本类声明的所有方法
		for (int i = 0; i < allMethods.length; i++) {
			System.out.println(allMethods[i]);
		}
		Method[] allPublicMethods = clazz.getMethods(); // 获取本类及从父类继承的所有公共方法
		for (int i = 0; i < allPublicMethods.length; i++) {
			System.out.println(allPublicMethods[i]);
		}
	}
	
	// 写一个方法printClassDetails(String className)
	// 先打印类名和父类(getSuperClass())及实现的接口(getInterfaces())
	// 在方法中打印类模板中的所有构造器,所有属性(包含从父类继承的公共属性), 所有方法(包含从父类继承的公共方法) 要求不要重复打印
	// 打印的时候注意一下缩进
	public void printClassDetails(String className) throws ClassNotFoundException {
		Class clazz = Class.forName(className);
		System.out.print("public class " + clazz.getSimpleName() + " extends " + clazz.getSuperclass().getSimpleName());
		System.out.print(" implements ");
		Class[] allInterface = clazz.getInterfaces();
		for (int i = 0; i < allInterface.length; i++) {
			System.out.print(allInterface[i].getSimpleName() + ",");
		}
		System.out.println("{");
		System.out.println();
		Set<Field> allFields = new HashSet<Field>();
		for (Field field : clazz.getFields()) {
			allFields.add(field);
		}
		for (Field field : clazz.getDeclaredFields()) {
			allFields.add(field);
		}
		
		Iterator<Field> iterator = allFields.iterator();
		while (iterator.hasNext()) {
			System.out.println("\t" + iterator.next());
		}
		
		System.out.println();
		
		for (Constructor constructor : clazz.getDeclaredConstructors()) {
			System.out.println("\t" + constructor);
		}
		System.out.println();
		Set<Method> allMethods = new HashSet<Method>();
		for (Method method : clazz.getMethods()) {
			allMethods.add(method);
		}
		for (Method method : clazz.getDeclaredMethods()) {
			allMethods.add(method);
		}
		System.out.println();
		for (Method method : allMethods) {
			System.out.println("\t" + method);
		}
		System.out.println("}");
	}
	
	// 调用printClassDetails方法
	@Test
	public void exer1() {
		try {
			printClassDetails("java.io.ObjectOutputStream");
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
	
	// 静态属性、静态方法的访问
	@Test
	public void test11() {
		try {
			Class clazz = Class.forName("com.atguigu.javase.reflect.Teacher");
			//Object object = clazz.newInstance();
			Field counterField = clazz.getDeclaredField("counter");
			System.out.println(counterField);
			counterField.setAccessible(true);
			System.out.println(counterField.get(null)); // 静态属性的访问不需要对象, 所以传入null也可以
			counterField.set(null, 10000); // 静态的设置也不需要对象
			System.out.println(counterField.get(null)); // 静态属性的访问不需要对象, 所以传入null也可以
			
			Method testMethod = clazz.getMethod("test");
			testMethod.invoke(null);
			
		} catch (Exception e) {
			e.printStackTrace();
		}
	}	
	
	<span style="color:#ff0000;">// 反射在自定义泛型中的应用
	// 通过反射获取子类的泛型类型->创建父类对象</span>
	@Test
	public void test12() throws InstantiationException, IllegalAccessException {
		Parent parent1 = new Child1();
		Parent parent2 = new Child2();
	}	
}

// 上面test12测试所需要的类,其中父类为自定义泛型类,子类确定泛型的类型,在父类无参构造器中通过反射获取到子类的泛型// 类型从而确定父类的泛型类型,然后创建对象,从而实现对象的创建
class Parent<T> {
	
	T t;
	Class clazz;
	
	public Parent() {
		Type type = this.getClass().getGenericSuperclass();
		if (!(type instanceof ParameterizedType)) { // 在子类的声明中并没有任何的泛型信息
			clazz = Object.class;
		} else {
			ParameterizedType parameteredType = (ParameterizedType)type;
			Type[] types = parameteredType.getActualTypeArguments();
			clazz = (Class)types[0];
		}
		System.out.println(clazz);
		try {
			t = (T) clazz.newInstance();
			System.out.println(t);
		} catch (InstantiationException | IllegalAccessException e) {
			e.printStackTrace();
		}
	}
	
	public T getT() {
		return t;
	}
}

class Child1 extends Parent<Person> {
}
class Child2 extends Parent {
}
class Child3 extends Parent<PrintStream> {
}
// 反射可以应用在泛型类中,但是更加凸显出去其作用是在动态中

  • 4
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值