声明:    本篇博客绝大多数内容为《Spring3.x企业开发应用实战》一书原内容,所有版权归原书作者所有!,仅供学习参考,勿作他用!

3.2 相关Java基础知识

Java语言允许通过程序化的方式间接对Class对象实例操作,Class文件由类装载器装在后,在JVM(Java虚拟机)中将形成一份描述Class结构的元信息对象,通过该元信息对象可以获知Class的结构信息: 如构造函数、属性和方法等。Java允许用户借由这个Class相关的元信息对象间接调用Class对象的功能,这就为使用程序化方式操作CLass对象开辟了途径。

3.2.1 简单实例

我们将从一个简单例子开始探访Java反射机制。

该类是测试所需要用到的主体类。

package com.baobaotao.reflect;

public class Car {
 private String brand;

private String color;

private int maxSpeed;

public Car(){System.out.println("init car!!");}
 public Car(String brand,String color,int maxSpeed){
  this.brand = brand;
  this.color = color;
  this.maxSpeed = maxSpeed;
 }
 public void introduce() {
       System.out.println("brand:"+brand+";color:"+color+";maxSpeed:"+maxSpeed);
 }

public String getBrand() {
  return brand;
 }

public void setBrand(String brand) {
  this.brand = brand;
 }

public String getColor() {
  return color;
 }

public void setColor(String color) {
  this.color = color;
 }

public int getMaxSpeed() {
  return maxSpeed;
 }

public void setMaxSpeed(int maxSpeed) {
  this.maxSpeed = maxSpeed;
 }
}

一般情况下,我们会使用如下的代码创建Car的实例:

Car car = new Car( );

car.setBrand("some brand");

或者

Car car = new Car("some brand","some color",);

以上两种方式都是采用传统方式直接地调用目标类的方法创建对象,下面我们通过Java反射机制以一种更加通用的方法间接地操作目标类,从而创建对象。

package com.baobaotao.reflect;

import java.lang.reflect.Constructor;
import java.lang.reflect.Method;

public class ReflectTest {
 
 /*
  * 需求:
  *  以反射的方式获取com.baobaotao.reflect.Car类的对象。并设置其实例域的属性,最后输出。   
  */
 public static Car  initByDefaultConst() throws Throwable {
  //通过当前线程对象获取类装载器
  ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
  
  //通过类装载器加载com.baobaotao.reflect.Car类的字节码文件,从而获取到该类的Class对象。
  //类可能找不到,所以需要抛出异常。
  Class clazz = classLoader.loadClass("com.baobaotao.reflect.Car");
  
  //通过该类的默认(无参)构造方法创建对象
  Constructor cons = clazz.getDeclaredConstructor();
  Car car = (Car) cons.newInstance();
  //当然也可以通过该类的Class对象创建该类的实例
  //Car car = (Car) clazz.newInstance();
  
  
  //通过反射方法设置属性
  Method setBrand = clazz.getMethod("setBrand", String.class);
  setBrand.invoke(car, "红旗CA72");
  Method setColor = clazz.getMethod("setColor", String.class);
  setColor.invoke(car,"黑色");
  Method setMaxSpeed = clazz.getMethod("setMaxSpeed", int.class);
  setMaxSpeed.invoke(car, 200);
  
  return car;
 }
 
 public static void main(String[] args) throws Throwable {
  Car car = initByDefaultConst();
  car.introduce();
 }

}

结果:

init car!!
brand:红旗CA72;color:黑色;maxSpeed:200

这说明我们完全可以通过编程的方式调用Class的各项功能。这和直接通过构造函数和方法调用类功能的效果是一致的,不过前者是间接调用,后者是直接调用罢了。

在ReflectTest中,我们使用了几个重要的反射类: ClassLoader、Class、Constructor、Method。

ClassLoader:    用于将指定路径下的类的字节码文件装载到JVM中。注意,其方法ClassLoader#loadClass的参数一定要是类的全限定名称 —— 包名.类名

创建目标类的对象:

1 可以通过Class类的newInstance方法创建对象。这样创建的对象是通过默认构造器创建的,所以目标类Car中必须相应地给出默认构造器。

2 通过Constructor类创建。通过目标类对应的Class类的对象的getDeclaredConstructor方法创建Construcor类对象,该类描述了目标类的构造方法的信息。可以通过其newInstance()方法和newInstance(paramTypes)来分别创建不带参的对象和带参的对象。

