天天看点

JAVA基础WEB阶段第六天——反射

1.什么是反射机制

    JAVA反射机制是在运行状态中,对于任意一个实体类,都能够知道这个类的所有属性和方法;

    对于任意一个对象,都能够调用它的任意方法和属性;

    这种动态获取信息以及动态调用对象方法的功能称为java语言的反射机制。

2.反射机制 

3.Class类的介绍

        概念:Class 类的实例表示正在运行的 Java 应用程序中的类和接口

        我们理解: Class类,用它获取的对象,就是正在执行的.class字节码对象.

4.Class 创建的三种方式

        方式1:  

                Class clazz = 类.class属性;    MyTick.class (就代表的是Class 类型的对象)

        方式2:  

                1)创建对象

                2)Class clazz = 对象.getClass();

        方式3:

                Class clazz = Class.forName("类的完全路径名");

测试代码:
		public class ClazzTest {

			@Test
			public void testfun() throws ClassNotFoundException {
				//1.方式1:获取字节码对象    格式:Class clazz = 类.class属性;
				Class clazz01 =  Person.class;
				System.out.println(clazz01);

				//2.方式2:获取字节码对象    格式: 1)创建对象 2)Class clazz = 对象.getClass();
				Person p = new Person();
				Class clazz2 = p.getClass();
				System.out.println(clazz2);

				//3.方式3:获取字节码对象    格式:Class clazz = Class.forName("类的完全路径名");
				Class clazz3 = Class.forName("com.it.clazz.Person");
				System.out.println(clazz3);
			}
		}		
           

Class对象的特点:

        该对象在内存中只创建一次. 通过几种方式获取的对象都是同一个对象. 它们的地址值一样.

5.Class类的常用方法

        第一组方法:

        static Class                forName(String className)  静态方法,作用是获取Class对象

        ClassLoader(类加载器)      getClassLoader()  返回该类的类加载器。                            

          T                             newInstance() 创建此 Class 对象所表示的类的一个新实例。 

         String                 getSimpleName();     获得简单类名,只是类名,没有包    

         String                 getName(); 获取完整类名,包含包名+类名

        第二组方法:

        Constructor<T>             getConstructor(Class<?>... parameterTypes)  获取构造方法对象

        Constructor<T>                getDeclaredConstructor(Class<?>... parameterTypes)              

                                    获取构造方法对象(可以获取私有的构造方法)

        第三组方法:                            

        Method                        getMethod(String name, Class<?>... parameterTypes)  获取方法对象

        Method                         getDeclaredMethod(String name, Class<?>... parameterTypes) 

                                    可以获取私有的方法对象

        第四组方法:                            

        Field                         getField(String name) 获取属性对象

        Field                         getDeclaredField(String name) 可以获取私有的属性          

构造方法的练习:

 * 需求1:

         * 使用Class 获取构造方法对象.Student

         * 调用构造方法对象的newIntances方法,创建对象.

@Test
			public void test01() throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
				//1.获取student的字节码对象
				Class clazz = Student.class;
				//2.获取构造方法对象
				//Constructor<T>    getConstructor(Class<?>... parameterTypes)  获取构造方法对象
				Constructor constructor = clazz.getConstructor();
				//3.构造方法调用newIntances方法创建对象
				// T newInstance(Object... initargs)
				Student stu = (Student) constructor.newInstance();
				stu.fun();
			}
           

*  需求2:

             * 使用Class获取有参数的构造方法对象 Student

             * 调用有参数的构造方法对象,创建对象;

@Test
			public void test02() throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
				//1.获取student的字节码对象
				Class clazz = Student.class;
				//2.获取有参构造方法对象
				// //Constructor<T>    getConstructor(Class<?>... parameterTypes)  获取构造方法对象
				Constructor constructor = clazz.getConstructor(int.class, String.class);
				//3.调用newIntance创建对象
				Student stu = (Student) constructor.newInstance(2, "老王");
				System.out.println(stu);
			}
           

 *   需求3:

             * 使用Class 获取私有的构造方法  Student

             * 并且创建对象

             * 暴力反射获取私有构造

