【java学习】

java学习

一、JDK

JDK是Java开发工具包,其中包括编译工具(javac.exe)打包工具(jar.exe)等,也包括JRE。
在JDK的安装目录下有一个jre目录,里面有两个文件夹bin和lib,在这里可以认为bin里的就是jvm,lib中则是jvm工作所需要的类库,而jvm和 lib合起来就称为jre。
JDK是整个JAVA的核心,包括了Java运行环境,Java工具(javac/java/jdb等)和Java基础的类库(即Java API 包括rt.jar)
JDK安装目录下面有六个文件夹、一个src类库源码压缩包、和其他几个声明文件。其中真正在运行java时起作用的是 bin、include、lib、 jre这四个文件夹。
bin:最主要的是编译器(javac.exe)
include:java和JVM交互用的头文件
lib:类库
jre:java运行环境
关系:JDK包含JRE,而JRE包含JVM
总结:JDK用于java程序的开发,JRE只能运行class而没有编译的功能。

二、JRE

JRE,即Java运行环境,包含JVM标准实现(Jvm虚拟机)与Java核心类库。
单独有JVM不能执行class,因为在解释class的时候JVM需要调用解释所需要的类库lib(jre里有运行.class的java.exe)。在JRE目录里有bin和lib两个文件夹,可以认为bin里的就是jvm,lib中则是jvm工作所需要的类库,而jvm和 lib和起来就称为jre。所以,当写完java程序编译成.class之后,可以把这个.class文件和jre一起打包发给朋友,这样你的朋友就可以运行你写程序了。
总结:JRE 是运行 Java 程序必不可少的,编写好的Java程序必须要JRE才能运行。如果想要运行一个开发好的Java程序,计算机中只需要安装JRE即可。

三、JVM

JVM,即java虚拟机,是java运行时的环境,JVM是一种用于计算设备的规范,它是一个虚构出来的计算机,是通过在实际的计算机上仿真模拟各种计算机功能来实现的。Java虚拟机在执行字节码时,把字节码解释成具体平台上的机器指令执行,这就是Java能够“一次编译,到处运行”的原因。
它是整个java实现跨平台的最核心的部分,所有的java程序会先被编译为.class的类文件,该类型文件可以在虚拟机上执行,也就是说class并不直接与机器的操作系统相对应,而是经过虚拟机间接与操作系统交互,由虚拟机将程序解释给本地系统执行。
总结:可以把JVM理解为是一个虚拟出来的计算机,具备着计算机的基本运算方式,主要负责将java程序生成的字节码文件解释成具体系统平台上的机器指令。

四、三者的联系

JVM不能单独搞定class的执行,解释class的时候JVM需要调用JRE的类库lib。在JRE目录里有两个文件夹bin和lib,可以认为bin里的就是jvm,lib里的则是jvm工作所需要的类库,而jvm和 lib和起来就称为JRE。
利用JDK(调用JAVA API)开发了JAVA程序后,通过JDK中的编译程序(javac)将java文件编译成JAVA字节码,在JRE上运行这些JAVA字节码,JVM解析这些字节码,映射到CPU指令集或OS的系统调用。
在这里插入图片描述

五、三者的区别

JDK和JRE区别:JDK的bin目录里有javac.exe而JRE里面没有,javac指令是用来将java文件编译成class文件的,这是开发者需要的,而用户是不需要的。JDK还有jar.exe, javadoc.exe等用于开发的可执行指令文件。证实了一个jdk是开发环境,而jre是运行环境。
注意: JVM并不代表可以执行class,因为JVM执行.class还需要JRE下的lib类库的支持,尤其是rt.jar。

六、总结

JDK(Java Development Kit)是针对Java开发员的产品,是整个Java的核心,包括了Java运行环境JRE、Java工具和Java基础类库。
JRE(Java Runtime Environment)是运行JAVA程序所必须的环境的集合,包含JVM标准实现及Java核心类库。
JVM(Java Virtual Machine)即Java虚拟机,是整个java实现跨平台的最核心的部分,能够运行以Java语言写作的软件程序。

switch不通用法

1.标准写法

int dayOfWeek = 2;
switch (dayOfWeek) {
    case 1:
        System.out.println("星期一");
    case 2:
        System.out.println("星期二");
    case 3:
        System.out.println("星期三");
    case 4:
        System.out.println("星期四");
    case 5:
        System.out.println("星期五");
    case 6:
        System.out.println("星期六");
    default:
        System.out.println("星期日");
}

