反射机制本质上就是一种用于实现动态编程的机制,可以在运行阶段动态的创建对象,并且动态的调用方法,具体功能由实参决定。反射技术破坏了面向对象,在底层发挥作用。
目前主流的框架SSH等底层是采用反射机制实现。java里的动态编程技术就是反射。
动态编程
编译期间变量的类型和调用的方法都不确定,运行时根据参数确定。动态编程可以让代码有更广泛的适应性,一段代码可以针对很多的类,但是程序的可读性非常低,编程难度也很高。
Class类
java.lang.Class类的实例可以描述java中的基本数据类型和引用数据类型。
该类没有公共的构造方法,是由java虚拟机和类加载器自动构造实例。
Class获取对象的方式
获取对象的作用:只有获得了对象,才能调用Class类中的方法
-
使用数据类型.Class的方式可以获取该类型的Class对象(重)
【既能获取引用类型的Class对象,也可以获得基本数据类型的Class对象】
Class c1 = String.class;
System.out.println(“c1=”+c1); //自动调用toString,c1=class java.lang.String。类的完全限定名
System.out.println(Integer.class);//class java.lang.Integer.类的完全限定名
System.out.println(int.class); //int
System.out.println(void.class); //void当Class对象为一个类类型时,toString 打印包名.类名 当Class对象为一个基本数据类型时,toString直接打印该基本数据类型
-
使用对象.getClass()的方法可以获取该类型的Class对象
【只能获取引用类型的Class对象,不能获取基本类型的Class对象】String s1 = new String("hello"); System.out.println(s1.getClass()); //class java.lang.String Integer it1 = new Integer(10); System.out.println(it1.getClass()); //class java.lang.Integer int num = 20; System.out.println(num.getClass()); //error int并不是一种引用类型
-
使用包装类.TYPE的方式来获取对应基本数据类型的Class对象
【获取到基本数据类型】
System.out.println(Integer.TYPE); //int
System.out.println(Integer.class); //class java.lang.Integer -
使用Class.forName()的方法可以获取参数类型的Class对象(重)
System.out.println(Class.forName(“java.lang.String”)); //Class java.lang.String
System.out.println(Class.forName(“String”)); //error 不能省略包名
System.out.println(Class.forName(“int”)) //error 不能处理基本数据类型
java中创建对象的方法 (补充)
-
new 直接创建 String str = new String ( ) ;
-
静态工厂方法方式 (单例模式获取对象的方式) Calendar cal = Calendar . getInstance ( ) ;
-
实例工厂方法方式 (通过一个对象 来获取另外一个对象) Date d = cal . getTime ( ) ;
-
反射
//使用反射机制来创建对象
//1.获取Class对象,调用forName()方法
Class c1 = Class.forName(“xdl.day21.Person”);
//2.创建该Class对象对应类的实例,调用newInstance()方法
System.out.println(c1.newInstance());//创建Person类型的实例 null//使用反射机制并有参形式来创建对象 //1.获取Class对象,调用forName()方法,使用上述Class对象即可 Class c1 = Class.forName("xdl.day21.Person"); //2.获取Constructor类型的对象,调用getConstructor()方法 获取构造方法相当于将Person类中的Person(String name,int age)构造方法获取到了 Constructor ct1 = c1.getConstructor(String.class, int.class); //3.使用有参构造方法来创建Class对象表示类的新实例 调用newInstance()方法使用ct1表示的Person(String name, int age)构造方法来构造对象 System.out.println(ct1.newInstance("zhangfei", 30));//zhangfei 30
反射中涉及到的包与类
软件包 java.lang.reflect 的描述
提供类和接口,以获得关于类和对象的反射信息。在安全限制内,反射允许编程访问关于加载类的字段、方法和构造方法的信息,并允许使用反射字段、方法和构造方法对其底层对等项进行操作。
Array提供动态创建和访问数组的静态方法。
java.lang.Class 用来描述其它类类型的一个类型
java.lang.reflect.Constructor 构造类型 描述构造函数的
java.lang.reflect.Feild 描述字段的类型
java.lang.reflect.Method 描述方法的类型
java.lang.reflect.Array 动态数组
Class 类型中常用的API
static Class<?> forNmae(String className) - 获取参数指定类名的Class对象并返回
---------------------------------------------------------------------------------------
调用无参构造
T newInstance() - 用于获取该Class引用表示的类的一个新实例。
调用有参构造
Constructor<T> getConstructor(Class<?>... parameterTypes)
- 根据参数指定的类型来获取该Class对象表示类中的一个公共构造方法(...为变长数组)
Constructor<?>[] getConstructors() - 获取该Class对象表示类中的所有公开构造方法
Constructor getDeclaredConstructor() - 获取该Class对象表示类中的构造方法(包括公、私、保)
Constructor getDeclaredConstructor() - 获取该Class对象表示类中的所有构造方法。
---------------------------------------------------------------------------------------
获取成员变量
Field getDeclaredField(String name) - 获取该Class对象表示类中名字为name的成员变量并返回
Field[] getDeclaredFields() - 获取该Class对象表示类中所有的成员变量并返回
---------------------------------------------------------------------------------------
获取成员方法
Method getMethod(String name, Class<?>... parameterTypes)
- 获取该Class对象表示的类或接口中名字为name,参数为parameterTypes的公共成员方法并返回
Method[] getMethods() - 获取该Class对象表示类中所有的公共成员方法并返回
Constructor 类
Constructor 是用于描述Class对象对应类中的单个构造方法。 即用于描述构造方法
T newInstance(Object... initargs) - 使用当前调用对象表示的构造方法来构造Class对象表示类的新实例,调用构造方法的实参由该方法的形参传入。即创建一个对象,并用指定的初始化参数初始化该实例。
int getModifiers() - 以整数形式返回构造方法的修饰符。
Field 类
Field类用于描述Class对象对应类中的单个成员变量。
通过Field给具体的对象赋值:赋值使用set(具体的对象,值);获取值使用get(具体的对象);
如果要访问私有属性需要使用setAccesible(true);
Object get(Object obj) - 获取对象obj中成员变量的数值并返回。
String getName() - 获取当前调用对象中成员变量的名称并返回。
Class<?> getType() - 返回当前调用对象所表示字段的类型。
void set(Object obj, Object value) - 将对象obj中的成员变量值改为value。
void setAccessible(boolean flag) - 用于设置是否进行java语言访问检查
设置为true,即取消java语言的访问检查
Method 类
Method 用于描述Class对象对应类中的单个成员方法。
String getName() - 以 String 形式返回此 Method 对象的方法名。
getReturnType() - 返回该方法的返回值类型。
int getModifiers() - 以整数形式返回该方法的修饰符。
【Object invoke(Object obj, Object... args)】
- 使用obj对象调用带有指定参数的方法,实参传递args。
代码实现
public static void main(String[] args) throws Exception {
//1.获取Class对象,调用forName()方法
Class<?> c1 = Class.forName("xdl.day21.Person");
//2.使用有参的形式创建Person类型的对象,调用getConstructor()方法
Constructor<?> ct1 = c1.getConstructor(String.class, int.class);
//3.使用Constructor类型的引用去构造对象,调用newInstance()方法
Person p1 = (Person) ct1.newInstance("zhangfei", 30);
//4.获取Person类中名字为getName()的方法,调用getMethod()方法
Method m1 = c1.getMethod("getName");
//5.调用getName()方法,使用Method类型的引用调用invoke()方法
//p1.getName()
System.out.println(m1.invoke(p1)); //zhangfei
}
JavaBean内省
javabean是符合一定规范的可复用的java类。本质上就是一种习惯性编程规范,并不是明确的编程规则/语法格式
内省技术(Introspector )是针对javabean另一套和反射技术一样的获取类信息的API。
需要符合以下规范:
a.要求满足JavaBean规范的类必须在一个包中。
b.要求满足JavaBean规范的类必须提供无参的构造方法。
c.要求满足JavaBean规范的类中成员变量都是私有的。
d.要求满足JavaBean规范的类中提供公有的get成员变量和set成员变量的方法。
e.要求满足JavaBean规范的类需要支持序列化操作。
boolean 类型的get()方法 以 is开头
一般要实现序列化接口(什么也不做,只是做个标记)
1.对象形式的文件读写:如磁盘的读写需要实现序列化 2.网络传输