2021-07-04

Java查漏补缺-基础篇-面向对象相关知识:单例模式、抽象、接口新特性与内部类

Java基础篇

面向对象

单例模式

定义

单例模式,就是采取一定的方法保证在整个的软件系统中,对某个类只能存在一个对象实例(哪怕是多线程),并且该类只提供一个取得其对象实例的方法。

如果要让一个类在JVM中只产生一个实例,可以采用以下方法:

  • 类的构造器的访问权限设置为private => 这样在类的外部无法通过new操作符获取类的实例
  • 此时,在类的内部可以产生该类的对象,由于类外部无法获取实例,因此需要提供一个静态方法来返回类内部创建的实例
  • 由于静态方法只能访问类中的静态成员变量,因此,类内部创建的实例必须定义为static的

分类

饿汉式(线程安全)
public class Singletion{	private Singletion() {		}		private static Singleton single = new Singletion();  public static Singleton getInstance() {  return single; }}
懒汉式

以下代码存在线程安全问题:如果有多个访问者同时去获取对象实例,就像⼀堆人在抢厕所,就会造成多个同样的实例并存,从而没有达到单例的要求。

public class Singletion{	private Singletion() {		}		private static Singleton single = null;  public static Singleton getInstance() {  if (single == null) {   single = new Singleton();  }  return single; }}

修复线程安全问题

  • 使用synchronized关键字(不推荐)

由于把锁加到⽅法上后,所有的访问都因需要锁占⽤导致资源的浪费。 如果不是特殊情况下,不建议此种⽅式实现单例模式。

public class Singletion{	private Singletion() {		}		private static Singleton single = null;  public static synchronized Singleton getInstance() {  if (single == null) {   single = new Singleton();  }  return single; }}
  • 使用内部类(推荐)

既保证了线程安全有保证了懒加载,同时不会因为加锁的方式耗费性能。因为JVM虚拟机可以保证多线程并发访问的正确性,也就是⼀个类的构造方法在多线程环境下可以被正确的加载。

public class Singleton { private static class SingletonHolder {  private static Singleton single = new Singleton(); } 	private Singletion() {		}  public static Singleton getInstance() {  return SingletonHolder.single; }}
  • 双重锁校验

双重锁校验是方法级锁的优化,减少了部分获取实例的耗时。

public class Singletion{	private Singletion() {		}		private static Singleton single = null;  public static Singleton getInstance() {  if (single != null) {   return single;  }  synchronized (Singleton.class) {   if (single == null) {    single = new Singleton();   }  }  return single; }}

优点

由于单例模式只生成一个实例,减少了系统性能开销,当一个对象的产生需要比较多的资源时,e.g.读取配置、产生其他依赖对象,则可以通过在应用启动时直接产生一个单例对象,然后永久驻留内存的方式来解决。(e.g.java.lang.Runtime)

应用场景

  • 网站的计数器:如不采用单例模式则难以实现同步
  • 应用程序的日志应用:一般都使用单例模式实现,因为共享的日志文件一般一直处于打开状态,只能有一个实例去操作,否则内容不便于追加
  • 数据库连接池:数据库连接是一种数据库资源
  • 读取配置文件的类:配置文件也是一种资源,没有必要每次使用配置文件数据,都生成一个对象去读取
  • Windows的任务管理器和回收站

注意

在平时的开发中如果可以确保此类是全局可用不需要做懒加载,那么直接创建并给外部调用即可。但如果是很多的类,有些需要在用户触发⼀定的条件后(游戏关卡)才显示,那么⼀定要用懒加载。线程的安全上可以按需选择。

抽象类与抽象方法

抽象类是用来模型化那些父类无法确定全部实现,而是由其子类提供具体实现的对象的类。

相关概念

  • 抽象类:用abstract修饰的类
  • 抽象方法:用abstract修饰的方法,只有方法的声明,没有方法的实现,即没有方法体,该方法的实现由抽象类的子类提供
  • 含有抽象方法的类必须声明为抽象类
  • 抽象类中一定有构造器。
  • 抽象类是用来被继承的,它不能被实例化,其子类必须重写抽象方法,提供方法体;若未重写全部抽象方法,则子类仍然是抽象类
  • 不能用abstract修饰变量、代码块、构造器、私有方法、静态方法、final方法、final类
