反射基本知识点

反射概念

      1、反射是框架的基石
      
      2、反射是java语言的一种机制,
      
      通过反射可以动态地实例化对象、读取属性、调用方法。

为什么要学习反射

   反射是框架的基石
   能够让代码更具灵活性!
   JAVA反射机制是在运行状态中,
   对于任意一个类,都能够知道这个类的所有属性和方法;
   对于任意一个对象,都能够调用它的任意方法和属性;
   这种动态获取信息以及动态调用对象方法的功能称为java语言的反射机制。
   这也就恰好符合了反射的概念以及三大作用!

注意要点

1、一切类对象相关的代码都从获得类对象开始!

2、反射用的大部分方法都是在java.lang.reflect.*里面的

反射的三大作用

1、动态地实例化对象
这个在通用分页的查询时使用!

 实例化对象的三种方式:
 1、Class.forName("完整的类名");
 2、类名.class;
 3、对象.getClass();

2、调用方法

  Method m;
  m.invoke

3、读取属性

  Field   set/get

具体演示请看下面代码展示以及描述!

反射实例演示以及常见错误

1、实例化对象的三种方式实战演示:

首先导入一个需要的实体类,我这里以Student类为例:

package com.wangqiuping.reflect;

public class Student {
	
	private String sid;

	private String sname;

	public Integer age;
	
	static{
		System.out.println("加载进jvm中!");
	}

	public Student() {
		super();
		System.out.println("调用无参构造方法创建了一个学生对象");
	}

	public Student(String sid) {
		super();
		this.sid = sid;
		System.out.println("调用带一个参数的构造方法创建了一个学生对象");
	}

	public Student(String sid, String sname) {
		super();
		this.sid = sid;
		this.sname = sname;
		System.out.println("调用带二个参数的构造方法创建了一个学生对象");
	}

	@SuppressWarnings("unused")
	private Student(Integer age) {
		System.out.println("调用Student类私有的构造方法创建一个学生对象");
		this.age = age;
	}

	public String getSid() {
		return sid;
	}

	public void setSid(String sid) {
		this.sid = sid;
	}

	public String getSname() {
		return sname;
	}

	public void setSname(String sname) {
		this.sname = sname;
	}

	public void hello() {
		System.out.println("你好!我是" + this.sname);
	}

	public void hello(String name) {
		System.out.println(name + "你好!我是" + this.sname);
	}

	@SuppressWarnings("unused")
	private Integer add(Integer a, Integer b) {
		return new Integer(a.intValue() + b.intValue());
	}
}

    1.1    Class.forName("完整的类名");
注意:
1、 这里在获取完整类名的时候,有的小伙伴们可能自己手贱不小心自己
    少打了字母或者怎么样,我建议你还是按我这种操作比较好,不易出错!

点开Student下面------选种带有绿色小图标的Student-----然后右键Copy
Qualified name就好!

2、一定要注意自己的完整类名有没有写错,
如果是写错了的话会报java.lang.ClassNotFoundExecption;

一般出现这个错误大多是因为
一个没有导入需要的jar,
要不就是类名写错了,所以会报类找不到异常!

3、当Class.forName("完整类名")这一行代码写完之后,
     要记得抛异常!

错误的代码是这样的:

package com.wangqiuping.reflect;
/**
 * 
 * @author 小汪同学  2020年5月23日 下午4:11:18
 * 获得类对象的三种方式:
 * 1、Class.forName("完整的类名");
 * 2、类名.Class;
 * 3、类对象.getClass();
 */
public class Demo1 {

public static void main(String[] args) throws ClassNotFoundException {
	//1、Class.forName("完整的类名");
	Class<?> cla = Class.forName("com.wangqiuping.reflect.Student1");
	System.out.println(cla);
}
}

运行后的结果是这样子的:

在这里插入图片描述
其实就是因为Class.forName(“com.wangqiuping.reflect.Student1”):里面多了一个1,所以导致类名错误!

欧克,下面我来展示一下正确的代码:

package com.wangqiuping.reflect;
/**
 * 
 * @author 小汪同学  2020年5月23日 下午4:11:18
 * 获得类对象的三种方式:
 * 1、Class.forName("完整的类名");
 * 2、类名.Class;
 * 3、类对象.getClass();
 */
public class Demo1 {

public static void main(String[] args) throws ClassNotFoundException {
	//1、Class.forName("完整的类名");
	Class<?> cla = Class.forName("com.wangqiuping.reflect.Student");
	System.out.println(cla);
}
}

这是正确的运行结果:
在这里插入图片描述
然后我现在来讲第二种实例化对象的方式:

1.2 类名.class;

