Java 反射机制 初探*
反射机制初探 *
走进沼泽
在正常的程序中,先有类,然后再有对象。
- 取得Class对象(类对象)
public final Class<?> getClass() ;
- 实例观察:
public class TestDemo {
public static void main(String [] args) {
Date date = new Date() ; // 产生对象
System.out.println(date.getClass());
// 因为所有类都是 Object的子类,而getClass是final型所以所有类都有getClass()方法
}
}
- 运行结果
class java.util.Date
发现:调用getClass()方法输出的是类的完整名称,等于找到了对象出处:
——这就是“反”
Class 类对象实例化
java.lang.Class是一个类,这个类就是反射操作的源头,即:所有的反射都要从Class类开始运行 三种实例化方法;
- 调用Object中的Class方法
Class<?> cls = date.getClass();
// 此代码将Class类进行了实例化;getClass()是class类的实例化方法
- 使用 类.class 方法
Class<?> cls = Date.class;
前者是产生了类的实例化对象之后取得Class类对象,但是类.class方法并没有实例化对象产生
- 调用Class类提供的 forName() 方法
Class<?> cls = Class.forName(String ClassName) ;
此时可以不使用 import 语句导入一个明确的类名称,而类名称采用字符串的方式进行描述
反射实例化对象
当获得一个类时,使用关键字 new 进行类对象实例化操作;但是如果有了Class对象,那么就可以利用反射进行对象实例化操作。
实例化对象的方法:
public T newInstance();
- 实例分析:
class Book {
public Book() {
System.out.println("**********Book类 ***********");
}
@Override
public String toString() {
return "Hello,World!";
}
}
public class TestDemo {
public static void main(String [] args) throws InstantiationException, ReflectiveOperationException {
Class<?> cls = Class.forName("helloworld.Book");
@SuppressWarnings("deprecation")
Object obj = cls.newInstance();
Book book = (Book) obj ;// 向下转型
System.out.println(book);// 调用了Book类的对象
// 此过程没有 new 关键字实例化Book类,而是通过反射来实例化对象
}
}
在反射机制的加持下,类的对象实例化则不再单独依靠 new关键字 。
- new 与 反射 实例化对象的区别
package helloworld;
interface Fruit { // 函数是接口
public void eat() ;
}
class Apple implements Fruit {
@Override
public void eat() {
System.out.println("苹果");
}
}
class Factory {
public static Fruit getInstance(String className) {
if ("apple".equals(className)) {
return new Apple();
}
return null ;
}
}
public class TestFactory {
public static void main(String[] args) {
Fruit f = Factory.getInstance("apple");// 实例化Fruit对象
f.eat();
}
}
- 如果Fruit接口子类被增加了一个,那么就表示程序需要修改工厂类
package helloworld;
interface Fruit { // 函数是接口
public void eat() ;
}
class Apple implements Fruit {
@Override
public void eat() {
System.out.println("苹果");
}
}
class Orange implements Fruit{
@Override
public void eat() {
System.out.println("橘子");
}
}
class Factory {// 工厂类
public static Fruit getInstance(String className) {
if ("apple".equals(className)) {
return new Apple();
} else if ("orange".equals(className)) {
return new Orange();
} else {
return null ;
}
}
}
public class TestFactory {
public static void main(String[] args) {
Fruit f = Factory.getInstance("apple");// 实例化Fruit对象
f.eat();
}
}
如上两则程序可以看出:
每增加一个类,就要修改工厂类,非常的繁琐复杂;因为工厂类中的对象都是通过new直接实例化,而new就造成了这种高耦合的问题。
解决方法:
依靠反射实例化对象来完成
package helloworld;
interface Fruit { // 函数是接口
public void eat() ;
}
class Apple implements Fruit {
@Override
public void eat() {
System.out.println("苹果");
}
}
class Orange implements Fruit{
@Override
public void eat() {
System.out.println("橘子");
}
}
class Factory {// 工厂类
@SuppressWarnings("deprecation")
public static Fruit getInstance(String className) throws InstantiationException, ReflectiveOperationException, ClassNotFoundException {
Fruit f = null ;
try {
f = ((Fruit) Class.forName(className).newInstance());
// 因为 Class.forName()方法返回的是Object(默认/推荐),所以需要向下转型为Fruit
} catch (Exception e) { }
return f ;
}
} public class TestFactory {
public static void main(String[] args) throws InstantiationException, ClassNotFoundException, ReflectiveOperationException {
Fruit f = Factory.getInstance("helloworld.Apple");
f.eat();
}
}
// 程序中出现疑虑,可以参照"实例分析"
此时的程序就完成了解耦和的目的,而且可扩展性非常的强
反射调用方法
- 定义Book类
package helloworld;
public class Book {
private String title ;
public void setTitle(String title) {
this.title = title;
}
public String getTitle() {
return title;
}
}
类中有 无参构造方法 所以实例化对象的时候可以直接利用Class类中的newInstance()方法
在Class类中定义有如下的取得类中Method的操作:
- 取得类中的全部方法:
public Method [] getMethods();
- 取得指定类中方法:
public Method getMethod(String className , Class<?>... parameterTypes);
以上返回的是:java.lang.reflect.Method 类的对象
Methos类中的调用方法:
public Object invoke(Object obj , Object … args);
实例:
package helloworld;
import java.lang.reflect.Method;
public class TestDemo {
public static void main(String [] args) throws InstantiationException, ReflectiveOperationException {
String classname = "title" ;
Class<?> cls = Class.forName("helloworld.Book");
Object obj = cls.newInstance(); // 给出了Book类的实例化对象
Method setMet = cls.getMethod("set" + initcap(classname),String.class);
Method getMed = cls.getMethod("get" + initcap(classname));
setMet.invoke(obj, "Java");
System.out.println(getMed.invoke(obj));
}
private static String initcap(String str) { // 首字母大写
return str.substring(0,1).toUpperCase() + str.substring(1) ;
}
}
反射调用成员
类中的属性,一定要在本类实例化对象产生之后才可以分配内存空间。
取得全部成员:
public Field [] getDeclaredFields() ;
取得指定成员:
public Field getDeclaredFields() ;
返回的类型:java.lang.reflect.Field 类对象
- 取得属性内容:
public Object get(Object obj);
- 设置属性内容:
public void set(Object obj , Object Value);
定义Book类:
package helloworld;
public class Book {
public String title ;
}
package helloworld;
import java.lang.reflect.Field;;
public class TestDemo {
public static void main(String [] args) throws InstantiationException, ReflectiveOperationException {
String classname = "title" ;
Class<?> cls = Class.forName("helloworld.Book");
Object obj = cls.newInstance(); // 给出了Book类的实例化对象
java.lang.reflect.Field titleField = cls.getDeclaredField("title") ;
titleField.set(obj, "Java");
System.out.println(titleField.get(obj));
}
}
- 另外,还有一个访问private私有成员的方法,利用 setAccessible() 方法取消封装,然后调用成员。
package helloworld;
import java.lang.reflect.Field;;
public class TestDemo {
public static void main(String [] args) throws InstantiationException, ReflectiveOperationException {
String classname = "title" ;
Class<?> cls = Class.forName("helloworld.Book");
Object obj = cls.newInstance(); // 给出了Book类的实例化对象
Field titleField = cls.getDeclaredField("title") ;
titleField.setAccessible(true);// 取消封装
titleField.set(obj, "Java");
System.out.println( titleField.get(obj) );
}
}
构造方法和普通方法,也同样可以取消封装,但很少使用。
总结
- 实例化对象的方法增加一种“反射”
- 反射调用类机构只是一个开始
Java 反射机制 初探*的更多相关文章
- java反射机制初探
最近和一位师兄交流了一下Java,真可谓是大有收获,让我好好的学习了一下javad的反射机制,同终于明白了spring等框架的一个基本实现的思想,那么今天就和大家分享一下java的反射机制. 反射,r ...
- java反射机制初探
最近和一位师兄交流了一下Java,真可谓是大有收获,让我好好的学习了一下javad的反射机制,同终于明白了spring等框架的一个基本实现的思想,那么今天就和大家分享一下java的反射机制. 反射,r ...
- 初探Java反射机制
反射库提供了一个非常丰富且精心设计的工具集,以便编写能够动态操纵java代码的程序库.这项功能被大量地应用于JavaBeans中.反射机制提供了在运行状态中获得和调用修改任何一个类的属性和方法的能力. ...
- Java反射机制详解(3) -java的反射和代理实现IOC模式 模拟spring
IOC(Inverse of Control) 可翻译为“控制反转”,但大多数人都习惯将它称为“依赖注入”.在Spring中,通过IOC可以将实现类.参数信息等配置在其对应的配置文件中,那么当 需要更 ...
- 浅谈java反射机制
目录 什么是反射 初探 初始化 类 构造函数 属性 方法 总结 思考 什么是反射 JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法:对于任意一个对象,都能够调用它的任意 ...
- 第28章 java反射机制
java反射机制 1.类加载机制 1.1.jvm和类 运行Java程序:java 带有main方法的类名 之后java会启动jvm,并加载字节码(字节码就是一个类在内存空间的状态) 当调用java命令 ...
- Java反射机制
Java反射机制 一:什么事反射机制 简单地说,就是程序运行时能够通过反射的到类的所有信息,只需要获得类名,方法名,属性名. 二:为什么要用反射: 静态编译:在编译时确定类型,绑定对象,即通过 ...
- java基础知识(十一)java反射机制(上)
java.lang.Class类详解 java Class类详解 一.class类 Class类是java语言定义的特定类的实现,在java中每个类都有一个相应的Class对象,以便java程序运行时 ...
- java基础知识(十一)java反射机制(下)
1.什么是反射机制? java反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法,对于任意一个对象都能够调用他的属性和方法,这种动态获取属性和方法的功能称为java的反射机制. ...
随机推荐
- C#线程学习笔记五:线程同步--事件构造
本笔记摘抄自:https://www.cnblogs.com/zhili/archive/2012/07/23/Event_Constructor.html,记录一下学习过程以备后续查用. 前面讲的线 ...
- Sql将一列数据拆分为多行显示的两种方法
原始数据与期望结果有表tb, 如下:id value----------- -----------1 aa,bb2 aaa,bbb,ccc欲按 ...
- C# dictionary to bytes and bytes convert to dictionary
static byte[] GetBytesFromDic(Dictionary<string,string> dic) { if(dic==null || !dic.Any()) { r ...
- Hadoop2.8分布式集群安装与测试
1.hadoop2.x 概述 个).每一个都有相同的职能.一个是active状态的,一个是standby状态的.当集群运行时,只有active状态的NameNode是正常工作的,standby状态的N ...
- 基于vue+leaflet+echart的足迹分享评论平台
(其实题目是随便取的,目的只是用来证明Vue+leaflet+springboot技术栈的可行性) 效果 小专栏不支持上传视频?想看的话可以去我的知乎看最新的文章,那个应该可以.在这里 主要功能描述 ...
- HA: Infinity Stones Vulnhub Walkthrough
下载地址: https://www.vulnhub.com/entry/ha-infinity-stones,366/ 主机扫描: 目录枚举 我们按照密码规则生成字典:gam,%%@@2012 cru ...
- oopday02(面向对象-构造方法&静态static)
面向对象之封装 01_面向对象(构造方法Constructor概述和格式) * A:构造方法概述和作用 * 给对象的数据(属性)进行初始化 * B:构造方法格式特点 * a:方法名与类名相同(大小也要 ...
- linux学习第一周
1. 按系列罗列Linux的发行版,并描述不同发行版之间的联系与区别 2. 安装Centos7.6操作系统,创建一个自己名字的用户名,并可以正常登录,将主要步骤截图. 3. 配置环境变量,实现执行hi ...
- js的动态表格的增删改查思路
1. 首先我们要知道,动态添加,肯定不是 在页面上写死得,而是通过js调用循环放入到页面上的,我们在写动态表格的时候不要先着急写,我们第一步要做的就是构思,要把自己的逻辑先弄清楚,不然的话,前面是好写 ...
- [20191220]关于共享内存段相关问题.txt
[20191220]关于共享内存段相关问题.txt --//我一直很好奇如果设置内核参数kernel.shmmax = 68719476736足够大,为什么我的测试实例还是建立3个共享内存段.--// ...