-
JAVA反射之工厂模式和invoke
2020-03-20 23:08:54工厂设计模式: ...可通过反射进行工厂模式的设计,完成动态的对象创建。 创建对象的两种方式(以Student为例): Student s = new Student(); Class c = Student.class; Object o = c.newInstance(); Stude...工厂设计模式:
开发中有一个非常重要的原则“开闭原则”,对拓展开放、对修改关闭。
工厂模式主要负责对象创建的问题
可通过反射进行工厂模式的设计,完成动态的对象创建。
创建对象的两种方式(以Student为例):
Student s = new Student();
Class c = Student.class;
Object o = c.newInstance();
Student s2 = (Student)o;//通过输入流获取全限定名
FileReader fr = new FileReader("Files\\properties.txt");
BufferedReader br = new BufferedReader(fr);
String str = br.readLine();
Object oo = createObject(str);//创建对象!
//工厂:创建对象工厂
public static Object createObject(String str){
try {
Class c = Class.forName(str);
Object o = c.newInstance();
return o;//通过一系列的转换返回一个Object对象
} catch (Exception e) {
e.printStackTrace();
}
return null;
}invoke:
一:通过Class类对象去调用对象的方法:
//反射 类的对象
Object o = createObject("com.qf.day35.t1.reflects.Student");
//类对象
Class c =o.getClass();
//name->方法名 ,parameterTypes ->参数列表类型
Method m = c.getMethod("study",null);
//通过invoke方法,执行某个实例方法,参数:Object->所需对象,args->调用的方法所需的实参
m.invoke(o, null);二:通过方法输入对象,形参类型和实参:
Object o = TestInvoke.createObject("com.qf.day35.t0.invoke.Student");//获取对象
invokeAny(o,"exam",new Class[]{int.class,double.class,String.class},1,90,"赵公民");
invokeAny(o, "study",null,null);//调用invokeAny()方法执行其中的方法//通用编程(调用任何一个方法)
public static void invokeAny(Object obj,String methodName,Class[] types,Object... args) throws Exception {
//使用反射技术执行任何方法
//类对象
Class c = obj.getClass();
//获得方法的对象Method
Method m = c.getDeclaredMethod(methodName, types);
//执行方法
m.invoke(obj, args);
} -
设计模式之单例模式,六种实现,以及反射破解
2020-08-15 22:13:38行为型模式(11种):策略模式、模板方法模式、观察者模式、迭代子模式、责任链模式、命令模式、备忘录模式、状态模式、访问者模式、中介者模式、解释器模式。 设计模式的六原则 开闭原则:对扩展开放,对修改关闭 ...在介绍设计模式之前,先贴一下设计模式的三种类型,和六大原则。
- 创建型模式(5种):工厂方法模式,抽象工厂模式,单例模式,建造者模式,原型模式。
- 结构型模式(7种):适配器模式,装饰器模式,代理模式,外观模式,桥接模式,组合模式,享元模式。
- 行为型模式(11种):策略模式、模板方法模式、观察者模式、迭代子模式、责任链模式、命令模式、备忘录模式、状态模式、访问者模式、中介者模式、解释器模式。
设计模式的六原则
- 开闭原则:对扩展开放,对修改关闭
- 里氏代换原则:任何基类可以出现的地方,子类一定可以出现,(子类代换基类)
- 依赖倒转原则:对接口编程,依赖于抽象,而不依赖于具体
- 接口隔离原则:使用多个隔离的接口,比使用单个好,降低耦合度
- 合成复用原则:尽量使用合成/聚合的方式,而不是使用继承
- 迪米特法则(最少知道原则):实体之间尽量少发生相互作用,使模块相对独立
下面开始介绍最简单常见的单例模式
使用场景:一个类全局只有一个实例的情况。该实例由单例类自己创建,并提供访问该实例的方法。使用单例类一般是实例创建比较复杂的情况,且对象不保存状态信息(即没有可供修改的成员变量,否则很容易被修改)。可以将单例类理解成一个工具类,提供全局访问,只有一个实例。Spring中的bean默认使用的就是单例模式。
下面开始介绍单例模式的六种实现
饿汉模式
饿汉模式是在类被加载的时候就创建了实例,即使这个单例都不一定会被使用。
public class Singleton{ private Singleton(){} // 构造方法私有化 private static final Singleton instance = new Singleton(); // 实例在类加载时就被创建 public static Singleton getInstance(){ return instance; } }
懒汉模式
懒汉模式是在只有单例类被使用的时候才创建出来。
public class Singleton { private Singleton(){} private static Singleton instance = null; // 默认为null public static Singleton getInstance(){ if (instance == null) { // 方法被调用的时候才创建 instance = new Singleton(); } return instance; } }
线程安全的懒汉模式
在多线程环境下,上面的懒汉模式,很容易创建出多个实例。于是需要加锁。加一个synchronized就不会有多线程创建多个实例了。
public class Singleton { private Singleton(){} private static Singleton instance = null; // 默认为null public static synchronized Singleton getInstance(){ if (instance == null) { // 方法被调用的时候才创建 instance = new Singleton(); } return instance; } }
双重检验锁 的懒汉模式
既然是多线程环境下,直接在方法上加synchronized,那效率就很低了,肯定不满足要求。所以需要在内部创建对象的时候才加锁。
但是看下面的代码,我们发现在获取到锁开始创建对象前,又进行了一次非空校验。这个应该很好理解吧,在创建时加锁只是让线程一个一个进去。两个线程同时访问,第一个获取到锁的线程进去创建了实例后,第二个进入,如果不判空,第二个还是会创建另一个实例。双重校验锁在平时写代码中很常见(划重点)
然后其实只有一个应该注意的是
volatile
关键字,该关键字能够防止java指令重排序。instance = new Singleton();
在jvm中包含多个操作(划分一块内存 ->在内存上创建对象 -> 将instance指向对应内存等),然后进过jvm重排序后,可能就是 (划分一块内存 -> 将instance指向对应内存等 -> 在内存上创建对象) 这样的话,就会返回一个没有实例化完全的对象了,比如null。public class Singleton { private Singleton(){} private static volatile Singleton instance = null; public static synchronized Singleton getInstance(){ if (instance == null) { synchronized (Singleton.class) { if (instance == null) { instance = new Singleton(); } } } return instance; } }
静态内部类模式 (登记式)
这种方法也是在使用时才实例化。但看代码里面貌似直接new了。这是利用了静态内部类的特性,只有在访问静态内部类时,它才会被加载。
public class Singleton{ private static class Inner{ private static final Singleton instance= new Singleton(); } private Singleton(); public static Singleton getInstance(){ //调用该方法时,Inner类才会被加载,然后实例化instance return Inner.instance; } }
枚举类模式
最简单粗暴的方式当然是我们的枚举类了。都不需要写getInstance方法,直接 Singleton.instance 访问。
public enum Singleton{ instance; }
这样咋一看,感觉枚举类和饿汉模式差不多嘛。不不不,在反射面前,前面5中模式都是渣渣。只有枚举类不能通过反射修改构造方法。
public static void main(String[] args) { Class<Singleton> aClass = Singleton.class; try { Constructor<Singleton> constructor = aClass.getDeclaredConstructor(); constructor.setAccessible(true); Singleton singleton = constructor.newInstance(); Singleton singleton2 = constructor.newInstance(); } catch (Exception e) { e.printStackTrace(); } }
然后看到有人说,加一个类变量,然后调用构造方法时判断其状态,如果时第二次就抛异常。比如下面这样
public class Singleton { private static boolean init = false; private Singleton(){ if (init) { throw new RuntimeException(); } init = true; System.out.println("hahah"); } private static Singleton instance = new Singleton(); public static Singleton getInstance() { return instance; } }
天真!以为反射只能修改构造方法的可见性?
public static void main(String[] args) { Class<Singleton> aClass = Singleton.class; try { Constructor<Singleton> constructor = aClass.getDeclaredConstructor(); constructor.setAccessible(true); Field init = aClass.getDeclaredField("init"); init.setAccessible(true); init.setBoolean(null, false); Singleton singleton = constructor.newInstance(); init.setBoolean(null, false); Singleton singleton2 = constructor.newInstance(); } catch (Exception e) { e.printStackTrace(); } }
-
工厂模式结合反射——遵循开闭原则
2020-09-03 11:30:24目录介绍传统工厂模式工厂模式结合反射机制总结 介绍 工厂模式是一种创建型模式,在工厂模式中,创建对象时不会对客户端暴露创建细节(将创建的代码封装到一个工厂类中),而是通过一个接口指向由工厂类创建并返回的...介绍
工厂模式是一种创建型模式,在工厂模式中,创建对象时不会对客户端暴露创建细节(将创建的代码封装到一个工厂类中),而是通过一个接口指向由工厂类创建并返回的对象。
对于设计模式和各个原则来说,无非就是要实现代码的高内聚和低耦合,还有尽量遵循开闭原则。开闭原则简单来说就是:软件中的对象(类,函数,模块)对扩展开放,对修改关闭。于是,围绕开闭原则展开以下讨论。
传统工厂模式是如何违背了开闭原则的,工厂模式加反射机制是如何遵循开闭原则的。以披萨为话题,我们要创建各种口味的披萨,例如奶酪披萨,水果披萨。
这个显然可以就通过工厂模式来实现,下面用传统工厂模式。
首先我们要声明一个IPizza接口:public interface IPizza { void eat(); }
IPizza的实现类:
//奶酪披萨 public class CheesePizza implements IPizza { private String pizzaType="奶酪披萨"; @Override public void eat() { System.out.println(pizzaType+"真香!"); } }
//水果披萨 public class FruitPizza implements IPizza { private String pizzaType="水果披萨"; @Override public void eat() { System.out.println(pizzaType+"真好吃!"); } }
下面通过工厂创建各种口味的披萨。
传统工厂模式
写一个工厂类,把创建各种口味披萨的任务交给它。
//披萨工厂类 public class PizzaFactory { private PizzaFactory(){} public static IPizza createPizza(String pizzaType){ IPizza pizza=null; if ("奶酪披萨".equals(pizzaType)) { pizza=new CheesePizza(); } else if ("水果披萨".equals(pizzaType)) { pizza=new FruitPizza(); } return pizza; } }
测试:
public class PizzaTest { public static void main(String[] args) { IPizza pizza=PizzaFactory.createPizza("水果披萨"); pizza.eat(); pizza=PizzaFactory.createPizza("奶酪披萨"); pizza.eat(); } }
控制台结果:
OK!就是那么简单,但是问题来了,我现在突然想到还有一种口味的披萨:蛋黄披萨。我想把它添加到系统中,要怎么做呢?
第一步,实现IPizza接口//蛋黄披萨 public class EggyolkPizza implements IPizza { private String pizzaType="蛋黄披萨"; @Override public void eat() { System.out.println(pizzaType+"贼香!"); } }
第二步,修改工厂类(emmm,思考一下,这是不是违背了开闭原则)
修改过程就是添加一个else if分支。
public class PizzaFactory { private PizzaFactory(){} public static IPizza createPizza(String pizzaType){ IPizza pizza=null; if ("奶酪披萨".equals(pizzaType)) { pizza=new CheesePizza(); } else if ("水果披萨".equals(pizzaType)) { pizza=new FruitPizza(); } else if ("蛋黄披萨".equals(pizzaType)) { pizza=new EggyolkPizza(); } return pizza; } }
代码搞定,测试一下:
添加披萨口味是成功了,但是我们也违背了开闭原则,如果有很多个口味的披萨引进来,那我们岂不是要改工厂类改到吐?工厂模式结合反射机制
同样也是写一个工厂类,把创建各种口味披萨的任务交给它。
public class PizzaFactory { private PizzaFactory(){} public static IPizza createPizza(String pizzaType){ IPizza pizza=null; try { Class clazz=Class.forName(pizzaType); pizza=(IPizza)clazz.newInstance(); } catch (Exception e) { e.printStackTrace(); } return pizza; } }
测试:
public class PizzaTest { public static void main(String[] args) { IPizza pizza=PizzaFactory.createPizza("cn.thg.community.pizza.impl.CheesePizza"); pizza.eat(); pizza=PizzaFactory.createPizza("cn.thg.community.pizza.impl.FruitPizza"); pizza.eat(); } }
控制台结果:
OK!
添加一个口味的披萨,还是蛋黄披萨吧。
很简单,只需要扩展多一个类就行了,不需要取修改工厂类。
只需一步,扩展一个蛋黄披萨的类public class EggyolkPizza implements IPizza { private String pizzaType="蛋黄披萨"; @Override public void eat() { System.out.println(pizzaType+"贼香!"); } }
测试:
搞定。这样无论要加多少种口味,只需要拓展就行了,这不就很好的遵循了开闭原则吗,无论添加多少个披萨类,都不用对工厂类进行任何改变,直接在客户端(main方法)调用即可,相比较与传统工厂模式简直不要方便太多。总结
很显然,传统工厂模式违背了开闭原则(扩展新口味要修改工厂类),而工厂模式结合反射的方式则没有违背。只不过是后者传参的方式变成了传全限定类名。
-
【Java】反射机制实现工厂模式和通用编程写法
2020-03-21 11:46:36Java工厂模式和通用编程1. 工厂模式2. 通用编程 ...可通过反射进行工厂模式的设计,完成动态的对象创建。 public class TestNewInstanceForFile { public static void main(String[] args) thr...1. 工厂模式
- 开发中有一个非常重要的原则“开闭原则”,对拓展开放、对修改关闭;
- 工厂模式主要负责对象创建的问题;
- 可通过反射进行工厂模式的设计,完成动态的对象创建。
public class TestNewInstanceForFile { public static void main(String[] args) throws Exception { // 创建出入流对象 FileReader fr = new FileReader("files\\application.txt"); BufferedReader br = new BufferedReader(fr); // 读出文件中的类的全限定名 String className = br.readLine(); // 创建Object对象返回后进行强转为对应类型,进而使用 Teacher t3 = (Teacher)createObject(className); System.out.println(t3); br.close(); } /** * 工厂:创建对象工厂 * @param className String类型的类的全限定名 * @return Object Object类型的对象 */ public static Object createObject(String className) { try { Class<?> c = Class.forName(className); return c.newInstance(); } catch (Exception e) { e.printStackTrace(); } return null; } } /* * files\\application.txt 内容: * com.methods.Teacher */
2. 通用编程
使用反射机制,实现执行任何类的任意方法。
突破封装示例:
// 反射:类的对象 Object o = createObject("com.day.t1_factory.Student"); // 类对象 Class<?> c = o.getClass(); Method m = c.getDeclaredMethod("calc", null); // 获取自身方法,包含私有方法 // 【注意】反射是一种底层技术,可取消语言检查,突破private封装! // AccessibleObject类:@true 忽略Java语言访问检查 @false 反之 m.setAccessible(true); m.invoke(o, null);
调用任意类的任意方法的演示:
public class TestInvokeAnything { public static void main(String[] args) throws Exception { // invokeAny() 执行任何方法 // 传入:对象(Object)、方法名称(String)、形参(.class)、实参(Object) invokeAny( createObject("com.day.t1_factory.Student"), "exam", new Class[] {int.class, double.class, String.class}, 2, 10, "小明" ); // public void exam(int n, double score, String name) Object o = createObject("com.day.t1_factory.Student"); invokeAny(o, "study", null, null); // public void study() invokeAny(o, "study", new Class[] {Integer.class}, 100); // public int study(Integer a) } /** * 反射技术,执行任何方法 * @param obj Objcet类型对象 * @param methodName String类型方法名称 * @param types Class[]数组类型的types * @param args Object类型的可变长参数 * @throws Exception */ public static void invokeAny(Object obj, String methodName, Class<?>[] types, Object...args) throws Exception { Class<?> c = obj.getClass(); // 1.获取类对象 Method m = c.getDeclaredMethod(methodName, types); // 2.获得方法的对象Method m.invoke(obj, args); // 3.执行方法 } /** * 反射技术,工厂设计模式 * @param className 类的全限定名 * @return 返回Object类型的对象 */ public static Object createObject(String className) { try { Class<?> c = Class.forName(className); return c.newInstance(); } catch (Exception e) { e.printStackTrace(); } return null; } }
-
Java学习笔记--设计原则与设计模式、类加载、反射的介绍
2018-10-02 13:39:03文章目录设计原则、设计模式类加载反射JDK动态代理 设计原则、设计模式 面向对象思想设计原则 单一职责原则:每个类应该只有一个职责,对外只能提供一种功能。其实就是”高内聚,低耦合”。 开闭原则:对扩展开放... -
反射内存安装使用方法
2019-08-14 17:02:16物理安装 PCI反射内存 兼容的系统外观不同,并且有不同的安装流程,建议安装前 检查主机系统的安装程序,以下步骤简单的描述了一个 ...所需的模式。 确保 PCI 连接器正确插入,安装螺丝。 关闭机箱,接通电源。 ... -
设计模式
2020-10-16 10:41:09可以通过反射进行工厂设计模式的设计,完成动态的对象创建 /** * 父类产品 * @author ASUS * */ public interface Usb { void service(); } public class Upan implements Usb{ @Override public void ... -
java设计模式之工厂模式
2018-08-27 02:26:00在实际使用过程中,违背了开放-关闭原则,当然有些情况下可以通过反射调用来弥补这种不足。 抽象工厂模式: 提供一个创建——系列相关相互依赖对象的接口,而无需指定他们具体的类。抽象工厂为不同产... -
java_IO,反射机制,jdk动态代理
2017-01-14 15:08:36关闭流时只需要关闭最外层的流。字节流和字符流之间的转换: InputStreamReader需要和InputStream套接;OutputStreamWriter需要和OutputStream套接。 2.反射机制 java的反射机制允许程序在运行时加载、探知、使用... -
工厂设计模式
2020-08-18 01:23:00什么是设计模式 一套被反复使用、多数人知晓的、经过分类编目的、代码设计经验的总结。简单理解:特定问题的固定解决方法。 好处:使用设计模式是...可通过反射进行工厂模式的设计,完成动态的对象创建。 工厂类... -
单例模式-懒汉模式(一)
2018-08-18 17:38:34/** * 懒汉模式(一) * @author moke */ public class LazyModeA { private volatile static LazyModeA instance = null;... * 关闭new方式实例化(然后还是能通过反射创建的......) */ p... -
单例模式-懒汉模式(二)
2018-08-18 17:39:14/** * 懒汉模式(二)特别 * @author moke */ public class LazyModeB { private volatile static LazyModeB instance = null;... * 关闭new方式实例化(然后还是能通过反射创建的......) */ ... -
大话设计模式----代理模式
2021-01-06 14:25:24代理模式:对其他对象提供一种代理,来控制对这个对象的访问 分类: ...(1)设计模式中有一个设计原则是开闭原则,是说对修改关闭对扩展开放,我们在工作中有时会接手很多前人的代码,里面代码逻... -
java 反射之静态and动态代理
2018-10-14 13:57:00(1)设计模式中有一个设计原则是开闭原则,是说对修改关闭对扩展开放,我们在工作中有时会接手很多前人的代码,里面代码逻辑让人摸不着头脑(sometimes the code is really like shit),这时就很难去下手修改代码,... -
java 工厂模式的应用
2020-06-17 09:16:43可通过反射进行工厂模式的设计,完成动态的对象创建 package ch3; //产品家族 abstract class Car{ private String brand; public Car() { } public Car(String brand) { this.brand = brand; } public ... -
大话设计模式二
2017-08-10 23:50:00这样的好处就是,不用在工厂类里new对象,对修改关闭.可以通过反射来创建新的对象,对扩展开放. 5.原型模式 就是一个类提供clone方法(可以实现IConleable),利用this.MemberwiseClone()实现浅复制... -
java 设计原则和设计模式
2021-01-11 21:06:21上一章内容,java 反射机制 常用设计原则和设计模式 常用的设计原则 软件开发的流程 需求分析文档、概要设计文档、详细设计文档、编码和测试、安装和调试、维护和升级 常用的设计原则 开闭原则(Open Close ... -
色彩理论和图层混合模式
2010-11-09 20:03:00色彩理论和图层混合模式 一、RGB颜色CMYK颜色 我们首先看一下实验的环境。这是一个四周墙壁全是白色的封闭的房间,我们就用它来研究色光的混合。现在房间里开着灯,我们可以看到各面墙壁 将... -
Android AP模式创建有/无密码热点
2016-10-20 16:15:551、用到的类(可以不用反射) WifiManager:控制wifi的状态监测和打开、关闭。 WifiConfiguration:配置wifi的用户名、密码和加密方式等。 KeyMgmt:设置加密的方式,并设置到config中 2、... -
设计模式之面向对象设计的6个原则
2019-03-31 15:35:03一个软件实体对扩展开放,对修改关闭,即在不修改源代码的情况下改变这个模块的行为 方式:配置文件,DOM解析,反射 2、里氏替换原则 如果能够使用基类对象,那么一个能够使用子类对象,把基类都替换成子类,程序... -
01.DesignParttern设计模式,简单工厂,工厂方法,抽象工厂三大工厂的区别与联系...
2019-06-17 17:34:00工厂用来生产对象,对象具有方法和属性。 简单工厂的缺点(简单工厂并不是23中设计模式): ...改进方法:能够直接通过反射去改进简单工厂的开闭原则(对扩展开放,对修改关闭); 工厂方法: 定... -
WEBLOGIC的BUG??? 关闭的连接
2008-11-13 16:03:16java.sql.SQLException: 关闭的连接 at oracle.jdbc.driver.DatabaseError.throwSqlException(DatabaseError.java :125) at oracle.jdbc.driver.DatabaseError.throwSqlException(DatabaseError.java :162) ... -
动态代理是基于什么原理?
2019-04-12 20:31:00代理模式(通过代理静默地解决一些业务无关的问题,比如远程、安全、事务、日志、资源、关闭……让应用开发者可以只关心他的业务) 静态代理:事先写好代理类,可以手工编写,也可以用工具生成。缺点是每个业务类都... -
【Java核心技术】 动态代理是基于什么原理
2018-11-02 09:57:27代理模式(通过代理静默地解决一些业务无关的问题,比如远程、安全、事务、日志、资源关闭……让应用开发者可以只关心他的业务) 静态代理:事先写好代理类,可以手工编写,也可以用工具生成。缺点是每个业务类都... -
千锋逆战班学习日志
2020-03-20 20:20:07千锋逆战班学习第34天总结-反射总结-反射 千锋逆战班学习第34天 努力或许没有收获,但不努力一定没收获,加油。 今天我学了Java课程的反射和JDK8。...可通过反射进行工厂模式的设计,完成动态的对象创建。... -
2020-03-23
2020-03-23 19:01:45Java工厂模式和通用编程 工厂模式2. 通用编程1....可通过反射进行工厂模式的设计,完成动态的对象创建。public class TestNewInstanceForFile { public static void main(String[] args) throws Excep... -
不想面试一
2018-10-21 16:38:11final 修饰不可变变量,不可覆盖...反射的用途实现 通过反射机制可以在运行期间获取对象的类型信息 (工厂模式,代理模式等),解决java泛型擦除等 获取一个对象的反射类 getClass() Class.forName() 类.class ... -
vray渲染器的工作流程你清楚吗?
2020-08-17 16:28:10① 把图像采样器改为“固定模式“,把抗锯齿系数调低,并关闭材质反射、折射和默认灯。 ② 勾选GI,将“首次反射”调整为lrradiance map模式(发光贴图模式),调整min rate(最小采样)和max rate(最大采样)为-6,-5...