反射机制初探 *

走进沼泽

在正常的程序中,先有类,然后再有对象。

  • 取得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) );
}
}

构造方法和普通方法,也同样可以取消封装,但很少使用。

总结

  • 实例化对象的方法增加一种“反射”
  • 反射调用类机构只是一个开始

最新文章

  1. DOM官方定义
  2. Android IOS WebRTC 音视频开发总结(七十)-- 移动端音视频技术优化的七个方向
  3. Cocos2dx使用wxsqlite开源加密SQLite3数据库
  4. 二模 (13)day1
  5. u-boot-1.1.6移植之dm9000
  6. C# 笛卡尔积
  7. iOS 设计模式之单例
  8. Java [Leetcode 100]Same Tree
  9. JavaScript 的 Date 最详细解读
  10. 三——第二部分——第二篇论文 计划建设SQL Server镜像
  11. 201521123036 《Java程序设计》第6周学习总结
  12. ●BZOJ 3129 [Sdoi2013]方程
  13. #017 python实验课第五周
  14. centOS 7下无法启动网络(service network start)错误解决办法
  15. location的三种连接方式和区别
  16. LY.JAVA面向对象编程思想概述
  17. Java基础语法 第4节 常见软件安装-Mysql和SQLyog
  18. 牛客网试卷: 京东2019校招笔试Java开发工程师笔试题(1-)
  19. java学习笔记10--泛型总结
  20. Jquery使容器自适应浏览器窗口

热门文章

  1. Android 音视频技术之录音获取实时音量
  2. 基于JS的ajax的实现,JSON和JSONP,基于JQuery的ajax的实现
  3. 【编码】彻底弄懂ASCII、Unicode、UTF-8之间的关系
  4. Linux ipv6 无状态 设置为 eui64
  5. day 26-1 property、绑定与非绑定方法
  6. Flask 特殊装饰器
  7. Python中Pyyaml模块的使用
  8. MySQL 字符串分隔成行&amp;子串统计
  9. report for PA2
  10. OSG嵌入QT的简明总结