防止case穿透

int dayOfWeek = 2;
switch (dayOfWeek) {
    case 1:
        System.out.println("星期一");
        break;
    case 2:
        System.out.println("星期二");
        break;
    case 3:
        System.out.println("星期三");
        break;
    case 4:
        System.out.println("星期四");
        break;
    case 5:
        System.out.println("星期五");
        break;
    case 6:
        System.out.println("星期六");
        break;
    default:
        System.out.println("星期日");
        break;
}

2.lambda表达式简化书写jdk12以后

int dayOfWeek = 2;
switch (dayOfWeek) {
    case 1 -> System.out.println("星期一");
    case 2 -> System.out.println("星期二");
    case 3 -> System.out.println("星期三");
    case 4 -> System.out.println("星期四");
    case 5 -> System.out.println("星期五");
    case 6 -> System.out.println("星期六");
    default -> System.out.println("星期日");
}

3.赋值接受

int dayOfWeek = 2;
String weekday = switch (dayOfWeek) {
    case 1:
        yield "星期一";
    case 2:
        yield "星期二";
    case 3:
        yield "星期三";
    case 4:
        yield "星期四";
    case 5:
        yield "星期五";
    case 6:
        yield "星期六";
    default:
        yield "星期日";
};
System.out.println(weekday);

java内存分配

一、 基本概念
每运行一个java程序会产生一个java进程,每个java进程可能包含一个或者多个线程,每一个Java进程对应唯一一个JVM实例,每一个JVM实例唯一对应一个堆,每一个线程有一个自己私有的栈。进程所创建的所有类的实例(也就是对象)或数组(指的是数组的本身,不是引用)都放在堆中,并由该进程所有的线程共享。Java中分配堆内存是自动初始化的,即为一个对象分配内存的时候,会初始化这个对象中变量。虽然Java中所有对象的存储空间都是在堆中分配的,但是这个对象的引用却是在栈中分配,也就是说在建立一个对象时在堆和栈中都分配内存,在堆中分配的内存实际存放这个被创建的对象的本身,而在栈中分配的内存只是存放指向这个堆对象的引用而已。局部变量 new 出来时,在栈空间和堆空间中分配空间,当局部变量生命周期结束后,栈空间立刻被回收,堆空间区域等待GC回收。
具体的概念: JVM的内存可分为3个区: 堆(heap)、栈(stack)和方法区(method,也叫静态区):
堆区:
1.存储的全部是对象,每个对象都包含一个与之对应的class的信息(class的目的是得到操作指令) ;
2.jvm只有一个堆区(heap),且被所有线程共享,堆中不存放基本类型和对象引用,只存放对象本身和数组本身;
栈区:
1.每个线程包含一个栈区,栈中只保存基础数据类型本身和自定义对象的引用;
2.每个栈中的数据(原始类型和对象引用)都是私有的,其他栈不能访问;
3.栈分为3个部分:基本类型变量区、执行环境上下文、操作指令区(存放操作指令);
方法区(静态区):
1.被所有的线程共享,方法区包含所有的class(class是指类的原始代码,要创建一个类的对象,首先要把该类的代码加载到方法区中,并且初始化)和static变量。
2.方法区中包含的都是在整个程序中永远唯一的元素,如class,static变量

内存分配方式

栈:方法运行时使用的内存,比如main方法运行,进入方法栈中执行
堆:存储对象或者数据,new来创建的,都存储在堆内存中
方法区:存储可以于小宁的class文件
本地方栈:jvm在使用操作系统功能是使用,与开发无关
寄存器:CPU使用,与开发无关

1、内存分配有哪些策略
我们从编译原理讲起,不同的开发环境、开发语言都会有不同的策略。一般来说,程序运行时有三种内存分配策略:静态的、栈式的、堆式的

静态存储

是指在编译时就能够确定每个数据目标在运行时的存储空间需求,因而在编译时就可以给它们分配固定的内存空间。
这种分配策略要求程序代码中不允许有可变数据结构的存在,也不允许有嵌套或者递归的结构出现,因为它们都会导致编译程序无法计算准确的存储空间。

栈式存储