abstract class A { abstract void method1(); public void method2() {  System.out.println("methon2"); }}class B extends A { void method1() {  System.out.println("methon1 in class B"); }}public class Test { public static void main(String[] args) {  A instance = new B();  instance.methon1();  instance.method2(); }}

应用:模板方法设计模式

模板方法:当功能内部一部分实现是确定的,一部分实现是不确定的,这时可以将不确定的部分暴露出去,让子类去实现。

抽象类体现的就是一种模板模式的设计,抽象类作为多个子类的通用模板,子类在抽象类的基础上进行扩展改造,但子类总体上会保留抽象类的行为方式。

模板方法的核心设计思路是:在抽象类中定义抽象方法的执行顺序(执行策略与标准),并将抽象方法设定为只有子类实现,但不设计独立访问的方法。

接口

概念

接口就是规范,定义的是一组规则,体现了现实世界中"如果你是/要...则必须能..."的思想。

继承:"是不是"的关系

接口:"能不能"的关系

接口的本质是契约、标准、规范,制定好后大家都要遵守。

接口是抽象方法常量值定义的集合。

特点

  • 使用关键字interface
  • 接口中所有成员变量默认是用public static final修饰
  • 接口中所有抽象方法默认是用public abstract修饰
  • 接口中没有构造器
  • 接口采用多继承机制,一个类可以实现多个接口,接口也可以继承其他接口

e.g.接口定义

public interface Runner { int ID = 1; // public static final int ID = 1 void start(); // public abstract void start() void run(); // public abstract void run() void stop(); // public abstract void stop()}
  • 一个类既有继承又有实现时,先写extends后写implements

e.g. class SubClass extends SuperClass implements InterfaceA{}

  • 接口的实现类中必须提供接口中所有方法具体实现内容才能实例化,否则仍然是抽象类

应用:代理模式

代理模式是Java开发中使用较多的一种设计模式。代理设计就是为其他对象提供一种代理以控制对这个对象的访问

public interface Network { public void browse();}// 被代理类class RealServer implements Network { @Override public void browse() {  System.out.println("真实服务器上网流量信息"); }}// 代理类class ProxyServer implements Network { private Network network; public ProxyServer(Network n) {  this.network = n; } public void check() {  System.out.println("检查网络连接"); } public void browse() {  // 代理做的一些其他行为  check();  network.browse(); }}public class ProxyDemo { public static void main(String[] args) {  Network net = new ProxyServer(new RealServer());  net.browse(); }}
场景
  • 安全代理:屏蔽对真实角色的直接访问
  • 远程代理:通过代理类处理远程方法调用
  • 延迟加载:先加载轻量级的代理对象,真正需要再加载真实对象

e.g. 开发一个大文档查看软件,其中有较大的图片,在打开文件时不可能将所有的图片都显示出来,就可以使用代理模式,当需要查看图片时,用proxy来进行大图片的打开

分类
  • 静态代理:静态定义代理类
  • 动态代理:动态生成代理类,JDK自带动态代理,涉及到反射

应用:工厂模式

工厂模式实现了创建者与调用者的分离,即将创建对象的具体过程屏蔽隔离起来,达到提高灵活性的目的。

工厂模式分为3种:

