例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对象:

    每个类被加载后,系统就会为该类生成一个对应的Class对象,通过该Class对象就可以访问JVM中的这个类
  (1)、使用Class类的forName()静态方法,参数是类的全限定类名
  (2)、调用某个类的class属性来获取该类对应的Class对象。例如,Person.class将会返回Person类对应的Class对象
  (3)、调用某个对象的getClass(),该方法是java.lang.Object类中的一个方法,所以所有对象都可以调用该方法
  
      上述第(2)种方式具有如下优势:
  (1)、代码更安全,程序在编译阶段就可以检查要访问的Class对象是否存在  (2)、程序性能更高,无须方法调用

2、第5-19行,通过Class对象,获取其ClassLoader  Class对象.getClassLoader()

  • 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 checkPermission method with a RuntimePermission("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 its checkPermission method denies access to the class loader for the class.
    See Also:
    ClassLoaderSecurityManager.checkPermission(java.security.Permission)RuntimePermission

3、第25行,获取系统类加载器 

  ClassLoader c14 = ClassLoader.getSystemClassLoader();  //获取系统加载器

java.lang

Class 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 checkPermission method with a RuntimePermission("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 the Throwable.getCause() method.

JAVA类的加载(3) ——类加载后能够有效运行的更多相关文章

  1. jvm系列(一):java类的加载机制

    java类的加载机制 1.什么是类的加载 类的加载指的是将类的.class文件中的二进制数据读入到内存中,将其放在运行时数据区的方法区内,然后在堆区创建一个java.lang.Class对象,用来封装 ...

  2. 【Java基础】Java类的加载和对象创建流程的详细分析

    相信我们在面试Java的时候总会有一些公司要做笔试题目的,而Java类的加载和对象创建流程的知识点也是常见的题目之一.接下来通过实例详细的分析一下. 实例问题 实例代码 Parent类 package ...

  3. JAVA类的加载、连接与初始化

    JAVA类的加载.连接与初始化 类的声明周期总共分为5个步骤1.加载2.连接3.初始化4.使用5.卸载 当java程序需要某个类的时候,java虚拟机会确保这个类已经被加载.连接和初始化,而连接这个类 ...

  4. java 类的加载、连接和初始化

    JVM和类 调用Java命令运行Java程序时,该命令将会启动一条Java虚拟机进程,不管该Java程序启动了多少条线程,创建了多少个变量,它们都处于该Java虚拟机进程里,共享该JVM进程的内存区. ...

  5. 别翻了,这篇文章绝对让你深刻理解java类的加载以及ClassLoader源码分析【JVM篇二】

    目录 1.什么是类的加载(类初始化) 2.类的生命周期 3.接口的加载过程 4.解开开篇的面试题 5.理解首次主动使用 6.类加载器 7.关于命名空间 8.JVM类加载机制 9.双亲委派模型 10.C ...

  6. java类从加载、连接到初始化过程

    类加载器 在了解Java的机制之前,需要先了解类在JVM(Java虚拟机)中是如何加载的,这对后面理解java其它机制将有重要作用. 每个类编译后产生一个Class对象,存储在.class文件中,JV ...

  7. JVM(1):Java 类的加载机制

    原文出处: 纯洁的微笑 java类的加载机制 1.什么是类的加载 类的加载指的是将类的.class文件中的二进制数据读入到内存中,将其放在运行时数据区的方法区内,然后在堆区创建一个java.lang. ...

  8. 透过现象看本质:Java类动态加载和热替换

    摘要:本文主要介绍类加载器.自定义类加载器及类的加载和卸载等内容,并举例介绍了Java类的热替换. 最近,遇到了两个和Java类的加载和卸载相关的问题: 1) 是一道关于Java的判断题:一个类被首次 ...

  9. 第42天学习打卡(Class类 Class类的常用方法 内存分析 类的加载过程 类加载器 反射操作泛型 反射操作注解)

    Class类 对象照镜子后得到的信息:某个类的属性.方法和构造器.某个类到底实现了哪些接口.对于每个类而言,JRE都为其保留一个不变的Class类型的对象.一个Class对象包含了特定某个结构(cla ...

  10. JAVA - 类的加载过程

    JAVA - 类的加载过程 JVM类加载机制分为五个部分:加载,验证,准备,解析,初始化. 加载 加载是类加载过程中的一个阶段,这个阶段会在内存中生成一个代表这个类的java.lang.Class对象 ...

随机推荐

  1. Codeforces Round #875 (Div. 2) A-D

    比赛链接 A 代码 #include <bits/stdc++.h> using namespace std; using ll = long long; bool solve() { i ...

  2. Java 中怎样将 bytes 转换为 long 类型?

    将bytes 转换为long类型: 第一种方式: String 接收 bytes 的构造器转成 String,再 Long.parseLong: 但此种情况需要注意:字节数组中的每个字节都必须是有效的 ...

  3. 磁盘问题和解决: fsck,gdisk,fdisk等

    错误: Resize inode not valid 对于gpt分区的硬盘一般fsck只能检查分区, 不能用于检查整个硬盘, 但是如果对硬盘设备运行时遇到这样的错误 $ sudo fsck -n /d ...

  4. Django: 后台常用操作

    指定状态码 return JsonResponse(data, status=201) Djano删除数据库 删除对应数据库后,删除对应文件 删除对应的记录 Django后台管理 创建超级管理员 py ...

  5. 【技术积累】Linux中的命令行【理论篇】【三】

    apt-get命令 命令介绍 Debian Linux发行版中的APT软件包管理工具,apt-get命令 是Debian Linux发行版中的APT软件包管理工具.所有基于Debian的发行都使用这个 ...

  6. 你真的知道吗?catch、finally和return哪个先执行

    我的一位朋友前阵子遇到一个问题,问题的核心就是try--catch--finally中catch和finally代码块到底哪个先执.这个问题看起来很简单,当然是"catch先执行.final ...

  7. 从read 系统调用到 C10M 问题

    一.前言 从上个世纪到现在,工程师们在优化服务器性能的过程中,提出了各种不同的io模型,比如非阻塞io,io复用,信号驱动式io,异步io.具体io模型在不同平台上的实现也不一样,比如io复用在bsd ...

  8. 预处理器 Less 的十个语法

    Less 是一门 CSS 预处理语言,它扩充了 CSS 语言,增加了诸如变量.混合(mixin).函数等功能,让 CSS 更易维护.方便制作主题.扩充. 不过浏览器只能识别 CSS 语言,所以 Les ...

  9. C# OpenCVSharp图像入门_给绿幕图片视频加背景

    OpenCV的全称是Open Source Computer Vision Library,是一个跨平台的计算机视觉库.OpenCV是由英特尔公司发起并参与开发,以BSD许可证授权发行,可以在商业和研 ...

  10. SpringBoot3数据库集成

    标签:Jdbc.Druid.Mybatis.Plus: 一.简介 项目工程中,集成数据库实现对数据的增晒改查管理,是最基础的能力,而对于这个功能的实现,其组件选型也非常丰富: 通过如下几个组件来实现数 ...