栈式存储分配是动态存储分配,是由一个类似于堆栈的运行栈来实现的,和静态存储的分配方式相反。
在栈式存储方案中,程序对数据区的需求在编译时是完全未知的,只有到了运行的时候才能知道,但是规定在运行中进入一个程序模块的时候,必须知道该程序模块所需要的数据区的大小才能分配其内存。和我们在数据结构中所熟知的栈一样,栈式存储分配按照先进后出的原则进行分配。

堆式存储

堆式存储分配专门负责在编译时或运行时,无法确定存储要求的数据结构的内存分配。
比如可变长度串和对象实例,堆由大片的可利用块或空闲块组成,堆中的内存可以按照任意顺序分配和释放。

2.2 堆和栈的比较

上面的定义从编译原理的教材中总结而来,除静态存储分配之外,都显得很呆板和难以理解,下面撇开静态存储分配,集中比较堆和栈:
从堆和栈的功能和作用来通俗的比较,堆主要用来存放对象的,栈主要是用来执行程序的.而这种不同又主要是由于堆和栈的特点决定的:
在编程中,例如C/C++中,所有的方法调用都是通过栈来进行的,所有的局部变量,形式参数都是从栈中分配内存空间的。实际上也不是什么分配,只是从栈顶向上用就行,就好像工厂中的传送带(conveyor belt)一样,Stack Pointer会自动指引你到放东西的位置,你所要做的只是把东西放下来就行.退出函数的时候,修改栈指针就可以把栈中的内容销毁.这样的模式速度最快, 当然要用来运行程序了.需要注意的是,在分配的时候,比如为一个即将要调用的程序模块分配数据区时,应事先知道这个数据区的大小,也就说是虽然分配是在程序运行时进行的,但是分配的大小多少是确定的,不变的,而这个"大小多少"是在编译时确定的,不是在运行时.
堆是应用程序在运行的时候请求操作系统分配给自己内存,由于从操作系统管理的内存分配,所以在分配和销毁时都要占用时间,因此用堆的效率非常低.但是堆的优点在于,编译器不必知道要从堆里分配多少存储空间,也不必知道存储的数据要在堆里停留多长的时间,因此,用堆保存数据时会得到更大的灵活性。事实上,面向对象的多态性,堆内存分配是必不可少的,因为多态变量所需的存储空间只有在运行时创建了对象之后才能确定.在C++中,要求创建一个对象时,只需用 new命令编制相关的代码即可。执行这些代码时,会在堆里自动进行数据的保存.当然,为达到这种灵活性,必然会付出一定的代价:在堆里分配存储空间时会花掉更长的时间!这也正是导致我们刚才所说的效率低的原因,看来列宁同志说的好,人的优点往往也是人的缺点,人的缺点往往也是人的优点(晕~).

2.3 JVM中的堆和栈

JVM是基于堆栈的虚拟机.JVM为每个新创建的线程都分配一个堆栈.也就是说,对于一个Java程序来说,它的运行就是通过对堆栈的操作来完成的。堆栈以帧为单位保存线程的状态。JVM对堆栈只进行两种操作:以帧为单位的压栈和出栈操作。
我们知道,某个线程正在执行的方法称为此线程的当前方法.我们可能不知道,当前方法使用的帧称为当前帧。当线程激活一个Java方法,JVM就会在线程的 Java堆栈里新压入一个帧。这个帧自然成为了当前帧.在此方法执行期间,这个帧将用来保存参数,局部变量,中间计算过程和其他数据.这个帧在这里和编译原理中的活动纪录的概念是差不多的.
从Java的这种分配机制来看,堆栈又可以这样理解:堆栈(Stack)是操作系统在建立某个进程时或者线程(在支持多线程的操作系统中是线程)为这个线程建立的存储区域,该区域具有先进后出的特性。
每一个Java应用都唯一对应一个JVM实例,每一个实例唯一对应一个堆。应用程序在运行中所创建的所有类实例或数组都放在这个堆中,并由应用所有的线程共享.跟C/C++不同,Java中分配堆内存是自动初始化的。Java中所有对象的存储空间都是在堆中分配的,但是这个对象的引用却是在堆栈中分配,也就是说在建立一个对象时从两个地方都分配内存,在堆中分配的内存实际建立这个对象,而在堆栈中分配的内存只是一个指向这个堆对象的指针(引用)而已。

2.4 GC的思考