package com.wangqiuping.reflect;
/**
 * 
 * @author 小汪同学  2020年5月23日 下午4:11:18
 * 获得类对象的三种方式:
 * 1、Class.forName("完整的类名");
 * 2、类名.Class;
 * 3、类对象.getClass();
 */
public class Demo1 {

public static void main(String[] args) throws ClassNotFoundException {

	//2、类名.Class;
    Class clb=Student.class;
    System.out.println(clb);
}
}

这是第二种实例化对象的运行结果:

在这里插入图片描述
第三种实例化对象的方式:

对象.getClass();

代码展示:

package com.wangqiuping.reflect;
/**
 * 
 * @author 小汪同学  2020年5月23日 下午4:11:18
 * 获得类对象的三种方式:
 * 1、Class.forName("完整的类名");
 * 2、类名.Class;
 * 3、类对象.getClass();
 */
public class Demo1 {

public static void main(String[] args) throws ClassNotFoundException {

    //3、类对象.getClass();
    Student  stu=new Student();
    Class<? extends Student> clc = stu.getClass();
    System.out.println("----------------------------");
	System.out.println(clc);
}
}

运行结果:
在这里插入图片描述
一、实例化对象的具体方法:

1、无参的公有构造方法

代码展示:

package com.wangqiuping.reflect;
/**
 *   实例化对象
 * 1、无参的公有的实例化
 * 2、有一个参数的公有构造器实例化
 * 3、有两个参数的公有构造器实例化
 * 4、私有的构造器实例化
 * @author 小汪同学  2020年5月23日 下午4:45:00
 *
 */
public class Demo2 {
public static void main(String[] args) throws Exception {
	Student  stu=new Student();//oop实例化对象
	Class    clz = stu.getClass();//反射实例化
	//1、无参的公有的实例化  这里记得抛异常  并且记得强转
    Student  stu1=(Student)clz.newInstance();
    System.out.println(stu1);
}
}

运行结果:在这里插入图片描述
运行结果之所以调用了两次无参构造方法,是因为代码中用oop实例化了一次之后,又用反射实例化了一次!

2、有一个参数的公有构造器实例化

package com.wangqiuping.reflect;

import java.lang.reflect.Constructor;

/**
 *    实例化对象
 * 1、无参的公有的实例化
 * 2、有一个参数的公有构造器实例化
 * 3、有两个参数的公有构造器实例化
 * 4、私有的构造器实例化
 * @author 小汪同学  2020年5月23日 下午4:45:00
 *
 */
public class Demo2 {
public static void main(String[] args) throws Exception {
	//Student  stu=new Student();//oop实例化对象
	Class    clz = stu.getClass();//反射实例化
	//2、有一个参数的公有构造器实例化
     Constructor<? extends Student>c=clz.getConstructor(String.class);
	 Student stu2 = c.newInstance("s002");
	 System.out.println(stu2);
}
}

运行结果:

在这里插入图片描述
3、有两个参数的公有构造器实例化

代码展示:

package com.wangqiuping.reflect;

import java.lang.reflect.Constructor;

/**
 *    实例化对象
 * 1、无参的公有的实例化
 * 2、有一个参数的公有构造器实例化
 * 3、有两个参数的公有构造器实例化
 * 4、私有的构造器实例化
 * @author 小汪同学  2020年5月23日 下午4:45:00
 *
 */
public class Demo2 {
public static void main(String[] args) throws Exception {
	Student  stu=new Student();//oop实例化对象
	Class    clz = stu.getClass();//反射实例化
	 //3、有两个参数的公有构造器实例化
	 Constructor<? extends Student> c2=clz.getConstructor(String.class,String.class);
	 Student stu3 = c2.newInstance("s002","李易峰");
	 System.out.println(stu3);
}
}

运行结果:

在这里插入图片描述
4、私有的构造器实例化
这种方式是最常用的!

代码展示:

package com.wangqiuping.reflect;

import java.lang.reflect.Constructor;

/**
 *    实例化对象
 * 1、无参的公有的实例化
 * 2、有一个参数的公有构造器实例化
 * 3、有两个参数的公有构造器实例化
 * 4、私有的构造器实例化
 * @author 小汪同学  2020年5月23日 下午4:45:00
 *
 */
public class Demo2 {
public static void main(String[] args) throws Exception {
	Student  stu=new Student();//oop实例化对象
	Class    clz = stu.getClass();//反射实例化
	 //getConstructor
	 //getDeclaredConstructor
	 Constructor<? extends Student> c3=clz.getDeclaredConstructor(Integer.class);
	 c3.setAccessible(true);//公开权限
	 Student stu4 = c3.newInstance(22);
	 System.out.println(stu4);
}
}

