• Java中级知识归纳(四)


    十六、Java内存模型

      特点:原子性、可见性、有序性。

      原子性:read、load、use、store、write、synchronized关键字保证原子性

      可见性:synchronized、volatile、final保证可见性

      有序性:synchronized保证有序性

    十七、设计模式

      ①分类

        创建型模式(5种):工厂方法模式、抽象工厂模式、单例模式、建造者模式、原型模式

        结构型模式(7种):适配器模式、装饰器模式、代理模式、外观模式、桥接模式、组合模式、享元模式。

        行为型模式(11种):策略模式、模板方法模式、观察者模式、迭代子模式、责任链模式、命令模式、备忘录模式、状态模式、访问者模式、中介者模式、解释器模式。

        other:并发型模式和线程池模式。

      ②设计模式6大原则

        开闭原则(Open Close Principle):开闭原则就是说对扩展开放,对修改关闭。在程序需要进行拓展的时候,不能去修改原有的代码,实现一个热插拔的效果。所有一句话概括就是:为了使程序的扩展性好,易于维护和升级。想要达到这样的效果,我们需要使用接口和抽象类。

        里氏代换原则(Liskov Substitution Principle,缩写为:LSP):面向对象设计的基本原则之一。里氏代换原则中说,任何基类可以出现的地方,子类一定可以出现。LSP是继承复用的基石,只有当衍生类可以替换掉基类,软件单位的功能不受到影响时,基类才能真正被复用,而衍生类也能够在基类的基础上增加新的行为。里氏代换原则是对“开-闭”原则的补充。实现“开-闭”原则的关键步骤就是抽象化。而基类与子类的继承关系就是抽象化的具体实现,所以里氏代换原则是对实现抽象化的具体步骤的规范。

        依赖倒转原则(Dependence Inversion Principle):这个是开闭原则的基础,具体内容:针对接口编程,依赖于抽象而不依赖具体。

        接口隔离原则(Interface Segregation Principle):这个原则的意思是:使用多个隔离的接口,比使用单个接口要好。还是一个降低类之间的耦合度的意思,从这儿我们看出,其实设计模式就是一个软件的设计思想,从大型软件架构触发,为了升级和维护方便。所以上文中多次出现:降低依赖,降低耦合。

        迪米特法则(最少知道原则)(Demeter Principle):为什么叫最少知道原则,就是说:一个实体应当尽量少的与其他实体之间发生相互作用,使得系统功能模块相对独立。

        合成复用原则(Composite Reuse Principle):原则是尽量使用合成/聚合的方式,而不是使用继承。

    十八、Java反射(重点)

      反射机制指的是程序在运行时能够获取自身的信息。

      为什么要用反射机制?直接创建对象不就可以了吗,这就涉及到了动态与静态的概念:

        静态编译:在编译时确定类型,绑定对象,即通过。

        动态编译:运行时确定类型,绑定对象。动态编译最大限度发挥了java的灵活性,体现了多态的应用,用以降低类之间的藕合性。

      一句话,反射机制的优点就是可以实现动态创建对象和编译,体现出很大的灵活性,特别是在J2EE的开发中它的灵活性就表现得十分明显。

      作用:①首先得根据传入的类的全名来创建Class对象。 ②获得类方法的方法。③  获得类中属性的方法。

      缺点:①性能第一:反射包括了一些动态类型,所以JVM无法对这些代码进行优化。因此,反射操作的效率要比那些非反射操作低得多。我们应该避免在经常被 执行的代码或对性能要求很高的程序中使用反射。②安全限制:使用反射技术要求程序必须在一个没有安全限制的环境中运行。如果一个程序必须在有安全限制的环境中运行,如Applet。③内部暴露:由于反射允许代码执行一些在正常情况下不被允许的操作(比如访问私有的属性和方法),所以使用反射可能会导致意料之外的副作用--代码有功能上的错误,降低可移植性。反射代码破坏了抽象性,因此当平台发生改变的时候,代码的行为就有可能也随着变化。

    十九、Java引用

    ①假设我们在函数中写了如下这个简单的语句:

    StringBuffer str= new StringBuffer("Hello world"); 

    别看这个语句简单,其实包含了如下三个步骤:

    首先,new StringBuffer("Hello world")在堆里申请了一坨内存,把创建好的StringBuffer对象放进去。其次,StringBuffer str声明了一个指针。这个指针本身是存储在栈上的(因为语句写在函数中),可以用来指向某个StringBuffer类型的对象。或者换一种说法,这个指针可以用来保存某个StringBuffer对象的地址。最后,当中这个等于号(赋值符号)把两者关联起来,也就是把刚申请的那一坨内存的地址保存成str的值,完成引用。

    ②final常量的问题

    针对引用类型变量的final修饰符也是很多人搞混淆的地方。实际上final只是修饰指针的值(也就是限定指针保存的地址不能变)。至于该指针指向的对象,内容是否能变,那就管不着了。所以,对于如下语句:

    final StringBuffer strConst = new StringBuffer();

    你可以修改它指向的对象的内容,比如:

    strConst.append(" ");

    但是不能修改它的值,比如:

    strConst = null;

    ③传参的问题:

    例如:System.out.println(str);这个语句又是什么意思捏?这时候就两说了。

    第一种理解:可以认为传进函数的是str这个指针,指针说白了就是一个地址的值,说得再白一点,就是个整数。按照这种理解,就是传值的方式。也就是说,参数传递的是指针本身,所以是传值的。

    第二种理解:可以认为传进去的是StringBuffer对象,按照这种理解,就是传引用方式了。因为我们确实是把对象的地址(也就是引用)给传了进去。

    二十、线程、线程池

    ①创建线程有两种方式:继承Thread或实现Runnable。Thread实现了Runnable接口,提供了一个空的run()方法,所以不论是继承Thread还是实现Runnable,都要有自己的run()方法。一个线程创建后就存在,调用start()方法就开始运行(执行run()方法),调用wait进入等待或调用sleep进入休眠期,顺利运行完毕或休眠被中断或运行过程中出现异常而退出。

    ②wait和sleep比较:sleep方法有:sleep(long millis),sleep(long millis, long nanos),调用sleep方法后,当前线程进入休眠期,暂停执行,但该线程继续拥有监视资源的所有权。到达休眠时间后线程将继续执行,直到完成。若在休眠期另一线程中断该线程,则该线程退出。等待有其它的线程调用notify()或notifyAll()进入调度状态,与其它线程共同争夺监视。

    ③线程池:多线程技术主要解决处理器单元内多个线程执行的问题,它可以显著减少处理器单元的闲置时间,增加处理器单元的吞吐能力。一个线程池包括以下四个基本组成部分:

    A、线程池管理器(ThreadPool):用于创建并管理线程池,包括创建线程池,销毁线程池,添加新任务;

    B、工作线程(PoolWorker):线程池中线程,在没有任务时处于等待状态,可以循环的执行任务;

    C、任务接口(Task):每个任务必须实现的接口,以供工作线程调度任务的执行,它主要规定了任务的入口,任务执行完后的收尾工作,任务的执行状态等;

    D、任务队列(taskQueue):用于存放没有处理的任务。提供一种缓冲机制。

    ④线程池分类:

    A、newFixedThreadPool  创建一个指定工作线程数量的线程池。

    每当提交一个任务就创建一个工作线程,如果工作线程数量达到线程池初始的最大数,则将提交的任务存入到池队列中。

    B、newCachedThreadPool创建一个可缓存的线程池。

    这种类型的线程池特点是:

    1).工作线程的创建数量几乎没有限制(其实也有限制的,数目为Interger.MAX_VALUE), 这样可灵活的往线程池中添加线程。

    2).如果长时间没有往线程池中提交任务,即如果工作线程空闲了指定的时间(默认为1分钟),则该工作线程将自动终止。终止后,如果你又提交了新的任务,则线程池重新创建一个工作线程。

    C、newSingleThreadExecutor创建一个单线程化的Executor,即只创建唯一的工作者线程来执行任务,如果这个线程异常结束,会有另一个取代它,保证顺序执行(我觉得这点是它的特色)。

    单工作线程最大的特点是可保证顺序地执行各个任务,并且在任意给定的时间不会有多个线程是活动的。

    D、newScheduleThreadPool  创建一个定长的线程池,而且支持定时的以及周期性的任务执行,类似于Timer。

    ⑤Executors类,提供了一系列静态工厂方法用于创先线程池,返回的线程池都实现了ExecutorService接口。

    ⑥线程池参数:

    A、corePoolSize(线程池的基本大小)

    B、runnableTaskQueue(任务队列):用于保存等待执行的任务的阻塞队列。

    1)LinkedBlockingQueue:一个基于链表结构的阻塞队列,此队列按FIFO (先进先出) 排序元素,吞吐量通常要高于ArrayBlockingQueue。静态工厂方法Executors.newFixedThreadPool()使用了这个队列。

    2)SynchronousQueue:一个不存储元素的阻塞队列。每个插入操作必须等到另一个线程调用移除操作,否则插入操作一直处于阻塞状态,吞吐量通常要高于LinkedBlockingQueue,静态工厂方法Executors.newCachedThreadPool使用了这个队列。

    3)PriorityBlockingQueue:一个具有优先级的无限阻塞队列。

    C、maximumPoolSize(线程池最大大小):线程池允许创建的最大线程数。

    D、ThreadFactory:用于设置创建线程的工厂,可以通过线程工厂给每个创建出来的线程设置更有意义的名字。

    E、RejectedExecutionHandler(饱和策略):当队列和线程池都满了,说明线程池处于饱和状态,那么必须采取一种策略处理提交的新任务。这个策略默认情况下是AbortPolicy,表示无法处理新任务时抛出异常。以下是JDK1.5提供的四种策略:

    1)AbortPolicy:直接抛出异常。

    2)CallerRunsPolicy:只用调用者所在线程来运行任务。

    3)DiscardOldestPolicy:丢弃队列里最近的一个任务,并执行当前任务。

    4)DiscardPolicy:不处理,丢弃掉。

    5)当然也可以根据应用场景需要来实现RejectedExecutionHandler接口自定义策略。如记录日志或持久化不能处理的任务。

    F、keepAliveTime(线程活动保持时间):线程池的工作线程空闲后,保持存活的时间。所以如果任务很多,并且每个任务执行的时间比较短,可以调大这个时间,提高线程的利用率。

    G、TimeUnit(线程活动保持时间的单位):可选的单位有天(DAYS),小时(HOURS),分钟(MINUTES),毫秒(MILLISECONDS),微秒(MICROSECONDS, 千分之一毫秒)和毫微秒(NANOSECONDS, 千分之一微秒)。

        

  • 相关阅读:
    Android视图动画集合AndoridViewAnimations
    调整窗口大小时进行页面刷新(设定定时器)
    通过拖动来变换元素顺序
    jquery的input:type=file实现文件上传
    ajax请求的data数据格式
    Cookie的新增,设置与清除
    比较两个对象是否一样的代码
    5.3日,7:20开始 阮一峰js的早课学习
    在线代码编辑器使用案例代码
    layui当点击增加的时候,将form中的值获取的添加到table行中代码
  • 原文地址:https://www.cnblogs.com/tizer/p/11361333.html
Copyright © 2020-2023  润新知