一. 反射机制
1 .什么是反射?
JAVA反射机制是在运行状态中,对于任意实体类,都能知道这个类的所有属性和方法;对于任意一个对象,都能够调用他的属性和方法;这种动态获取信息以及动态调用方法的功能称为JAVA语言的反射机制.
2.为什么要使用反射,直接创建对象不可以吗?这里涉及到了动态与静态的概念
- 静态编译 在编译的时候确定类型,同时绑定对象
Student stu = new Student("zhangsan",30)
- 动态编译: 在运行时确定好类型,绑定具体对象. 动态编译最大发挥了java的灵活性,体现多态的应用,用来类之间的耦合度.
Class.forName("com.mysql.jdbc.Driver").newInstance();
-
总结:
- 反射机制的优点就是可以实现动态创建对象和编译,体现出很大的灵活性,特别是在J2EE的开发中
- 它的缺点是对性能有影响。使用反射基本上是一种解释操作,要解析字节码文件,将内存中的对象进行进行解析,这类操作总是慢于直接执行的相同操作。
二 . Class类
在程序运行时,Java运行时系统始终为所有的对象维护一个被称为运行时的类型标识,这个信息跟踪着每个对象所属的类。
每个对象在运行的时候都有一份与之对象的Class对象,Class对象中描述了此对象中的相关特性,比如:字段,构造方法,方法,包名等相关对象的结构信息
Class对象是在类加载的时候由Java虚拟帮忙创建的对象
三、获取Class对象的常用方式
● 通过对象名.getClass()
String str = "abc"; Class c1 = str.getClass();
● 直接使用类名.class来获取
Class listClass = ArrayList.class;
● Class.forName("类的全限定名"),这种方式使用比较多
Class c1 = Class.forName("java.lang.String");
四、通过反射构建对象
● 调用无参构造函数创建对象
Class<?> objClass = Class.forName("com.hwua.entity.User"); User user = (User)objClass.newInstance();
● 调用带参构造函数创建对象
Class<?> objClass = Class.forName("com.hwua.entity.User"); Constructor<?> constructor = objClass.getDeclaredConstructor(new Class[] {String.class,int.class}); User user = (User)constructor.newInstance(new Object[] {"张三",10});
五、通过反射调用方法
Method m1 = objClass.getDeclaredMethod("setUsername", new Class[] { String.class }); m1.invoke(obj, new Object[] {"陈豪"}); Method m2 = objClass.getDeclaredMethod("setAge", new Class[] { int.class }); m2.invoke(obj, new Object[] {100}); Method m3 = objClass.getDeclaredMethod("toString", new Class[] {}); System.out.println(m3.invoke(obj, new Object[] {}));
六、通过反射设置属性
// 获得用户名字段
Field field = objClass.getDeclaredField("username");
// 设置private的属性可以设置赋值 field.setAccessible(true); field.set(obj, "陈豪");
七、练习:
1. 使用反射复制一个对象
// 拷贝任意对象的工具类 package com.hwua.utils; import java.lang.reflect.Field; import java.lang.reflect.Method; public class ObjectCopyUtil { public static Object copyObject(Object obj) throws Exception { Class<?> classType = obj.getClass(); Object dst = classType.newInstance(); Field[] fields = classType.getDeclaredFields(); for(Field field:fields) { String fName = field.getName();//得到字段名 Class<?> ftype = field.getType(); Method setMethod = classType.getDeclaredMethod("set"+fName.substring(0,1).toUpperCase()+fName.substring(1), new Class[] {ftype}); Method getMethod = classType.getDeclaredMethod("get"+fName.substring(0,1).toUpperCase()+fName.substring(1), new Class[] {}); Object value = getMethod.invoke(obj, new Object[] {}); setMethod.invoke(dst,value); } return dst; } }
八、面向对象六大设计原则
● 在实际的开发中,我们要想更深入的了解面向对象思想,就必须熟悉前人总结过的面向对象思想的设计原 则。
1. 单一职责原则(Single Responsiblity Principle)
其实就是开发人员经常说的”高内聚,低耦合” 也就是说,每个类应该只有一个职责,对外只能提供一种功能,而引起类变化的原因应该只有一个。 在设计模式中,所有的设计模式都遵循这一原则。
2. 开闭原则(Open Closed Principle)
核心思想是:对扩展开放,对修改关闭。 也就是说,对已经使用的类的改动是通过增加代码进行的,而不是修改现有代码。
3. 里式替换原则(Liskov Substitution Principle)
核心思想:在任何父类出现的地方都可以用它的子类来替代。 也就是说,同一个继承体系中的对象应该有共同的行为特征。
4. 依赖倒转原则(Dependency Inversion Principle)
核心思想:要依赖于抽象和接口,不要依赖于具体实现。 其实就是说:在应用程序中,所有的类如果使用或依赖于其他的类,则应该依赖这些其他类的抽象类 或者接口,而不是直接依赖这些其他类的具体类。 为了实现这一原则,就要求我们在编程的时候针对抽象类或者接口编程,而不是针对具体实现编程。
5. 接口分离原则(Interface Segregation Principle)
核心思想:不应该强迫程序依赖它们不需要使用的方法。 其实就是说:一个接口不需要提供太多的行为,一个接口应该只提供一种对外的功能,不应该把所有 的操作都封装到一个接口中。
6. 迪米特原则(最少认知原则,Principle of Least Knowledge)
核心思想:一个实体应当尽量少的与其他实体之间发生相互作用,使得系统功能模块相对独立 其实就是说:降低各个对象之间的耦合,提高系统的可维护性。在模块之间应该只通过接口编程,而 不理会模块的内部工作原理,它可以使各个模块耦合度降到最低,促进软件的复用
九、设计模式
1. 什么是设计模式?
设计模式(Design Pattern)是一套被反复使用、多数人知晓的、经过分类的、代码设计经验的总 结。 设计模式(Design pattern)代表了最佳的实践,通常被有经验的面向对象的软件开发人员所采用。 设计模式是软件开发人员在软件开发过程中面临的一般问题的解决方案。这些解决方案是众多软件开 发人员经过相当长的一段时间的试验和错误总结出来的。 使用设计模式的目的:为了代码可重用性、让代码更容易被他人理解、保证代码可靠性。 设计模式 使代码编写真正工程化;设计模式是软件工程的基石脉络,如同大厦的结构一样。 设计模式不是一种技术,是一种思想。
2. 设计模式类型
● 创建型(5种):简单工厂模式、工厂方法模式、单例模式、原型模式、构建者模式
● 结构型(7种):适配器模式、装饰模式、代理模式、外观模式、桥接模式、组合模式、享元模式
● 行为型(11种):模板方法模式、策略模式、观察者模式、中介者模式、状态模式、责任链模式、 命令模式、迭代器模式、访问者模式、解释器模式、备忘录模式
3. 常用设计模式介绍
1. 简单工厂模式
就是建立一个工厂类,对实现了同一接口的一些类进行实例的创建。简单工厂模式的实质是由一个工 厂类根据传入的参数,动态决定应该创建哪一个产品类(这些产品类继承自一个父类或接口)的实 例。
优点:工厂类是整个模式的关键.包含了必要的逻辑判断,根据外界给定的信息,决定究竟应该创建哪个 具体类的对象.通过使用工厂类,外界可以从直接创建具体产品对象的尴尬局面摆脱出来,仅仅需要负 责“消费”对象就可以了。而不必管这些对象究竟如何创建及如何组织的.明确了各自的职责和权利, 有利于整个软件体系结构的优化。
缺点:由于工厂类集中了所有实例的创建逻辑,违反了高内聚责任分配原则,将全部创建逻辑集中到 了一个工厂类中;它所能创建的类只能是事先考虑到的,如果需要添加新的类,则就需要改变工厂类 了。当系统中的具体产品类不断增多时候,可能会出现要求工厂类根据不同条件创建不同实例的需 求.这种对条件的判断和对具体产品类型的判断交错在一起,很难避免模块功能的蔓延,对系统的维 护和扩展非常不利;
简单工厂模式demo
package com.hwua.simplefactory; // 接口 public interface Human { void say(); } // man类 package com.hwua.simplefactory; public class Man implements Human { @Override public void say() { System.out.println("我是男人"); } } // woman类 package com.hwua.simplefactory; public class Woman implements Human { @Override public void say() { System.out.println("我是女人"); } } // 简单工厂 package com.hwua.simplefactory; public class SampleFactory { //根据传入的类型去创建对应的对象 public static Human makeHuman(int type) { if(type==1) { return new Man(); }else if(type == 0) { return new Woman(); }else { return null; } } } //测试类 package com.hwua.simplefactory; public class HumanTest { public static void main(String[] args) { Human human = SampleFactory.makeHuman(0); if(human!=null) { human.say(); }else { System.out.println("没有你要的产品"); } } }
2. 工厂方法模式
工厂方法模式(FACTORY METHOD)是一种常用的对象创建型设计模式,此模式的核心精神是封装 类中不变的部分,提取其中个性化善变的部分为独立类,通过依赖注入以达到解耦、复用和方便后期 维护拓展的目的。它的核心结构有四个角色,分别是抽象工厂;具体工厂;抽象产品;
应用场景:第一种情况是对于某个产品,调用者清楚地知道应该使用哪个具体工厂服务,实例化该具体工 厂,生产出具体的产品来。
package com.hwua.singledemo1; //饿汉式:不管用不用的到都会先创建对象 class SingleTon{ private static SingleTon singleTon =new SingleTon(); private SingleTon() { System.out.println("singleton"); } public static SingleTon getInstance() { return singleTon; } } public class SingleTomDemo1 { public static void main(String[] args) { SingleTon.getInstance(); SingleTon.getInstance(); SingleTon.getInstance(); SingleTon.getInstance(); } }
package com.hwua.singledemo2; //懒汉式:用的时候再创建 class SingleTon { private static SingleTon singleTon = null; private SingleTon() { System.out.println("singleton"); } // 加锁,静态方法获取实例 public static synchronized SingleTon getInstance() { if (singleTon == null) { singleTon = new SingleTon(); } return singleTon; } } public class SingleTomDemo1 { public static void main(String[] args) { for (int i = 0; i < 100; i++) { new Thread() { @Override public void run() { SingleTon.getInstance(); } }.start(); } } }
package com.hwua.singledemo3; //双重检测机制 class SingleTon { private static SingleTon singleTon = null; private SingleTon() { System.out.println("singleton"); } public static SingleTon getInstance() { if (singleTon == null) {// 第一层检测 synchronized (SingleTon.class) { if (singleTon == null) { singleTon = new SingleTon(); } } } return singleTon; } } public class SingleTomDemo1 { public static void main(String[] args) { for (int i = 0; i < 100; i++) { new Thread() { @Override public void run() { SingleTon.getInstance(); } }.start(); } } }
package com.hwua.singledemo4; //静态内部类 class SingleTon { private SingleTon() { System.out.println("singleton"); } //静态内部类不会自动加载,只有当使用这个静态内部类的时候才加载 private static class SingleTonHolder{ private static SingleTon singleTon = new SingleTon(); } public static SingleTon getInstance() { return SingleTonHolder.singleTon; } public static void show() { } } public class SingleTomDemo1 { public static void main(String[] args) { for (int i = 0; i < 100; i++) { new Thread() { @Override public void run() { SingleTon.getInstance(); } }.start(); } } }
3. 构建者模式
建造者模式是属于创建型模式。建造者模式使用多个简单的对象一步一步构建成一个复杂的对象。这 种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式。简单的来说就是将一个复杂 的东西抽离出来,对外提供一个简单的调用,可以在同样的构建过程创建不同的表示。和工厂模式很 相似,不过相比而言更加注重组件的装配。
我们其实根本就不会知道具体是怎么造房子的,因为这个过程让director给代劳了。然后,我们的 HutBuilder类中才是真正的造房子的方法。director其实只是执行了这个过程。这样子,达到了分离模 块的功能。有了一些模块化的感觉,这样维护和扩展都是很方便的。适用一些基本组件不变,但是 组合经常变化的时候。比如超市促销的大礼包。所以设计模式的精髓还是那几个原则。感觉原则才 是法则,而这么多模式就是具体的招式。
demo
4. 责任链模式
责任链模式顾名思义,就是为请求创建了一个接收者对象的链。这种模式给予请求的类型,对请求的 发送者和接收者进行解耦。这种类型的设计模式属于行为型模式。在这种模式中,通常每个接收者都 包含对另一个接收者的引用。如果一个对象不能处理该请求,那么它会把相同的请求传给下一个接收 者,依此类推。
优点:耦合度低,请求者和执行者并没有必然的联系;灵活度高,可以通过内部成员来进行更改它们执 行的次序;扩展性好.
缺点:会在某程度上降低程序的性能,设置不当的话可能会出现循环调用。在链过长时,会降低代码的 阅读性以及增加代码的复杂度。
使用场景:需要动态指定处理某一组请求时,在不确定接受者的的情况下,向多个对象发送请求时。
5. 代理模式
代理模式概念:为其他对象提供一种代理以控制对这个对象的访问。在某些情况下,一个客户不想或 者不能直接引用另一个对象,而代理对象可以在客户端和目标对象之间起到中介的作用
动态代理
动态代理类:在程序运行时,通过反射机制动态生成。
动态代理类通常代理接口下的所有类。
动态代理事先不知道要代理的是什么,只有在运行的时候才能确定。
动态代理的调用处理程序必须事先InvocationHandler接口,及使用Proxy类中的 newProxyInstance方法动态的创建代理类。
Java动态代理只能代理接口,要代理类需要使用第三方的CLIGB等类库。