运行结果:
在这里插入图片描述

注意
1、getConstructor是获取到public修饰的构造方法!
2、getDeclaredConstructor能够获取到任意修饰符的构造器!

二、调用方法:
大多数时候在自定义mvc时增强子控制器可以使用!
Method m;
m.invoke

1、无参公有的方法调用
clz.getMethod(方法名, parameterTypes);
parameterTypes指的是可变数组 可不填!

错误演示一:

package com.wangqiuping.reflect;

import java.lang.reflect.Method;

/**
 * 调用方法
 * @author 小汪同学  2020年5月23日 下午8:18:52
 * 1、无参公有的方法调用
 * 2、有一个参数的方法调用
 * 3、私有的方法调用
 */
public class Demo3 {
public static void main(String[] args) throws Exception {
	Student stu=new Student();
	Class clz=stu.getClass();
	//1、无参公有的方法调用
	Method m= clz.getMethod("hello");
	Object invoke = m.invoke(stu);
	System.out.println(invoke);
}
}

运行结果:

在这里插入图片描述
注意:
当动态被调用的方法是void返回类型时,
那么被invoke之后,结果为空!

错误演示二:

package com.wangqiuping.reflect;

import java.lang.reflect.Method;

/**
 * 调用方法
 * @author 小汪同学  2020年5月23日 下午8:18:52
 * 1、无参公有的方法调用
 * 2、有一个参数的方法调用
 * 3、私有的方法调用
 */
public class Demo3 {
public static void main(String[] args) throws Exception {
	Student stu=new Student();
	Class clz=stu.getClass();
	Method m2 = clz.getMethod("hello",String.class);
	Object invoke2 = m2.invoke(stu,"zhangsan");
	System.out.println(invoke2);
}
}

运行结果:

在这里插入图片描述
注意:
这个也是符合上一条我所说的,当动态调用的方法为void类型时,
且被invoke后,返回的结果为null !

相反代码展示:

package com.wangqiuping.reflect;

import java.lang.reflect.Method;

/**
 * 调用方法
 * @author 小汪同学  2020年5月23日 下午8:18:52
 * 1、无参公有的方法调用
 * 2、有一个参数的方法调用
 * 3、私有的方法调用
 */
public class Demo3 {
public static void main(String[] args) throws Exception {
	//Student stu=new Student();
	Class clz=stu.getClass();
	
	Method m3= clz.getDeclaredMethod("add",Integer.class,Integer.class);
	m3.setAccessible(true);
	Object invoke3 = m3.invoke(stu,30,3);
	System.out.println(invoke3);
}
}

运行结果:
33
注意:
动态被调用的方法,如果不是void返回类型时,
那么被invoke后,就是被调用方法的返回结果!

常见错误之一:

java.lang.NoSuchMethodException

没有该方法

演示错误:

package com.wangqiuping.reflect;

import java.lang.reflect.Constructor;

/**
 * 调用方法
 * 1、无参的公有的实例化
 * 2、有一个参数的公有构造器实例化
 * 3、有两个参数的公有构造器实例化
 * 4、私有的构造器实例化
 * @author 小汪同学  2020年5月23日 下午4:45:00
 *
 */
public class Demo2 {
public static void main(String[] args) throws Exception {
	//Student  stu=new Student();//oop实例化对象
	Class    clz = stu.getClass();//反射实例化 
	 Constructor<? extends Student> c3=clz.getConstructor(Integer.class);
	 Student stu4 = c3.newInstance(22);
	 System.out.println(stu4);
}
}

运行结果展示:

在这里插入图片描述
这个结果的意思是 Student类中没有Interger为参数的方法!

常见错误之二:

java.lang.IllegalAccessException

非法访问异常

错误代码展示:

package com.wangqiuping.reflect;

import java.lang.reflect.Constructor;

/**
 * 调用方法
 * 1、无参的公有的实例化
 * 2、有一个参数的公有构造器实例化
 * 3、有两个参数的公有构造器实例化
 * 4、私有的构造器实例化
 * @author 小汪同学  2020年5月23日 下午4:45:00
 *
 */
public class Demo2 {
public static void main(String[] args) throws Exception {
	Student  stu=new Student();//oop实例化对象
	Class    clz = stu.getClass();//反射实例化 
	 Student stu4 = c3.newIns
	 Constructor<? extends Student> c3=clz.getDeclaredConstructor(Integer.class);
	 Student stu4 = c3.newInstance(22);
	 System.out.println(stu4);	 
}
}

运行结果:

在这里插入图片描述
注意:

