无师自通学编程之Java基础(二):继承以及接口
1.继承
继承基本知识详解
当我们在创立一个类的时候,我们总是在继承,默认所有的类都继承了Object类(java的标准根类)
继承的关键字:extends,继承只可以单继承!切记。
继承的真正含义:当创立了一个子类时,其实也隐含的创立了一个基类的对象,只不过这个对象被包装在了导出类的内部,我们可以用super关键字来引用它。
这也就意味着,当我们实例化一个导出类对象时,我们必需要首先实例化它的基类,通常这个必需要在导出类的构造器中实现。
public class Demo5 extends Test2{
Demo5(){
System.out.println(“Demo5已经初始化”);
}
public static void main(String[] args) {
Demo5 demo=new Demo5();
}
}
class Test2 {
Test2(){
System.out.println(“Test2已经实例化”);
}
}
效果:
但是当基类有带参数的构造器时,就必需要显式的写了。
public class Demo5 extends Test2{
Demo5(){
super(3);
System.out.println(“基类的a:”+super.getA());
System.out.println(“Demo5已经初始化”);
}
public static void main(String[] args) {
Demo5 demo=new Demo5();
}
}
class Test2 {
private int a;
Test2(int a){
this.a=a;
System.out.println(“Test2已经实例化”);
}
int getA(){
return this.a;
}
}
效果:
若是不写的话,那么会报错,其实,早在导出类的构造器可以访问基类之前,基类就已经实例化了。
使用super关键字的注意点
Super关键字和this关键字一样,我们知道,实例化一个导出类的同时,也会实例化他的基类,并将 它封装在导出类的对象的内部,而super关键字则可以引用这个对象。
1.Super关键字可以调用基类的方法和变量(前提是有访问的权限)。采用super.*的形式,但是在调用构造器的时候,则直接用super()的形式调用。
2.同样的,super关键字也必需在方法的最前面。
重写
当我们不想对基类的某些方法进行重载时,便可以采用关键字:@Override
重载和重写的异同:
1.重载发生在用一个类中具备相同的函数名但是参数列表不同的几个方法,(返回值不影响),而重写发生在导出类的方法中。
2.1、参数列表必需完全与被重写的方法相同,否则不能称其为重写而是重载。
2、返回的类型必需一直与被重写的方法的返回类型相同,否则不能称其为重写而是重载。
3、访问修饰符的限制肯定要大于被重写方法的访问修饰符(public>protected>default>private)
4、重写方法肯定不能抛出新的检查异常或者者比被重写方法申明更加宽泛的检查型异常。例如:
父类的一个方法申明了一个检查异常IOException,在重写这个方法是就不能抛出Exception,只能抛出IOException的子类异常,可以抛出非检查异常。
向上转型
继承最大的优点其实就是表现在向上转型这一点上,即新类是基类的一种类型。
导出类是基类的一个超集,他可能会含有比基类更多的方法,但是它至少含有基类中所含有的所有方法,在向上转型的过程中,我们唯一担心的事情是丢失方法,而不是获取他们。
简而言之,就是一个父类的引用可以指向子类,反过来尽管可以强转,但是在运行的时候却会报错。
final关键字
final:不可改变的,主要用于:数据,方法和类。
Final数据
当我们想用:
1.一个永不改变的编译常量
2.一个在运行是就初始化的值,而你不希望改变他。
用final修饰基本数据时,保持数值不变,这一点很好了解,但是用final修饰引用时,就规定了这个引用指向的对象不可改变,但是对象本身的内容是可以改变的。
当公告一个变量是final时,假如没有初始化,那么必需在构造器中进行初始化,否则会报错。
Final方法
使用final方法的起因:
1.将方法锁定,以防任何继承类修改它的含义
2.想要确保在继承中保持方法行为不变,不会别重写。
一般,所有公告为private的方法都隐含的被指定为final。
重写只有时在该方法是接口的一部分时才会生效,而private方法或者者final方法则会在继承的时候隐藏起来,就算写一个相同的方法,也不过是新生成了一个新方法而已,并没有覆盖。
Final类
当将一个类公告为final时,也就是说,你不打算继承该类,并且也不允许别人这么做,换句话说,你对该类的设计用不需要做出任何改动,你不希望它有子类。
具体的加载顺序:
public class Demo5 extends Test2 {
static {
System.out.println(“Demo5静态加载”);
}
{
System.out.println(“Demo5显式加载”);
}
Demo5() {
System.out.println(“Demo5已经初始化”);
}
@Override
Exception getA() {
return new NullPointerException();
}
public static void main(String[] args) {
Demo5 demo = new Demo5();
}
}
class Test2 extends Test3 {
static {
System.out.println(“Test2静态加载”);
}
{
System.out.println(“Test2显式加载”);
}
Test2() {
System.out.println(“Test2已经实例化”);
}
Exception getA() {
return new Exception();
}
}
class Test3 {
static {
System.out.println(“Test3静态加载”);
}
{
{
System.out.println(“Test3显式加载”);
}
}
Test3() {
System.out.println(“Test3已经实例化”);
}
}
结果:
由此,可以看出加载的顺序是:
先加载静态代码块(有基类到子类)
再栽在基类的显式代码块以及构造方法
一个准则,静态优先,而后从基类到子类以此实例化
多态
什么是多态
在面向对象的语言中,多态是继笼统、继承后第三个特点
多态通过分离做什么和怎样做,从另外一个角度将接口和实现分离开来,可以改善代码的组织结构和可读性,还能够创立可扩展的程序。
多态的实质是向上转型,即对象既可以作为它自己本身的类型使用,也可以作为他的基类来使用,即基类的引用可以指向子类。
这样带来的便利就是我们创立一个方法时,只要要创立基类的引用即可以传递多种不同的子类进去,这样就实现了多态。
但是,java是怎样知道如何正确的调用对应的方法的呢?
这就涉及到运行时绑定了。
原来,出了final和static方法,所有的方法都是在后期也就是运行时绑定的,只有在运行的时候,java 才才会知道究竟去调用哪一个方法体。
一句话,编译时看类型,运行时看对象。
多态的缺陷
1.私有方法是无法覆盖的,有多态的只有接口中可以继承的方法而已。
2.域和和静态方法。
对于域(成员变量而言,他的解析是在编译时期进行的,因而并没有多态)
public class Demo6 extends hello{
int a=1;
public int getA(){
return this.a;
}
public int getSuperA(){
return super.a;
}
public static void main(String[] args) {
hello hel=new Demo6();
System.out.println(“hello.a=”+hel.a+” hel.getA=”+hel.getA());
Demo6 demo =new Demo6();
System.out.println(“Demo6.a=”+demo.a+” Demo6.getA=”+demo.getA()+” Demo.getSuperA= “+demo.getSuperA());
}
}
class hello{
int a=0;
public int getA(){
return this.a;
}
}
结果:
3.静态方法也是没有多态的,究其起因,今天方法是属于类的,而不是属于每个对象实例的。
4.有时候,在构造器中调用一个被覆盖的方法时,会有意想不到的结果。
public class Deno7 extends test13{
public void draw(){
System.out.println(“Demo7.draw”);
}
public static void main(String[] args) {
Deno7 demo2=new Deno7();
}
}
class test13{
public void draw(){
System.out.println(“test1.draw”);
}
test13(){
draw();
}
}
结果是:
明明想调用test13的draw()方法,但是却返回的是覆盖后的方法避免这类的方法是将draw()方法设为私有的或者者final的,这样就不会不日覆盖了。
接口
笼统类和笼统方法
笼统方法:仅仅有方法公告,但是没有方法体。
E:abstract void f();
笼统类:包含笼统方法的类叫做笼统类。
笼统类不可能被实例化,否则编译器会报错。假如继承一个笼统类,并且想要为该类创立实例,那么就必需对基类的所有的笼统方法提供方法定义。
(可以这么说,笼统类不肯定包含笼统方法,但是包含笼统方法肯定是笼统类)
接口
1.接口是一种特殊的笼统类,它里面所有的方法都是笼统方法,用interface来定义,没有提供任何具体的实现,它允许人们通过创立一个能被向上转型为多种基类的类型,来实现相似多种继承的特性。
2.接口可以包括成员变量,但是他们隐式的显示为static和final的。
3.接口不可以被类继承,只可以被类实现,(关键字:implements)且一个类可以同时实现多个接口。但是接口可以被接口继承,而且是多种继承。
4.接口默认定义是public的,其中的方法也默认是public的(很简单,由于接口存在的意义就是用来实现的。)
5.策略设计模式:创立一个根据传递参数对象不同而具备不同的行为的方法。
6. 使用接口的核心起因:可以向上转型为多个基类型以及防止用户端程序员创立该类的对象,并确保这仅仅是建立一个接口。
7.在打算组合不同的接口使用相同的方法名通常会造成代码可读性的混乱。
1. 本站所有资源来源于用户上传和网络,如有侵权请邮件联系站长!
2. 分享目的仅供大家学习和交流,您必须在下载后24小时内删除!
3. 不得使用于非法商业用途,不得违反国家法律。否则后果自负!
4. 本站提供的源码、模板、插件等等其他资源,都不包含技术服务请大家谅解!
5. 如有链接无法下载、失效或广告,请联系管理员处理!
6. 本站资源售价只是摆设,本站源码仅提供给会员学习使用!
7. 如遇到加密压缩包,请使用360解压,如遇到无法解压的请联系管理员
开心源码网 » 无师自通学编程之Java基础(二):继承以及接口