发表时间:2022-03-25来源:网络
final关键字的作用:
修饰变量: 被他修饰的变量不可改变。一旦赋了初值,就不能被重新赋值。final int MAX_SPEED = 120;
修饰方法:该方法不可被子类重写。但是可以被重载!final void study(){}
修饰类: 修饰的类不能被继承。比如:Math、String、System等。final class A {}
注意:
注意:final不能修饰构造方法final修饰基本数据类型,值只能赋值一次,后续不能再赋值final修饰引用数据类型,final Dog dog = new Dog("亚亚");,不能变化的引用变量的值,可以变化的是对象的属性
接口(interface)就是规范,定义的是一组规则,体现了现实世界中“如果你是…则必须能…”的思想。如果你是天使,则必须能飞。如果你是汽车,则必须能跑。接口的本质是契约,就像我们人间的法律一样。制定好后大家都遵守。
声明格式:
[访问修饰符] interface 接口名 [extends 父接口1,父接口2…] {定义接口的详细说明:
访问修饰符:只能是public或默认。接口名:和类名采用相同命名机制。extends:接口可以多继承。常量:接口中的属性只能是常量,总是:public static final 修饰。不写也是。方法:接口中的方法只能是:public abstract。 省略的话,也是public abstract。总结1:接口的组成
接口和数组、类、抽象类是同一个层次的概念成员变量:接口中所有的变量都使用public static final修饰,都是全局静态常量成员方法: 接口中所有的方法都使用public abstract修饰,都是全局抽象方法构造方法:接口不能new,也没有构造方法接口做方法的形参,实参可以该接口的所有实现类
总结2:接口和多继承
好处 :可以从多个父类继承更多的功能
缺点:不安全 有两个父类Father1,Father2,都有一个方法giveMoney(),子类如果重写了,没有问题,如果子类没有重写,调用giveMoney()是谁的
好处:安全
缺点:功能受限
解决方案:既安全,功能又强大,采用接口。接口变相的使Java实现了C++的多继承,又没有C++多继承的不安全性
public class Bird extends Animal implements Flyable,Sleepable
必须先extends 再implements
对比接口和抽象类的异同
相同:
1 都可以有抽象方法,都要求子类/实现类重写,都是对子类/实现类的要求
2 都不可以被实例化
不同:
1 抽象类是被普通类继承,接口是被普通类实现,只有接口能继承接口
2 一个子类只能继承一个抽象类,一个实现类可以同时实现多个接口
3 抽象类中可以定义普通的成员变量,接口中只能定义共有的静态常量
4 抽象类中可以有非抽象方法,接口中只能是抽象方法(JDK1.7)
5 抽象类中可以有构造方法,接口中没有构造方法的
JDK7及其之前
接口的变量都是public final static 全局静态常量,无变化接口中都是抽象abstract方法,不能有static方法(因为abstract和static、final、private不能共存)JDK8及其之后
接口中可以添加非抽象方法(static),实现类不能重写,只能通过接口名调用。如果子类中定义了相同名字的静态方法,那就是完全不同的方法了,直接从属于子类。可以通过子类名直接调用接口中可以添加非抽象方法(default),实现类可以重写,只能通过对象名调用实现类可以直接使用default方法,可以重写default方法,但是必须去掉default。(default只能接口中使用)上级接口中default方法的调用:MyInterface.super.method2()提供非抽象方法的目的
为了解决实现该接口的实现类代码重复的问题为了既有的成千上万的Java类库的类增加新功能,且不必对这些类重新进行设计。比如只需在Collection接口中增加default Stream stream(),相应的Set和List接口以及它们的子类都包含此的方法,不必为每个子类都重新copy这个方法。JDK9及其之后
接口中可以定义private的非抽象方法,便于将多个方法中的冗余代码进行提取,并且不对外公开。减少冗余、也实现了代码隐藏。
面向接口编程是面向对象编程的一部分。
为什么需要面向接口编程? 软件设计中最难处理的就是需求的复杂变化,需求的变化更多的体现在具体实现上。我们的编程如果围绕具体实现来展开就会陷入”复杂变化”的汪洋大海中,软件也就不能最终实现。我们必须围绕某种稳定的东西开展,才能以静制动,实现规范的高质量的项目。
接口就是规范,就是项目中最稳定的核心! 面向接口编程可以让我们把握住真正核心的东西,使实现复杂多变的需求成为可能。
通过面向接口编程,而不是面向实现类编程,可以大大降低程序模块间的耦合性,提高整个系统的可扩展性和和可维护性。
面向接口编程的概念比接口本身的概念要大得多。设计阶段相对比较困难,在你没有写实现时就要想好接口,接口一变就乱套了,所以设计要比实现难!
图书类、学生类、新闻类、商品类等是不同的类,可是却都需要有比较的功能,怎么办?共同的父类不可以,可以定义一个比较接口Comparable,其中定义一个实现比较的方法compareTo(Object obj)。让各个类实现该接口即可。Java中就是这么来实现的,下面就来模拟实现一下Comparable接口吧。
自定义比较器算法
import java.util.Comparator; public class BJ implements Comparator { @Override public int compare(People o1, People o2) { int age1 = o1.getAge(); int age2 = o2.getAge(); return age1-age2; } }总结一下,两种比较器Comparable和Comparator,后者相比前者有如下优点:
1、如果实现类没有实现Comparable接口,又想对两个类进行比较(或者实现类实现了Comparable接口,但是对compareTo方法内的比较算法不满意),那么可以实现Comparator接口,自定义一个比较器,写比较算法
2、实现Comparable接口的方式比实现Comparator接口的耦合性 要强一些,如果要修改比较算法,要修改Comparable接口的实现类,而实现Comparator的类是在外部进行比较的,不需要对实现类有任何修 改。从这个角度说,其实有些不太好,尤其在我们将实现类的.class文件打成一个.jar文件提供给开发者使用的时候。实际上实现Comparator 接口的方式后面会写到就是一种典型的策略模式。
内部类是一类特殊的类,指的是定义在一个类的内部的类。实际开发中,为了方便的使用外部类的相关属性和方法,这时候我们通常会定义一个内部类。
一般情况,我们把类定义成独立的单元。有些情况下,我们把一个类放在另一个类的内部定义,称为内部类(innerclasses)。
在Java中内部类主要分为成员非静态成员内部类、静态成员内部类、局部内部类、匿名内部类。
作为类的成员存在,和成员变量、成员方法、构造方法、代码块并列。因为是类的成员,所以非静态成员内部类可以使用public、protected 、默认、private修饰,而外部类只能使用public、默认修饰。
总结1:基本特征
内部类可以直接访问外部类的成员外部类不能直接访问内部类的成员,需要先创建对象再通过对象名访问内部类如何访问外部类的同名成员变量:OuterClass.this.num必须先创建外部类的对象,才能创建内部类的对象。非静态成员内部类是属于某个外部类对象的总结2:更多特征
非静态内部类不能有静态方法、静态属性和静态初始化块。外部类的静态方法、静态代码块不能访问非静态内部类,包括不能使用非静态内部类定义变量、创建实例。总结:
静态内部类只能够访问外部类的静态成员静态内部类如何访问外部类的同名的成员变量:OuterClass.num静态内部类属于整个外部类的。创建静态内部类的对象,不需先创建外部类的对象外部类可以通过类名直接访问内部类的静态成员,访问非静态成员依旧需要先创建内部类对象。还有一种内部类,它是定义在方法内部的,作用域只限于本方法,称为局部内部类。
局部内部类的的使用主要是用来解决比较复杂的问题,想创建一个类来辅助我们的解决方案,到那时又不希望这个类是公共可用的,所以就产生了局部内部类。局部内部类和成员内部类一样被编译,只是它的作用域发生了改变,它只能在该方法中被使用,出了该方法就会失效。
局部内部类在实际开发中应用很少。
注意:局部内部类访问所在方法的局部变量,要求局部变量必须使用final修饰。JDK1.8中final可以省略,但是编译后仍旧会加final。
匿名内部类就是内部类的简化写法,是一种特殊的局部内部类。
前提:存在一个类或者接口,这里的类可以是具体类也可以是抽象类。
本质是什么呢?是一个继承了该类或者实现了该接口的子类匿名对象。
适合那种只需要创建一次对象的类。比如:Java GUI编程、Android编程键盘监听操作等等。比如Java开发中的线程任务Runnble、外部比较器Comparator等。
package com.bjsxt.innerClassDemo4; /* * 当一个接口中/抽象类中 抽象方法的数量比较少 应用的位置也比较少 * 接口的实现类对象 应用位置也比较少 * 用一个类去实现接口就显得比较麻烦 * 可以通过局部内部类去简化写法 * 匿名内部类可以帮助我们快速的为接口或者抽象类产生一个实现对象/子类对象 * 匿名内部类没有构造方法 * 匿名内部类自定义的方法和属性的getset方法往往是无法调用的 * 只能使用代码块对成员变量进行初始化 * 匿名内部类作为局部内部类的一种,是方法内的内部类 * * * */ public class Test1 { public static void main(String[] args) { int value=10; A a=new A(){ private String name; { String[] names={"Tom","Jhon","Mark","King","Allen","Scott"}; int index =(int)(Math.random()*names.length); name=names[index]; } public void methodA(){ } public void setName(String name){ this.name=name; } @Override public int getNum(int i) { System.out.println(name); System.out.println(value); methodA(); return (int)(Math.random()*i); } }; System.out.println(a.getNum(10)); B b =new B(){ @Override public int getNum(int i) { return 10; } }; } } interface A{ /** * 根据范围返回随机正整数 * @param i 范围 * @return 随机整数,不包含给定的范围值 */ int getNum(int i); } abstract class B{ public abstract int getNum(int i); }语法:
new 父类构造器(实参类表) \实现接口 () {结论:
匿名内部类可以实现一个接口,也可以继承一个类(可以是抽象类)。匿名内部类只能实现一个接口,而不是多个必须实现所有的方法,匿名内部类不能是抽象类匿名内部类不可能有构造方法,因为类是匿名的匿名内部类没有访问修饰符如果想实现构造方法的一些初始化功能,可以通过代码块实现如果要访问所在方法的局部变量,该变量需要使用final修饰。(JDK1.8可省略final)内部类的作用:
内部类提供了更小的封装。只能让外部类直接访问,不允许同一个包中的其他类直接访问。内部类可以直接访问外部类的私有属性,内部类被当成其外部类的成员。 但外部类不能访问内部类的内部属性。接口只是解决了多重继承的部分问题,而内部类使得多重继承的解决方案变得更加完整。用匿名内部类实现回调功能。我们用通俗讲解就是说在Java中,通常就是编写一个接口,然后你来实现这个接口,然后把这个接口的一个对象作以参数的形式传到另一个程序方法中, 然后通过接口调用你的方法,匿名内部类就可以很好的展现了这一种回调功能内部类的使用场合:
由于内部类提供了更好的封装特性,并且可以很方便的访问外部类的属性。所以,在只为外部类提供服务的情况下可以优先考虑使用内部类。使用内部类间接实现多继承:每个内部类都能独立地继承一个类或者实现某些接口,所以无论外部类是否已经继承了某个类或者实现了某些接口,对于内部类没有任何影响。虚拟机指通过软件模拟的具有完整硬件系统功能的、运行在一个完全隔离环境中的完整计算机系统。Java虚拟机对字节码进行解释生成对应平台的机器码并执行。Java虚拟机是Java跨平台的重要原因。
Java虚拟机在执行Java程序的过程中会把它所管理的内存划分为若干个不同的数据区域。
主要包括类加载器、运行时数据区、执行引擎、本地方法接口、本地方法库、垃圾回收器。其中重点关注的运行时数据区,又可细分为方法区、堆区、虚拟机栈、本地方法栈、程序计数器,其中方法区和堆区为进程的所有子线程共享,其它的为线程独有。

程序计数器
程序计数器是一块较小的内存空间,它的作用可以看作是当前线程所执行的字节码的行号指示器。每个线程都有一个独立的程序计数器,各条线程之间的计数器互不影响,独立存储,是线程私有内存。如果正在执行Native方法,则这个计数器为空。
Java虚拟机栈(Java Virtal Machine Stack)
同样也是属于线程私有区域,每个线程在创建的时候都会创建一个虚拟机栈,生命周期与线程一致,线程退出时,线程的虚拟机栈也回收。虚拟机栈内部保持一个个的栈帧,每次方法调用都会进行压栈,JVM对栈帧的操作只有出栈和压栈两种,方法调用结束时会进行出栈操作。该区域存储着局部变量表,编译时期可知的各种基本类型数据、对象引用、方法出口等信息。
本地方法栈(Native Method Stack)
与虚拟机栈类似,本地方法栈是在调用本地方法时使用的栈,每个线程都有一个本地方法栈。
Java堆(heap)
Java堆是垃圾收集器管理的主要区域,因此很多时候也被称为GC堆,Java堆是被所有线程共享的一块内存区域,在虚拟机启动时创建。此区域的唯一目的就是存放对象实例,几乎所有对象的实例都在这分配内存。
方法区
方法区和Java堆一样,是各个线程共享的内存区域,它用于存储已被虚拟机加载的类信息(Class对象,反射机制中重点讲授),常量,静态变量,即时编译器编译后的代码等数据。
方法区是一种Java虚拟机的规范。由于方法区存储的数据和堆中存储的数据一致,实质上也是堆,因此,在不同的JDK版本中方法区的实现方式不一样。
堆内存分为三部分
1.年轻代:Young
2.老年代:Tenured
3.永久代 PermGen JDK8中变成元空间MetaSpace


年轻代:分为eden区+两个大小相同的存活期s0、s1;
所有使用关键字new新实例化的对象,一定会在伊甸园区进行保存(除非大对象,伊甸园区容不下);存活区会分为两个相等大小的存活区,存活区保存的一定是在伊甸园区保存好久,并且经过了好几次的小GC还保存下来的活跃对象,那么这个对象将晋升到存活区中。
存活区一定会有两块大小相等的空间。目的是一块存活区未来晋升,另外一块存活区为了对象回收。这两块内存空间一定有一块是空的。
在年轻代中使用的是MinorGC,这种GC采用的是复制算法
老年代
主要接收由年轻代发送过来的对象,一般情况下,经过了数次Minor GC 之后还会保存下来的对象才会进入到老年代。每次进行Minor GC 后存活的对象,年龄都会+1,到了一定年龄后(默认15),进入老年代
如果要保存的对象超过了伊甸园区的大小,此对象也将直接保存在老年代之中;
当老年代内存不足时,将引发 “major GC”,即,“Full GC”。
永久代
永久代:是HotSpot的一种具体实现,实际指的就是方法区,JDK1.8 之后将最初的永久代内存空间取消了,代之以元空间(metaspace)。
为什么废弃永久代:除永久代是为融合HotSpot JVM与 JRockit VM而做出的努力,因为JRockit没有永久代,不需要配置永久代。另外由于永久代内存经常不够用或发生内存泄露,爆出异常java.lang.OutOfMemoryError: PermGen。
元空间功能和永久代类似,唯一到的区别是:永久代使用的是JVM的堆内存空间,而元空间使用的是物理内存,直接受到本机的物理内存限制。
注意1:
JDK6 及以前版本,字符串常量池是放在永久代的(方法区)。JDK7 的版本中,字符串常量池已经从Perm区移到正常的Java Heap区域了。为什么要移动,Perm 区域太小是一个主要原因JDK8中,永久代被元空间替代。注意2:
现在最新的垃圾回收算法中取消了年轻代、老年代的划分。方法区也几经变迁,但是对于我们初始学习时候,仍可按照最初的规范讲解,先熟悉基本的概念,不必过细的深入底层。
扩展:内存泄漏和内存溢出Java引入了垃圾回收机制(Garbage Collection),令C++程序员最头疼的内存管理问题迎刃而解。Java程序员可以将更多的精力放到业务逻辑上而不是内存管理工作上,大大的提高了开发效率。
不同类型的、不同版本的虚拟机有不同的垃圾回收器。各种垃圾回收器的回收算法也会有不同,表现各异。此处讲解一种分代垃圾回收机制。
分代垃圾回收机制,是基于这样一个事实:不同的对象的生命周期是不一样的。因此,不同生命周期的对象可以采取不同的回收算法,以便提高回收效率。我们将对象分为三种状态:年轻代、年老代、持久代。同时,将处于不同状态的对象放到堆中不同的区域。 JVM将堆内存划分为 Eden、Survivor 和 Tenured/Old 空间。
1. 年轻代:所有新生成的对象首先都是放在Eden区。 年轻代的目标就是尽可能快速的收集掉那些生命周期短的对象,对应的是Minor GC,每次 Minor GC 会清理年轻代的内存,算法采用效率较高的复制算法,频繁的操作,但是会浪费内存空间。当“年轻代”区域存放满对象后,就将对象存放到年老代区域。
2. 年老代:在年轻代中经历了N(默认15)次垃圾回收后仍然存活的对象,就会被放到年老代中。因此,可以认为年老代中存放的都是一些生命周期较长的对象。年老代对象越来越多,我们就需要启动Major GC和Full GC(全量回收),来一次大扫除,全面清理年轻代区域和年老代区域。
3. 永久代:用于存放静态文件,如Java类、方法等。持久代对垃圾回收没有显著影响。JDK7以前就是“方法区”的一种实现。JDK8以后已经没有“永久代”了,使用metaspace元数据空间和堆替代。

垃圾回收的相关技能点
垃圾回收机制主要是回收JVM堆内存里的对象空间。垃圾回收发生具有不可预知性,程序无法精确控制垃圾回收机制执行。STW:stop the world。垃圾回收时会暂停所有程序执行,不同的垃圾算法暂停的时间会差异很大。减少STW时间也是各垃圾回收算法追求的目标。可以将对象的引用变量设置为null,暗示垃圾回收机制可以回收该对象。程序员可以通过System.gc()或者Runtime.getRuntime().gc()来通知系统进行垃圾回收,会有一些效果,但是系统是否进行垃圾回收依然不确定。垃圾回收机制回收任何对象之前,总会先调用它的finalize方法(如果覆盖该方法,让一个新的引用变量重新引用该对象,则会重新激活对象)。永远不要主动调用某个对象的finalize方法,应该交给垃圾回收机制调用。上一篇:小白学JAVA之十四
下一篇:小白如何自学java
皓盘云建最新版下载v9.0 安卓版
53.38MB |商务办公
ris云客移动销售系统最新版下载v1.1.25 安卓手机版
42.71M |商务办公
粤语翻译帮app下载v1.1.1 安卓版
60.01MB |生活服务
人生笔记app官方版下载v1.19.4 安卓版
125.88MB |系统工具
萝卜笔记app下载v1.1.6 安卓版
46.29MB |生活服务
贯联商户端app下载v6.1.8 安卓版
12.54MB |商务办公
jotmo笔记app下载v2.30.0 安卓版
50.06MB |系统工具
鑫钜出行共享汽车app下载v1.5.2
44.7M |生活服务