@Test
			public void test03() throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
				//1.获取student的字节码对象
				Class clazz = Student.class;
				//2.获取构造方法对象
				Constructor cons = clazz.getDeclaredConstructor();
				//3.去除私有权限
				cons.setAccessible(true);
				//4.调用newIntance方法创建对象
				Student student = (Student) cons.newInstance();
				student.fun();
			}
           

Method类:

        描述:Method 提供关于类或接口上单独某个方法(以及如何访问该方法)的信息。

             Method可以表述类中的方法. 可以将方法变成对象.我们可以调用它的方法,让方法被调用.

        1.如何获取Method对象

        我们可以通过Class类的方法来获取Method对象.

        第三组方法:                            

        Method                         getMethod(String name, Class<?>... parameterTypes)  获取方法对象

        Method                         getDeclaredMethod(String name, Class<?>... parameterTypes) 

                                    可以获取私有的方法对象

        2.Method类中的常用方法

         使用method对象调用原来的方法.

         Object invoke(Object obj, Object... args) 

        3.Method 类的代码操作

        public class MethodAPI {

        //1.我们使用Method 类中的方法,调用一个无参的public的方法.

        @Test

        public void test01() throws NoSuchMethodException, IllegalAccessException, InstantiationException, InvocationTargetException {

            //1)获取Student类的字节码对象

            Class clazz =  Student.class;

            //2)调用:Method getMethod(String name, Class<?>... parameterTypes)  获取方法对象 ,  来获取方法对象

            Method methodObj = clazz.getMethod("fun1");

            //3)调用:Object invoke(Object obj, Object... args)  调用该方法,让fun1方法执行

            methodObj.invoke(clazz.newInstance());

        }

        @Test

        public void test02() throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InstantiationException, InvocationTargetException {

            Class clazz = Class.forName("com.it.classapi.Student");

            Method method = clazz.getDeclaredMethod("fun2");

            method.setAccessible(true);

            method.invoke(clazz.newInstance());

        }

        // 3.我们调用一个有参数,有返回值的public方法 (调用方法,获取返回值,打印返回值)

        @Test

        public void test03() throws NoSuchMethodException, IllegalAccessException, InstantiationException, InvocationTargetException {

            //快速补全:

            Class clazz = Student.class;

            // public String fun3(String name,int age){

            Method method = clazz.getMethod("fun3", String.class, int.class);  //反射阶段

            String str = (String) method.invoke(clazz.newInstance(), "柳岩", 18);

            System.out.println(str);

        }

        //4.调用一个有参数,有返回值的private方法

        @Test

        public void test04() throws NoSuchMethodException, IllegalAccessException, InstantiationException, InvocationTargetException {

            //1.创建Student字节码对象

            Class clazz = Student.class;

            //2.getDeclaredMethod(String name, Class<?>... parameterTypes)  参数1:方法名称  参数2: 参数的字节码对象

            Method method = clazz.getDeclaredMethod("fun4", String.class, int.class);

            //3.去除私有权限

            method.setAccessible(true);

            //4.调用

            String str = (String) method.invoke(clazz.newInstance(), "迪丽热巴", 18);

            System.out.println(str);

        }

        }

