Java第三阶段学习(九、类加载器、反射)
一、类加载器
1、类的加载:
当程序要使用某个类时,如果该类还未被加载到内存中,则系统会通过加载,连接,初始化三步来实现对这个类进行初始化。
1.1 加载:
就是指将class文件读入内存,并为之自动创建一个Class对象(字节码对象)。
任何类被使用时系统都会建立一个Class对象。
1.2 连接
验证 是否有正确的内部结构,并和其他类协调一致
准备 负责为类的静态成员分配内存,并设置默认初始化值
解析 将类的二进制数据中的符号引用替换为直接引用
1.3 初始化
就是初始化步骤
2、类初始化时机(也就是什么时候类会初始化):
1. 创建类的实例
2. 类的静态变量,或者为静态变量赋值
3. 类的静态方法
4. 使用反射方式来强制创建某个类或接口对应的java.lang.Class对象
5. 初始化某个类的子类
6. 直接使用java.exe命令来运行某个主类
3、类加载器:
作用: 负责将.class文件加载到内存中,并为之生成对应的Class对象。
虽然我们不需要关心类加载机制,但是了解这个机制我们就能更好的理解程序的运行
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类型的对象。
1、class类 字节码文件类
Class
没有公共构造方法。Class
对象是在加载类时由 Java 虚拟机以及通过调用类加载器中的 defineClass
方法自动构造的
获得字节码文件的三个方法:
方式一: 通过Object类中的getObject()方法
方式二:通过 类名.class获得
方式三:通过Class类中的方法(将类名作为字符串传递给Class类中的静态方法forName即可)
package com.oracle.Demo02; public class Demo01 {
//反射:目的就是不通过new 对象();得到所有属性和方法
public static void main(String[] args) throws ClassNotFoundException {
// 获取字节码对象的三个方式
//1.通过对象获取
Person p=new Person();
Class c=p.getClass();
System.out.println(c);
//2.通过类名获取(不管是引用类型还是基本数据类型都具备)
Class c1=Person.class;
System.out.println(c1);
//都为true 因为指向的字节码文件都是同一个
System.out.println(c==c1); //true
System.out.println(c.equals(c1)); //true
//3.通过Class类中的静态方法forName(完整的包名.类名);获取
Class c2=Class.forName("com.oracle.Demo02.Person");
System.out.println(c2);
} }
2、通过反射获得构造方法并使用
在反射机制中,把类中的成员(构造方法、成员方法、成员变量)都封装成了对应的类进行表示。其中,构造方法使用类Constructor表示。可通过Class类中提供的方法获取构造方法。
2.1 返回一个构造方法:
public Constructor<T> getConstructor(Class<?>... parameterTypes) 获取public修饰, 指定参数类型所对应的构造方法
public Constructor<T> getDeclaredConstructor(Class<?>... parameterTypes) 获取指定参数类型所对应的构造方法(包含私有的)
2.2 返回多个构造方法:
public Constructor<?>[ ] getConstructors() 获取所有的public 修饰的构造方法
public Constructor<?>[ ] getDeclaredConstructors() 获取所有的构造方法(包含私有的)
示例代码:
自定义Person类:
package com.oracle.Demo02; public class Person {
public String name;
private 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("有参构造");
}
private Person(int age,String name){
this.name=name;
this.age=age;
System.out.println("私有构造");
}
public void eat(){
System.out.println("吃饭");
}
public void work(String name){
System.out.println(name+"工作");
}
private void run(String name){
System.out.println(name+"跑步");
}
@Override
public String toString() {
return "Person [name=" + name + ", age=" + age + "]";
} }
获得构造方法并运行:
package com.oracle.Demo02; import java.lang.reflect.Constructor; public class Demo02 { public static void main(String[] args) throws Exception {
//反射获取空参构造方法并运行:.getConstructor();
Class c=Class.forName("com.oracle.Demo02.Person");
//获取该类中所有的公共构造方法数组
// Constructor[] con=c.getConstructors(); 本方法还需要循环数组,比较麻烦
// for(Constructor c1:con){
// System.out.println(c1);
// }
Constructor con=c.getConstructor();
//调用空参构造方法 .newInstance();
// Object obj=con.newInstance();
// System.out.println(obj);
//调用work()方法
// Person p=(Person)con.newInstance();
// p.work("张三"); } }
通过反射获取有参构造方法并运行:
package com.oracle.Demo02; import java.lang.reflect.Constructor; public class Demo03 { public static void main(String[] args) throws Exception {
// 通过反射获取有参构造方法并运行
Class c=Class.forName("com.oracle.Demo02.Person");
Constructor con=c.getConstructor(String.class,int.class);
Object obj=con.newInstance("张胜男",16);
System.out.println(obj);
} }
快速获取空参并创建对象:
package com.oracle.Demo02; import java.lang.reflect.Constructor; public class Demo04 { public static void main(String[] args) throws Exception {
// 快速获取空参并创建对象的方式
//1.类必须有空参构造,2.构造方法必须是public
// Class c=Class.forName("com.oracle.Demo02.Person");
// Object obj=c.newInstance();
// System.out.println(obj);
//获取私有的构造方法(不推荐)
//暴力反射,破坏了程序的封装性和安全性
Class c=Class.forName("com.oracle.Demo02.Person");
//获取所有的构造方法.getDeclaredConstructors();
// Constructor[] con=c.getDeclaredConstructors();
// for(Constructor cc:con){
// System.out.println(cc);
// }
//调用私有化构造方法
Constructor con=c.getDeclaredConstructor(int.class,String.class);
con.setAccessible(true); //暴力反射的开关,为true的时候,可以得到私有的成员
Object obj=con.newInstance(18,"张三");
System.out.println(obj); } }
3、通过反射获取成员变量并使用
在反射机制中,把类中的成员变量使用类Field表示。可通过Class类中提供的方法获取成员变量:
3.1 返回一个成员变量
public Field getField(String name) 获取指定的 public修饰的变量(不包含私有)
public Field getDeclaredField(String name) 获取指定的任意变量(包含私有)
3.2 返回多个成员变量
public Field [ ] getFields() 获取所有public 修饰的变量 (不包含私有)
public Field [ ] getDeclaredFields() 获取所有的 变量 (包含私有)
获取成员变量,步骤如下:
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 对象表示的成员变量的值
package com.oracle.Demo02; import java.lang.reflect.Field; public class Demo05 { public static void main(String[] args) throws Exception {
// 通过反射获取成员变量并改值
Class c=Class.forName("com.oracle.Demo02.Person");
Object obj=c.newInstance(); //反射获得的类对象
//获取所有的公共的成员变量
Field[] fields=c.getFields();
//遍历
// for(Field f:fields){
// System.out.println(f);
// }
//通过名字获取公共的成员变量
Field field=c.getField("name");
//给成员变量赋值
field.set(obj, "张三");
System.out.println(obj);
} }
4、通过反射获得成员方法并使用:
在反射机制中,把类中的成员方法使用类Method表示。可通过Class类中提供的方法获取成员方法:
4.1 返回获取一个方法:
public Method getMethod(String name, Class<?>... parameterTypes)
获取public 修饰的方法
public Method getDeclaredMethod(String name, Class<?>... parameterTypes)
获取任意的方法,包含私有的
参数1: name 要查找的方法名称; 参数2: parameterTypes 该方法的参数类型
4.2 返回获取多个方法:
public Method[ ] getMethods() 获取本类与父类中所有public 修饰的方法
public Method[ ] getDeclaredMethods() 获取本类中所有的方法(包含私有的)
package com.oracle.Demo02; import java.lang.reflect.Method; public class Demo06 { public static void main(String[] args) throws Exception {
Class c=Class.forName("com.oracle.Demo02.Person");
Object obj=c.newInstance();
//获取所有公共的方法(包括从父类继承来的)
// Method[] method=c.getMethods();
// for(Method m:method){
// System.out.println(m);
// }
//获取空参成员方法并运行,如果是空参方法,只需要写方法名就可以
Method method01=c.getMethod("eat");
//调用方法
method01.invoke(obj);
//如果是空参方法,只需要写方法名就可以
System.out.println(method01);
} }
获取有参方法并运行:
package com.oracle.Demo02; import java.lang.reflect.Method; public class Demo07 {
public static void main(String[] args) throws Exception {
//获取有参方法并运行
Class c=Class.forName("com.oracle.Demo02.Person");
Method method=c.getMethod("work", String.class);
//添加 .invoke
method.invoke(c.newInstance(), "韩凯");
}
}
5、通过反射,创建对象,调用指定的方法 重点
获取成员方法,步骤如下:
1. 获取Class对象
2. 获取构造方法
3. 通过构造方法,创建对象
4. 获取指定的方法
5. 执行找到的方法
public Object invoke(Object obj, Object... args)
执行指定对象obj中,当前Method对象所代表的方法,方法要传入的参数通过args指定。
package com.oracle.Demo02; import java.lang.reflect.Method; public class Demo07 {
public static void main(String[] args) throws Exception {
//获取有参方法并运行
Class c=Class.forName("com.oracle.Demo02.Person");
Method method=c.getMethod("work", String.class);
//添加 .invoke
method.invoke(c.newInstance(), "韩凯");
}
}
6、通过反射,创建对象,调用指定的private 方法
获取私有成员方法,步骤如下:
1. 获取Class对象
2. 获取构造方法
3. 通过构造方法,创建对象
4. 获取指定的方法
5. 开启暴力访问
6. 执行找到的方法
public Object invoke(Object obj, Object... args)
执行指定对象obj中,当前Method对象所代表的方法,方法要传入的参数通过args指定。
7、擦除泛型,添加元素
将已存在的ArrayList<Integer>集合中添加一个字符串数据,如何实现呢?
我来告诉大家,其实程序编译后产生的.class文件中是没有泛型约束的,这种现象我们称为泛型的擦除。那么,我们可以通过反射技术,来完成向有泛型约束的集合中,添加任意类型的元素
package com.oracle.Demo02; import java.lang.reflect.Method;
import java.util.ArrayList; public class Demo08 {
//有一个ArrayList<String> list
//然后往里面添加int类型数据
public static void main(String[] args) throws Exception {
ArrayList<String> arr=new ArrayList<String>();
arr.add("aaa");
//获取集合的字节码对象
Class c=arr.getClass();
//用反射获取 add的方法,Object.calss无关泛型
Method addd=c.getMethod("add", Object.class);
//添加int类型的元素
addd.invoke(arr, 1);
for(Object obj:arr){
System.out.println(obj);
} } }
8、反射配置文件:
package com.oracle.Demo03; import java.io.FileReader;
import java.io.IOException;
import java.lang.reflect.Method;
import java.util.Properties; public class Demo {
//反射配置文件
public static void main(String[] args) throws IOException, Exception {
//类不清楚,方法也不清楚
//通过配置文件实现,运行的类名和方法名以键值对的形式
//保存到properrties中,具体运行哪个类里面的方法通过该配置文件去设置
//步骤:
//1.准备配置文件,写好键值对
//2.IO读取配置文件Reader
//3.文件中的键值对存储到集合中,集合中保存的键值对就是类和方法名
//4.反射获取指定类的class文件对象
//5.class文件对象获取指定方法
//6.运行方法
// Person p=new Person();
// p.eat();
FileReader fr=new FileReader("config.properties");//读取配置好的配置文件
Properties pro=new Properties(); //创建个集合,用来存键值对的
pro.load(fr); //将文件中的键值对存到集合中
fr.close(); //记得关闭
String className=pro.getProperty("className"); //获得类名和方法名
String methodName=pro.getProperty("methodName");
Class c=Class.forName(className); //反射获取字节码文件对象
Object obj=c.newInstance(); //创建类对象
Method method=c.getMethod(methodName); //利用反射获得方法
method.invoke(obj); //执行方法
} }
自定义Person类:
package com.oracle.Demo03; public class Person {
public void eat(){
System.out.println("人在吃饭");
}
}
自定义Student类:
package com.oracle.Demo03; public class Student {
public void study(){
System.out.println("学生在学习");
}
}
自定义Worker类:
package com.oracle.Demo03; public class Worker {
public void work(){
System.out.println("工人在工作");
}
}
练习题:
自定义类:
Person类
package com.oracle.Demo04; public class Person {
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;
}
@Override
public String toString() {
return "Person [name=" + name + ", age=" + age + "]";
}
public Person(){ }
public Person(String name,int age){
this.name=name;
this.age=age;
}
}
Two类
package com.oracle.Demo04; public class Two {
private String name;
public Two(){
System.out.println(name);
}
public Two(String name) {
super();
this.name = name;
System.out.println(name);
}
public void Work(){
System.out.println("键盘敲烂,月薪过万");
}
@Override
public String toString() {
return "Two [name=" + name + "]";
} }
DamoClass自定义类:
package com.oracle.Demo04; public class DemoClass {
public void run(){
System.out.println("welcome to oracle");
}
}
1、ArrayList<Integer> list = new ArrayList<Integer>(); //这个泛型为Integer的ArrayList中存放一个String类型的对象
//1.ArrayList<Integer> list = new ArrayList<Integer>();
//这个泛型为Integer的ArrayList中存放一个String类型的对象
public class Demo01 { public static void main(String[] args) throws Exception{
ArrayList<Integer> list=new ArrayList<Integer>();
list.add(666);
//获取集合的字节码对象
Class c=list.getClass();
//获取集合类中的添加元素方法
Method addd=c.getDeclaredMethod("add", Object.class);
//调用方法,并添加元素
addd.invoke(list, "abc");
for(Object a:list){
System.out.println(a);
}
} }
2、用反射去创建一个对象,有2种方式,尽量用代码去体现
package com.oracle.Demo04; import java.lang.reflect.Constructor; public class Demo02 {
//2.用反射去创建一个对象,有2种方式,尽量用代码去体现
public static void main(String[] args) throws Exception {
//创建一个关于Two自定义类的字节码对象 要有完整的包名
Class c=Class.forName("com.oracle.Demo04.Two");
//调用.newInstance();空参构造方法
Object obj=c.newInstance();
System.out.println(obj);
//调用有参构造方法 Constructor构造器类
Constructor con=c.getConstructor(String.class);
Object obj01=con.newInstance("王五");
System.out.println(obj01);
} }
3、利用反射创建一个类对象,获取指定的方法并执行
package com.oracle.Demo04; import java.lang.reflect.Method; public class Demo03 { public static void main(String[] args) throws Exception {
// 创建一个字节码对象
Class c=Class.forName("com.oracle.Demo04.Two");
//利用反射创建一个类对象
Object obj=c.newInstance();
//通过反射获得方法名为“work”的方法
Method m=c.getMethod("Work");
//调用obj类中的m方法
m.invoke(obj);
} }
4、定义一个标准的JavaBean,名叫Person,包含属性name、age。 使用反射的方式创建一个实例、调用构造函数初始化name、age,使用反射方式调用setName方法对名称进行设置, 不使用setAge方法直接使用反射方式对age赋值。
package com.oracle.Demo04; import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method; public class Demo4 {
// 定义一个标准的JavaBean,名叫Person,包含属性name、age。
// 使用反射的方式创建一个实例、调用构造函数初始化name、age,使用反射方式调用setName方法对名称进行设置,
// 不使用setAge方法直接使用反射方式对age赋值。
public static void main(String[] args) throws Exception {
//创建字节码对象
Class c=Class.forName("com.oracle.Demo04.Person");
//获取构造方法
Constructor con=c.getConstructor(String.class,int.class);
//使用构造方法 创建类对象
Object obj=con.newInstance("张三",16);
Method m=c.getMethod("setName", String.class);
m.invoke(obj, "李四");
//通过反射与成员变量名称,获得成员变量对象
Field ageField=c.getDeclaredField("age");
//因为是私有化的成员变量,所以需要暴力访问
ageField.setAccessible(true);
//给年龄赋值
ageField.set(obj, 60);
System.out.println(obj);
} }
5、从文件中通过反射读取键值对
package com.oracle.Demo04; import java.io.FileReader;
import java.lang.reflect.Method;
import java.util.Properties; public class Demo05 { public static void main(String[] args) throws Exception {
//从文件中读取键值对
FileReader fr=new FileReader("democlass.properties");
//创建一个集合存放键值对
Properties pro=new Properties();
pro.load(fr);
fr.close();
//通过键获取值的字符串
String name=pro.getProperty("name");
String method=pro.getProperty("method");
//创建字节码对象
Class c=Class.forName(name);
//创建类对象
Object obj=c.newInstance();
//获得方法
Method m=c.getMethod(method);
//调用方法
m.invoke(obj); } }
Java第三阶段学习(九、类加载器、反射)的更多相关文章
- Java第三阶段学习(十、XML学习)
一.XML学习 1.模拟Servlet执行 在学习完前端及java与数据库后,将进行WEB编程阶段的学习.在WEB编程中,可以通过浏览器访问WEB服务器上的数据.这时WEB服务器就相当于另一台计算机. ...
- Java第三阶段学习(八:网络通信协议、UDP与TCP协议)
一.网络通信协议 1.概念: 通过计算机网络可以使多台计算机实现连接,位于同一个网络中的计算机在进行连接和通信时需要遵守一定的规则,在计算机网络中,这些连接和通信的规则被称为网络通信协议,它对数据的传 ...
- Java第三阶段学习(十四、JSP动态页面、EL表达式、JSTL标签库)
一.JSP技术 1.jsp脚本和注释 jap脚本: 1)<%java代码%> ----- 内部的java代码翻译到service方法的内部,比如写在doget.dopost 内的代码 2) ...
- Java第三阶段学习(五、流的操作规律、Properties流、序列化流与反序列化流、打印流、commons-IO jar包)
一.流的操作规律 四个明确: 明确一:明确要操作的数据是数据源还是数据目的地 源:InputStream Reader 目的地:OutputStream Writer 先根据需求明确是要读还是写 ...
- Java第三阶段学习(十三、会话技术、Cookie技术与Session技术)
一.会话技术 1. 存储客户端状态 会话技术是帮助服务器记住客户端状态(区分客户端)的. 2. 会话技术 从打开一个浏览器访问某个站点,到关闭这个浏览器的整个过程,称为一次会话.会话技术就是记录这 ...
- Java第三阶段学习(十二、HttpServletRequest与HttpServletResponse)
一.HttpServletRequest 1.概述: 我们在创建Servlet时会覆盖service()方法,或doGet()/doPost(),这些方法都有两个参数,一个为代表请求的request和 ...
- Java第三阶段学习(十一、Servlet基础、servlet中的方法、servlet的配置、ServletContext对象)
一.Servlet简介 1.什么是servlet: sun公司提供的一套规范(接口),用来处理客户端请求.响应给浏览器的动态资源.但servlet的实质就是java代码,通过java的API动态的向 ...
- Java第三阶段学习(六、多线程)
一.进程和线程的区别: 进程:指正在运行的程序,当一个程序进入内存运行,就变成一个进程. 线程:线程是进程的一个执行单元. 总结:一个程序运行后至少会有一个进程,一个进程可以有多个线程. 多线程:多线 ...
- Java第三阶段学习(四、缓冲流)
一.缓冲流: Java中提供了一套缓冲流,它的存在,可提高IO流的读写速度 缓冲流,根据流的分类分为:字节缓冲流与字符缓冲流. 二.字节缓冲流: 字节缓冲流根据流的方向,共有2个: 1.写入数据到流中 ...
随机推荐
- pom.xml文件中,添加自定义参数Properties
<properties> <powermock.version>1.6.6</powermock.version> </properties> < ...
- Django_重装系统后无法使用 sqlite 数据库报错:com.intellij.execution.ExecutionException: Exception in thread "main" java.lang.ClassNotFoundException: org.sqlite.JDBC
重装系统后无法使用 sqlite 数据库报错 报错 : com.intellij.execution.ExecutionException: Exception in thread "ma ...
- 【题解】 bzoj4033: [HAOI2015]树上染色* (动态规划)
bzoj4033,懒得复制,戳我戳我 Solution: 定义状态\(dp[i][j]\)表示\(i\)号节点为根节点的子树里面有\(j\)个黑色节点时最大的贡献值 然后我们要知道的就是子节点到根节点 ...
- 如何用React, Webcam和JS Barcode SDK创建Web扫码App
这篇文章分享下如何结合React Webcam和Dynamsoft JavaScript Barcode SDK来创建Web扫码App. Web实时扫码 从GitHub上下载react-webcam. ...
- caffe多任务、多标签
解决的目标问题:多分类问题,比如车辆的外形和颜色,苹果的大小和颜色:多任务:车牌角点的定位和车牌的颜色.定位在技术上属于回归,车牌颜色判断则属于分类. 技术点 caffe默认是单输入任务单标签的,也就 ...
- 【BZOJ5138】[Usaco2017 Dec]Push a Box(强连通分量)
[BZOJ5138][Usaco2017 Dec]Push a Box(强连通分量) 题面 BZOJ 洛谷 题解 这题是今天看到萝卜在做然后他一眼秒了,我太菜了不会做,所以就来做做. 首先看完题目,是 ...
- java绘图合并图像AlphaComposite模式测试
package com.hdwang.test; import javax.swing.*; import javax.swing.event.ChangeEvent; import javax.sw ...
- 【POJ1958】汉诺塔+
题目大意:给定一个四个柱子的汉诺塔,N 个盘子,求最少多少步移动到另一个柱子上. 题解:\(f[n]=min(2*f[i]+d[n-i])\),其中 \(d[i]\) 为汉诺三塔最小移动次数.M 塔同 ...
- WebService注解总结
@WebService 1.serviceName: 对外发布的服务名,指定 Web Service 的服务名称:wsdl:service.缺省值为 Java 类的简单名称 + Service.(字符 ...
- struts2拦截器interceptor的配置方法及使用
转: struts2拦截器interceptor的配置方法及使用 (2015-11-09 10:22:28) 转载▼ 标签: it 365 分类: Struts2 NormalText Code ...