Java类加载、反射及练习整理

类加载器

1.1      类的加载

当程序要使用某个类时,如果该类还未被加载到内存中,则系统会通过加载,连接,初始化三步来实现对这个类进行初始化。

加载

就是指将class文件读入内存,并为之创建一个Class对象。

任何类被使用时系统都会建立一个Class对象

连接

验证 是否有正确的内部结构,并和其他类协调一致

准备 负责为类的静态成员分配内存,并设置默认初始化值

解析 将类的二进制数据中的符号引用替换为直接引用

初始化

就是我们以前讲过的初始化步骤

1.2      类初始化时机

1. 创建类的实例

2. 类的静态变量,或者为静态变量赋值

3. 类的静态方法

4. 使用反射方式来强制创建某个类或接口对应的java.lang.Class对象

5. 初始化某个类的子类

6. 直接使用java.exe命令来运行某个主类

1.3      类加载器

负责将.class文件加载到内存中,并为之生成对应的Class对象。

虽然我们不需要关心类加载机制,但是了解这个机制我们就能更好的理解程序的运行

1.4      类加载器的组成

Bootstrap ClassLoader 根类加载器也被称为引导类加载器,负责Java核心类的加载

比如System,String等。在JDK中JRE的lib目录下rt.jar文件中Extension ClassLoader 扩展类加载器

负责JRE的扩展目录中jar包的加载。

在JDK中JRE的lib目录下ext目录

System ClassLoader 系统类加载器

负责在JVM启动时加载来自java命令的class文件,以及classpath环境变量所指定的jar包和类路径。

通过这些描述就可以知道我们常用的类,都是由谁来加载完成的。

反射

JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性;这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制。

要想解剖一个类,必须先要获取到该类的字节码文件对象。而解剖使用的就是Class类中的方法.所以先要获取到每一个字节码文件对应的Class类型的对象。

2.1      Class类

获取Class对象的三种方式

package com.oracle.FanShe;

public class Demo01 {

public static void main(String[] args) throws ClassNotFoundException {

//1.通过getClass方法获取,通过对象获取

Person p=new Person();

Class c1=p.getClass();

System.out.println(c1);

//2.通过类名获取

Class c2=Person.class;

System.out.println(c2);

System.out.println(c1==c2);

System.out.println(c1.equals(c2));

//3.通过完整的包名+类名

Class c3=Class.forName("com.oracle.FanShe.Person");

System.out.println(c3);

}

}

package com.oracle.FanShe;

import java.lang.reflect.Constructor;

import java.lang.reflect.InvocationTargetException;

import java.util.jar.Attributes.Name;

public class Demo02 {

//构造方法Constructor

//成员变量 Field

//方法  Method

public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, SecurityException, InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException {

//反射获取构造方法

//获取Person.class文件对象

Class c=Class.forName("com.oracle.FanShe.Person");

/*//获取所有公共的构造方法(构造方法数组)

Constructor[] cons=c.getConstructors();

//遍历

for(Constructor con:cons){

System.out.println(con);

}*/

//获取某个公共构造方法

//空参构造

/*Constructor con1=c.getConstructor();

//System.out.println(con1);

//有参构造

Constructor con2=c.getConstructor(String.class,int.class);

//System.out.println(con2);

//创建你对象

Object obj= con2.newInstance("乔治",16);

System.out.println(obj);*/

//获取 所有的构造方法数组

/*Constructor[] cons=c.getDeclaredConstructors();

for(Constructor con:cons){

System.out.println(con);

}*/

//获取某个私有构造方法

Constructor con=c.getDeclaredConstructor(String.class);

//System.out.println(con);

//暴力反射

con.setAccessible(true);

Object obj=con.newInstance("拉拉");

System.out.println(obj);

}

}

package com.oracle.FanShe;

public class Person {

private String name;

public int age;

static{

System.out.println("静态代码块");

}

public Person(){

System.out.println("空参构造");

}

public Person(String name, int age){

this.name=name;

this.age=age;

System.out.println("public Person(String name, int age)");

}

public Person(String name){

this.name=name;

System.out.println("public Person(String name)");

}

public void eat(){

System.out.println("公共空参方法");

}

public void sleep(String name){

System.out.println("公共有参方法");

}

private void smoke(){

System.out.println("私有空参构造");

}

@Override

public String toString() {

return "Person [name=" + name + ", age=" + age + "]";

}

}