  • 简单工厂模式:用来生产同一等级结构中的任意产品。(对于增加新的产品,需要修改已有代码,违反了开闭原则
// 工厂类class CarFactory { public static Car getCar(String type) {  if ("奥迪".equals(type)) {  	return new Audi();  } else if ("比亚迪".equals(type)) {  	return new BYD();  } else {  	return null; 	}	}}public class Test {	public static void main(String[] args) {  Car a = CarFactory.getCar("奥迪");  a.run();  Car b = CarFactory.getCar("比亚迪");  b.run(); } }

调用者只需要知道他要什么,从哪里拿和如何创建是不需要知道的。多出了一个专门生产Car的工厂类,把调用者与创建者分离

由于工厂类一般使用静态方法,通过接收参数来决定返回什么实例对象,因此简单工厂模式也叫静态工厂模式。

  • 工厂方法模式:用来生产同一等级结构中的固定产品。(支持增加任意产品
interface Car { void run();}class Audi implements Car { public void run(){}}class BYD implements Car { public void run(){}}// 工厂接口interface Factory { Cat getCar();}// 两个工厂类class AudiFactory implements Factory { public Audi getCar() {  return new Audi(); }}class BYDFactory implements Factory { public BYD getCar() {  return new BYD(); }}public class Test {	public static void main(String[] args) {  Car a = new AudiFactory().getCar();  a.run();  Car b = new BYDFactory().getCar();  b.run(); } }

简单工厂模式只有一个工厂类(对于一个项目/一个独立的模块),而工厂方法模式有一组实现了相同接口的工厂类,这样在简单工厂模式里集中在工厂方法上的压力可以有工厂方法模式里不同的工厂实现类来分担。

工厂方法模式也没有真正的避免代码改动,要么将判断逻辑留在抽象工厂角色中,要么在客户程序中将具体工厂角色固定(如上述例子),且产品对象创建条件的改变必然会引起工厂角色修改,面对这种情况,Java的反射机制与配置文件的巧妙结合突破了限制(体现在Spring中)。

  • 抽象工厂模式:用来生产不同产品族的全部产品。(对于增加新的产品无能为力,但支持增加产品族

抽象工厂模式和工厂方法模式的区别在于需要创建对象的复杂程度。抽象工厂模式的用意是给客户端提供一个接口,可以创建多个产品族中的产品对象

使用抽象工厂模式需要满足:

1)系统中有多个产品族,且系统一次只可能消费其中一族产品;

2)同属于同一产品族的产品一起使用

核心本质:实例化对象时用工厂方法代替new操作。

接口与抽象类对比

JDK8中的新特性

在JDK7及之前,接口是一种特殊的抽象类,只包含常量和抽象方法的定义,而没有变量和方法的实现。

  • 除了定义全局常量和抽象方法之外,还可以定义静态方法和默认方法
    • 静态方法:使用static修饰,实现类的实例无法获取静态方法只能通过接口调用
    • 默认方法:使用default修饰,只能通过实现类的实例来调用。如果实现了重写了默认方法,则调用的是重写后的方法。
public interface CompareA { // 静态方法 public static void method1() {  System.out.println("method1"); } // 默认方法 public default void method2() {  System.out.println("method2"); }}class SubClass implements CompareA { }public class SubClassDemo { public static void main(String[] args) {  SubClass s = new SubClass();  s.method1(); // 报错  CompareA.method1();  s.method2();  CompareA.method2(); ......

原文转载:http://www.shaoqun.com/a/846147.html

跨境电商:https://www.ikjzd.com/

周宁:https://www.ikjzd.com/w/1647

拍怕:https://www.ikjzd.com/w/2205

网络星期一:https://www.ikjzd.com/w/80


Java基础篇面向对象单例模式定义单例模式,就是采取一定的方法保证在整个的软件系统中,对某个类只能存在一个对象实例(哪怕是多线程),并且该类只提供一个取得其对象实例的方法。如果要让一个类在JVM中只产生一个实例,可以采用以下方法:将类的构造器的访问权限设置为private=>这样在类的外部无法通过new操作符获取类的实例此时,在类的内部可以产生该类的对象,由于类外部无法获取实例,因此需要提供
美森:https://www.ikjzd.com/w/1693
2018年全球购物App下载量报告出炉:Wish勇夺第一!:https://www.ikjzd.com/articles/15757
亚马逊各大促销活动BD,LD,DOTA详细解析!:https://www.ikjzd.com/articles/15758
四大方法,让你短时间内在亚马逊上找准热门产品:https://www.ikjzd.com/articles/15759
刚刚,全球"最有钱"国家宣布:美元不够用,我自己来印!:https://www.ikjzd.com/articles/15761
好湿好紧好浪好大好爽 老师在教室猛烈要了我:http://lady.shaoqun.com/a/247591.html
少妇被粗大的猛烈进出 三根根巨大同时填满:http://lady.shaoqun.com/m/a/247943.html
总裁埋头在双腿间吸允 啃咬她双腿之间的小核:http://www.30bags.com/m/a/249705.html
女人没有老公怎么解决老公的生活?已婚女性说实话!:http://lady.shaoqun.com/a/401732.html
我老公一夜没回,看他老婆怎么做。:http://lady.shaoqun.com/a/401733.html
绵阳狂欢岛冒险水世界有哪些好玩的项目?:http://www.30bags.com/a/471650.html
性功能障碍的症状及预防方法:http://lady.shaoqun.com/a/401734.html

No comments:

Post a Comment