Java为什么慢?JVM的存在当然是一个原因,但有人说,在Java中,除了简单类型(int,char等)的数据结构,其它都是在堆中分配内存(所以说Java的一切都是对象),这也是程序慢的原因之一。
我的想法是(应该说代表TIJ的观点),如果没有Garbage Collector(GC),上面的说法就是成立的.堆不象栈是连续的空间,没有办法指望堆本身的内存分配能够象堆栈一样拥有传送带般的速度,因为,谁会为你整理庞大的堆空间,让你几乎没有延迟的从堆中获取新的空间呢?
这个时候,GC站出来解决问题.我们都知道GC用来清除内存垃圾,为堆腾出空间供程序使用,但GC同时也担负了另外一个重要的任务,就是要让Java中堆的内存分配和其他语言中堆栈的内存分配一样快,因为速度的问题几乎是众口一词的对Java的诟病.要达到这样的目的,就必须使堆的分配也能够做到象传送带一样,不用自己操心去找空闲空间.这样,GC除了负责清除Garbage外,还要负责整理堆中的对象,把它们转移到一个远离Garbage的纯净空间中无间隔的排列起来,就象堆栈中一样紧凑,这样Heap Pointer就可以方便的指向传送带的起始位置,或者说一个未使用的空间,为下一个需要分配内存的对象"指引方向".因此可以这样说,垃圾收集影响了对象的创建速度,听起来很怪,对不对?
那GC怎样在堆中找到所有存活的对象呢?前面说了,在建立一个对象时,在堆中分配实际建立这个对象的内存,而在堆栈中分配一个指向这个堆对象的指针(引用),那么只要在堆栈(也有可能在静态存储区)找到这个引用,就可以跟踪到所有存活的对象.找到之后,GC将它们从一个堆的块中移到另外一个堆的块中,并将它们一个挨一个的排列起来,就象我们上面说的那样,模拟出了一个栈的结构,但又不是先进后出的分配,而是可以任意分配的,在速度可以保证的情况下, Isn’t it great?
但是,列宁同志说了,人的优点往往也是人的缺点,人的缺点往往也是人的优点(再晕~~).GC()的运行要占用一个线程,这本身就是一个降低程序运行性能的缺陷,更何况这个线程还要在堆中把内存翻来覆去的折腾.不仅如此,如上面所说,堆中存活的对象被搬移了位置,那么所有对这些对象的引用都要重新赋值.这些开销都会导致性能的降低.
此消彼长,GC()的优点带来的效益是否盖过了它的缺点导致的损失,我也没有太多的体会,Bruce Eckel 是Java的支持者,王婆卖瓜,话不能全信.个人总的感觉是,Java还是很慢,它的发展还需要时间.

上面的体会是我看了TIJ.3rdEdition.Revision4.0中第四章之后得出的,内容和前面的有些不同.我没有看过侯捷的中文版本,但我觉得,在关键问题上,原版的TIJ的确更值得一读.所以和中文版配合起来学习是比较不错的选择.
我只能算一个Java的初学者,没想到起了这么个题目,却受到这么多人的关注,欣喜之余,也决心尽力写好下面的每一篇.不过这一篇完了,我就该准备赴美签证了,如果成功,那就要等到8月27号CS的研究生院开学之后,才有时间会开始研究下一章了,希望可以多从原版中获取一点经验.

堆和栈的区别和联系

一、简单的可以理解为:

heap:是由malloc之类函数分配的空间所在地。地址是由低向高增长的。
stack:是自动分配变量,以及函数调用的时候所使用的一些空间。地址是由高向低减少的。

二、堆和栈的理论知识

2.1申请方式

stack:
由系统自动分配。 例如,声明在函数中一个局部变量 int b; 系统自动在栈中为b开辟空间
heap:
需要程序员自己申请,并指明大小,在c中malloc函数
如p1 = (char *)malloc(10);
在C++中用new运算符
如p2 = (char *)malloc(10);
但是注意p1、p2本身是在栈中的。

2.2

申请后系统的响应
栈:只要栈的剩余空间大于所申请空间,系统将为程序提供内存,否则将报异常提示栈溢出。
堆:首先应该知道操作系统有一个记录空闲内存地址的链表,当系统收到程序的申请时,
会遍历该链表,寻找第一个空间大于所申请空间的堆结点,然后将该结点从空闲结点链表中删除,并将该结点的空间分配给程序,另外,对于大多数系统,会在这块内存空间中的首地址处记录本次分配的大小,这样,代码中的delete语句才能正确的释放本内存空间。另外,由于找到的堆结点的大小不一定正好等于申请的大小,系统会自动的将多余的那部分重新放入空闲链表中。

