一.你了解类吗?

  在Java中,类文件是以.java为后缀的代码文件,在每个类文件中最多只允许出现一个public类,当有public类的时候,类文件的名称必须和public类的名称相同,若不存在public,则类文件的名称可以为任意的名称(当然以数字开头的名称是不允许的)。

  在类内部,对于成员变量,如果在定义的时候没有进行显示的赋值初始化,则Java会保证类的每个成员变量都得到恰当的初始化:

  1)对于  char、short、byte、int、long、float、double等基本数据类型的变量来说会默认初始化为0(boolean变量默认会被初始化为false);

  2)对于引用类型的变量,会默认初始化为null。

  如果没有显示地定义构造器,则编译器会自动创建一个无参构造器,但是要记住一点,如果显示地定义了构造器,编译器就不会自动添加构造器。注意,所有的构造器默认为static的。

  下面我们着重讲解一下 初始化 顺序:

  当程序执行时,需要生成某个类的对象,Java执行引擎会先检查是否加载了这个类,如果没有加载,则先执行类的加载再生成对象,如果已经加载,则直接生成对象。

  在类的加载过程中,类的static成员变量会被初始化,另外,如果类中有static语句块,则会执行static语句块。static成员变量和static语句块的执行顺序同代码中的顺序一致。记住,在Java中,类是按需加载,只有当需要用到这个类的时候,才会加载这个类,并且只会加载一次。看下面这个例子就明白了:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public class Test {
    public static void main(String[] args) throws ClassNotFoundException {
         
        Bread bread1 = new Bread();
        Bread bread2 = new Bread();
    }
}
 
 
class Bread {
    static{
        System.out.println("Bread is loaded");
    }
    public Bread() {
        System.out.println("bread");
    }
}

  运行这段代码就会发现"Bread is loaded"只会被打印一次。

  在生成对象的过程中,会先初始化对象的成员变量,然后再执行构造器。也就是说类中的变量会在任何方法(包括构造器)调用之前得到初始化,即使变量散步于方法定义之间。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
public class Test {
    public static void main(String[] args)  {
        new Meal();
    }
}
 
 
class Meal {
     
    public Meal() {
        System.out.println("meal");
    }
     
    Bread bread = new Bread();
}
 
class Bread {
     
    public Bread() {
        System.out.println("bread");
    }
}

  输出结果为:

bread
meal

二.你了解继承吗?

  继承是所有OOP语言不可缺少的部分,在java中使用extends关键字来表示继承关系。当创建一个类时,总是在继承,如果没有明确指出要继承的类,就总是隐式地从根类Object进行继承。比如下面这段代码:

1
2
3
4
5
6
7
8
9
10
11
class Person {
    public Person() {
         
    }
}
 
class Man extends Person {
    public Man() {
         
    }
}

  类Man继承于Person类,这样一来的话,Person类称为父类(基类),Man类称为子类(导出类)。如果两个类存在继承关系,则子类会自动继承父类的方法和变量,在子类中可以调用父类的方法和变量。在java中,只允许单继承,也就是说 一个类最多只能显示地继承于一个父类。但是一个类却可以被多个类继承,也就是说一个类可以拥有多个子类。

  1.子类继承父类的成员变量

  当子类继承了某个类之后,便可以使用父类中的成员变量,但是并不是完全继承父类的所有成员变量。具体的原则如下:

  1)能够继承父类的public和protected成员变量;不能够继承父类的private成员变量;

  2)对于父类的包访问权限成员变量,如果子类和父类在同一个包下,则子类能够继承;否则,子类不能够继承;

  3)对于子类可以继承的父类成员变量,如果在子类中出现了同名称的成员变量,则会发生隐藏现象,即子类的成员变量会屏蔽掉父类的同名成员变量。如果要在子类中访问父类中同名成员变量,需要使用super关键字来进行引用。

  2.子类继承父类的方法

  同样地,子类也并不是完全继承父类的所有方法。

  1)能够继承父类的public和protected成员方法;不能够继承父类的private成员方法;

  2)对于父类的包访问权限成员方法,如果子类和父类在同一个包下,则子类能够继承;否则,子类不能够继承;

  3)对于子类可以继承的父类成员方法,如果在子类中出现了同名称的成员方法,则称为覆盖,即子类的成员方法会覆盖掉父类的同名成员方法。如果要在子类中访问父类中同名成员方法,需要使用super关键字来进行引用。

  注意:隐藏和覆盖是不同的。隐藏是针对成员变量和静态方法的,而覆盖是针对普通方法的。(后面会讲到)

  3.构造器

  子类是不能够继承父类的构造器,但是要注意的是,如果父类的构造器都是带有参数的,则必须在子类的构造器中显示地通过super关键字调用父类的构造器并配以适当的参数列表。如果父类有无参构造器,则在子类的构造器中用super关键字调用父类构造器不是必须的,如果没有使用super关键字,系统会自动调用父类的无参构造器。看下面这个例子就清楚了:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
