反射的引入
/*
* 这个接口实现4个功能
* 注册
* 登录
* 添加
* 删除
*
*/
public interface Servlet {
/**
* 服务方法
*/
public void service();
}
public class RegisterServlet implements Servlet {
@Override
public void service() {
System.out.println("----register service----");
}
public RegisterServlet() {
System.out.println("-----RegisterServlet-------");
}
}
public class LoginServlet implements Servlet {
@Override
public void service() {
System.out.println("----login service----");
}
public LoginServlet(){
System.out.println("-------LoginServlet--------");
}
}
public class DeleteServlet implements Servlet {
@Override
public void service() {
System.out.println("---delete service----");
}
public DeleteServlet() {
System.out.println("--------DeleteServlet--------");
}
}
public class AddServlet implements Servlet {
@Override
public void service() {
System.out.println("------add service------");
}
public AddServlet() {
System.out.println("-----AddServlet---------");
}
}
- 功能:
* 键盘录入数字
* 录入1:调用注册功能(创建注册对象,调用注册方法)
* 录入2:调用登录功能(创建登录对象,调用登录方法)
* 录入3:调用添加功能(创建添加对象,调用添加方法)
*
* 问题1:使用多态代替具体的对象
* 问题2:新需求,需要增加删除的servlet
* java的开发原则:对扩展开放 ,对修改关闭
* 扩展:新增加的了一个删除的servlet
* 修改:修改了switch结构,很有可能造成其他地方受影响
* 问题3:java源代码,修改一次,就得重新编译一次,浪费时间
* 问题4:利用xml文件代替,原始的switch结构
* 问题5:获取到classname的字符串,但是如何将字符串转换为类Class?
* 如何解决了? 利用反射
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Scanner;
import java.util.Set;
import cn.sxt.day0107.util.XMLUtils;
public class Test {
* dom4J xml方式解析
* @param args
* @throws ClassNotFoundException
* @throws IllegalAccessException
* @throws InstantiationException
* @throws SecurityException
* @throws NoSuchMethodException
* @throws InvocationTargetException
* @throws IllegalArgumentException
*/
@SuppressWarnings("unchecked")
public static void main(String[] args) throws Exception {
//调用xml的方法
Map<String, String> map = XMLUtils.paserXML("web.xml");
Scanner sc = new Scanner(System.in);
System.out.println("请输入数字[1-4]");
String num = sc.nextLine();
String className = map.get(num);
Class<?> clazz = Class.forName(className);
//创建servlet的对象
Object obj = clazz.newInstance();
//获取service方法
Method method = clazz.getMethod("service");
//调用方法
method.invoke(obj);
}
/*public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
System.out.println("请输入数字");
int num = sc.nextInt();
Servlet servlet =null;
switch(num){
case 1:servlet = new RegisterServlet();
servlet.service();
break;
case 2:servlet = new LoginServlet();
servlet.service();
break;
case 4:servlet = new AddServlet();
servlet.service();
break;
case 3:servlet = new DeleteServlet();
servlet.service();
break;
default:System.out.println("数字只能在1-3之间");
}
}*/
}
- 1 创建学生对象
* 2 调用吃饭方法
*
* 反射的引入
* 1:当你知道对象类型的时候,可以直接创建对象,并且调用方法
* 2:在实际开发中,很多情况下,我们的类是在xml中定义的,需要通过一定的技术(dom4j),获取到xml中类名称(全名,带包名的)
* 3:获取到Class文件
* 如何创建对象
* 如何调用属性、
* 如何调用方法
* 反射的概念
* 1 JAVA反射机制是在运行状态中,对于任意一个实体类,都能够知道这个类的所有属性和方法;
* 2 对于任意一个对象,都能够调用它的任意方法和属性;
* 3 这种动态获取信息以及动态调用对象方法的功能称为java语言的反射机制。
*
* 反射的使用场合
* 在编译期间不知道类型信息,需要通过反射,在运行期间,创建对象,调用方法,调用属性
* 编程语言分类
* 静态语言 C C++
* 声明变量的时候,必须先声明数据类型,先声明类型,再给具体的值
* int a = 10;
* 动态语言 JS PHP
* 给什么具体的值,那么它的类型就是什么类型
* var a = true;
* a = 20;
* 半动态半静态 JAVA (多态,反射) 编译期间确定类型,运行期间确定对象
* People p = new People();
* People p = new Man();
* People p = new Women();
* 反射的作用: 可以获取Class文件中的所有信息,包括私有的
* 1:获取Class的属性信息
* 2:获取Class的方法信息
* 3:获取Class的构造器信息
- 反射的主要组成
* Class 表示一个类 反射的入口
* Constructor 表示构造器类
* Filed 表示属性类
* Method 表示方法类
public class Demo {
* @param args
* @throws ClassNotFoundException
* @throws IllegalAccessException
* @throws InstantiationException
*/
public static void main(String[] args) throws Exception {
//1:普通方案,编译期间知道类型,可以直接创建对象,调用方法
/*Student stu = new Student();
stu.eat();*/
//2:反射方案,编译期间不知道类型
Class clazz = Class.forName("cn.sxt.day0107.reflecter.Student");
clazz.newInstance();
}
}
public class Student {
private String name;
private int age;
private String sex;
public void eat(){
System.out.println("吃饭");
}
public Student(String name, int age, String sex) {
super();
this.name = name;
this.age = age;
this.sex = sex;
}
public Student() {
System.out.println("无参的构造器");
}
}
- Class:表示一个类
* 如何获取Class
* 1: Class.forName(“java.lang.String”); 开发常用
* 2: 类名.class
* 3: String s = new String(); s.getClass()
public class Demo {
public static void main(String[] args) throws ClassNotFoundException {
//获取String的Class
Class clazz = Class.forName("java.lang.String");
Class clazz2 = String.class;
Class clazz3 = void.class;
String s = new String();
Class clazz4 = s.getClass();
System.out.println(clazz2==clazz3);
}
}
反射:Class类的常用方法
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
public class Demo {
public static void main(String[] args) throws Exception {
//1:获取Student的Class
Class clazz = Class.forName("cn.sxt.day0107.reflect3.Student");
//2:常用方法
//获取public属性
Field[] fields = clazz.getFields();
//获取所有属性,包括私有的
Field[] declaredFields = clazz.getDeclaredFields();
//获取指定属性 只能获取public属性
Field field = clazz.getField("name");
//获取指定属性 获取所有指定的属性
Field field2 = clazz.getDeclaredField("sex");
//获取所有的public的方法 包括父类的公开方法
Method[] methods = clazz.getMethods();
//获取所有的方法,包括私有的 只能获取本类的所有方法
Method[] declaredMethods = clazz.getDeclaredMethods();
//获取指定的public方法
Method m = clazz.getMethod("sleep", int.class,String.class);
//获取所有的指定方法,包括私有的
Method m2= clazz.getDeclaredMethod("work");
//获取所有的public的构造器
Constructor[] cons = clazz.getConstructors();
//获取所有的构造器,包括私有的
Constructor[] cons2 = clazz.getDeclaredConstructors();
//获取指定的public的构造器
Constructor con = clazz.getConstructor(String.class,int.class);
//获取指定的构造器,包括私有的
Constructor con2 =
clazz.getDeclaredConstructor(String.class,int.class,String.class);
//获得类的完整名称
System.out.println(clazz.getName());
//获取此类所属的包
System.out.println(clazz.getPackage());
//获取此类的父类
System.out.println(clazz.getSuperclass());
//获取此类实现的接口
Class[] it1 = clazz.getInterfaces();
}
}
public class People {
public void a(){
System.out.println("a方法");
}
}
public class Student extends People implements Serializable,Comparable{
public String name;
private int age;
private String sex;
public void eat(){
System.out.println("吃饭");
}
public void sleep(int a,String s){
System.out.println("睡觉");
}
private void work(){
System.out.println("工作");
}
private Student(String name, int age, String sex) {
super();
this.name = name;
this.age = age;
this.sex = sex;
}
public Student(String name, int age) {
super();
this.name = name;
this.age = age;
}
public Student() {
System.out.println("无参的构造器");
}
@Override
public int compareTo(Object o) {
// TODO Auto-generated method stub
return 0;
}
}
使用反射技术创建对象
1.获取Student的Class
- 功能:以Student类为例
* 属性设值
* 属性获取
* 普通方案
* 1 Student stu = new Student();
* 2 stu.name = “张三”;
* 反射方案
* 1:获取Student的Class
* 2:获取Student类的Constructor类
* 3:创建Student的对象
* 4:获取指定的属性
* 5:通过对象给属性赋值
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
public class Demo {
public static void main(String[] args) throws Exception {
//1 获取Student的Class
Class<?> clazz = Class.forName("cn.sxt.day0107.reflect4.Student");
//2 获取Student类的Constructor类
Constructor<?> con = clazz.getConstructor();
//3 使用此 Constructor 对象表示的构造方法来创建该构造方法的声明类的新实例,
并用指定的初始化参数初始化该实例。 newInstance()
Object stu = con.newInstance();
//4:获取指定的public属性
Field name = clazz.getField("name");
//5:通过对象给属性赋值
name.set(stu, "张三");
//6:获取属性的值
System.out.println(name.get(stu));
System.out.println("------------------");
//5:获取私有的属性
Field age = clazz.getDeclaredField("age");
//6:解除私有化,暴力破解
age.setAccessible(true);
//6:给age赋值
age.set(stu, 20);
//7:获取age的值
System.out.println(age.get(stu));
}
}
public class People {
public void a(){
System.out.println("a方法");
}
}
import java.io.Serializable;
public class Student extends People implements Serializable,Comparable{
public String name;
private int age;
private String sex;
public void eat(){
System.out.println("吃饭");
}
public void sleep(int a,String s){
System.out.println("睡觉");
}
private void work(){
System.out.println("工作");
}
private Student(String name, int age, String sex) {
super();
this.name = name;
this.age = age;
this.sex = sex;
}
public Student(String name, int age) {
super();
this.name = name;
this.age = age;
}
public Student() {
System.out.println("无参的构造器");
}
@Override
public int compareTo(Object o) {
// TODO Auto-generated method stub
return 0;
}
}
获取Student类的Constructor类
- Constructor 类的用法
- 1:获取Student的Class *
2:创建对象 *
2.1 直接通过Class.newInstance();
只能调用无参的构造函数 *
2.2 先获取Constructor,再通过Constructor,
调用newInstance(Class… args) *
注意:如果要调用有参的构造器,必须先获取Constructor
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
public class Demo {
public static void main(String[] args) throws Exception {
//1:获取Student的Class
Class<?> clazz = Class.forName("cn.sxt.day0107.reflect5.Student");
//2:可以直接通过Class调用无参的构造器
//clazz.newInstance();
//2:获取无参的构造器
//Constructor<?> con = clazz.getConstructor();
//3:获取1个参数的构造器 传的是形参的类型
/*Constructor<?> con = clazz.getConstructor(String.class);
//4:创建对象 传的是实参的值
Object obj = con.newInstance("张三");
//5:获取name的Field
Field field = clazz.getField("name");
//6:给name属性赋值
field.set(obj, "李四");
//7:获取name的属性值
System.out.println(field.get(obj));*/
System.out.println("--------------------");
//获取2个参数的构造器
/*Constructor<?> con2 = clazz.getConstructor(String.class,int.class);
//给name和age初始话
Object obj2 = con2.newInstance("张三",20);
//获取name和age的Field属性
Field name = clazz.getField("name");
Field age = clazz.getDeclaredField("age");
//设置age的访问权限
age.setAccessible(true);
//获取name和age值
System.out.println(name.get(obj2));
System.out.println(age.get(obj2));*/
System.out.println("--------------------");
//1:获取3 个参数的构造器
Constructor<?> con =
clazz.getDeclaredConstructor(String.class,int.class,String.class);
//2:设置构造器的访问权限
con.setAccessible(true);
//3:创建对象 属性初始化
Object obj = con.newInstance("张三",20,"男");
//4:获取name,age,sex的Field
Field name = clazz.getField("name");
Field age = clazz.getDeclaredField("age");
Field sex = clazz.getDeclaredField("sex");
//5:设置age和sex的访问权限
age.setAccessible(true);
sex.setAccessible(true);
//6:获取name,age,sex的属性值
System.out.println(name.get(obj));
System.out.println(age.get(obj));
System.out.println(sex.get(obj));
//普通方案
Student stu = new Student("张三", 20, "男");
}
}
Constructor的常用方法
public class Demo2 {
// 以String为例
public static void main(String[] args) throws Exception {
//1:获取Object的Class
Class<?> clazz = Class.forName("java.lang.String");
//2:获取String的所有构造器
/*Constructor<?>[] con = clazz.getDeclaredConstructors();
//3:遍历构造器
for (Constructor<?> c : con) {
System.out.println(c);
}*/
//4:获取指定的构造器
Constructor<?> con = clazz.getConstructor(byte[].class,String.class);
System.out.println(con);
//5:获取构造函数的修饰符
System.out.println(Modifier.toString(con.getModifiers()));
//6 获取构造函数的名称
System.out.println(con.getName());
//7 获取构造函数的形参
Class<?>[] ty = con.getParameterTypes();
for (Class<?> c1 : ty) {
System.out.println(c1.getTypeName());
}
//8 获取构造器的异常
Class<?>[] et = con.getExceptionTypes();
System.out.println(et[0].getName());
//5:创建String对象
//Object obj = con.newInstance(new byte[]{97,98,99},"UTF-8");
//System.out.println(obj);
}
}
public class Student{
public static transient String name;
private int age;
private String sex;
public void eat(){
System.out.println("吃饭");
}
public void sleep(int a,String s){
System.out.println("睡觉");
}
private void work(){
System.out.println("工作");
}
public Student(String name, int age, String sex) {
this.name = name;
this.age = age;
this.sex = sex;
System.out.println("3个参数的构造器");
}
public Student(String name, int age) {
this.name = name;
this.age = age;
System.out.println("2个参数的构造器");
}
public Student(String name) {
this.name = name;
System.out.println("1个参数的构造器");
}
public Student() {
System.out.println("无参的构造器");
}
}
public class Demo {
/*
* Method 的用法
* 以Student为例
* 1:创建Student的Class
* Class<?> clazz = Class.forName("cn.sxt.day0107.reflect6.Student");
* 2:获取Student的无参构造器
* Object obj = clazz.newInstance();
* 3:获取指定的public方法 eat
* Method method = clazz.getMethod("eat");
* 4:通过对象调用方法
* method.invoke(obj);
*
* 普通方案
* 1:创建Student对象
* Student stu = new Student();
* 2:调用方法
* stu.eat();
*
*/
public static void main(String[] args) throws Exception {
//1:创建Student的Class
Class<?> clazz = Class.forName("cn.sxt.day0107.reflect6.Student");
//2:获取Student的无参构造器
Object obj = clazz.newInstance();
//3:获取指定的public方法 eat
/*Method method = clazz.getMethod("eat");
//4:通过对象调用方法
method.invoke(obj);*/
//1:创建无参无返回值的Method
Method method = clazz.getMethod("show1");
System.out.println(method.invoke(obj));
//2:创建无参有返回值的Method
Method method1 = clazz.getMethod("show2");
System.out.println(method1.invoke(obj));
//3:创建有参无返回值的Method
Method method2 = clazz.getMethod("show3",int.class);
System.out.println(method2.invoke(obj, 100));
//4:创建有参有返回值的Method
Method method3 = clazz.getMethod("show4",String.class);
System.out.println(method3.invoke(obj, "你好"));
}
}
public class Demo2 {
/*
* Method调用实体类的set和get方法
*
*/
public static void main(String[] args) throws Exception {
Class<?> clazz = Class.forName("cn.sxt.day0107.reflect6.Student");
Object obj = clazz.newInstance();
String s = "set";
String s1 = "get";
String name = "name";
//属性的首字母转为大写
String ss = name.substring(0, 1).toUpperCase()+name.substring(1);
//获取setName的Method
Method method = clazz.getMethod(s+ss, String.class);
//调用方法
method.invoke(obj, "张三");
//获取getName的Method
Method method1 = clazz.getMethod(s1+ss);
//调用方法
System.out.println(method1.invoke(obj));
}
}
public class Demo3 {
/*
* Method的常用方法
* 以String类型
*
*/
public static void main(String[] args) throws Exception {
Class<?> clazz = Class.forName("java.lang.String");
Object obj = clazz.newInstance();
//获取String的所有方法
/*Method[] method = clazz.getDeclaredMethods();
//遍历
for (Method m : method) {
System.out.println(m);
}*/
//获取String的指定方法
Method method = clazz.getMethod("getBytes", String.class);
//获取方法的修饰符
System.out.print(Modifier.toString(method.getModifiers())+" ");
//获取方法的返回值
System.out.print(method.getReturnType().getTypeName()+" ");
//获取方法的名称
System.out.print(method.getName()+"(");
//获取方法的形参
System.out.print(method.getParameters()[0].getType().getName()+") ");
//获取方法的异常
System.out.println("throws "+method.getExceptionTypes()[0].getName());
System.out.println(method);
}
}
public class Student{
public static transient String name;
private int age;
private String sex;
public static String getName() {
return name;
}
public static void setName(String name) {
Student.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
public void eat(){
System.out.println("吃饭");
}
public void sleep(int a){
System.out.println("睡觉");
}
public void show1(){
System.out.println("无参无返回值");
}
public int show2(){
System.out.println("无参有返回值");
return 10;
}
public void show3(int a){
System.out.println("有参无返回值");
}
public String show4(String s){
System.out.println("有参有返回值");
return s;
}
private void work(){
System.out.println("工作");
}
public Student(String name, int age, String sex) {
this.name = name;
this.age = age;
this.sex = sex;
System.out.println("3个参数的构造器");
}
public Student(String name, int age) {
this.name = name;
this.age = age;
System.out.println("2个参数的构造器");
}
public Student(String name) {
this.name = name;
System.out.println("1个参数的构造器");
}
public Student() {
System.out.println("无参的构造器");
}
}
利用反射突破泛型的限制
public class Demo {
public static void main(String[] args) throws Exception {
ArrayList<String> al = new ArrayList<>();
al.add("a");
al.add("b");
al.add("c");
//使用反射突破泛型限制
Class<? extends ArrayList> clazz = al.getClass();
//获取add的Method 参数类型是Object类型
Method method = clazz.getMethod("add", Object.class);
//调用方法
method.invoke(al, 100);
method.invoke(al, 100.123F);
method.invoke(al, true);
System.out.println(al);
}
}