java基础【Reflection反射】

java基础【Reflection反射】,第1张

java基础【Reflection反射】

1、基本概念

java的动态处理技术,在运行时进行。

2、反射的例子

public class Student {
    public String name;
    public int age;
    public String gender;

    public Student() {
    }

    public Student(String name, int age, String gender) {
        this.name = name;
        this.age = age;
        this.gender = gender;
    }

    public String getName() {
        return name;
    }

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

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public String getGender() {
        return gender;
    }

    public void setGender(String gender) {
        this.gender = gender;
    }

    @Override
    public String toString() {
        return "Student{" +
                "name='" + name + ''' +
                ", age=" + age +
                ", gender='" + gender + ''' +
                '}';
    }
}

    @Test
    public void test1(){    //软编码,灵活,把问题延迟到运行时解决
        try {
            //干预类的加载,直接获取类模板对象
            Class clazz = Class.forName("com.hike.javase.reflect.Student");
            //通过类模板对象.newInstance创建实体对象
            Object object = clazz.newInstance();    //调用无参构造器创建对象
            System.out.println(object);
        } catch (ClassNotFoundException e) {    // 在运行时动态加载类时, 发现没有找到类
            e.printStackTrace();
        } catch (IllegalAccessException e) {    // 非法访问, 访问权限不够时出现
            e.printStackTrace();
        } catch (InstantiationException e) {    // 在创建对象时出现异常, 可能是构造器不存在
            e.printStackTrace();
        }
    }

    @Test
    public void test(){     //编译时必须依赖类,硬编码
        Student s1 = new Student();     //强烈依赖类

        s1.name = "张三";
        s1.age = 15;
        s1.gender = "男";

        System.out.println(s1.getName());
        System.out.println(s1.getAge());
        System.out.println(s1.getGender());

        Student s2 = new Student("小红", 16, "女");
        System.out.println(s2);
    }
}

3、反射中关于属性的访问