2.3申请大小的限制

栈:在Windows下,栈是向低地址扩展的数据结构,是一块连续的内存的区域。这句话的意思是栈顶的地址和栈的最大容量是系统预先规定好的,在 WINDOWS下,栈的大小是2M(也有的说是1M,总之是一个编译时就确定的常数),如果申请的空间超过栈的剩余空间时,将提示overflow。因此,能从栈获得的空间较小。
堆:堆是向高地址扩展的数据结构,是不连续的内存区域。这是由于系统是用链表来存储的空闲内存地址的,自然是不连续的,而链表的遍历方向是由低地址向高地址。堆的大小受限于计算机系统中有效的虚拟内存。由此可见,堆获得的空间比较灵活,也比较大。

2.4申请效率的比较:

栈由系统自动分配,速度较快。但程序员是无法控制的。
堆是由new分配的内存,一般速度比较慢,而且容易产生内存碎片,不过用起来最方便.
另外,在WINDOWS下,最好的方式是用VirtualAlloc分配内存,他不是在堆,也不是在栈是直接在进程的地址空间中保留一快内存,虽然用起来最不方便。但是速度, 也最灵活

2.5堆和栈中的存储内容

栈: 在函数调用时,第一个进栈的是主函数中后的下一条指令(函数调用语句的下一条可执行语句)的地址,然后是函数的各个参数,在大多数的C编译器中,参数是由右往左入栈的,然后是函数中的局部变量。注意静态变量是不入栈的。
当本次函数调用结束后,局部变量先出栈,然后是参数,最后栈顶指针指向最开始存的地址,也就是主函数中的下一条指令,程序由该点继续运行。
堆:一般是在堆的头部用一个字节存放堆的大小。堆中的具体内容有程序员安排。

抽象类和接口的区别

抽象类和接口的定义:

抽象类(abstract class):

使用abstract修饰符修饰的类。(如果一个类没有包含足够多的信息来描述一个具体的对象,这样的类就是抽象类。)
实际点来说,一个抽象类不能实例化,因为“没有包含足够多的信息来描述一个具体的对象”。但仍然拥有普通类一样的定义。依然可以在类的实体(直白点就是能在{}里面)定义成员变量,成员方法,构造方法等。
抽象方法:只声明,不实现。具体的实现由继承它的子类来实现。实际点就是:被abstract修饰的方法,只有方法名没有方法实现,具体的实现要由子类实现。方法名后面直接跟一个分号,而不是花括号。例如:public abstract int A();
一个类中含有抽象方法(被abstract修饰),那么这个类必须被声明为抽象类(被abstract修饰)。

接口(interface)

定义:接口在java中是一个抽象类型,是抽象方法的集合。一个类通过继承接口的方式,从而继承接口的抽象方法。从定义上看,接口是个集合,并不是类。类描述了属性和方法,而接口只包含方法(未实现的方法)。
接口和抽象类一样不能被实例化,因为不是类。但是接口可以被实现(使用 implements 关键字)。实现某个接口的类必须在类中实现该接口的全部方法。虽然接口内的方法都是抽象的(和抽象方法很像,没有实现)但是不需要abstract关键字。
接口中没有构造方式(因为接口不是类)
接口中的方法必须是抽象的(不能实现)
接口中除了static、final变量,不能有其他变量
接口支持多继承(一个类可以实现多个接口)

抽象类和接口的区别:

1.默认的实现方法:
(1)抽象类可以有默认的方法实现完全是抽象的。
抽象类中可以有已经实现了的方法,也可以有被abstract修饰的方法(抽象方法),因为存在抽象方法,所以该类必须是抽象类。
(2)接口根本不存在方法的实现。
但是接口要求只能包含抽象方法,抽象方法是指没有实现的方法。接口就根本不能存在方法的实现。
2.子类使用的关键词不一样:
(1)实现抽象类使用extends关键字来继承抽象类。如果子类不是抽象类的话,它需要提供抽象类中所有声明的方法的实现。
抽象类虽然不能实例化来使用,但是可以被继承,让子类来具体实现父类的所有抽象方法。但是如果子类将抽象方法没有全部实现,就必须把自己也修饰成抽象类,交于继承它的子类来完成实现。以此类推,直到没有抽象函数。
(2)子类使用关键字implements来实现接口。它需要提供接口中所有声明的方法的实现。
接口的实现,通过implements关键字。实现该接口的类,必须把接口中的所有方法给实现。不能再推给下一代。(和抽象类相比,抽象类是将梦想传给家族,一代一代去完成。那么接口就是掌门人找大师兄来完成帮派的鸿星伟业,这时候就只有一次希望,要么有能力就实现,没能力就不要接。)

