`
小哥1900
  • 浏览: 56717 次
  • 性别: Icon_minigender_1
  • 来自: 广州
文章分类
社区版块
存档分类
最新评论

反射机制和工厂设计模式学习笔记

阅读更多
    工厂模式专门负责将大量有共同接口的类实例化。工厂模式可以动态的决定将哪个类实例化。工厂模式有以下几种形态:
    A.简单工厂模式(Simple Factory):又称静态工厂方法(Static Factory Method)模式;
    B.工厂方法模式(Factory Method):又称多态性方法(PolyMorphic Factory)模式,或虚拟 构造方法(Viutual Constructor)模式;
    C.抽象工厂模式(Abstract Factory):又称工具箱(ToolKit)模式
   
    设计一个简单的工厂类如下:
  
interface Fruit{
	public void grow();
	public void eat();
}
class Apple implements Fruit {
	public void grow() {
		System.out.println("苹果在生长");
	}
	public void eat() {
		System.out.println("吃苹果");
	}
}
class Orange implements Fruit {
	public void grow() {
		System.out.println("橘子在生长");
	}
	public void eat() {
		System.out.println("吃橘子");
	}
}
class Factory {
	public static Fruit getFruit(int i) {
		Fruit f = null;
		if(i == 1) {
			f = new Apple();
		}
		if(i == 2) {
			f = new Orange();
		}
		return f;
	}
}
public class TestFactory {
	public static void main(String[] args){
		Fruit f = Factory.getFruit(1);
		f.grow();
	}
}

运行结果:
 

   客户端只与工厂和直接的接口有关了,而与其他的无关,但是有一个问题,如果现在要扩展多个子类,那么工厂也必须同时进行修改那么有没有一种方法可以让子类扩展后而不用去修改工厂呢?我们可以通过Class.forName()来完成。
   看如下代码:
  
interface Fruit {
	public void grow();
	public void eat();
}
class Apple implements Fruit {
	public void grow() {
		System.out.println("苹果在生长");
	}
	public void eat() {
		System.out.println("吃苹果");
	}
}
class Orange implements Fruit {
	public void grow() {
		System.out.println("橘子在生长");
	}
	public void eat() {
		System.out.println("吃橘子");
	}
}
class Banana implements Fruit {
	public void grow() {
		System.out.println("香蕉在生长");
	}
	public void eat() {
		System.out.println("吃香蕉");
	}
}
class Factory {
	public static Fruit getFruit(String className) {
		Fruit f = null;
		try {
			f = (Fruit)Class.forName(className).newInstance();
		} catch(Exception e) {
			e.printStackTrace();
		}
		return f;
	}
}
public class TestFactory2 {
	public static void main(String[] args) {
		Fruit f = Factory.getFruit("Banana");
		f.grow();
	}
}

运行结果:
 


上面程序中的“f = (Fruit)Class.forName(className).newInstance()”就是用的反射机制。关于反射机制,我们从Class类开始说起。
    从API文档中查阅Class类定义如下:
  
引用
Instances of the class Class represent classes and interfaces in a running Java application. An enum is a kind of class and an annotation is a kind of interface. Every array also belongs to a class that is reflected as a Class object that is shared by all arrays with the same element type and number of dimensions. The primitive Java types (boolean, byte, char, short, int, long, float, and double), and the keyword void are also represented as Class objects.
Class has no public constructor. Instead Class objects are constructed automatically by the Java Virtual Machine as classes are loaded and by calls to the defineClass method in the class loader.

    由以上API文档来理解,Class它和一般的classes一样都是继承自Object。它的实体(instance)用以表达Java程序运行时的classes和interface,也用来表达enum,array,primitive Java types(boolean,byte,char,short,int ,long.float,double)以及关键词void。Class 没有公共构造函数。当一个class被加载时,或当加载器(class loader)的defineClass()被JVM(Java 虚拟机)调用,JVM自动产生一个Class Object。
  
引用
Java程序在运行时,Java运行时系统一直对所有的对象进行所谓的运行时类型标识。这项信息记录了每个对象所属的类。虚拟机通常使用运行时类型信息选准放正确方法去执行。用来保存这些类型信息的类就是Class类。Class类封装了一个对象和接口运行时的状态,当装载类时,Class类型的对象自动创建。
虚拟机为每种类型管理一个独一无二的class对象。也就是说每个类型都有一个class对象。运行程序时,Java虚拟机首先检查所要加载的类对应的Class对象是否已经加载。如果没有加载,JVM就会根据类名查找.class文件,并将其Class对象载入。
--选自51CTO网站网友熔岩的博客文章《深入研究Java.lang.class类》

    那么如何获得Class对象呢?有一下三种方法:
    A.调用Object类的getClass()方法得到Class对象。
   
class Person {
	private String name;
	private int age;
	public void setName(String name) {
		this.name = name;
	}
	public void setAge(int age) {
		this.age = age;
	}
	public String getName() {
		return this.name;
	}
	public int getAge() {
		return this.age;
	}
}
public class TestReflect {
	public static void main(String[] args) {
		Person p = new Person();
		Class c = null;
		c = p.getClass();
		System.out.println(c.getName());
	}
}

运行结果:
  
Person

    2.使用Class类的静态方法forName(String str)方法获得与字符串对应的Class对象。
   
import java.lang.reflect.*;

class Person {
	private String name;
	private int age;
	/*public Person(String name) {
		this.name = name;
	}*/
	public void setName(String name) {
		this.name = name;
	}
	public void setAge(int age) {
		this.age = age;
	}
	public String getName() {
		return this.name;
	}
	public int getAge() {
		return this.age;
	}
}
public class TestReflect {
	public static void main(String[] args) {
		Person p = null;
		Class c = null;
		try {
			c = Class.forName("Person");
		} catch(ClassNotFoundException e) {
			e.printStackTrace();
		}
		try{
			p = (Person)c.newInstance();
		} catch(Exception e) {
			e.printStackTrace();
		}
		p.setName("Heaven");
		p.setAge(24);
		System.out.println(p.getName() + "---->" + p.getAge());
	}
}

运行结果:
  

以上程序中的newInstance()方法,API中定义如下:
  
引用
Creates a new instance of the class represented by this Class object.

    也就是创建了一个这个Class对象所代表的类的实例。注意:如果要用以上代码来实例化一个对象,则必须有一个前提条件:在对象所在的类中必须要有一个无参的构造方法,如果没有此无参构造方法,则会出现错误。就是说如果将以上程序中的Person类的构造方法去掉了注释符号,此时Person类就失去了它的默认的无参构造方法,那么即使编译通过,最终运行还是发生以下错误:
  

关于newInstance方法实例对象与用new关键字来实例化对象的区别,参考网上的一篇文章(我发现网上大部分对这个问题的回答都是Ctrl+C Ctrl+V了这篇文章,至于原创者是谁也无从得知了。):
  
引用
在初始化一个类,生成一个实例的时候;newInstance() 和 new 有什么区别?
  用newInstance与用new是区别的,区别在于创建对象的方式不一样,前者是使用类加载机制,那么为什么会有两种创建对象方式?这个就要从可伸缩、可扩展,可重用等软件思想上解释了。
  Java中工厂模式经常使用newInstance来创建对象,因此从为什么要使用工厂模式上也可以找到具体答案。
  例如:
  Class c = Class.forName(“A”);factory = (AInterface)c.newInstance();
  其中AInterface是A的接口,如果下面这样写,你可能会理解:
  String className = "A";Class c = Class.forName(className);factory = (AInterface)c.newInstance();
  进一步,如果下面写,你可能会理解:
  String className = readfromXMlConfig;//从xml 配置文件中获得字符串Class c = Class.forName(className);factory = (AInterface)c.newInstance();
  上面代码就消灭了A类名称,优点:无论A类怎么变化,上述代码不变,甚至可以更换A的兄弟类B , C , D....等,只要他们继承Ainterface就可以。
   从jvm的角度看,我们使用new的时候,这个要new的类可以没有加载;
  但是使用newInstance时候,就必须保证:1、这个类已经加载;2、这个类已经连接了。而完成上面两个步骤的正是class的静态方法forName()方法,这个静态方法调用了启动类加载器(就是加载java API的那个加载器)。
  有了上面jvm上的理解,那么我们可以这样说,newInstance实际上是把new这个方式分解为两步,即,首先调用class的加载方法加载某个类,然后实例化。
  这样分步的好处是显而易见的。我们可以在调用class的静态加载方法forName时获得更好的灵活性,提供给了我们降耦的手段。

[补充:]
newInstance: 弱类型。低效率。只能调用无参构造。
new: 强类型。相对高效。能调用任何public构造。
newInstance()是实现IOC、反射、面对接口编程 和 依赖倒置 等技术方法的必然选择,new 只能实现具体类的实例化,不适合于接口编程。
里面就是通过这个类的默认构造函数构建了一个对象,如果没有默认构造函数就抛出InstantiationException, 如果没有访问默认构造函数的权限就抛出IllegalAccessException


   3.第三种方法很简单,如果T是一个Java类型,那么T.class就代表了匹配的类对象。
如:
Class c3 = Manager.class;
Class c4 = int.class;
Class c5 = Double[].class;
  • 大小: 4.9 KB
  • 大小: 4.9 KB
  • 大小: 5.1 KB
  • 大小: 18.4 KB
分享到:
评论

相关推荐

    java学习笔记及设计模式

    Java学习笔记及设计模式是程序员进阶过程中必不可少的资源,涵盖了广泛的Java基础知识和高级概念,同时结合了设计模式这一软件工程的重要组成部分。本资源集合旨在帮助开发者深化对Java语言的理解,提升编程技能,并...

    Java入门学习笔记

    "Java入门第三季学习笔记"可能涵盖了更多高级话题,如反射、注解、设计模式和Java库的使用。反射允许程序在运行时检查类、接口、字段和方法的信息,提供了更大的灵活性。注解是一种元数据,可以用来提供编译器或运行...

    java学习笔记markdown

    7. **设计模式**:介绍常见的设计模式,如单例、工厂、装饰器、观察者等,帮助提升代码的复用性和可维护性。 8. **反射机制**:探讨Java反射API的使用,包括动态获取类信息、创建对象、调用方法等功能,这对于理解...

    Java学习笔记(源码)

    12. **设计模式**:笔记可能涵盖了常见的设计模式,如单例、工厂、观察者、装饰器、适配器等,这些都是提高代码质量和可维护性的关键。 13. **JVM原理**:理解Java虚拟机的工作方式,包括类加载、内存管理和垃圾...

    非常详细javaSE学习笔记.rar

    16. **设计模式**:可能包含常见的23种设计模式,如单例,工厂,观察者,装饰器,适配器等模式的应用场景和实现。 17. **JVM内部机制**:虚拟机内存结构,类加载机制,字节码执行,性能优化等方面的知识。 这份...

    良葛格JAVA 学习笔记

    11. **设计模式**:介绍常见的设计模式,如工厂模式、单例模式、观察者模式等,以及如何在实际开发中应用它们。 12. **Spring框架**:作为良葛格另一部著作的主题,Spring框架的基本概念、依赖注入、AOP(面向切面...

    Java语言程序设计学习笔记

    26. **设计模式**:单例、工厂、观察者、装饰器等常见设计模式的实现。 27. **异常分类**:检查异常和运行时异常的区别,理解异常的层次结构。 28. **JNI(Java Native Interface)**:允许Java代码调用本地(C/...

    JAVA学习笔记和例子程序值得看看

    这份"JAVA学习笔记和例子程序值得看看"的压缩包显然包含了作者在深入学习Java过程中的重要发现和理解,以及帮助深化概念理解的示例程序。让我们来详细探讨一下可能包含的知识点。 1. **基础语法**:Java的基础包括...

    javase学习笔记(全)

    13. **设计模式**:学习常见的设计模式(如单例,工厂,观察者,装饰者等)可以提高代码的可读性和可维护性。 这份笔记详细记录了上述知识点的学习过程和实例,对于初学者来说,是系统学习和巩固Java基础知识的宝贵...

    Java学习笔记(整理)

    17. **设计模式**:Java开发者应熟悉一些常见的设计模式,如单例、工厂、观察者、装饰器等,它们是解决常见问题的最佳实践。 这些知识点构成了Java编程的基础,对于初学者来说,理解和掌握它们是至关重要的。通过...

    Java公司培训经典学习笔记

    - **常见设计模式**:单例模式、工厂模式、装饰器模式、代理模式等,以及它们在实际开发中的应用。 这份Java公司培训经典学习笔记全面覆盖了Java开发的核心知识点,对于初学者来说是一份很好的启蒙材料,对于有...

    java超强学习笔记

    9. **设计模式**:笔记可能会涵盖常见的设计模式,如单例、工厂、观察者、装饰器等,这些模式是解决软件设计问题的通用策略。 10. **Java EE相关**:如果笔记内容深入,还可能包含Java服务器端开发,如Servlet、JSP...

    java校招学习笔记

    9. **设计模式**:常见的23种设计模式,如单例、工厂、观察者等,它们在实际开发中的应用场景。 10. **网络编程**:TCP和UDP协议,Socket编程基础,以及HTTP协议的理解。 除了这些基础知识,Java校招学习笔记可能...

    Java 基础 第3阶段:高级应用-尚硅谷学习笔记(含面试题) 2023年

    在这个阶段的学习中,尚硅谷提供了2023年的学习笔记和面试题,帮助你提升Java技能并为求职做好准备。 首先,多线程是Java的一个关键特性,允许程序同时执行多个任务。理解线程的创建(通过Thread类或实现Runnable...

    Java基础尚硅谷宋红康学习笔记

    8. **设计模式**:设计模式是解决软件设计中常见问题的通用解决方案,如工厂模式、单例模式、观察者模式、装饰者模式等。 9. **Spring框架**:Spring是Java企业级应用的主流框架,提供依赖注入、AOP、数据访问、Web...

    高质量JAVA程序设计-个人学习笔记

    8. **设计模式**:笔记中可能涵盖常见的设计模式,如工厂模式、单例模式、观察者模式、装饰器模式等,这些模式为解决特定问题提供了标准解决方案。 9. **异常性能优化**:学习如何通过优化代码、减少不必要的对象...

    Java学习笔记(必看经典)

    11. **设计模式**:学习笔记可能还会涵盖常见的设计模式,如工厂模式、单例模式、观察者模式等,这些都是软件开发中的最佳实践。 12. **Java EE**:如果深入到进阶部分,可能还会介绍Java企业版(Java EE),包括...

    java学习笔记全面

    - 设计模式是解决软件设计中常见问题的通用解决方案,如单例模式、工厂模式、观察者模式等,学习和应用设计模式能提升代码的可维护性和复用性。 以上只是Java学习笔记中的部分核心知识点,实际的学习过程中,还...

    java面试题 学习笔记

    十、设计模式 1. 创建型模式:单例、工厂、抽象工厂、建造者、原型等模式。 2. 结构型模式:适配器、装饰器、代理、桥接、组合、外观、享元等模式。 3. 行为型模式:观察者、模板方法、策略、状态、职责链、命令、...

    java 学习笔记大全

    18. 设计模式:常见的有单例模式、工厂模式、装饰器模式等,是解决常见问题的成熟方案。 十二、Java 8及更高版本新特性 19. Lambda表达式:简化匿名函数的写法。 20. Stream API:处理集合的新方式,支持函数式编程...

Global site tag (gtag.js) - Google Analytics