JAVA基础课程(第二十四天)

JAVA基础课程

第二十四天 Java 反射

Java 反射机制概述

​ (1)Reflection(反射)是被视为动态语言的关键,反射机制允许程序再执行期借助Reflection API取得任何类的内部信息,并能直接操作任意对象的内部属性和方法

​ (2)加载完类以后,再堆内存的方法区中就产生了一个Class类型的对象(一个类只有一个Class对象),这个对象就包含了完整的类的结构信息,我们可以通过这个对象看到类的结构。这个对象就像一面镜子,透过这个镜子看到类的结构,所以称为:反射

​ (3)Java反射机制研究及应用

​ ①在运行是判断任意一个对象所属的类

​ ②在运行是钩爪任意一个类的对象

​ ③在运行是判断任意一个类所具有的成员变量和方法

​ ④在运行是获取泛型信息

​ ⑤在运行是调用任意一个对象的成员变量和方法

​ ⑥在运行是处理注解

​ ⑦生成动态代理

​ (4)Java反射主要的API

​ ①java.lang.Class:代表一个类

​ ②java.lang.reflect.Method:代表类的方法

​ ③java.lang.reflect.Field:代表类的成员变量

​ ④java.lang.reflect.Constuctor:代表类的构造器

​ (5)简单使用

package com.test.course.reflectiontest;

import org.junit.Test;

import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;

/**
 * 〈Reflection〉
 *
 * @author PitterWang
 * @create 2020/5/14
 * @since 1.0.0
 */
public class ReflectionTest {
    
    


	@Test
	public void test(){
    
    
		//1.创建Persion类的对象
		Persion persion = new Persion(1,"TT");


	}
	@Test
	public void test2() throws Exception {
    
    


		Class<Persion> clazz = Persion.class;

		/***
		 * 通过反射创建Persion类的对象
		 */
		Constructor<Persion> persionConstructor = clazz.getConstructor(int.class, String.class);
		Persion persion = persionConstructor.newInstance(1, "TT");
		System.out.println(persion.toString());

/*
		persion.name = "NIBABA";
		persion.setId(2);
		System.out.println(persion.toString());
		persion.speak();
*/

		/**
		 * 通过反射,调用属性,私有的和公共的都可以调用
		 */
		Field name = clazz.getDeclaredField("name");
		name.set(persion,"NIBABA");

		System.out.println(persion.toString());

		Method speak = clazz.getDeclaredMethod("speak");
		speak.invoke(persion);
		
		/***
		 * 调用私有属性
		 */
		Field id = clazz.getDeclaredField("id");
		id.setAccessible(true);
		id.set(persion,12);
		System.out.println(persion.toString());


		/***
		 * 调用私有方法
		 */
		Method eat = clazz.getDeclaredMethod("eat",String.class);
		eat.setAccessible(true);
		eat.invoke(persion,"biebie");
	}
}


class Persion{
    
    
	private int id;
	String name;

	public Persion(int id, String name) {
    
    
		this.id = id;
		this.name = name;
	}

	private Persion(String name) {
    
    
		this.name = name;
	}

	public int getId() {
    
    
		return id;
	}

	public void setId(int id) {
    
    
		this.id = id;
	}

	public String getName() {
    
    
		return name;
	}

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


	public void speak(){
    
    
		System.out.println(this.name + "说话了");
	}

	private void eat(String food){
    
    
		System.out.println(this.name + "吃"+ food);
	}
	@Override
	public String toString() {
    
    
		return "Persion{" +
				"id=" + id +
				", name='" + name + '\'' +
				'}';
	}
}

理解Class类并获取Class实例

​ (1)类的加载过程

​ 程序经过javac.exe命令后,会生成一个或者多个字节码文件(.class)接着我们使用java.exe命令对某个字节码文件进行解释运行,相当于将某个字节码文件加载到内存中,次过程就叫做类的加载。加载到内存中的类,我们就称为运行时类,此时运行时类,就叫为Class的一个实例。

​ 换句话说,Class的实例对应着一个运行时类。

​ (2)那些类型可以成为有Class对象?

​ ①class:外部类,成员(成员内部类,静态内部类),局部内部类,匿名内部类

