反射与内省.md
文章目录
1、 什么是反射
得到Class 类对象有三种方法
- Object 类的对象中的getClass() 方法
- 类.class
- 通过Class 类的forName方法
没有任何方式能够阻止反射到达并调用非公共访问权限的方法。对于域来说,的确如此,即便是 private域;
public static void main(String[] args){
Dog dog1 = new Dog("往往");
// 通过对象的getClass方法
Class aClass = dog1.getClass();
System.out.println(aClass);
// 通过类.class
Class godClass = Dog.class;
// 通过Class.forName 方法
try {
Class class1 = Class.forName("code.Dog");
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
}
2、 Class 类
Class<?> 优于平凡的Class,即便他们是等价的;但是 Class不会产生编译器警告信息;
向 Class 引用添加泛型语法的原因仅仅是为了提供编译期类型检查,如果操作有误,编译期就可以发现;如果是没有带泛型的Class引用,则直到运行时才可以发现该错误;
public void test2() {
Class<Dog> dogClass = Dog.class;
try {
// 实例化一个对象,调用了默认无参的构造方法
Dog dog = (Dog) dogClass.newInstance();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
3、 通过Class 类获取类信息
获得构造方法,并调用构造方法
@Test
public void test3() {
Class<Dog> dogClass = Dog.class;
Constructor<?>[] constructors = dogClass.getConstructors();
for (int i = 0; i < constructors.length; i++) {
System.out.println(constructors[i].getName());
System.out.println(constructors[i].getParameterCount());
}
Constructor<Dog> constructor = null;
try {
constructor = dogClass.getConstructor(String.class);
Dog dog = constructor.newInstance("小白");
}catch (InstantiationException|IllegalAccessException|InvocationTargetException|NoSuchMethodException e) {
e.printStackTrace();
}
}
查询类的成员变量
@Test
public void test4() {
Class<Dog> dogClass = Dog.class;
// 查询公有属性数量
Field[] fields = dogClass.getFields();
System.out.println(fields.length);
Field[] declaredFileds = dogClass.getDeclaredFields();
System.out.println(declaredFileds.length);
for(int i = 0; i < declaredFileds.length; i++){
int modifier1 = declaredFileds[i].getModifiers();
System.out.println(Modifier.toString(modifier1) + " "+ declaredFileds[i].getType()+" "+declaredFileds[i].getName());
}
}
4、 通过Class 类调用属性或方法
调用方法(包括私有方法)
@Test
public void test5(){
Dog testDog = new Dog("往往");
Class<Dog> dogClass = Dog.class;
// 获取类的包名
Package aPackage = dogClass.getPackage();
System.out.println(aPackage.getName());
// 获取公有方法
Method[] methods = dogClass.getMethods();
for(int i = 0; i < methods.length; i++){
System.out.println(methods[i]);
if(methods[i].getName().equals("toString")){
try {
String s = (String)methods[i].invoke(testDog);
System.out.println("toString "+s);
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
}
}
System.out.println("*****************");
// 访问私有方法,不包括父类的方法
Method[] declaredMethods = dogClass.getDeclaredMethods();
for(int i = 0; i < declaredMethods.length; i ++){
System.out.println(declaredMethods[i]);
if(declaredMethods[i].getName().equals("privateMethod"));
declaredMethods[i].setAccessible(true);
try {
declaredMethods[i].invoke(testDog);
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
}
}
5、 动态代理
通过代理类:Proxy的代理,接口和实现类之间可以不直接发生联系,而可以在运行期实现动态关联
Java动态代理主要是通过Java.lang.reflect 包中的两个类
InvocationHandler 类
public Object invoke(Object obj, Method method, Object[] obs)
其中第一个参数obj 指的是代理类,method 是被代理的对象,obs是指被代理的方法的参数组,此方法由代理类来实现
Proxy 类
动态代理其实是运行时生成class,所以,必须提供一组interface,然后告诉他class 已经实现了这些interface,而在生成Proxy的时候,必须给他提供一个Handler,让他来接管实际的工作
接口
public interface Hotel {
public void reserve();
}
public interface Subject {
public void shopping();
}
接口实现
public class Person implements Subject, Hotel{
public void shopping(){
System.out.println("付款,买到心仪的商品");
}
@Override
public void reserve() {
System.out.println("预定付款,打飞机飞往目的地");
}
}
public class CreateProxy implements InvocationHandler {
private Object target;
// 用于创建代理对象的方法
public Object create(Object target){
this.target = target;
Object proxy = Proxy.newProxyInstance(target.getClass().getClassLoader(),target.getClass().getInterfaces(),this);
return proxy;
}
/**
* 代理对象要执行的方法
* @param proxy 代理类对象
* @param method 被代理对象的方法
* @param args 被代理对象方法的参数
* @return
* @throws Throwable
*/
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("上海寻找客户需要的产品");
System.out.println("客户确定物品");
method.invoke(target, args);
System.out.println("完成海淘");
return null;
}
}
测试
public class testDemo {
@Test
public void testProxy(){
CreateProxy cp = new CreateProxy();
Hotel hotel = new Person();
Hotel proxy = (Hotel) cp.create(hotel);
Subject subject = new Person();
Subject proxy1 = (Subject) cp.create(hotel);
proxy.reserve();
proxy1.shopping();
}
}
5、类加载器原理分析
1、类的加载过程
JVM将类加载过程分为三个步骤:装载(Load), 链接(Link),初始化(Initialize),链接又分为三个步骤
- 装载 : 查找并加载类的二进制数据
- 链接 (验证:确保被加载类的正确性, 准备:为类的静态变量分配内存,并将其初始化为默认值 解析:把类中的符号引用转换为直接引用)
- 初始化:为类的静态变量赋予正确的初始值
装载:查找并加载类的二进制数据
-
类的初始化,类什么时候才被初始化 ? ( 6 种情况 )
-
创建类的实例,也就是new 一个对象
-
访问某个类或接口的静态变量,或者对该静态变量赋值
-
调用类的静态方法
-
反射(Class.forName(“com.vince.Dog”))
-
初始化一个类的子类(首先初始化子类的父类)
-
JVM 启动时表明的启动类,即文件名和类名相同的那个类
3 类的加载
指的是将类的.class 文件中的二进制数据读入到内存中,将其放在运行时数据区的方法区内,然后再堆内创建一个这个类的Java.lang.Class 对象,用来封装类在方法区类的对象。
6、 JavaBean 概念
什么是JavaBean
Bean 理解为组件的意思,JavaBean 就是Java 组件,在广泛的理解就是一个类,对于组件来说关键在于要具有“能够被IDE构建工具侦测其属性和事件”的能力,通常在Java 中。
JavaBean 命名规则
- 对于一个命名为xxx的属性,通常要写两个方法getXxx(), setXxx() 方法,任何浏览这些方法的工具,都会把get或set后面的第一个字母自动转换为小写
- 对于布尔型属性,可以使用以上get 和set 的方式,不过也可以把get 替换成is
- Bean 的普通方法不必遵循以上的命名规则,不过他们必须是public 的
- 对于事件,要使用Swing 中处理监听器的方式,如addWindowsListener removeWindowListener
7、 内省基本概念
introspector 是java 语言对Bean 类属性、事件的一种缺省处理方法。例如类A中有属性name,那我们可以通过getName setName来得到其值或者设置其值,通过getName 和setName 来访问name 属性,这就是默认的规则
Java 中提供了一套API 用来访问某个属性的getter/setter 方法,通过这些API 可以使你不需要了解这些规则,这些API存放于包Java.beans 中,一般做法是通过类Introspector 的getBeanInfo 方法,来获取某个对象的BeanInfo 信息,然后通过BeanInfo 来获取属性的描述器(PropertyDescriptor),通过这个属性描述器就可以描述某个属性对应的getter/setter 方法,然后我们就可以通过反射机制来调用这些方法。
1 Introspector 类
Introspector 类公国工具学习有关受目标Java Bean 支持的属性、事件和方法的只是提供一个标准方法
static BeanInfo getBeanInfo(Class<?> beanClass) 在Java Bean 上进行内省,了解其所有属性、公开的方法和事件
2、 BeanInfo 类
该类实现此BeanInfo 接口并提供有关其bean 方法、属性、事件等显式信息。
MethodDescriptor[] getMethodDescriptors() 获得beans MethodDescriptors() ;
PropertyDescriptor[] getPropertyDescriptors() 获得beans PropertyDescriptor.
Properties 属性文件工具类的使用
3、 PropertyDescriptor 类
propertyDescriptor 描述Java Bean 通过一对存储器方法导出的一个属性
Method getReadMethod() 获得应该用于读取属性值的方法
Method getWriteMethod() 获得应该用于写入属性值的方法
4、 MethodDescriptor 类
MethodDescriptor 描述了一种特殊方法
即Java Bean 支持从其他组件对其进行外部访问
Method getMethod() 获得此MethodDescriptor 封装的方法
8、 理解可配置的AOP配置
1、 AOP 的概念:Aspect Oriented Programming(面向切面编程)
9、 单例模式优化
- 使用同步保证线程安全
- 使用volatile 关键字
volatile 提醒编译器它后面所定义的变量随时都有可能变化,因此编译后的程序每次需要存储或读取这个变量的时候,都会直接从变量地址中读取数据,如果没有volatile 关键字,则编译器可能优化读取和存储,可能暂时使用寄存器中的值,如果这个变量由别的程序更新了的话,将出现不一致的现象
- 防止反射调用私有构造方法
- 让单例类序列化安全
懒汉式
public class Singleton implements Serializable {
private static Singleton singleton = null;
private Singleton() {
if(singleton!=null){
throw new RuntimeException("此类为单例模式,已经被实例化了");
}
}
public static Singleton getInstance() {
if (singleton == null) {
synchronized (Singleton.class) {
if (singleton == null) {
singleton = new Singleton();
}
}
}
return singleton;
}
}
饿汉式
public class Test {
private Test() {
}
public static Test instance = new Test();
public Test getInstance() {
return instance;
}
}
推荐阅读
-
Java学习笔记-注解与反射
-
Java 注解与反射学习笔记
-
Java编程反射机制用法入门与实例总结
-
利用反射获取与修改private的属性的值 博客分类: java基础 javareflect
-
利用反射获取与修改private的属性的值 博客分类: java基础 javareflect
-
Java反射机制概念、原理与用法总结
-
Gulp学习指南之CSS合并、压缩与MD5命名及路径替换_html/css_WEB-ITnose
-
[Git] 快速签出与更新所有远程分支.md
-
md5 16位二进制与32位字符串相互转换示例_php实例
-
nodejs md5 与 php md5 中英文加密结果不一样,怎么办?