2.2      通过反射获取构造方法并使用

在反射机制中,把类中的成员(构造方法、成员方法、成员变量)都封装成了对应的类进行表示。      其中,构造方法使用类Constructor表示。可通过Class类中提供的方法获取构造方法:

2.2.1    通过反射方式,获取构造方法,创建对象

获取构造方法,步骤如下:

1. 获取到Class对象

2. 获取指定的构造方法

3. 通过构造方法类Constructor中的方法,创建对象

public T newInstance(Object... initargs)

package com.oracle.FanShe;

import java.lang.reflect.Constructor;

import java.lang.reflect.InvocationTargetException;

import java.util.jar.Attributes.Name;

public class Demo02 {

//构造方法Constructor

//成员变量 Field

//方法  Method

public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, SecurityException, InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException {

//反射获取构造方法

//获取Person.class文件对象

Class c=Class.forName("com.oracle.FanShe.Person");

//获取所有公共的构造方法(构造方法数组)

/*Constructor[] cons=c.getConstructors();

//遍历

for(Constructor con:cons){

System.out.println(con);

}*/

//获取某个公共构造方法

//空参构造

Constructor con1=c.getConstructor();

//System.out.println(con1);

//有参构造

Constructor con2=c.getConstructor(String.class,int.class);

//System.out.println(con2);

//创建你对象

Object obj= con2.newInstance("乔治",16);

System.out.println(obj);

}

}

运行结果:

2.2.2    通过反射方式,获取私有构造方法,创建对象

AccessibleObject 类是 Field、Method 和 Constructor 对象的父类。它提供了将反射的对象标记为在使用时取消默认 Java 语言访问控制检查的能力。

对于公共成员、默认(打包)访问成员、受保护成员和私有成员,在分别使用 Field、Method 或 Constructor 对象来设置或获取字段、调用方法,或者创建和初始化类的新实例的时候,会执行访问检查

public void setAccessible(boolean flag) throws SecurityException

参数值为 true 则指示反射的对象在使用时应该取消 Java 语言访问检查。参数值为 false 则指示反射的对象应该实施 Java 语言访问检查。

获取私有构造方法,步骤如下:

1. 获取到Class对象

2. 获取指定的构造方法

3. 暴力访问, 通过setAccessible(boolean flag)方法

4. 通过构造方法类Constructor中的方法,创建对象

public T newInstance(Object... initargs)

package com.oracle.FanShe;

import java.lang.reflect.Constructor;

import java.lang.reflect.InvocationTargetException;

import java.util.jar.Attributes.Name;

public class Demo02 {

//构造方法Constructor

//成员变量 Field

//方法  Method

public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, SecurityException, InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException {

//反射获取构造方法

//获取Person.class文件对象

Class c=Class.forName("com.oracle.FanShe.Person");

//获取所有公共的构造方法(构造方法数组)

/*Constructor[] cons=c.getConstructors();

//遍历

for(Constructor con:cons){

System.out.println(con);

}*/

//获取某个公共构造方法

//空参构造

//Constructor con1=c.getConstructor();

//System.out.println(con1);

//有参构造

/*Constructor con2=c.getConstructor(String.class,int.class);

//System.out.println(con2);

//创建你对象

Object obj= con2.newInstance("乔治",16);

System.out.println(obj);*/

//获取 所有的构造方法数组

/*Constructor[] cons=c.getDeclaredConstructors();

for(Constructor con:cons){

System.out.println(con);

}*/

//获取某个私有构造方法

Constructor con=c.getDeclaredConstructor(String.class);

//System.out.println(con);

//暴力反射

con.setAccessible(true);

Object obj=con.newInstance("拉拉");

System.out.println(obj);

}

}

运行结果:

2.3      通过反射获取成员方法并使用

2.3.1        通过反射,创建对象,获取指定的成员变量,进行赋值与获取值操作