​ ②interface:接口

​ ③数组

​ ④enum:枚举

​ ⑤annotation:注解

​ ⑥primitive type:基本数据类型

​ ⑦void

	@Test
	public void test1(){
    
    
		Class c = Object.class;
		Class c1 = Comparable.class;
		Class c2 = String[].class;
		Class c3 = int[][].class;
		Class c4 = Override.class;
		Class c5 = int.class;
		Class c6 = void.class;
		Class c7 = Class.class;
	}

​ (3)Claaa实例的四种方式

package com.test.course.reflectiontest;

import org.junit.Test;

/**
 * 〈Claaa实例〉
 *
 * @author PitterWang
 * @create 2020/5/16
 * @since 1.0.0
 */
public class ClassTest {
    
    


	@Test
	public void test1(){
    
    
		Class c = Object.class;
		Class c1 = Comparable.class;
		Class c2 = String[].class;
		Class c3 = int[][].class;
		Class c4 = Override.class;
		Class c5 = int.class;
		Class c6 = void.class;
		Class c7 = Class.class;
	}

	@Test
	public void test() throws ClassNotFoundException {
    
    

		/***
		 * 1.调用运行时类的属性:.class
		 */
		Class clazz = Persion.class;
		System.out.println(clazz);

		/***
		 * 2.通过运行时类的对象,调用getClass()
		 */
		Persion persion = new Persion();
		Class<? extends Persion> aClass = persion.getClass();
		System.out.println(aClass);

		/***
		 * 3.调用Class的静态方法:forName(String classPath)
		 */
		Class<?> aClass1 = Class.forName("com.test.course.reflectiontest.Persion");
		System.out.println(aClass1);

		/**
		 * 4.通过类加载器:Classloader
		 */
		ClassLoader classLoader = ClassTest.class.getClassLoader();
		Class<?> aClass2 = classLoader.loadClass("com.test.course.reflectiontest.Persion");
		System.out.println(aClass2);


	}
}

类的加载与ClassLoader的理解

​ 以后在学习JVM中写,这里写一个ClassLoader加载配置文件

package com.test.course.reflectiontest;

import org.junit.Test;

import java.io.IOException;
import java.io.InputStream;
import java.util.Properties;

/**
 * 〈ClassLoader〉
 *
 * @author PitterWang
 * @create 2020/5/16
 * @since 1.0.0
 */
public class ClassLoaderTest {
    
    

	@Test
	public void test() throws IOException {
    
    
		Properties properties = new Properties();

		ClassLoader classLoader = ClassLoaderTest.class.getClassLoader();
		InputStream resourceAsStream = classLoader.getResourceAsStream("test.propertise");

		properties.load(resourceAsStream);

		String name = properties.getProperty("name");
		System.out.println(name);
	}
}

创建运行时类的对象

package com.test.course.reflectiontest;

import org.junit.Test;

import java.util.Random;

/**
 * 〈通过反射创建对应运行时类的对象〉
 *
 * @author PitterWang
 * @create 2020/5/16
 * @since 1.0.0
 */
public class ClassTest1 {
    
    

	@Test
	public void test() throws IllegalAccessException, InstantiationException {
    
    
		Class<Persion> persionClass = Persion.class;
		/**
		 * newInstance();调用此方法,创建运行时类的对象,内部调用了运行时类的空参构造器
		 *
		 * 成功调用此方法,必须
		 * ①运行时类必须有空参构造器
		 * ②空参构造器的权限必须时public
		 */
		Persion persion = persionClass.newInstance();
		System.out.println(persion);
	}


	/**
	 * 动态创建运行时类对象
	 * @throws Exception
	 */
	@Test
	public void test1() throws Exception{
    
    
		for(int j = 0;j<100;j++){
    
    
			int i = new Random().nextInt(2);
			String namePath = "";
			if(i == 0){
    
    
				namePath = "com.test.course.reflectiontest.Persion";
			}else if(i == 1){
    
    
				namePath = "java.lang.String";

			}else{
    
    
				namePath = "java.util.Date";

			}


			System.out.println(namePath);
			Object o = getInstance(namePath);
			System.out.println("******************");
			System.out.println(o);
		}

	}
	public Object getInstance(String namePath) throws Exception {
    
    
		Class<?> aClass = Class.forName(namePath);
		return aClass.newInstance();
	}
}