class Shape {
     
    protected String name;
     
    public Shape(){
        name = "shape";
    }
     
    public Shape(String name) {
        this.name = name;
    }
}
 
class Circle extends Shape {
     
    private double radius;
     
    public Circle() {
        radius = 0;
    }
     
    public Circle(double radius) {
        this.radius = radius;
    }
     
    public Circle(double radius,String name) {
        this.radius = radius;
        this.name = name;
    }
}

  这样的代码是没有问题的,如果把父类的无参构造器去掉,则下面的代码必然会出错:

  改成下面这样就行了:

  4.super

  super主要有两种用法:

  1)super.成员变量/super.成员方法;

  2)super(parameter1,parameter2....)

  第一种用法主要用来在子类中调用父类的同名成员变量或者方法;第二种主要用在子类的构造器中显示地调用父类的构造器,要注意的是,如果是用在子类构造器中,则必须是子类构造器的第一个语句。

三.常见的面试笔试题

1.下面这段代码的输出结果是什么?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
public class Test {
    public static void main(String[] args)  {
        new Circle();
    }
}
 
class Draw {
     
    public Draw(String type) {
        System.out.println(type+" draw constructor");
    }
}
 
class Shape {
    private Draw draw = new Draw("shape");
     
    public Shape(){
        System.out.println("shape constructor");
    }
}
 
class Circle extends Shape {
    private Draw draw = new Draw("circle");
    public Circle() {
        System.out.println("circle constructor");
    }
}
shape draw constructor
shape constructor
circle draw constructor
circle constructor

这道题目主要考察的是类继承时构造器的调用顺序和初始化顺序。要记住一点:父类的构造器调用以及初始化过程一定在子类的前面。由于Circle类的父类是Shape类,所以Shape类先进行初始化,然后再执行Shape类的构造器。接着才是对子类Circle进行初始化,最后执行Circle的构造器。

2.下面这段代码的输出结果是什么?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
public class Test {
    public static void main(String[] args)  {
        Shape shape = new Circle();
        System.out.println(shape.name);
        shape.printType();
        shape.printName();
    }
}
 
class Shape {
    public String name = "shape";
     
    public Shape(){
        System.out.println("shape constructor");
    }
     
    public void printType() {
        System.out.println("this is shape");
    }
     
    public static void printName() {
        System.out.println("shape");
    }
}
 
class Circle extends Shape {
    public String name = "circle";
     
    public Circle() {
        System.out.println("circle constructor");
    }
     
    public void printType() {
        System.out.println("this is circle");
    }
     
    public static void printName() {
        System.out.println("circle");
    }
}
shape constructor
circle constructor
shape
this is circle
shape

这道题主要考察了隐藏和覆盖的区别。

  覆盖只针对非静态方法(终态方法不能被继承,所以就存在覆盖一说了),而隐藏是针对成员变量和静态方法的。这2者之间的区别是:覆盖受RTTI(Runtime type  identification)约束的,而隐藏却不受该约束。也就是说只有覆盖方法才会进行动态绑定,而隐藏是不会发生动态绑定的。在Java中,除了static方法和final方法,其他所有的方法都是动态绑定。因此,就会出现上面的输出结果。

原文链接:

  http://www.cnblogs.com/dolphin0520/p/3803432.html