获取成员变量,步骤如下:

1. 获取Class对象

2. 获取构造方法

3. 通过构造方法,创建对象

4. 获取指定的成员变量(私有成员变量,通过setAccessible(boolean flag)方法暴力访问)

5. 通过方法,给指定对象的指定成员变量赋值或者获取值

public void set(Object obj, Object value)

在指定对象obj中,将此 Field 对象表示的成员变量设置为指定的新值

public Object get(Object obj)

返回指定对象obj中,此 Field 对象表示的成员变量的值

2.4      通过反射获取成员方法并使用

在反射机制中,把类中的成员变量使用类Field表示

返回一个成员变量

public Field getField(String name) 获取指定的 public修饰的变量

public Field getDeclaredField(String name) 获取指定的任意变量

返回多个成员变量

public Field[] getFields() 获取所有public 修饰的变量

public Field[] getDeclaredFields() 获取所有的 变量 (包含私有)

2.4.1    通过反射,创建对象,调用指定的方法

获取成员方法,步骤如下:

1. 获取Class对象

2. 获取构造方法

3. 通过构造方法,创建对象

4. 获取指定的方法

5. 执行找到的方法

u  public Object invoke(Object obj,  Object... args)

执行指定对象obj中,当前Method对象所代表的方法,方法要传入的参数通过args指定。

package com.oracle.FanShe;

import java.lang.reflect.Constructor;

import java.lang.reflect.InvocationTargetException;

import java.util.jar.Attributes.Name;

public class Demo02 {

//构造方法Constructor

//成员变量 Field

//方法  Method

public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, SecurityException, InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException {

//反射获取构造方法

//获取Person.class文件对象

Class c=Class.forName("com.oracle.FanShe.Person");

//获取某个公共构造方法

//空参构造

Constructor con1=c.getConstructor();

//System.out.println(con1);

//有参构造

Constructor con2=c.getConstructor(String.class,int.class);

//System.out.println(con2);

//创建你对象

Object obj= con2.newInstance("乔治",16);

System.out.println(obj);

}

}

运行结果:

2.4.2    通过反射,创建对象,调用指定的private 方法

获取私有成员方法,步骤如下:

1. 获取Class对象

2. 获取构造方法

3. 通过构造方法,创建对象

4. 获取指定的方法

5. 开启暴力访问

6. 执行找到的方法

u  public Object invoke(Object obj,  Object... args)

执行指定对象obj中,当前Method对象所代表的方法,方法要传入的参数通过args指定。

Person类

package com.oracle.FanShe;

public class Person {

private String name;

public int age;

static{

System.out.println("静态代码块");

}

public Person(){

System.out.println("空参构造");

}

public Person(String name, int age){

this.name=name;

this.age=age;

System.out.println("public Person(String name, int age)");

}

public Person(String name){

this.name=name;

System.out.println("public Person(String name)");

}

public void eat(){

System.out.println("公共空参方法");

}

public void sleep(String name){

System.out.println("公共有参方法");

}

private void smoke(){

System.out.println("私有空参构造");

}

@Override

public String toString() {

return "Person [name=" + name + ", age=" + age + "]";

}

}

package com.oracle.FanShe;

import java.lang.reflect.Constructor;

import java.lang.reflect.InvocationTargetException;

import java.util.jar.Attributes.Name;

public class Demo02 {

//构造方法Constructor

//成员变量 Field

//方法  Method

public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, SecurityException, InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException {

//反射获取构造方法

//获取Person.class文件对象

Class c=Class.forName("com.oracle.FanShe.Person");

//获取某个私有构造方法

Constructor con=c.getDeclaredConstructor(String.class);

//System.out.println(con);

//暴力反射

con.setAccessible(true);

Object obj=con.newInstance("拉拉");

System.out.println(obj);

}

}

运行结果:

反射练习

3.1      泛型擦除

其实程序编译后产生的.class文件中是没有泛型约束的,这种现象我们称为泛型的擦除。那么,我们可以通过反射技术,来完成向有泛型约束的集合中,添加任意类型的元素

//Person类:

package com.oracle.demo01;

public class Person {

private String name;

public int age;

static{

System.out.println("静态代码块");

}

public Person(){

System.out.println("空参构造");

}

public Person(String name,int age){

this.name=name;

this.age=age;

System.out.println("Person(String name,int age)");

}

private Person(String name){

this.name=name;

System.out.println("Person(String name)");

}

public void eat(){

System.out.println("公共空参方法");

}

public void sleep(String name){

System.out.println("公共有参方法");

}

private void smoke(){

System.out.println("私有空参构造");

}

@Override

public String toString() {

return "Person [name=" + name + ", age=" + age + "]";

}

}

//测试类:

package com.oracle.demo01;

import java.lang.reflect.InvocationTargetException;

import java.lang.reflect.Method;

import java.util.ArrayList;

public class Demo02 {

public static void main(String[] args) throws NoSuchMethodException, SecurityException, IllegalAccessException, IllegalArgumentException, InvocationTargetException {

//泛型擦除

ArrayList<Integer> arr=new ArrayList<Integer>();

arr.add(1);

//arr.add("aaa");

//获取ArrayList的字节码文件对象

Class c=arr.getClass();

//通过反射的方式获取add方法

Method add=c.getMethod("add",Object.class);

//调用方法

add.invoke(arr,"aaa");

System.out.println(arr);

}

}

运行结果:

3.2      反射配置文件

通过反射配置文件,运行配置文件中指定类的对应方法

读取Peoperties.txt文件中的数据,通过反射技术,来完成Person对象的创建

Peoperties.txt文件内容如下:

className=cn.oracle_01_Reflect.Person

methodName=method5

读取配置文件,调用指定类中的对应方法

public class ReflectTest2 {

public static void main(String[] args)

throws FileNotFoundException, IOException, ClassNotFoundException, NoSuchMethodException, SecurityException,

InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException {

// 通过Properties集合从文件中读取数据

Properties prop = new Properties();

// 读取文件中的数据到集合中

prop.load(new FileInputStream("properties.txt"));

// 获取键所对应的值

String className = prop.getProperty("className");

System.out.println(className);

// 1,获取Person.class 字节码文件对象

Class c = Class.forName(className);

// 2,获取构造方法

// public Person(String name, int age, String address)

Constructor con = c.getConstructor(String.class, int.class, String.class);

// 3,创建对象

Object obj = con.newInstance("小明", 20, "中国");

System.out.println(obj);

// 4,获取指定的方法

// private void method5(){}

String methodName = prop.getProperty("methodName");

Method m5 = c.getDeclaredMethod(methodName, null);

// 5,开启暴力访问

m5.setAccessible(true);

// 6,执行找到的方法

m5.invoke(obj, null);

}

}

原文地址:https://www.cnblogs.com/mengmengi/p/10652376.html

时间: 2024-11-13 08:18:53

Java类加载、反射及练习整理的相关文章

java中反射学习整理

转载请注明:http://blog.csdn.net/j903829182/article/details/38405735 反射主要是指程序可以访问,检测和修改它本身的状态或行为的一种能力. java中反射是一种强大的工具,它能够创建灵活的代码,这些代码可以在运行时装载,无须在组件之间进行链接.反射允许在编写与执行时,使程序能够接入到jvm中的类的内部信息,而不是源代码中选定的类协作的代码.这使反射成为构建灵活应用代码的主要工具.需要注意的是,如果使用不当,反射的成本会很高. package

第16篇-JAVA 类加载与反射

第16篇-JAVA 类加载与反射 每篇一句 :敢于弯曲,是为了更坚定的站立 初学心得: 追求远中的欢声笑语,追求远中的结伴同行 (笔者:JEEP/711)[JAVA笔记 | 时间:2017-05-12| JAVA 类加载与反射 ] 1.类加载 类加载器负责将 .class 文件(可能在磁盘上, 也可能在网络上) 加载到内存中, 并为之生成对应的 java.lang.Class 对象 当程序主动使用某个类时,如果该类还未被加载到内存中,系统会通过加载.连接.初始化三个步骤来对该类进行初始化,如果没