获取运行时类的完整结构

​ (1)获取运行时类的方法结构

	/***
	 * 获取运行时类方法
	 */
	@Test
	public void test(){
    
    
		Class<Persion> clazz = Persion.class;

		/**
		 * 获取运行时类及其父类的中什么为public的方法
		 */
		Method[] methods = clazz.getMethods();

		for (Method method : methods) {
    
    
			System.out.println(method);
		}
		System.out.println("******************");
		/**
		 * 获取运行时类中所有的方法,不包含父类的方法
		 */
		Method[] declaredMethods = clazz.getDeclaredMethods();

		/***
		 * 获取方法的修饰

		 * 注解 权限修饰符 返回值类型 方法名(参数) throws 异常{}
		 */
		for (Method method: declaredMethods) {
    
    
			System.out.println(method);
			System.out.println("************************");

			//获取方法上的注解
			Annotation[] annotations = method.getAnnotations();
			for (Annotation annotation : annotations) {
    
    
				System.out.println(annotation);
			}

			//方法的权限修饰符
			int modifiers = method.getModifiers();
			System.out.print(Modifier.toString(modifiers) + "\t");

			//方法的返回类型
			Class<?> returnType = method.getReturnType();
			System.out.println(returnType.getName());


			//方法名
			System.out.println(method.getName());

			//形成列表
			Class<?>[] parameterTypes = method.getParameterTypes();

			for (Class<?> parameterType : parameterTypes) {
    
    
				System.out.println(parameterType.getName());
			}

			//抛出的异常

			Class<?>[] exceptionTypes = method.getExceptionTypes();
			for (Class<?> exceptionType : exceptionTypes) {
    
    
				System.out.println(exceptionType.getName());
			}
		}
	}

​ (2)获取运行时类的属性结构

/***
 * 获取运行时类属性
 */
@Test
public void test1(){
    
    
   Class<Persion> clazz = Persion.class;

   Field[] declaredFields = clazz.getDeclaredFields();
   for (Field declaredField : declaredFields) {
    
    

      int modifiers = declaredField.getModifiers();//权限修饰符
      System.out.print(Modifier.toString(modifiers) + "\t");

      Class<?> type = declaredField.getType();//数据类型
      System.out.print(type.getName() + "\t");

      String name = declaredField.getName();//变量名
      System.out.print(name);

      System.out.println();

   }
}

​ (3)获取运行时类的构造器

/***
 * 获取运行时类的构造器
 */
@Test
public void test2(){
    
    
   Class<Persion> clazz = Persion.class;
   /**
    * 获取运行时类中声明为public的构造器
    */
   Constructor<?>[] constructors = clazz.getConstructors();

   for (Constructor<?> constructor : constructors) {
    
    
      System.out.println(constructor);
   }

   System.out.println("*****************************");
   /***
    * 获取运行时类的所有构造器
    */
   Constructor<?>[] declaredConstructors = clazz.getDeclaredConstructors();
   for (Constructor constructor : declaredConstructors) {
    
    
      System.out.println(constructor);
   }
}

​ (4)获取运行时类的父类及泛型类型

/**
 * 获取运行时类的父类及泛型类型
 */
@Test
public void test3(){
    
    
   Class<Persion> clazz = Persion.class;

   /**
    * 获取运行时类的父类s
    */
   Type genericSuperclass = clazz.getGenericSuperclass();
   System.out.println(genericSuperclass);
   /***
    * 获取父类的泛型类型
    */
   ParameterizedType parameterizedType =  (ParameterizedType) genericSuperclass;
   Type[] actualTypeArguments = parameterizedType.getActualTypeArguments();

   for (Type actualTypeArgument : actualTypeArguments) {
    
    
      System.out.println(actualTypeArgument);
   }
}

​ (4)获取运行时类实现的接口及其父类实现的接口