public void test2(){
        try {
            Class clazz = Class.forName("com.hike.javase.reflect.Student");
            Object object = clazz.newInstance();
            System.out.println(object);

            //想要使用属性,先获取属性定义的对象
            //Field ageField = clazz.getField("age");    //只能获取公共的属性,不可以获取私有属性
            Field ageField = clazz.getDeclaredField("age");    //获取类中的任意属性
            //暴力反射,不推荐使用
            ageField.setAccessible(true);    //设置此属性为可访问的

            //根据属性名获取属性的定义对象
            ageField.set(object,15);    //相当于object.age = 15;
            System.out.println(ageField.get(object));   //相当于 System.out.println(object.age)

            //Field nameField = clazz.getField("name");
            //nameField.set(object,"小李");
            //System.out.println(nameField.get(object));

            System.out.println(object);

        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (NoSuchFieldException e) {
            e.printStackTrace();
        } catch (SecurityException e){
            e.printStackTrace();
        }
    }

4、一些方法

    @Test
	public void test5() throws ClassNotFoundException {
		Class clazz = Class.forName("com.hike.javase.reflect.Student");
		String name = clazz.getName();
		System.out.println("类名 : " + name);
		System.out.println("简单类名 :  " + clazz.getSimpleName());
		Class superclass = clazz.getSuperclass();
		System.out.println("父类 : " + superclass);
		Class[] interfaces = clazz.getInterfaces();
		System.out.println("接口列表 ");
		for (Class class1 : interfaces) {
			System.out.println(class1);
		}
		
	}

5、获取类模板对象的几种方法

    @Test
    public void test6() throws ClassNotFoundException {
        // 获取类模板对象的方法 ,有4种
        // 1) 直接通过类.class, 效率最高, 最安全.
        Class clazz1 = Student.class;

        // 2) 根据对象, 调用它的getClass()方法获取, 此方法也很常用.
        Student student = new Student("佟刚", 40, "男");
        Class clazz2 = student.getClass();

        System.out.println(clazz1 == clazz2);

        // 3) 反射中最常用的 Class.forName("全限定类名");
        Class clazz3 = Class.forName("com.hike.javase.reflect.Student");
        System.out.println(clazz2 == clazz3);

        // 4) 通过类加载器对象动态加载类
        ClassLoader classLoader = this.getClass().getClassLoader();
        Class clazz4 = classLoader.loadClass("com.hike.javase.reflect.Student");
        System.out.println(clazz3 == clazz4);
    }

	
    @Test
	public void test7()  {
		Class strClazz = String.class;
		System.out.println(strClazz);
		
		// 基本数据类型的类模板只能用第一种方式获取.
		Class clazz1 = int.class; // 基本数据类型也有相应的类模板对象, 但是不能获取属性和方法, 只能作为一个标记来使用.
		Class clazz2 = Integer.class; // 这是一个普通类模板.
		System.out.println(clazz1 == clazz2);
		
		// 判断类模板类型
		System.out.println("是否是基本型 : " + clazz1.isPrimitive());
		System.out.println("是否是基本型 : " + clazz2.isPrimitive());
	}

6、类加载器

   @Test
    public void test8()  {
        ClassLoader classLoader1 = ClassLoader.getSystemClassLoader(); // 获取系统类加载器
        System.out.println(classLoader1);
        ClassLoader classLoader2 = this.getClass().getClassLoader(); // 使用最多的, 获取当前类的类加载器
        System.out.println(classLoader2);

        ClassLoader classLoader3 = classLoader1.getParent(); // 获取父 "类加载器",  是 扩展 "类加载器"
        System.out.println(classLoader3);

        ClassLoader classLoader4 = classLoader3.getParent(); // 获取到的是引导类加载器(Bootstrap)
        System.out.println(classLoader4); // 这个类加载器无法获取, 无法使用

		
    }

重要应用:使用类加载器读取资源文件

    @Test
	public void test9() throws IOException  {
		//FileInputStream fis = new FileInputStream("只能读当前目录下的文件");
		ClassLoader classLoader = this.getClass().getClassLoader();
		// 只能加载build-path和src下的文件
		//InputStream inputStream = classLoader.getResourceAsStream("com/sun/corba/se/impl/logging/LogStrings.properties"); // 读取资源文件, 只要是Build-Path(classpath)中的文件都可以
		InputStream inputStream = classLoader.getResourceAsStream("test.properties");
		Properties properties = new Properties();
		properties.load(inputStream);
		
		Set> entrySet = properties.entrySet();
		for (Entry entry : entrySet) {
			System.out.println(entry);
		}
	}

使用全参构造器实例化对象

    @Test
	public void test10() {
		try {
			Class clazz = Class.forName("com.hike.javase.reflect.Student");
			//Object object = clazz.newInstance(); 没有无参构造器时出问题
			
			//public Student(String name, int age, String gender) 要想定位这个构造器, 必须让参数列表一致.
			
			// 提供形式参数类型列表, 是类模板对象的列表
			Constructor constructor = clazz.getConstructor(String.class, int.class, String.class); // 定位合适的构造器
			// 调用时必须给定实参列表
			Object object = constructor.newInstance("程程", 20, "女"); // new Teacher("程程", 20, "女");
			System.out.println(object);
			
		} catch (ClassNotFoundException e) {
			e.printStackTrace();
		} catch (InstantiationException e) {
			e.printStackTrace();
		} catch (IllegalAccessException e) {
			e.printStackTrace();
		} catch (NoSuchMethodException e) { // 参数列表出错, 或者方法名出错
			e.printStackTrace();
		} catch (SecurityException e) {
			e.printStackTrace();
		} catch (IllegalArgumentException e) { // 方法调用时实参和形参不匹配
			e.printStackTrace();
		} catch (InvocationTargetException e) {
			e.printStackTrace();
		}
	}

7、反射实现方法的调用

在Student类中添加方法

 public void study(String content, int time){
        System.out.println("学生在上[" + content + "]课, 共上了[" + time +"]小时");
        //return true;
        //throw new RuntimeException("一个异常");
    }
    @Test
    public void test11() {
        try {
            Class clazz = Class.forName("com.hike.javase.reflect.Student");
            Constructor constructor = clazz.getConstructor(String.class, int.class, String.class);
            Object object = constructor.newInstance("小明", 20, "女");

            //object.study("JavaWEB", 5);
            //先获取方法
            Method studyMethod = clazz.getMethod("study", String.class, int.class); // 后面是方法参数类型列表
            Short n = 5;
            Object retValue = studyMethod.invoke(object, "JavaWEB", n); // 后面是实参列表, 如果方法没有返回值, 它的返回值是null
            System.out.println(retValue);
        } 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();
        }
    }

当调用的方法为private时,使用以下方法进行调用。

            // getMethod只能获取公共的方法, 包括从父类继承的.
            //Method studyMethod = clazz.getMethod("study", String.class, int.class);

            // getDeclaredMethod可以获取本类中所有声明的方法
            Method studyMethod = clazz.getDeclaredMethod("study", String.class, int.class);
            studyMethod.setAccessible(true);

通过反射访问静态方法

Object retValue = studyMethod.invoke(null, "JavaWEB", n); // 静态方法传null, 不需要传入对象

8、通过反射获取类模板的一些内容

    @Test
	public void test14() throws Exception {
		Class clazz = Class.forName("com.hike.javase.reflect.Student");
		System.out.println("父类 : " + clazz.getSuperclass());
		Constructor[] constructors = clazz.getConstructors();
		for (int i = 0; i < constructors.length; i++) {
			System.out.println("构造器 : " + constructors[i]);
		}
		System.out.println("************************************************");
		Field[] fields = clazz.getFields(); // 所有公共属性
		for (int i = 0; i < fields.length; i++) {
			System.out.println(fields[i]);
		}
		Field[] declaredFields = clazz.getDeclaredFields(); // 所有本类属性
		for (Field field : declaredFields) {
			System.out.println(field);
		}
		System.out.println("************************************************");
		Method[] methods = clazz.getMethods();
		for (Method method : methods) {
			System.out.println(method);
		}
		System.out.println("************************************************");
		Method[] declaredMethods = clazz.getDeclaredMethods();
		for (Method method : declaredMethods) {
			System.out.println(method);
		}
	}

熟悉运行机制,思路,在非高级编程中应用不多。

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/zaji/5713015.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-12-17
下一篇 2022-12-17

发表评论

登录后才能评论

评论列表(0条)

保存