3.是否有构造器:

(1)抽象类可以有构造器
抽象类是属于类,享有类的所有特性(但是不能实例化),当然包括类的构造方法,也就是构造器。
(2)接口不能有构造器

接口是所有抽象方法的集合,注意,是集合,不是类。当然没有构造方法一说,更别提什么构造器了。

4.可使用的修饰符:

(1)抽象方法可以有public、protected和default这些修饰符
抽象类的目的就是被继承,抽象方法就是为了被重写,所以肯定不能用private修饰符,肯定是可以用public的。但是protected和default也是可以的。
(2)接口方法默认修饰符是public。你不可以使用其它修饰符。
接口就有且只有一个public修饰。(感觉抽象类像小儿子各种耍无赖,接口就像私生子,说什么只能是什么)

5.速度方面:

(1)抽象方法比接口速度要快(抽象方法是小儿子,从小吃的好所以跑的快)
(2)接口是稍微有点慢的,因为它需要时间去寻找在类中实现的方法。(接口是私生子,从小日子苦,营养不良)

6.增加新方法对子类的影响:
(1)如果你往抽象类中添加新的方法,你可以给它提供默认的实现。因此你不需要改变你现在的代码。
抽象类可以有一些非抽象方法的存在,这些方法被称为默认实现。如果添加一个默认实现方法(不能是抽象方法),就不需要在子类中去实现,所以继承这个抽象类的子类无须改动。
如果你往接口中添加方法,那么你必须改变实现该接口的类。

(2)接口中只能添加抽象方法,当你添加了抽象方法,实现该接口的类就必须实现这个新添加的方法。
因为,定义中说的很清楚,接口的实现必须实现所有的方法。所有,当然包括新添加的方法。

7.子类能继承的数量:

抽象类在java语言中所表示的是一种继承关系,一个子类只能存在一个父类,但是可以存在多个接口。
java在类的继承上并没有多继承。抽象类属于类,所以可以被继承。但子类只能继承一个父类。
java为了实现多继承,使用了接口。一个类可以实现多个接口。继承就好比生了孩子,只能有一个爹,但是这个孩子可以学语文,学数学,学英语等等很多东西,而语文、数学、英语就相当于接口。
总的来说,因为java中抽象类只有单继承,接口就可以实现多继承。

重写和重载

一、java中的重载与重写的区别:

1、重载发生在本类,重写发生在父类与子类之间;
2、重载的方法名必须相同,重写的方法名相同且返回值类型必须相同;
3、重载的参数列表不同,重写的参数列表必须相同。

二、重载(Overload)(同一个类参数不同)

重载发生在本类,方法名相同,参数列表不同,与返回值无关,只和方法名,参数列表,参数的类型有关.
重载(Overload):首先是位于一个类之中或者其子类中,具有相同的方法名,但是方法的参数不同,返回值类型可以相同也可以不同。
(1):方法名必须相同
(2):方法的参数列表一定不一样。
(3):访问修饰符和返回值类型可以相同也可以不同。
其实简单而言:重载就是对于不同的情况写不同的方法。 比如,同一个类中,写不同的构造函数用于初始化不同的参数。

二、重写(Overriding)(父与子类参数相同)

重写发生在父类子类之间,比如所有类都是继承与Object类的,Object类中本身就有equals, hashcode,toString方法等.在任意子类中定义了重名和同样的参数列表就构成方法重写.
重写(override):一般都是表示子类和父类之间的关系,其主要的特征是:方法名相同,参数相同,但是具体的实现不同。

重写的特征:

(1):方法名必须相同,返回值类型必须相同
(2):参数列表必须相同
(3):访问权限不能比父类中被重写的方法的访问权限更低。例如:如果父类的一个方法被声明为public,那么在子类中重写该方法就不能声明为protected。
(4):子类和父类在同一个包中,那么子类可以重写父类所有方法,除了声明为private和final的方法。
(5):构造方法不能被重写,
简单而言:就是具体的实现类对于父类的该方法实现不满意,需要自己在写一个满足于自己要求的方法。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值