如:

//已经获取目标类对应的Class类的对象clazz

//得到的未设置实例域的对象(不带参的)

Car car  = (Car)clazz.getDeclaredConstructor( ).newInstance( );

//得到的已设置实例域的对象(带参的)

(Car)clazz.getDeclaredConstructor(String.class,String.class,int.class).newInstance("红旗CA72","黑色",200);

3.2.2 类装载器ClassLoader

    类装载器工作原理

类装载器就是寻找类的字节码文件并构造出类再JVM内部的表示的对象组件。在Java中,将一个类装载到JVM中需要经过以下步骤:

1 装载:    查找和导入Class文件;

2 链接:    执行校验’准备和解析步骤,其中解析步骤是可以选择的:

a)   校验:    检查载入的Class文件的正确性。

b)   准备:    给类的静态变量分配内存空间。

c)    解析:    将符号引用转成直接引用。

类装载器工作由ClassLoader及其子类负责,ClassLoader是一个重要的Java运行时组件,它负责在运行时查找和装入Class字节码文件。JVM在运行时会产生三个类装载器:  根装载器、ExtClassLoader(扩展类装载器)、和AppClassLoader(系统装载器)。其中,根装载器不是ClassLoader的子类,它由C++编写,因此我们在Java中看不到它。

默认情况下,使用AppClassLoader装载应用程序的类。我们可以做个试验。

public static void main(String[] args) throws Throwable {
  ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
  System.out.println("current:"+classLoader);
  System.out.println("parrent:"+classLoader.getParent());
  System.out.println("grandparrent:"+classLoader.getParent().getParent());
 }

结果;

current:sun.misc.Launcher$AppClassLoader@73d16e93
    parrent:sun.misc.Launcher$ExtClassLoader@6d06d69c
    grandparrent:null

通过以上信息,可知装载当前类的装载器为AppClassLoader,父装载器是ExtClassLoader,祖父装载器是根装载器,因为在Java中找不到其句柄,所以直接返回null。

JVM装载类装载类时使用”全盘负责委托机制“,”全盘负责“指的是当一个类装载器装载类时,默认会选择它该类和其依赖和引用的类,除非显式地声明了使用别的装载器。”委托机制“指的是首先委托父装载器装载目标类的字节码文件,只有在找不到的情况下才从自己的类路径中查找并装载目标类。这是出于安全的考虑。试想,如果某人编写了一个恶意的基础类(如java.lang.String),并装载到了JVM中,这会造成多么可怕的后果!而”全盘委托负责机制“中,基础类永远是由根装载器装载,这便可以杜绝这种现象的发生。

实战经验:

许多Java开发者都会遇到这样的异常: java.lang.NoSuchMethodError。这便是JVM的“全盘委托机制”造成的。出现该错误说明存在不同版本的类包。

如commons-lang 2.x.jar和commons-lang3.x.jar都位于类路径中。代码中用到了后者的某个方法,而该方法在前者中并不存在,但是JVM又碰巧从前者中装载类。这便出现了该错误。

 菊子曰微博群发没烦恼!