之所以无法访问的原因是,是使用了private修饰符进行修饰!
解决方案:公开权限就好!
(也就是添加上下面这一行代码就欧克啦!)
c3.setAccessible(true);//公开权限

3、读取属性
BaseDao的增删改时使用
代码展示:

package com.wangqiuping.reflect;

import java.lang.reflect.Field;

/**
 * 
 * @author 小汪同学  2020年5月24日 上午9:31:07
 * 公有的  私有地读写属性
 */
public class Demo4 {
public static void main(String[] args) throws NoSuchFieldException, SecurityException, IllegalArgumentException, IllegalAccessException {
	Student stu=new Student("s003","liyifeng");
	stu.age=18;
	Class<? extends Student> clz=stu.getClass();
	System.out.println(stu.getSname());//没有使用反射时
	Field f = clz.getDeclaredField("sname");//这里要记得抛异常
	f.setAccessible(true);
	System.out.println(f.get(stu));//这里也要抛异常!
}
}

运行结果:

在这里插入图片描述

反射读写属性的常用方法

(通俗一点来说,就是可以一次性获取到所有的属性值,这样的好处就是优化了一部分的代码!)

代码展示:

package com.wangqiuping.reflect;

import java.lang.reflect.Field;

/**
 * 
 * @author 小汪同学  2020年5月24日 上午9:31:07
 * 公有的  私有地读写属性
 */
public class Demo4 {
public static void main(String[] args) throws NoSuchFieldException, SecurityException, IllegalArgumentException, IllegalAccessException {
	
	Field[] ff = clz.getDeclaredFields();
	for (Field fs : ff) {
		fs.setAccessible(true);
		System.out.println(fs.get(stu));
	}
}
}

运行结果:

在这里插入图片描述
如果想通过反射改变sname对应的值,就像下面这样在原有代码的基础上加上这几行代码就好:

    System.out.println("-------设置---------");
	f.set(stu, "王一博");
	System.out.println(stu.getSname());

运行结果:
在这里插入图片描述

补充知识点(访问修饰符)

1、访问修饰符用来干嘛的?

是一种可以用来判断类或变量、方法的修饰符!

2、常见的访问修饰符有哪些呢?
(自己从网上查阅了解到的这些!)

		PUBLIC: 1               公开的
		PRIVATE: 2              私有的
		PROTECTED: 4            受保护的
		STATIC: 8               静态的
		FINAL: 16               常  量
		SYNCHRONIZED: 32        同步的
		VOLATILE: 64           (相当于轻级的SYNCHRONIZED)
		TRANSIENT: 128          可以用来序列化
		NATIVE: 256             本地的
		INTERFACE: 512          接  口
		ABSTRACT: 1024          抽象的
		STRICT: 2048            严格的

3、为什么要使用访问修饰符?

Field的 getModifiers() 方法返回的int类型值可以用来表示该字段的修饰符,
也就是说这个方法就是返回一个int型的返回值,代表类、成员变量、方法的修饰符。

4、实例演示

把这行代码添加到Student类中,再继续下面的操作!

public  static  final String USER_NAME="hhh";
package com.wangqiuping.reflect;

import java.lang.reflect.Field;
import java.lang.reflect.Modifier;

/**
 * 
 * @author 小汪同学  2020年5月24日 上午9:31:07
 * 公有的  私有地读写属性
 */
public class Demo4 {
public static void main(String[] args) throws NoSuchFieldException, SecurityException, IllegalArgumentException, IllegalAccessException {
	Student stu=new Student();
	Class<? extends Student> clz=stu.getClass();
	//访问修饰符  使用二进制的方式去识别修饰符
	Field ft = clz.getDeclaredField("USER_NAME");
	int n=ft.getModifiers();
	System.out.println(n);//结果为数字
	
	System.out.println(Modifier.PUBLIC);
	System.out.println(Modifier.STATIC);
	System.out.println(Modifier.FINAL);
}
}

运行结果:

在这里插入图片描述
注意:
访问修饰符返回的结果本身就是数字,因为这些访问修饰符都是有一个特定的二进制表示数字,就像我上面展示的代码那样,USER_NAME被PUBLIC,STATIC,FINAL三个访问修饰符所修饰,而这个访问修饰符最开始得到的总和恰好就是这三个访问修饰符相加过后的数字!

总结

反射是框架之中的一个很基础的知识点,反射学习中的实例化对象、调用方法、读取属性中的一些常用方法可区别记忆,之后才能够灵活使用,访问修饰符可能在当前的某些方面应用不是很多,但是在一些框架和底层开发之中也还是会有使用,今天关于反射的基本知识点就分享到这了,有什么好的建议或者不足之处欢迎留言评论交流噢!

在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/qq_45464930/article/details/106302181