`
jgnan
  • 浏览: 87487 次
  • 性别: Icon_minigender_1
  • 来自: 广州
社区版块
存档分类
最新评论

每天简单JAVA教学:类继承,重写、重构及重载,final的用法

阅读更多
昨天事忙,所以没时间给大家写blog,抱歉一下。

今天说的内容有三个,首先来说java的类继承:
前面已经说过,要继承,只要在定义class的类名后面使用关键字extends,然后再在后面声明当前的类是继承哪个类就好了。
package extendsdemo;

public class Child extends Father
{
    public Child()
    {
        System.out.println("I'm the child");
    }

    public static void main(String[] args)
    {
        new Child();
    }
}

class Father extends Grandfather
{
    Father()
    {
        System.out.println("I'm the father");
    }
}

class Grandfather
{
    Grandfather()
    {
        System.out.println("I'm the ancestor");
    }
}


上面就是个继承的例子。首先大家会发现,一个java文件其实是可以定义多个class的对吧?不过有个规则,一个java文件里面只能有一个public的class,而且这个class名字还是要和文件名一致。第二点就是,console最后跑出以下内容:


这说明了继承类实例的构造过程是先调用最顶级的构造函数,按照继承关系自上而下的,最后调用自己的构造函数。为什么呢?

因为继承的实际用法就是要让子类继承父类的public、protected及default属性及方法。修改一下上面的例子:
package extendsdemo;

public class Child extends Father
{
    public Child()
    {
        System.out.println("I'm the child");
    }

    public static void main(String[] args)
    {
        Child child = new Child();
    }
}

class Father extends Grandfather
{
    Father()
    {
        System.out.println("I'm the father");
    }
    
    protected void goldenDish()
    {
        System.out.println("It is for me and my son!");
    }
    
    private void football()
    {
        System.out.println("Personal collection!");
    }
}

class Grandfather
{
    Grandfather()
    {
        System.out.println("I'm the ancestor");
    }
    
    public void myStory()
    {
        System.out.println("For every body");
    }
    
    protected void treasureMap()
    {
        System.out.println("For whole family");
    }
    
    private void wife()
    {
        System.out.println("My dear of life!");
    }

    void garden()
    {
        System.out.println("All neighbours can visit it");
    }
}


然后,我们在Child类的main方法里面尝试打"child."然后使用eclipse的content assist功能,热键是Alt+/,就会出现以下的画面:



这些都是子类可以访问到的方法。其中蓝色三角表示default方法,黄色菱形表示protected方法,而绿色圆圈表示public方法。

大家可能会奇怪,为什么除了Father和Grandfater之外,child类还能访问很多其它方法,比如equals。那好,我们就来看看这个方法来自什么地方。调用child.equals(object),然后按住Ctrl键用鼠标左键点一下这个方法可以查看这个方法的源代码(如果有源代码可查的话)。大家就会发现我们被带到Object这个类里面来了。

原来在java的类世界里面,所有的class都是默认继承Object这个类的。也就是说所有类的根都是Object,可以用Eclipse的Hiearchy视图证明这点。随便点哪个类,然后按F4键就可以打开这个继承关系视图:


看到了吧,这个Object就像是夏娃那样,是所有类的祖先。而且你不需要写extends去继承它!

好了,言归正传,刚刚说到继承的作用,就是把已有的类模板的public、protected及default的字段和方法拷贝到自己的类模板里面。其实以其说是拷贝,倒不如说是引用更加贴切。正因如此,所以我们才需要先初始化最上级资源的地址,再逐级下来初始化各层级的资源。否则如果是自下而上的初始化,当子集某些资源会调用到父级资源的时候,那就要死翘翘了。这也是为什么继承的时候所有父级成员的构造函数都要被调用一次的原因。

说到继承就会提及重写。而提起重写就往往也会提起重构和重载这两个名词。为了省事我就一次过再此说明了:
首先说重构,在java里面规定,同一个类里面,不允许有两个方法名相同而且参数相同的方法,例如:
public void sameMethod(String param1, Integer param2)
{
}

// the same with previous one
private String sameMethod(String param1, Integer param2)
{
}

// also the same
public void sameMethod(String aa, Integer bb)
{
}


不允许在同一个class里面这样定义,编译器会报错。只要方法名和()里面的类型相同就会出错。注意括号里面我们只看类型是否相同,而这个相同指的是按照顺序对照的相同,而且参数数目也要求相同,以下方法不算相同的两个方法:

public void sameMethod(String param1, Integer param2)
{
}

//Not the same with previous one
public void sameMethod(Integer param2,String param1)
{
}


这个原因我们会在日后说映射的时候说明。现在大家只要记住这点就好了。

那好,上面的例子给了我们一个启示,只要不是名字相同而且参数类型相同的话,在同一个类里面写两个相同名字的方法,是可能的,例如:
package refact;

public class Overload {
	public void overload(){}
	public void overload(String p1){}
	private String overload(Integer p2){return null;}
	protected static void overload(String p1,String p2){}
	
}


上面四个方法都是叫overload,但是它们的调用参数类型不一样,数目不一样,甚至是返回类型都不一样。所以这些方法都不算同一个方法。而我们对于这类从同一个方法名衍生出多个方法的做法叫做方法的重载(overload)。重载体现出类行为的多态,在实际应用中会让代码可读性和可用性都得到提高。

刚刚说了java只是不允许同一个类里面有两个相同的方法,那么在继承类里面,允不允许呢?答案是肯定的,而这种做法,我们叫做方法的重写。
package extendsdemo;

public class Overwrite extends Parent
{
    public void overwrite()
    {
        System.out.println("I'm overwritten!");
    }

    public static void main(String[] args)
    {
        new Overwrite().overwrite();        
    }
}

class Parent
{
    public void overwrite()
    {
        System.out.println("I'm the original one!");
    }
}


在上面例子里面,我们把Parent的overwrite方法重写了,自然,控制台最后打出来的结果就是"I'm overwritten!"。

但是,重写时不能够改变父类方法原有的返回类型,可以改变modifier,但是只能够往高开放程度的方向改。

modifier的开放程度:
private < default < protected < public

而由于继承时不会继承private方法的,所以重写的规则对于父类的private方法无效。。。。

所以下面的重写是不正确的重写:
class Child extends Parent
{
    void overwrite(){...}
}

class Parent
{
    public void overwrite(){...}
}


下面的也不正确
class Child extends Parent
{
    String overwrite(){...}
}

class Parent
{
    void overwrite(){...}
}


重写可以改变父类的行为,这个就是它的作用。但是如果我们要在子类重写了父类的一个方法,比如时方法a(),但是又想调用父类原本方法a()的代码时要怎么办呢?这时候就需要用关键字super和this来区分父类的方法a()和子类的方法a()了。这个就是我们下节课的内容。

好了,到最后一个名词,重构。什么叫重构?这个是一个应用项目中使用的名词。如字面的意思一样,就是重新构造。无论是对类的重写,对逻辑的重新实现等,都叫做重构。这并不是代码级别的行为,而是项目级别的行为。

好了,今天最后的内容,也是为了和之前的内容相呼应,我们来说final这个关键字的用法。它的其中一个功能简单来说就是不允许子类对其进行重写,这是当我们在声明方法时使用它的时候的功效。而另一个功能则是在我们用它来声明变量或者字段时的功效,就是说这个变量或者字段的值不允许被修改。

所以从本质上说,这个关键字的功用就是声明其休息对象的内存地址段内容不允许被修改。就这么简单。

好了,今天的内容就这么多,多谢大家观看。有问题欢迎随时提问或者指正。
  • 大小: 4.9 KB
  • 大小: 4.9 KB
  • 大小: 7.9 KB
分享到:
评论
发表评论

文章已被作者锁定,不允许评论。

相关推荐

Global site tag (gtag.js) - Google Analytics