@Test
public void test4(){
    
    
   Class<Persion> clazz = Persion.class;

   /**
    *运行时类实现的接口
    */
   Class<?>[] interfaces = clazz.getInterfaces();
   for (Class<?> anInterface : interfaces) {
    
    
      System.out.println(anInterface);
   }

   System.out.println("*********************8");

   /**
    * 运行时类父类实现的接口
    */
   Class<?>[] interfaces1 = clazz.getSuperclass().getInterfaces();
   for (Class<?> aClass : interfaces1) {
    
    
      System.out.println(aClass);
   }

}

​ (5)获取运行时类所在的包

/***
 *获取运行时类所在的包
 */
@Test
public void test5() {
    
    
   Class<Persion> clazz = Persion.class;
   Package aPackage = clazz.getPackage();
   System.out.println(aPackage);
}

​ (6)获取运行时类声明的注解

/***
 *获取运行时类实现的注解
 */
@Test
public void test6() {
    
    
   Class<Persion> clazz = Persion.class;
   Annotation[] annotations = clazz.getAnnotations();
   for (Annotation annotation : annotations) {
    
    
      System.out.println(annotation);
   }
}

调用运行时类的指定结构

​ (1)操作运行时指定类的属性

/**
 * 操作运行时指定类的属性
 * @throws IllegalAccessException
 * @throws InstantiationException
 * @throws NoSuchFieldException
 */
@Test
public void test() throws IllegalAccessException, InstantiationException, NoSuchFieldException {
    
    
   Class<Persion> clazz = Persion.class;

   /***
    * 方法1:
    */
   /**
    * 创建运行时类的对象
    */
   Persion persion = clazz.newInstance();

   /**
    * 获取指定的属性public的属性
    */
   Field name = clazz.getField("name");

   /**
    * 为指定属性设置值
    * 参数1时那个对象设值
    * 参数2时设置的内容
    */
   name.set(persion,"DD");

   System.out.println(persion);


   /***
    * 获取指定对象的属性值
    */
   Object o = name.get(persion);
   System.out.println(o);


   /**
    * 方法2  获取任意权限的值
    */
   /**
    * 获取指定属性
    */
   Field id = clazz.getDeclaredField("id");
   /**
    * 设置属性可访问
    */
   id.setAccessible(true);
   /**
    * 设值
    */
   id.set(persion,123);

   System.out.println(persion);

   /**
    * 取值
    */
   System.out.println(id.get(persion));
}

​ (2)操作运行时类的指定方法

@Test
	public void test1() throws Exception {
    
    
		/**
		 * 创建运行时类
		 */
		Class<Persion> clazz = Persion.class;

		Persion persion = clazz.newInstance();

		/**
		 * 获取指定方法
		 */
		Method eat = clazz.getDeclaredMethod("eat", String.class);
		/**
		 * 设置可访问
		 */
		eat.setAccessible(true);
		/**
		 * 调用方法
		 */
		eat.invoke(persion,"吃屎");




		/**
		 * 获取指定方法
		 */
		Method tett = clazz.getDeclaredMethod("tett", String.class);
		/**
		 * 设置可访问
		 */
		tett.setAccessible(true);
		/**
		 * 调用方法  获取返回值
		 */
		Object ret = tett.invoke(persion,"吃屎");
		System.out.println(ret);
	}

​ (3)操作运行时类的构造器

@Test
	public void test2() throws Exception {
    
    
		/**
		 * 创建运行时类
		 */
		Class<Persion> clazz = Persion.class;

		/***
		 * 调用无参构造器方法1
		 */
		Persion persion = clazz.newInstance();
		System.out.println(persion);
		/***
		 * 调用无参构造器方法2
		 */
		Constructor<Persion> declaredConstructor1 = clazz.getDeclaredConstructor();
		Persion persion1 = declaredConstructor1.newInstance();
		System.out.println(persion1);
		System.out.println("************************");

		/**
		 * 调用指定的构造器
		 */
		Constructor<Persion> declaredConstructor = clazz.getDeclaredConstructor(String.class);
		declaredConstructor.setAccessible(true);
		Persion persion3 = declaredConstructor.newInstance("DD");
		System.out.println(persion3);


		//Constructor<?>[] declaredConstructors = clazz.getDeclaredConstructors();
	}

猜你喜欢

转载自blog.csdn.net/weixin_35133235/article/details/106163133