Java(1)-知识点(面试题)整理

基本概念 操作系统中 heap 和 stack 的区别 什么是基于注解的切面实现 什么是 对象/关系 映射集成模块 什么是 Java 的反射机制 什么是 ACID BS与CS的联系与区别 Cookie 和 Session的区别 fail-fast 与 fail-safe 机制有什么区别 get 和 post请求的区别 Interface 与 abstract 类的区别 IOC的优点是什么 IO 和 NIO的区别,NIO优点 Java 8 / Java 7 为我们提供了什么新功能 什么是竞态条件?

Java中反射机制和Class.forName、实例对象.class(属性)、实例对象getClass()的区别(转)

一.Java的反射机制   每个Java程序执行前都必须经过编译.加载.连接.和初始化这几个阶段,后三个阶段如下图:  其中 i.加载是指将编译后的java类文件(也就是.class文件)中的二进制数据读入内存,并将其放在运行时数据区的方法区内,然后再堆区创建一个Java.lang.Class对象,用来封装类在方法区的数据结构.即加载后最终得到的是Class对象,并且更加值得注意的是:该Java.lang.Class对象是单实例的,无论这个类创建了多少个对象,他的Class对象时唯一的!!!!.

Java:反射

初识Java反射机制: 从上面的描述可以看出Java的反射机制使得Java语言可以在运行时去认识在编译时并不了解的类/对象的信息,并且能够调用相应的方法或修改属性的值.Java反射机制的核心就是允许在运行时通过Java Reflection APIs来取得已知名字的class类的内部信息(包括其modifiers(如public, static等).superclass(如Object).interfaces(如Serializable),也包括fields和methods的所有信息),动态地生

java的反射机制

一.java的反射机制浅谈 最近研究java研究得很给力,主要以看博文为学习方式.以下是我对java的反射机制所产生的一些感悟,希望各位童鞋看到失误之处不吝指出.受到各位指教之处,如若让小生好好感动,说不定会请各位吃饭哦! 1.何谓反射机制 根据网文,java中的反射机制可以如此定义: JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法:对于任意一个对象,都能够调用它的任意一个方法:这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制. 2.反射

深入探讨 Java 类加载器

转自:http://www.ibm.com/developerworks/cn/java/j-lo-classloader/ 类加载器(class loader)是 Java™中的一个很重要的概念.类加载器负责加载 Java 类的字节代码到 Java 虚拟机中.本文首先详细介绍了 Java 类加载器的基本概念,包括代理模式.加载类的具体过程和线程上下文类加载器等,接着介绍如何开发自己的类加载器,最后介绍了类加载器在 Web 容器和 OSGi™中的应用. 类加载器是 Java 语言的一个创新,也是

Java 中反射机制的深入研究

昨天学习了java的反射机制,今天继续深入学习一下. 一.通过反射操作数组 反射不光只能用在类中,也可用在任意的引用数据类型上.当然包括数组. 通过java.lang.reflect.Array 类 可操作数组,java.lang.reflect.Array 类 下面提供了很多方法. 例如 public static Object get(Object array,int index)throws IllegalArgumentException,ArrayIndexOutOfBoundsExc

java笔记--理解java类加载器以及ClassLoader类

类加载器概述: java类的加载是由虚拟机来完成的,虚拟机把描述类的Class文件加载到内存,并对数据进行校验,解析和初始化,最终形成能被java虚拟机直接使用的java类型,这就是虚拟机的类加载机制.JVM中用来完成上述功能的具体实现就是类加载器.类加载器读取.class字节码文件将其转换成java.lang.Class类的一个实例.每个实例用来表示一个java类.通过该实例的newInstance()方法可以创建出一个该类的对象. 类的生命周期: 类从加载到虚拟机内存到被从内存中释放,经历的

java中反射

反射 避免硬编码 类对象 (存储了类的信息的对象 类加载的产物) Class 类名.class 直接获得类对象 (简单类型的类对象 int.class) 类的对象.getClass() Class.forName("类名") 通过类名主动加载一个类并获得类对象 类对象.newInstance() 创建类的对象 java中反射,布布扣,bubuko.com