概念/叙述
在不修改源码的基础上可以任意的创建对象。在程序运行过程中动态创建对象。
反射的基石:字节码文件 (jvm将字节码文件加载到内存中后,字节码文件就变成了字节码文件对象 )
反射是框架设计的灵魂
框架:半成品软件。可以在框架的基础上进行软件开发,简化编码.
反射:将类的各个组成部分封装为对象,就是反射机制
好处:
可以在程序运行过程中,操作这些对象.
可以解耦,提高程序的可扩展性.
/**
*字节码文件的类型是class
*/
public class Demo {
public static void main(String[] args) { Person pser=new Person();//通过person类new的方式创建,程序运行多少遍都是创建person对象
//Student stu=new Student();如果我们在此处不通过new的方式,如何创建Student对象
//即不修改源码,仍然可以动态创建对象,这种方式为反射
}
}
获得类或对象的字节码文件对象(获取class对象的方式 )
1. class.forName("全名类"):将字节码文件加载进内存,返回class对象
*多用于配置文件,将类名定义在配置文件中.读取文件,加载类
2. 类名.class:通过类名的属性class获取
*多用于参数的传递
3. 对象.getClass():getClass()方法在Object类中定义着.
*多用于对象类的获取字节码的方法
实例:
package com.atbdqn.reflect;
/**
*获得类或对象的字节码文件对象三种方法
*1.Object类的getClas()方法
*2.类名.class属性
*3.class类的forName
*问题?:同一个类的对象或者同一个类得到的字节码文件对象是否是同一个
*/
public class Demo2 {
public static void main(String[] args) throws ClassNotFoundException {
//Object类的getClass()方法
Person p=new Person();
Person p1=new Person();
Class clazz=p.getClass();
Class clazz4=p1.getClass();
System.out.println(clazz==clazz4);//true 是同一个字节码文件对象。在第一次new 时,已经加载
Student s=new Student();
Class clazz1=s.getClass();
Class clazz2=int.class;//类型class属性
//Class类的forName()
Class clazz3=Class.forName("com.atbdqn.reflect.Person");
}
}
结论:
同一个字节码文件(*.class)在一次程序运行过程中,只会被加载一次,不论通过哪一种方法获取的class对象都是同一个.
Class对象功能
- 获取功能
*获取成员变量们
Field[ ] getFields( ) :获取所有public修饰的成员变量
Field getField(String name) :获取指定名称 public修饰的成员变量
Field[ ] getDeclaredFields( ): 获取所有的成员变量,不考虑修饰符
Field getDeclaredField( String name):获取指定的成员变量,不考虑修饰符
使用:set(对象,值):设置属性;get(对象):获取属性值 - 获取构造方法们
Constructor[ ] getConstructors( ) :解释和上面差不多
Constructor getConstructor( 类< >…prameterTypes)
Constructor[ ] getDeclaredConstructors(类< >…prameterTypes )
Constructor getDeclaredConstructor( )
使用:拿到构造方法后,用Constructor对象调用newInstance()方法就可以调用该构造方法创建对象。 - 获取成员方法们
Method[ ] getMethods( ) :解释和上面差不多
Method getMethod(String name, 类< >…prameterType)
Method[ ] getDeclaredMethods( )
Method getDeclaredMethod(String name, 类< >…prameterType )
使用:invoke(对象名,实参) - 获取类名
String getName
操作步骤
- Field:成员变量
操作:
1.设置值
void set ( Object obj,Object value)
2.获取值
get( Object obj)
3.忽略访问权限修饰符的安全检查
setAccessible(true):暴力反射
注意:Field Constructor Method 使用私有的都要用setAccessible(true)才可以访问要不就会报错 - Constructor:构造方法
创建对象:
T newInstance(Object … initargs)
如果使用空参数构造方法创建对象,操作可以简化:Class对象的newInstance方法
注意:创建新的对象(newInstance(Object … initargs))返回Object 类或是继承了Object 类 - Method:方法对象
执行方法
Object invoke(Object obj,Object … args)
注意:Object invoke(类对象,方法)
获取方法名称
String getName:获取方法名
使用反射创建对象
package com.atbdqn.reflect;
import java.lang.reflect.Constructor;
/**
* 字节码文件的类型是Class
*
*/
public class Demo {
public static void main(String[] args) throws Exception {
//构造方法的造用
//构建一个类的实例 Person p = new Person();
//1.得到字节码文件对象
Class clazz=Person.class;
//2.获得构造器对象
// public com.atbdqn.reflect.Person(int)
// public com.atbdqn.reflect.Person(java.lang.String)
// public com.atbdqn.reflect.Person(java.lang.String,int)
// public com.atbdqn.reflect.Person()
Constructor[] constructors=clazz.getConstructors();
for (Constructor constructor : constructors) {
System.out.println(constructor);
}
//得到指定构造器对象
Constructor constructor=clazz.getConstructor(String.class);
//用构造器对象创建该类的实例
Object obj=constructor.newInstance("zs");
Person p=(Person)obj;
//问题:用普通的方式创建方便,为何要用反射创建?当然是做普通方式做不到的事
//比如:我们将一个类的构造私有化,那么我们用普通的方式就无法创建对象,此时可以用反射机 制创建对象。详见Student类
}
}
使用反射得私有化的构造创建对象
package com.atbdqn.reflect;
public class Student {
private Student() {
}
@Override
public String toString() {
return "hello";
}
}
package com.atbdqn.reflect;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
public class Demo3 {
public static void main(String[] args) throws NoSuchMethodException, SecurityException, InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException {
//Student s=new Student();不允许创建对象,因为构造私有化
//利用反射 为所欲为
Class clazz=Student.class;
//getConstructor()只能得到公共的构造方法
//Constructor constructor=clazz.getConstructor();若用此种方式报下图一所示错误
Constructor constructor=clazz.getDeclaredConstructor();//得到所有构造器
//简单暴力访问 设置访问权限
constructor.setAccessible(true);//若不设置此权限,报Exception in thread "main" java.lang.IllegalAccessException详见图二
Object obj=constructor.newInstance();
System.out.println(obj);//最终正确输出结果详见图三
}
}
使用反射的便捷方式创建对象
package com.atbdqn.reflect;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
/**
* 使用完整反射方式创建一个类的实例
* 使用反射的便捷方式创建对象
*/
public class Demo3 {
public static void main(String[] args) throws NoSuchMethodException, SecurityException, InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException {
//Student s=new Student();不允许创建对象,因为构造私有化
//利用反射 为所欲为
// Class clazz=Student.class;
//getConstructor()只能得到公共的构造方法
//Constructor constructor=clazz.getConstructor();
// Constructor constructor=clazz.getDeclaredConstructor();//得到所有构造器
//简单暴力访问 设置访问权限
// constructor.setAccessible(true);//若不设置此权限,报Exception in thread "main" java.lang.IllegalAccessException
//
// Object obj=constructor.newInstance();
//
// System.out.println(obj);
//使用反射的便捷方式创建对象
//不直接使用构造器
//只支持无参、public的构造器的类;
//若类中没有无参构造,或不是public的构造,则报错
Class clazz = Person.class;
Object obj=clazz.newInstance();
System.out.println(obj);
}
}
使用反射创建对象后,调用方法
package com.atbdqn.reflect1;
public class Student {
private String name;
private int age;
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 void eat() {
System.out.println("学生会吃饭");
}
public Student() {
}
@Override
public String toString() {
return "hello";
}
}
package com.atbdqn.reflect1;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
/**
* 使用反射调用类的方法
*/
public class Demo3 {
public static void main(String[] args) throws NoSuchMethodException, SecurityException, InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException {
//得到字节码文件对象
Class clazz=Student.class;
//得到字节码文件对象的所有方法
Method[] methods=clazz.getDeclaredMethods();
for (Method method : methods) {
System.out.println(method);
}
//得到指定方法
//若方法的访问修饰符是private,处理方式同私有构造。得到所有方法后,设置权限即可
Method method1=clazz.getDeclaredMethod("eat",null);
//method1.setAccessible(true);
//正常调用方法 对象.方法名()
//反射的调用 方法
//方法.对象====>方法对象invoke(对象,参数)
Object obj=clazz.newInstance();//便捷式创建对象
method1.invoke(obj, null);//利用反射调用方法
}
}
使用反射创建对象后,访问属性
package com.atbdqn.reflect2;
public class Student {
public String name;
private int age;
public void eat() {
System.out.println("学生会吃饭");
}
public Student() { }
@Override
public String toString() {
return "hello";
}
}
package com.atbdqn.reflect2;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
/**
* 使用反射访问对象的成员变量
*/
public class Demo3 {
public static void main(String[] args) throws Exception{
//用反射访问对象成员变量
Class clazz=Student.class;
Object obj=clazz.newInstance();
//得到Field
Field field1=clazz.getField("name");
Field field2=clazz.getDeclaredField("age");
field1.set(obj,"张三");
field2.set(obj,20);
field2.setAccessible(true);
//t私有属性权限设置
System.out.println(((Student)obj).name);
}
}
实例
package SqlTest;
public class Demo {
private int id;
private String name;
private int age;
public Demo() {
}
public Demo(int id, String name, int age) {
this.id = id;
this.name = name;
this.age = age;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
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;
}
@Override
public String toString(){
return "id="+id+"\tname="+name+"\tage="+age;
}
}
package SqlTest;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
public class DemoTest {
public static String upFirst(Field field){
String str=field+"";
str=str.substring(str.lastIndexOf(".")+1);
if(str.charAt(0)>='A'&&str.charAt(0)<='Z'){
return str;
}else {
str=str.substring(0,1).toUpperCase()+str.substring(1);
return str;
}
}
public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
Object[] objs =new Object[]{1,"Logan",23};
Class<?> c=Class.forName("SqlTest.Demo");
Object obj=c.getConstructor().newInstance();
Demo demo=(Demo) obj;
Field[] fields=c.getDeclaredFields();
for(int i=0;i<fields.length;i++){
Method method=c.getMethod("set"+upFirst(fields[i]),fields[i].getType());
method.invoke(demo,objs[i]);
}
System.out.println(demo);
}
}