Spring3.x企业开发应用实战读书笔记 —— 第三章IoC容器概述的更多相关文章

  1. 《Linux内核设计与分析》第六周读书笔记——第三章

    <Linux内核设计与实现>第六周读书笔记——第三章 20135301张忻估算学习时间:共2.5小时读书:2.0代码:0作业:0博客:0.5实际学习时间:共3.0小时读书:2.0代码:0作 ...

  2. Spring AOP (Spring 3.x 企业应用开发实战读书笔记第六章)

    从面相对象编程到面相切面编程,是一种代码组织方式的进化. 每一代的代码组织方式,其实是为了解决当时面对的问题.比如写编译器和写操作系统的时候的年代当然要pop,比如写界面的时候当然要oop,因为界面这 ...

  3. 《CSS3实战》读书笔记 第三章:选择器:样式实现的标记

    第三章:选择器:样式实现的标记 选择器的魔力在于,让你完全实现对网页样式的掌控.不同的选择器可以用在不同的情况下使用.总之把握的原则是:规范的编码,根据合理地使用选择器,比去背选择器的定义有价值的多. ...

  4. maven实战读书笔记(三)

    maven将一系列的步骤都封装为一系列的插件,运行命令后一系列的插件运行

  5. jQuery 实战读书笔记之第二章:选择元素

    基本选择器 html 代码如下,后面的 js 使用的 html 基本大同小异. <!doctype html> <html> <head> <title> ...

  6. 《R语言实战》读书笔记--第三章 图形初阶(二)

    3.4添加文本.自定义坐标轴和图例 很多作图函数可以设置坐标轴和文本标注.比如标题.副标题.坐标轴标签.坐标轴范围等.需要注意的是并不是所有的绘图函数都有上述的参数,需要进行验证.可以将一些默认的参数 ...

  7. 《R语言实战》读书笔记--第三章 图形初阶(一)

    3.1使用图形 可以使用pdf等函数将图形直接保存在文件中.在运用attach和detach函数的使用中经常出现错误,比如命名重复的问题,所以,应该尽量避免使用这两个函数. plot是一般的画图函数, ...

  8. Maven实战读书笔记(三):Maven依赖

    3.1 依赖的配置 一个依赖声明可以包含下面元素: <dependencies> <dependency> <groupId></groupId> &l ...

  9. Maven实战读书笔记(一):Maven概述

    1.1 Maven是什么,能做什么 Maven是一个跨平台的项目管理工具,主要服务于Java平台的项目构建.依赖管理和项目信息管理. Maven的用途之一是项目构建,能够自动化构建过程,从清理.编译. ...

随机推荐

  1. P2024食物链

    题目描述 动物王国中有三类动物 A,B,C,这三类动物的食物链构成了有趣的环形.A 吃 B,B 吃 C,C 吃 A. 现有 N 个动物,以 1 - N 编号.每个动物都是 A,B,C 中的一种,但是我 ...

  2. php结合redis实现高并发下的抢购、秒杀功能 (转载)

    抢购.秒杀是如今很常见的一个应用场景,主要需要解决的问题有两个: 1 高并发对数据库产生的压力 2 竞争状态下如何解决库存的正确减少("超卖"问题) 对于第一个问题,已经很容易想到 ...

  3. UWP 五星好评

    var pfn = Package.Current.Id.FamilyName; await Launcher.LaunchUriAsync(new Uri("ms-windows-stor ...

  4. Yii2如何添加sql日志记录的配置信息

    在使用Yii2框架的时候,常常会出现没有sql日志记录的问题.在代码里一句一句的打印sql语句也不现实.所以就要用文件记录起来. 在 config/web.php 里面的 log配置中增加如下配置 [ ...

  5. Netty4 学习笔记之三:粘包和拆包

    前言 在上一篇Netty 心跳 demo 中,了解了Netty中的客户端和服务端之间的心跳.这篇就来讲讲Netty中的粘包和拆包以及相应的处理. 名词解释 粘包: 会将消息粘粘起来发送.类似吃米饭,一 ...

  6. calc() ---一个会计算的css属性

    最近这个月一直在赶项目开发,遇到的问题和学到的前端知识没有更新到博客园,现在闲了下来,就整理一下前端知识. 在项目开发中,在样式这方面花费的时间较多,因为针对于数字的变化特别多,本人不爱记数字,在看设 ...

  7. 支持国内版Office 365的PowerShell模块现已发布

    作者:陈希章 发表于2017年5月12日 上一篇文章我详细介绍了如何在PowerShell中访问到Office 365的Graph API,在文章结尾处我留了一个问题,希望有朋友可以根据那个思路,尝试 ...

  8. MyBatis_查询缓存01

    一.查询缓存 查询缓存的使用,主要是为了提高查询访问速度.将用户对同一数据的重复查询过程简单化,不在每次均从数据库中查询获取结果数据,从而提高访问速度. MyBatis的查询缓存机制,根据缓存区的作用 ...

  9. 60、jQuery其余操作

    上篇主要介绍了jQuery,和一些基本用法,这篇主要讲解动画.常用事件.还有一些jQuery的补充内容. 本篇导航: 动画 常用事件 插件 jQuery API 中文文档 一.动画 1.基本 show ...

  10. 【java】Date与String之间的转换及Calendar类:java.text.SimpleDateFormat、public Date parse(String source) throws ParseException和public final String format(Date date)

    package 日期日历类; import java.text.ParseException; import java.text.SimpleDateFormat; import java.util. ...