3.属性类Field

            概念:

            Field 提供有关类或接口的单个字段的信息.

            Field 是我们类中的成员的变量的描述.

            如何创建: Class对象的方法创建

            Field         getField(String name) 获取属性对象public

            Field         getDeclaredField(String name) 可以获取私有的属性    

            常用方法:

            Object get(Object obj)  可以获取对象的属性对象 , 参数(当前类对象,举例来说就是student对象)

            void set(Object obj, Object value)  给属性对象设置值; 参数对象(Student对象) 参数2:具体参数值

            练习:

            public class FieldAPI {

                @Test

                public void test0() throws NoSuchFieldException, IllegalAccessException, InstantiationException {

                    // 1)获取Student的字节码对象

                    Class clazz = Student.class;

                    //  2) clazz对象调用 getField(String name) 获取属性对象public  , 参数字段名称    useranme   ===> fieldUserNameObj

                    //     clazz对象调用 getField(String name) 获取属性对象public  , 参数字段名称    age         ====> fieldAgeObj

                    Field fieldUserNameObj = clazz.getField("username");

                    Field fieldAgeObj = clazz.getField("age");

                    //3)给对象fieldUserNameObj 调用 void set(Object obj, Object value)  给username属性设置

                    // 给对象fieldUserNameObj 调用 void set(Object obj, Object value)  给age属性设置

                    Student stu = (Student) clazz.newInstance();

                    fieldUserNameObj.set(stu,"柳岩"); // stu.setUserName("liuyan");

                    fieldAgeObj.set(stu,18);         // stu.setAge(18);

                    //4)获取属性值

                    //调用Object get(Object obj)  参数:哪个类的属性,哪个类的对象 student ;  返回值: 我们设置的属性值

                    String username = (String) fieldUserNameObj.get(stu);  //stu.getUserName("username');

                    int age = (int) fieldAgeObj.get(stu);                ///stu.getAge("age");

                    System.out.println(username);

                    System.out.println(age);

                }

                // 3.给Student的private属性设置值

                // 4.使用反射获取 private的属性值

                @Test

                public void test02() throws ClassNotFoundException, NoSuchFieldException, IllegalAccessException, InstantiationException {

                    //1.获取Student的字节码对象

                    Class clazz = Class.forName("com.it.classapi.Student");

                    //2.调用 getDeclaredField(String name)

                    Field idField = clazz.getDeclaredField("id");

                    Field nameField = clazz.getDeclaredField("name");

                    //3.去除私有权限

                    idField.setAccessible(true);

                    nameField.setAccessible(true);

                    //4.设置属性值

                    Student stu = (Student) clazz.newInstance();

                    idField.set(stu,12);

                    nameField.set(stu,"唐嫣");

                    //5.获取属性

                    int id = (int) idField.get(stu);

                    String name = (String) nameField.get(stu);

                    System.out.println(id);

                    System.out.println(name);

                }

            }

6.反射练习:

        需求: 类加载器加载配置文件信息, 反射读取配置信息创建对象,并调用方法执行.

        代码实现:

        public interface Person {

            void eat();

            void sleep();

        }

        学生类

        public class Student implements Person{

            @Override

            public void eat() {

                System.out.println("学生吃饭");

            }

            @Override

            public void sleep() {

                System.out.println("学生睡觉");

            }

        }

        老师类

        public class Teacher implements Person {

        @Override

            public void eat() {

                System.out.println("老师吃饭..");

            }

            @Override

            public void sleep() {

                System.out.println("老师睡觉..");

            }

        }

        配置文件: demo.properties

        classpath=com.it.reflect_demo.Teacher

        method=eat

测试类:

        public class ReflectTest {

            @Test

            public void test01() throws IOException, ClassNotFoundException, NoSuchMethodException, InvocationTargetException, IllegalAccessException, InstantiationException {

                //1.获取ReflectTest 字节码对象 ,目的是获取类加载器

                Class clazz = ReflectTest.class;

                //2.获取类加载器

                ClassLoader classLoader = clazz.getClassLoader();

                //3.调用类加载器的getResourceAsStream 读取配置文件 demo.properties

                InputStream inputStream = classLoader.getResourceAsStream("demo.properties");

                //4.创建Properties对象

                Properties properties = new Properties();

                //5.调用集合的load方法加载流

                properties.load(inputStream);

                //6.获取集合中的数据

                String classpath = properties.getProperty("classpath");

                String method = properties.getProperty("method");

                //System.out.println(classpath + "   "+ method);

                //7.创建新的字节码对象

                Class clazzNew = Class.forName(classpath);

                //8.获取方法对象

                Method methodFieldObj = clazzNew.getDeclaredMethod(method);

                //9.调用方法

                methodFieldObj.invoke(clazzNew.newInstance());

            }

        }