java继承2——类与继承(转)的更多相关文章

  1. Java编程里类的继承

    今天,我们将要讨论的内容是Java里面类的继承的相关概念. 说到继承,我相信大家都不陌生.生活中,子承父业,子女继承父母的财产,这就是继承.实际上,Java里的继承也是如此.对于一个类来说,它的数据成 ...

  2. java类为什么是单继承。类的继承,实现接口。

    java中提供类与类之间提供单继承. 提供多继承会可能出现错误,如:一个类继承了两个父类,而两个父类里面都有show()方法. class Fulei1{ public void show(){ Sy ...

  3. java中阻止类的继承

    1.使用final来修饰类 final表示这个类是继承树的末端,不能被继承. 2.将类的构造方法声明为private的,再提供一个static的方法来返回一个类的对象. JAVA语言要求继承时必须在构 ...

  4. [Java学习]面向对象-类的继承;方法覆盖

    一.类的继承 实现方法: public Class SubClass extends SuperClass{ } 继承最基本作用: 代码重用. 继承最重要的作用: 方法可以重写. 关于类的继承: 子类 ...

  5. 【代码笔记】Java基础:类的继承(构造器)

    在Java中,创建对象的格式为: 类名 对象名 = new 类名(): 如: 1 JFrame jf = new JFrame(); 一个对象被创建出来时,经常要先做一些事这个对象才能正常使用,也可以 ...

  6. JS原型继承和类式继承

    前言 一个多月前,卤煮读了一篇翻译过来的外国人写的技术博客.此君在博客中将js中的类(构造)继承和原型继承做了一些比较,并且得出了结论:建议诸位在开发是用原型继承.文中提到了各种原型继承的优点,详细的 ...

  7. js原生设计模式——2面向对象编程之继承—new类式继承

    <!DOCTYPE html><html lang="en"><head>    <meta charset="UTF-8&qu ...

  8. js原生继承之——类式继承实例(推荐使用)

    <!DOCTYPE html><html lang="en"><head>    <meta charset="UTF-8&qu ...

  9. JS原型继承与类的继承

    我们先看JS类的继承 <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> &l ...

随机推荐

  1. Spring配置文件头信息

    代码如下: <?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http:// ...

  2. django和mysql

    一.在python2中使用mysql django.core.exceptions.ImproperlyConfigured: Error loading MySQLdb module: No mod ...

  3. JavaScript:用JS实现加载页面前弹出模态框

    用JS实现加载页面前弹出模态框 主要的JavaScript 代码是: <script> //加载模态框 $('#myModal').modal(); $(document).ready(f ...

  4. ngx_lua学习笔记 -- capture + proxy 实现httpclient

    题注 最近我在学习nginx的lua插件,发现结合nginx的异步io和lua的流程控制能力,还是有很丰富的想象空间的:几乎所有常见的http请求的处理逻辑都能搞定,诸如查查数据库,访问一下memca ...

  5. pdb文件 PDB文件:每个开发人员都必须知道的 .NET PDB文件到底是什么?

    pdb文件包含了编译后程序指向源代码的位置信息,用于调试的时候定位到源代码,主要是用来方便调试的. 在程序发布为release模式时,建议将 pdb文件删除, 同时,对外发布的时候,也把 pdb删除, ...

  6. [MFC]图形附加alpha透明通道

    改动图形而且附加透明通道: 要附加透明度,能够要把图片转化为32位png图片,然后设置对应的alpha值: 1.      怎样把一张图片改动为32位的Png: a)        读取原图片颜色信息 ...

  7. stm32 spi1 bug

    stm32 spi1调试NRF24L01时该模块作为接收机时,能收到数据,作为发送机时,发不出数据(虽然读NRF的寄存器显示数据已经发出,但实际并发不出),换到SPI2问题解决

  8. 啸叫抑制(howling suppression)

    作者:桂. 时间:2017-05-16 链接:http://www.cnblogs.com/xingshansi/p/6862683.html 前言 下午看到群里讨论有人提到这个问题,记录一下. 一. ...

  9. 分享下今天研究的流量上限DDos攻击分析和解决方式

    分享下今天研究的流量上限DDos攻击分析和解决方式 常常听到或者碰到某个站点被攻击.一般都是流量攻击.今天自己写了个程序測下相关的上限,程序仅仅简单做了个get html操作(不包括图片等资源文件). ...

  10. Linux下nagios网络监控与/proc/net/tcp文件详解

    问题描述:nagios自带的check_antp太过简约,除了状态统计输出外,什么参数都不提供.在面对不同应用服务器时,报警就成了很大问题. 问题描述:nagios自带的check_antp太过简约, ...