JAVA类的加载(3) ——类加载后能够有效运行
例1:
1 package classobject;
2
3 import java.lang.reflect.Constructor;
4 import java.lang.reflect.InvocationTargetException;
5 import java.util.Arrays;
6 import java.lang.reflect.Method;
7
8
9
10
11 public class Reflect_Example {
12
13 public static void main(String[] args) {
14 Class<?> lcdTVClass = null;
15 /*
16 疑问:为什么不用new呢 LcdTV lcdTV = new LcdTV(); ? 如果这么写,说明main方法依赖LcdTV这个类,
17 如果这个类不存在,main方法所在的类编译不通过
18
19 原理:main方法执行时候,并不知道我将要加载和使用什么类
20 通常不会在main不可能有明确的new方法去实例化类,因为这个类可能在执行main的时候可能还不存在
21 */
22
23 //注释掉LcdTV类,main方法不报错,说明main方法是没有强依赖于两个业务类的,根据业务类型需要的时候再加载进来
24 try {
25 lcdTVClass = Class.forName("classobject.LcdTV"); //这个类 有可能存在,也有可能不存在;获得这个类的Class对象
26 } catch (ClassNotFoundException e) {
27 e.printStackTrace();
28 }
29
30 System.out.println("类名:"+lcdTVClass.getName());
31 System.out.println(lcdTVClass.getName() + "是一个接口吗?" + lcdTVClass.isInterface());
32
33 Class<?> superClass = lcdTVClass.getSuperclass();
34 System.out.println(lcdTVClass.getName() + "的父类?" + superClass);
35
36 System.out.println(lcdTVClass.getName() + "实现了接口:");
37 Class<?>[] interfaces = lcdTVClass.getInterfaces(); //复数,interfaces
38 for (Class<?> i : interfaces) { // for (Class<?> i : interfaces)
39 System.out.println(" "+i);
40 }
41
42 Object instance = null;
43 try {
44 instance = lcdTVClass.newInstance(); //怎么实例化?(lcdTVClass.newInstance()调用默认构造器实例化)
45 } catch (InstantiationException e) {
46 e.printStackTrace();
47 } catch (IllegalAccessException e) {
48 e.printStackTrace();
49 }
50 System.out.println("使用newInstance()创建对象:" + instance);
51
52 Constructor<?>[] constructors = lcdTVClass.getConstructors(); //通过class对象找到它的构造器
53 for (Constructor<?> con : constructors) {
54 System.out.println(lcdTVClass.getName() + "的构造器" + con);
55 Class<?>[] parameters = con.getParameterTypes();
56 System.out.println("参数类型:" + Arrays.toString(parameters));
57 }
58
59 Object instance2 = null;
60 try {
61 Constructor<?> con = lcdTVClass.getConstructor(int.class); //有参数的构造器如何实例化,传入的是参数类型.class
62 instance2 = con.newInstance(54);
63 System.out.println("使用构造器 " + con + " 创建对象:" + instance2);
64 } catch (SecurityException e) {
65 e.printStackTrace();
66 } catch (NoSuchMethodException e) {
67 e.printStackTrace();
68 } catch (IllegalArgumentException e) {
69 e.printStackTrace();
70 } catch (InstantiationException e) {
71 e.printStackTrace();
72 } catch (IllegalAccessException e) {
73 e.printStackTrace();
74 } catch (InvocationTargetException e) {
75 e.printStackTrace();
76 }
77
78 Method[] methods = lcdTVClass.getMethods(); //获取class对象有多少方法,自己的方法以及从Object继承的方法
79 System.out.println(lcdTVClass.getName() + "的方法");
80 for (Method m : methods) {
81 System.out.println(" " + m);
82 }
83
84 System.out.println("通过反射调用方法turnOn"); //通过反射调用方法
85 try {
86 Method method = lcdTVClass.getMethod("turnOn", new Class[]{}); // new Class[]{}如何使用? turnOn没有参数,空的class数组
87 method.invoke(instance2, new Object[]{}); //new Object[]{} 参数1:实例,参数2:方法的实参列表
88 System.out.println(instance2);
89 } catch (SecurityException e) {
90 e.printStackTrace();
91 } catch (NoSuchMethodException e) {
92 e.printStackTrace();
93 } catch (IllegalArgumentException e) {
94 e.printStackTrace();
95 } catch (IllegalAccessException e) {
96 e.printStackTrace();
97 } catch (InvocationTargetException e) {
98 e.printStackTrace();
99 }
100 }
101 }
102
103 interface Televition {
104 void turnOn();
105 void turnOff();
106 }
107
108 //液晶电视
109 class LcdTV implements Televition {
110
111 private boolean on = false;
112 public final int size; //public final int size=0;会报错
113
114 public LcdTV() {
115 size = 32; //The blank final field size may not have been initialized
116 }
117
118 public LcdTV(int size) {
119 this.size = size;
120 }
121
122 @Override
123 public void turnOn() {
124 System.out.println("电视被打开");
125 on = true;
126 }
127
128 @Override
129 public void turnOff() {
130 System.out.println("电视被关闭");
131 on = false;
132 }
133 }
解释:
1、第18-20行
疑问:为什么不用new呢 LcdTV lcdTV = new LcdTV(); ? 如果这么写,说明main方法依赖LcdTV这个类,如果这个类不存在,main方法所在的类编译不通过 原理:main方法执行时候,并不知道我将要加载和使用什么类 通常不会在main不可能有明确的new方法去实例化类,因为这个类可能在执行main的时候可能还不存在
2、第23行
注释掉LcdTV类,main方法不报错,说明main方法是没有强依赖于两个业务类的,根据业务类型需要的时候再加载进来——利用反射
3、第25行
lcdTVClass = Class.forName("classobject.LcdTV"),获得这个类的Class对象
4、第30-40行
lcdTVClass.getName()获得类名,lcdTVClass.isInterface()判断是否是接口,lcdTVClass.getSuperclass()获得父类,lcdTVClass.getInterfaces()实现了哪些接口
5、怎么实例化
(1)第44行 instance = lcdTVClass.newInstance() 使用Class对象的newInstance()方法来创建该Class对象对应类的实例 (实际上是利用Class对象对应类的默认构造器来创建该类的实例)
(2)第61-63行,有参数的构造器如何实例化,传入的是参数类型.class ——先使用Class对象获取指定的Constructor对象,再调用Constructor对象的newInstance()来创建该Class对象对应类的实例
Constructor<?> con = lcdTVClass.getConstructor(int.class); //有参数的构造器如何实例化,传入的是参数类型.class
instance2 = con.newInstance(54);
第(1)种方式是比较常见的,因为很多JAVA EE框架中都需要根据配置文件信息来创建Java对象,从配置文件读取的只是某个类的字符串类名,程序就需要根据该字符串来创建对应的实例,就必须使用反射 ——详见例2
PS:第52行,lcdTVClass.getConstructors() 通过class对象找到它的构造器
6、第78行
Method[] methods = lcdTVClass.getMethods(); //获取class对象有多少方法,自己的方法以及从Object继承的方法
7、第86=87行 通过反射调用方法
Method method = lcdTVClass.getMethod("turnOn", new Class[]{}); // 参数2:方法的参数类型 new Class[]{}如何使用? turnOn没有参数,空的class数组
method.invoke(instance2, new Object[]{}); //new Object[]{} 参数1:实例,参数2:方法的实参列表
执行结果:请手动一行行调试代码
1 类名:classobject.LcdTV
2 classobject.LcdTV是一个接口吗?false
3 classobject.LcdTV的父类?class java.lang.Object
4 classobject.LcdTV实现了接口:
5 interface classobject.Televition
6 使用newInstance()创建对象:classobject.LcdTV@7f5f5897
7 classobject.LcdTV的构造器public classobject.LcdTV()
8 参数类型:[]
9 classobject.LcdTV的构造器public classobject.LcdTV(int)
10 参数类型:[int]
11 使用构造器 public classobject.LcdTV(int) 创建对象:classobject.LcdTV@11cfb549
12 classobject.LcdTV的方法
13 public void classobject.LcdTV.turnOn()
14 public void classobject.LcdTV.turnOff()
15 public final native void java.lang.Object.wait(long) throws java.lang.InterruptedException
16 public final void java.lang.Object.wait() throws java.lang.InterruptedException
17 public final void java.lang.Object.wait(long,int) throws java.lang.InterruptedException
18 public boolean java.lang.Object.equals(java.lang.Object)
19 public java.lang.String java.lang.Object.toString()
20 public native int java.lang.Object.hashCode()
21 public final native java.lang.Class java.lang.Object.getClass()
22 public final native void java.lang.Object.notify()
23 public final native void java.lang.Object.notifyAll()
24 通过反射调用方法turnOn
25 电视被打开
26 classobject.LcdTV@11cfb549
因此,反射的威力很强大:main在完全不需要感知Lcd电视以及Television这两个类(或接口)时候,可以通过一系列的class的方法来得到它们的信息:有哪些构造器,哪些方法,知道它有多少参数、什么类型;根据相关情况进行调用
反射的优缺点:
1、强大之处:能够在运行时获取类的信息,并进行调用
2、劣势:
(1)没有编译检查做保护:有大量的异常需要处理;重构困难
(2)性能较差
例2:
1 import java.util.*;
2 import java.io.*;
3
4 public class ObjectPoolFactory {
5 //定义一个对象池,前面是对象名,后面是实际对象
6 private Map<String, Object> objectPool = new HashMap<String, Object>();
7
8 //定义一个创建对象的方法,该方法只要传入一个字符串类目,就可以根据该类名生成字符串对象
9 private Object createObject(String clazzName)
10 throws ClassNotFoundException, InstantiationException, IllegalAccessException {
11 //根据字符串获取对应的Class对象
12 Class<?> clazz = Class.forName(clazzName);
13 //使用clazz对应类的默认构造器创建实例
14 return clazz.newInstance();
15 }
16
17 //该方法根据指定文件来初始化对象池,它会根据配置文件来创建对象
18 public void initPool(String fileName)
19 throws ClassNotFoundException, InstantiationException, IllegalAccessException {
20 FileInputStream fis = null;
21 try {
22 fis = new FileInputStream(fileName);
23 Properties props = new Properties();
24 props.load(fis);
25 for (String name : props.stringPropertyNames()) {
26 //每取出一对属性名-属性值对,就根据属性值创建一个对象
27 //调用createObject创建对象,并将对象添加到对象池中
28 objectPool.put(name, createObject(props.getProperty(name)));
29 }
30 } catch(IOException ex) {
31 System.out.println("读取" + fileName + "异常");
32 } finally {
33 try {
34 if (fis != null ) {
35 fis.close();
36 }
37 } catch (IOException ex) {
38 ex.printStackTrace();
39 }
40 }
41 }
42
43 public Object getObject(String name) {
44 //从objectPool中取出指定name对应的对象
45 return objectPool.get(name);
46 }
47
48 public static void main(String[] args)
49 throws ClassNotFoundException, InstantiationException, IllegalAccessException {
50 ObjectPoolFactory pf = new ObjectPoolFactory();
51 pf.initPool("obj.txt");
52 System.out.println(pf.getObject("a"));
53 }
54
55
56 }
结果:
类加载器的补充: 基础可以参考 http://www.cnblogs.com/wxdlut/p/3419462.html
1、Java通过ClassLoader加载Class文件,并生成类对应的Class对象 (类加载 指的是将类的class文件读入内存,并为之创建一个java.lang.Class对象)
2、可以通过Class对象,获取其ClassLoader
例3:
1 package classloader;
2
3 public class Example {
4 public static void main(String[] args) throws ClassNotFoundException {
5 /*
6 通过三种方式获得类的java.lang.Class对象
7 通过.getClassLoader()获取到加载这个类的ClassLoader
8 */
9 ClassLoader cl1 = Example.class.getClassLoader(); //(1)类.class 获取到class对象;
10
11 Example obj = new Example(); //实例化了一个当前这个类Example
12 ClassLoader cl2 = obj.getClass().getClassLoader(); //(2)对象.getClass() 获取到class对象 ;
13
14 //Class.forName("Example")会抛ClassNotFoundException
15 ClassLoader cl3 = Class.forName("classloader.Example").getClassLoader(); //(3)通过Class.forName()活动class对象;
16
17
18 System.out.println("cl1.equals(cl2) ? " + cl1.equals(cl2));
19 System.out.println("cl1.equals(cl3) ? " + cl1.equals(cl3));
20
21 //用cl1这个ClassLoader去加载一个类,但是静态块没有执行;不论用cl1、cl2、cl3 Dog的静态化块都不会被初始化
22 Class<?> loadClass = cl1.loadClass("classloader.Dog");
23 System.out.println(cl1 + ".loadClass加载的类为:" + loadClass.getName());
24
25 // ClassLoader c14 = ClassLoader.getSystemClassLoader(); //获取系统加载器
26
27 }
28 }
29
30 class Dog {
31 static {
32 System.out.println("Dog 的静态块初始化");
33 }
34 }
结果:
cl1.equals(cl2) ? true
cl1.equals(cl3) ? true
sun.misc.Launcher$AppClassLoader@425224ee.loadClass加载的类为:classloader.Dog
解释:
1、第5-19行,如何获得Class对象:
(1)、代码更安全,程序在编译阶段就可以检查要访问的Class对象是否存在 (2)、程序性能更高,无须方法调用
2、第5-19行,通过Class对象,获取其ClassLoader Class对象.getClassLoader()
- java.lang.Object
- java.lang.Class<T>
getClassLoader
public ClassLoader getClassLoader()
Returns the class loader for the class. Some implementations may use null to represent the bootstrap class loader. This method will return null in such implementations if this class was loaded by the bootstrap class loader.If a security manager is present, and the caller's class loader is not null and the caller's class loader is not the same as or an ancestor of the class loader for the class whose class loader is requested, then this method calls the security manager's
checkPermissionmethod with aRuntimePermission("getClassLoader")permission to ensure it's ok to access the class loader for the class.If this object represents a primitive type or void, null is returned.
- Returns:
- the class loader that loaded the class or interface represented by this object.
- Throws:
SecurityException- if a security manager exists and itscheckPermissionmethod denies access to the class loader for the class.- See Also:
ClassLoader,SecurityManager.checkPermission(java.security.Permission),RuntimePermission
3、第25行,获取系统类加载器
ClassLoader c14 = ClassLoader.getSystemClassLoader(); //获取系统加载器
Class ClassLoader
- java.lang.Object
- java.lang.ClassLoader
getSystemClassLoader
public static ClassLoader getSystemClassLoader()
Returns the system class loader for delegation. This is the default delegation parent for new ClassLoader instances, and is typically the class loader used to start the application.This method is first invoked early in the runtime's startup sequence, at which point it creates the system class loader and sets it as the context class loader of the invoking Thread.
The default system class loader is an implementation-dependent instance of this class.
If the system property "java.system.class.loader" is defined when this method is first invoked then the value of that property is taken to be the name of a class that will be returned as the system class loader. The class is loaded using the default system class loader and must define a public constructor that takes a single parameter of type ClassLoader which is used as the delegation parent. An instance is then created using this constructor with the default system class loader as the parameter. The resulting class loader is defined to be the system class loader.
If a security manager is present, and the invoker's class loader is not null and the invoker's class loader is not the same as or an ancestor of the system class loader, then this method invokes the security manager's
checkPermissionmethod with aRuntimePermission("getClassLoader")permission to verify access to the system class loader. If not, a SecurityException will be thrown.- Returns:
- The system ClassLoader for delegation, or null if none
- Throws:
SecurityException- If a security manager exists and its checkPermission method doesn't allow access to the system class loader.IllegalStateException- If invoked recursively during the construction of the class loader specified by the "java.system.class.loader" property.Error- If the system property "java.system.class.loader" is defined but the named class could not be loaded, the provider class does not define the required constructor, or an exception is thrown by that constructor when it is invoked. The underlying cause of the error can be retrieved via theThrowable.getCause()method.
JAVA类的加载(3) ——类加载后能够有效运行的更多相关文章
- jvm系列(一):java类的加载机制
java类的加载机制 1.什么是类的加载 类的加载指的是将类的.class文件中的二进制数据读入到内存中,将其放在运行时数据区的方法区内,然后在堆区创建一个java.lang.Class对象,用来封装 ...
- 【Java基础】Java类的加载和对象创建流程的详细分析
相信我们在面试Java的时候总会有一些公司要做笔试题目的,而Java类的加载和对象创建流程的知识点也是常见的题目之一.接下来通过实例详细的分析一下. 实例问题 实例代码 Parent类 package ...
- JAVA类的加载、连接与初始化
JAVA类的加载.连接与初始化 类的声明周期总共分为5个步骤1.加载2.连接3.初始化4.使用5.卸载 当java程序需要某个类的时候,java虚拟机会确保这个类已经被加载.连接和初始化,而连接这个类 ...
- java 类的加载、连接和初始化
JVM和类 调用Java命令运行Java程序时,该命令将会启动一条Java虚拟机进程,不管该Java程序启动了多少条线程,创建了多少个变量,它们都处于该Java虚拟机进程里,共享该JVM进程的内存区. ...
- 别翻了,这篇文章绝对让你深刻理解java类的加载以及ClassLoader源码分析【JVM篇二】
目录 1.什么是类的加载(类初始化) 2.类的生命周期 3.接口的加载过程 4.解开开篇的面试题 5.理解首次主动使用 6.类加载器 7.关于命名空间 8.JVM类加载机制 9.双亲委派模型 10.C ...
- java类从加载、连接到初始化过程
类加载器 在了解Java的机制之前,需要先了解类在JVM(Java虚拟机)中是如何加载的,这对后面理解java其它机制将有重要作用. 每个类编译后产生一个Class对象,存储在.class文件中,JV ...
- JVM(1):Java 类的加载机制
原文出处: 纯洁的微笑 java类的加载机制 1.什么是类的加载 类的加载指的是将类的.class文件中的二进制数据读入到内存中,将其放在运行时数据区的方法区内,然后在堆区创建一个java.lang. ...
- 透过现象看本质:Java类动态加载和热替换
摘要:本文主要介绍类加载器.自定义类加载器及类的加载和卸载等内容,并举例介绍了Java类的热替换. 最近,遇到了两个和Java类的加载和卸载相关的问题: 1) 是一道关于Java的判断题:一个类被首次 ...
- 第42天学习打卡(Class类 Class类的常用方法 内存分析 类的加载过程 类加载器 反射操作泛型 反射操作注解)
Class类 对象照镜子后得到的信息:某个类的属性.方法和构造器.某个类到底实现了哪些接口.对于每个类而言,JRE都为其保留一个不变的Class类型的对象.一个Class对象包含了特定某个结构(cla ...
- JAVA - 类的加载过程
JAVA - 类的加载过程 JVM类加载机制分为五个部分:加载,验证,准备,解析,初始化. 加载 加载是类加载过程中的一个阶段,这个阶段会在内存中生成一个代表这个类的java.lang.Class对象 ...
随机推荐
- 行行AI人才直播第13期:刘红林律师《AIGC创业者4大法律问题需注意》
行行AI人才(海南行行智能科技有限公司)是博客园和顺顺智慧共同运营的AI行业人才全生命周期服务平台. AIGC爆火至今,商业落地已成为各行各业焦点的问题.它的广泛应用也带来了一系列的法律风险和挑战.一 ...
- CTF比赛中Web的php伪协议类型题小结
php协议类型 file:// - 访问本地文件系统 http:// - 访问 HTTP(s) 网址 ftp:// - 访问 FTP(s) URLs php:// - 访问各个输入/输出流(I/O s ...
- 看,这些 plugins 常用又简单
前面文章中 体验了webpack的打包 .解析css资源 .处理图片字体等文件 接下来看看 plugins 有什么作用吧~ 项目路径如下,和上一篇 处理图片字体等文件 项目保持一致 demo ├─ s ...
- [golang]使用gopsutil获取系统信息
前言 在python中有个psutil库用于获取系统信息,而go语言也有一个类似的库--gopsutil,功能差不多. 项目地址:https://github.com/shirou/gopsutil ...
- 从源码角度了解Vue生命周期
每个Vue应用都是通过new Vue()创建一个Vue实例开始.Vue()函数可以传入选项Options,常见的有el.template和data选项等. el 只在new创建实例时生效,其值可以是一 ...
- Android Studio Giraffe安装与gradle配置
本机环境:win10专业版,64位,16G内存. 原先用的AS2.2,是很早之前在看<第一行代码Android(第2版)>的时候,按书里的链接下载安装的,也不用怎么配置.(PS:第一行代码 ...
- nflsoj 5924 选排列
与全排列略微有些不同,只需要将退出条件需要改成 u==r #include <iostream> using namespace std; const int N = 15; int r, ...
- docker swarm 使用详解
转载请注明出处: 1.docker swarm 的组成架构 一个基本的docker swarm 的架构如下: 它主要包含这几个核心组件: Manager节点(Manager Nodes): 管理节点是 ...
- Elasticsearch 保姆级入门篇
Elasticsearch 是一个分布式的.面向生产规模工作负载优化的搜索引擎. Kibana 可以将 Elasticsearch 中的数据转化为直观的图表.图形和仪表盘. 这篇文章,您将学习本地安装 ...
- 解决git出现fatal: detected dubious ownership in repository at XXXXX的错误
在window环境下,使用git命令时报错fatal: detected dubious ownership in repository at XXXXXX,图片如下 解决方法如下 添加一行代码 gi ...