J2EE基础-反射

前言

上篇(http://t.csdn.cn/vUffo)中我们已经认识了XML的建模,这篇我们将学习反射

目录

反射

A、什么是反射?

B、类类

类类的获取方式

反射实例化

不用反射实例化:

 使用反射实例化

反射动态调用方法

 反射读写属性

 通过反射拿到属性对应的修饰符

反射的常用场景


反射

A、什么是反射?

概念:反射是Java的一种机制,让我们可以在运行时获取类的信息

作用:通过反射,我们可以在程序运行时动态创建对象,还能获取到类的所有信息,比如它的属性、构造器、方法、注解等;

Java反射机制主要提供了以下功能:

  •  1.在运行时判断任意一个对象所属的类。
  •  2.在运行时构造任意一个类的对象。
  •  3.在运行时判断任意一个类所具有的成员变量和方法。
  •  4.在运行时调用任意一个对象的方法。

Java中反射的用法非常多,常见的有以下几种

一、在运行时获取一个类的 Class 对象
二、在运行时构造一个类的实例化对象
三、在运行时获取一个类的所有信息:变量、方法、构造器、注解

B、类类

一切反射从类类开始

Student 类:

package com.oyang.reflect;

/**
 * 学生实体类
 * @author yang 
 *
 * @date 2022年6月16日上午11:51:28
 */
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. 类.Class
  2. 类实例.getClass
  3. Class.forName("类的全路径名");
package com.oyang.reflect;


/**
 * 类类的获取方式
 * @author yang 
 *
 * @date 2022年6月16日上午8:51:43
 */
public class Demo1 {
	public static void main(String[] args) throws Exception {
		//1.类.Class
	    Class clz1=	Student.class;
	    
	    //确定本工程有这个类,你才可以实例化
//	    Student stu = new Student();
	    
	    //本工程没有这个类,也可以编译通过
	    //Object newInstance = Class.forName("com.oyang.reflect.Student").newInstance();
	    
	    
	    //2.类实例.getClass
	    Student stu = new Student();
	    Class clz2 = stu.getClass();
	    
	    //3.Class.forName("类的全路径名");
	    Class clz3 = Class.forName("com.oyang.reflect.Student");    
	}
}

运行结果:

反射实例化

不用反射实例化:

package com.oyang.reflect;

import java.lang.reflect.Constructor;

/**
 * 反射实例化
 * @author yang 
 *
 * @date 2022年6月16日上午10:04:16
 */
public class Demo2 {
	public static void main(String[] args) throws Exception {
	Student stu1 = new Student();	
	Student stu2 = new Student("S001");
	Student stu3 = new Student("S001", "oyang");
    }
}

new 不到私有的构造方法

 使用反射实例化

无参数,公有的构造方法:

package com.oyang.reflect;

import java.lang.reflect.Constructor;

/**
 * 反射实例化
 * 1.无参数,公有的构造方法
 * @author yang 
 *
 * @date 2022年6月16日上午10:04:16
 */
public class Demo2 {
	public static void main(String[] args) throws Exception {	
	//获取类类
	Class<? extends Student> clz1 = stu1.getClass();
	//默认就是调用无参  公有的构造函数
	
	//1.无参数,公有的构造方法
	Student stu4 = clz1.newInstance();
	}
}

 有参数 公有的构造方法

package com.oyang.reflect;

import java.lang.reflect.Constructor;

/**
 * 反射实例化
 * 有参的,公有的构造方法
 * @author yang 
 *
 * @date 2022年6月16日上午10:04:16
 */
public class Demo2 {
	public static void main(String[] args) throws Exception {
	Student stu1 = new Student();	
	//获取类类
	Class<? extends Student> clz1 = stu1.getClass();

	//2.有参数 公有的构造方法
	// 拿到构造器对象	三个.代表可以传1个2个..n个参数	-->拿到一个参数为String的构造对象
	Constructor<? extends Student> c1 = clz1.getConstructor(String.class);
	Student sru5 = c1.newInstance("s001");
	}
}

有多个参数 公有的构造方法:

package com.oyang.reflect;

import java.lang.reflect.Constructor;

/**
 * 反射实例化
 * 有多个参数 公有的构造方法
 * @author yang 
 *
 * @date 2022年6月16日上午10:04:16
 */
public class Demo2 {
	public static void main(String[] args) throws Exception {
	Student stu1 = new Student();	
	//new 不到私有的构造方法
	
	/**
	 * 一下均为反射的方式实例化对象
	 */
	
	//获取类类
	Class<? extends Student> clz1 = stu1.getClass();

//	有多个参数 公有的构造方法
	Constructor<? extends Student> c2 = clz1.getConstructor(String.class,String.class);
	Student stu6 = c2.newInstance("s001","陽");
	}
}

 

 私有构造方法:

package com.oyang.reflect;

import java.lang.reflect.Constructor;

/**
 * 反射实例化
 * 私有的构造方法
 * @author yang 
 *
 * @date 2022年6月16日上午10:04:16
 */
public class Demo2 {
	public static void main(String[] args) throws Exception {
	Student stu1 = new Student();	
	//new 不到私有的构造方法
	
	/**
	 * 一下均为反射的方式实例化对象
	 */
	
	//获取类类
	Class<? extends Student> clz1 = stu1.getClass();
    // 私有构造方法
	//getConstructor只能获取公有的构造方法,要获取私有的构造器getDeclaredConstructor
	Constructor<? extends Student> c3 = clz1.getDeclaredConstructor(Integer.class);
	//打开访问权限
	c3.setAccessible(true);
	Student wtu7 = c3.newInstance(3);
	}
}

getConstructor只能获取公有的构造方法,要获取私有的构造器getDeclaredConstructor

反射动态调用方法

思路:

  1. 拿到类类
  2. 拿到方法对象
  3. 调用对应的方法 
package com.oyang.reflect;

import java.lang.reflect.Method;

/**
 * 反射动态调用方法
 * 1.调用无参数,公有的方法
 * 2.调用有1个参数的,公有的方法
 * 3.调用2个有参数的 私有方法
 * @author yang 
 *
 * @date 2022年6月16日上午10:25:34
 */
public class Demo3 {
	public static void main(String[] args) throws Exception {
		/**
		 * 1.拿到类类
		 * 2.拿到方法对象
		 * 3.调用对应的方法
		 */
//		调用无参数,公有的方法
		
//		1.先拿到类类
		Class<Student> clz=	Student.class;
		//name:方法名		parameterTypes:方法对应的参数
		Method m1 = clz.getMethod("hello");
		 
		//3.调用对应的方法
		//第一个参数:那个类实例   第二个参数:方法调用时的实参
		//m1.invoke方法调用的返回值	就是方法对象本身的返回值hello方法的反回值
		Object invoke = m1.invoke(clz.newInstance());
		System.out.println(invoke);
		
		//调用有1个参数的,公有的方法
		Method m2 = clz.getMethod("hello", String.class);
		Object invoke2 = m2.invoke(clz.newInstance(), "陽");
		System.out.println(invoke2);
		
		
		//调用2个有参数的 私有方法
		Method m3 = clz.getDeclaredMethod("add",Integer.class,Integer.class);
		m3.setAccessible(true);
		Object invoke3 = m3.invoke(clz.newInstance(), 13,32);
		System.out.println(invoke3);
	} 
}

结果:

 反射读写属性

package com.oyang.reflect;

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

/**
 * 反射读写属性
 * @author yang 
 *
 * @date 2022年6月16日上午10:45:01
 */
public class Demo4 {
	public static void main(String[] args) throws Exception {
		Student stu = new Student("s003","张三");
		stu.age=20;
		//需求:要拿到这个学生所有的属性值
		System.out.println("sid:"+stu.getSid());
		System.out.println("sname:"+stu.getSname());
		System.out.println("sage:"+stu.age);
	
		/**
		 * 上述代码存在的问题
		 * 1.事先得知道这个类有哪些属性
		 * 2.假设Student有30个属性呢?
		 */
		
		//一切反射从类类开始
		Class<? extends Student> clz = stu.getClass();
		//当前类的所有属性对象
		Field[] f = clz.getDeclaredFields();
		System.out.println(f.length);
		//for循环中的fi代表每一个属性对象
		for (Field fi : f) {
			//打开访问权限
			fi.setAccessible(true);
			//通过属性对象拿到属性名
			System.out.println(fi.getName());
			//拿到当前的属性对象的 属性值
			System.out.println(fi.get(stu));
		}
	}
}

 

 通过反射拿到属性对应的修饰符

package com.oyang.reflect;

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

/**
 * 反射拿到对应的修饰符
 * @author yang 
 *
 * @date 2022年6月16日上午10:45:01
 */
public class Demo4 {
	public static void main(String[] args) throws Exception {
		Student stu = new Student("s003","歐陽");
		stu.age=20;
		//一切反射从类类开始
		Class<? extends Student> clz = stu.getClass();
		//当前类的所有属性对象
		Field[] f = clz.getDeclaredFields();
		System.out.println(f.length);
		//for循环中的fi代表每一个属性对象
		for (Field fi : f) {
			//打开访问权限
			fi.setAccessible(true);
			//通过属性对象拿到属性名
			System.out.println(fi.getName());
			//拿到当前的属性对象的 属性值
			System.out.println(fi.get(stu));
			//返回一个用数字表示的java修饰符
			System.out.println(fi.getModifiers());
			//通过数字拿到对应的修饰符
			System.out.println(Modifier.toString(fi.getModifiers()));
		}
	}
}

 运行结果:

反射的常用场景

 1、Spring 实例化对象:当程序启动时,Spring 会读取配置文件applicationContext.xml并解析出里面所有的标签实例化到IOC容器中。
2、反射 + 工厂模式:通过反射消除工厂中的多个分支,如果需要生产新的类,无需关注工厂类,工厂类可以应对各种新增的类,反射可以使得程序更加健壮。
3、JDBC连接数据库:使用JDBC连接数据库时,指定连接数据库的驱动类时用到反射加载驱动类


 OK,今日的学习就到此结束啦,如果对个位看官有帮助的话可以留下免费的赞哦(收藏或关注也行),如果文章中有什么问题或不足以及需要改正的地方可以私信博主,博主会做出改正的。个位看官,小陽在此跟大家说拜拜啦!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

歐陽。

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值