`

方法能重写,属性能重写吗?

    博客分类:
  • Java
F# 
阅读更多

覆写是多态的一种表现,我们平时所说的覆写一般是针对方式来说,在网上看到过有人讨论试着覆写属性,于是有点兴趣,属性真能覆写吗?回答问题之前,我们还是回忆一下方法的覆写具备哪些条件,或都说哪些方法能覆写。
先回顾一下方法覆写要注意的地方:
1、重载(也叫过载)时只与方法特征有关,但重写(覆写)是会进一步检查两个方法的返回类型是否相同、访问修饰权限是否缩小(假设public->protected方向是缩小,反之叫扩大)和抛出的异常范围是否扩大。那么什么是方式特征呢?一个方法的特征(也可叫方法签名)仅包括方法的名字、参数的个数、类型、顺序(实质上就是参数列表),而不包括方法的返回类型、访问修饰权限与所抛出的异常。

public class A {
    public void overwrite(int i) throws IOException {}
}

class B extends A {
    // !! 编译通不过,不能缩小访问权限
    //    void overwrite(int i) throws IOException {}

    // !! 编译通不过,不能扩大异常范围
    //    public void overwrite(int i) throws Exception {}

    // 正常,编译没问题,可以不抛出异常
    // public void overwrite(int i) {}

    // 覆写父类方法
    public void overwrite(int i) throws IOException {}

    protected void overload(int i) {}

    //重载上面的方法
    int overload(long i) throws IOException {
        return 0;
    }
}

另外,要补充说明的是重载一般是指在同一个类中多个方法间,但也可重父类的的方法,而重写只发生面父子与子类的方法间。

2、非私有非静态方法不能被任何静态方法覆写,如果子类中试着以静态方式(不管访问权限修饰符是什么)来覆写父类的方法,编译时会报错。

public class A {
    void f() {}
}

class B extends A {
    // !! 编译出错,下面错误都一样
    //    static void f(){};
    //    private static void f(){};
    //    protected static void f(){};
    //    public static void f(){};
}

3、非私有静态方法不能被任何非静态方法覆写,如果子类中试着以非静态方式(不管访问权限修饰符是什么)来覆写父类的方法,编译时会报错。

public class A {
    public static void f() {}
}

class B extends A {
    // !! 编译出错,下面错误都一样
    //    public void f(){}
    //    protected void f() {}
    //    void f() {}
    //    private void f() {}
}

4、子类与父类中有方法特征相同的静态方法时,覆写规则与非静态方法覆写规则一样,但一般我们不把静态方法的覆写叫覆写,虽然语法规则上与非静态方法相同。

public class A {
    public static void overwrite(int i) throws IOException {
        System.out.println("父类静态方法...");
    }
}

class B extends A {
    // !! 编译通不过,不能缩小访问权限
    //    static void overwrite(int i) throws IOException {}

    // !! 编译通不过,不能扩大异常范围
    //    public static void overwrite(int i) throws Exception {}

    // 正常,编译没问题,可以不抛出异常
    // public static void overwrite(int i) {}

    // 覆写父类静态方法
    public static void overwrite(int i) throws IOException {
        System.out.println("子类静态方法...");
    }

    public static void main(String[] args) throws IOException {
        A a = new B();
        //覆写静态在语法上是合法的,但没有多态效果
        a.overwrite(0);//print: 父类静态方法...
        A.overwrite(0);//print: 父类静态方法...
        B.overwrite(0);//print: 子类静态方法...
    }
}

上面重写了父类的静态方法,但却没有多态作用,也就是说,静态方法不存在重写这一说,只不过在语法规则上与非静态方法一样罢了。

5、私有方法对子类同名方法不产生任何影响,也就是说私有方法不能被重写,即使试着在子类覆写了父类的私有方法,不管访问权限修饰符是什么,在编译时也不会报错。原因就是私有方法对子类也是不可见的。

public class A {
    private void f() {
    }

    // 加上static修饰符,其结果都一样
    // private static void f() {}
}

class B extends A {
    // 尝试每个方式,都会编译能过
    // private void f() {}
    // void f() {}
    // protected void f() {}
    // public void f() {}

    // private static void f() {}
    // static void f() {}
    // protected static void f() {}
    public static void f() {}
}

好了,上面总结并理解方法覆后,我们再来看属性能不能覆写,其实,这是一个很无聊的问题,不像上面讨论方法那有点价值,可以说属性是没有覆写这一说的,这有点像静态方法一样,不过还是稍微看一下:

public class A {
    // 这行不能去掉,否则①编译通不过
    int i = 1;

    A() {
        System.out.println("父类构造方法 i=" + this.i);//①
        this.f();//②
        System.out.println("父类中 " + (this == getThis()));//③ print:true
    }

    public void f() {
        System.out.println("父类方法f() i=" + this.i);
    }

    public A getThis() {
        System.out.println("父类getThis");
        return this;
    }
}

class B extends A {
    int i = 2;

    B() {
        System.out.println("子类构造方法 i=" + this.i);
        System.out.println("子类中 " + (this == super.getThis()));//④
    }

    public void f() {
        System.out.println("子类方法f() i=" + this.i);
    }

    public A getThis() {
        System.out.println("子类getThis");
        return this;
    }

    public static void main(String[] args) {
        /*
         * 从下面 a.i 与 b.i 的输出可以看出,某对象的属性只与声明 的类型相
         * 关,与对象本身是什么类型无关,这与方法是完全不同的
         */
        A a = new B();
        System.out.println("main方法 a.i=" + a.i);
        B b = (B) a;
        System.out.println("main方法 b.i=" + b.i);
       
        /*
         * output:
        父类构造方法 i=1
        子类方法f() i=0
        子类getThis
        父类中 true
        子类构造方法 i=2
        父类getThis
        子类中 true
        main方法 a.i=1
        main方法 b.i=2
         */
    }
}

这里一直有个疑问:上面①②处的this肯定都是同一个对象,且都指向子类对象,还并且与子类中this是同一象,由第③④行代码可以证明这一点。但为什么①处的this好像指向了父类对象,不然为什么①处输出的i是父类中的i呢?这说明属性除了只与定义他的类型有关外,如果在类的内部自身访问时,就会访问当前所在类的属性,与this无关,这进一步说明了属性是不具有多态这一特性的。

分享到:
评论

相关推荐

    jquery插件使用方法大全

    1.4重要新特性: ·常用方法的性能大幅提升:重写了大部分较早期的函数; ·更容易使用的设置函数(setter function):为所有对象新增了许多易用的设置函数; ·对Ajax的改进:引入了许多Ajax和JSON处理方面的更新...

    java 面试题 总结

    如果在子类中定义某方法与其父类有相同的名称和参数,我们说该方法被重写 (Overriding)。子类的对象使用这个方法时,将调用子类中的定义,对它而言,父类中的定义如同被"屏蔽"了。如果在一个类中定义了多个同名的...

    超级有影响力霸气的Java面试题大全文档

    如果在子类中定义某方法与其父类有相同的名称和参数,我们说该方法被重写 (Overriding)。子类的对象使用这个方法时,将调用子类中的定义,对它而言,父类中的定义如同被"屏蔽"了。如果在一个类中定义了多个同名的...

    最新jquery.1.8.1

    jQuery 1.8.1中重写了选择器引擎,大大提升了性能。此外,选择器引擎Sizzle修复了一些边缘问题和bug,包括对于多个选择符(~ > +)的改进、更好地检测浏览器bug等。 5. XSS防护 $()方法可以创建HTML元素,如果...

    ease template

     Ease Template 经过多年的发展已经被很多框架所采用,其中比较有名气的当属FleaPHP、ThinkPHP。有些框架直接集成了Ease Template插件,用户选择Ease Template的时候无需担心兼容性以及稳定性。  当Ease Template...

    最新JQuery版本1.8

    jQuery 1.8中重写了选择器引擎,大大提升了性能。此外,选择器引擎Sizzle修复了一些边缘问题和bug,包括对于多个选择符(~ > +)的改进、更好地检测浏览器bug等。 5. XSS防护 $()方法可以创建HTML元素,如果被...

    重构HTML改善Web应用设计

    取代滥用本用于呈现表格数据的table元素而使用表格布局,可以考虑频繁使用的分栏式布局:根据以往项目开发经验:width和height属性能让浏览器更快地样式化页面并展现给用户。但注意,这样做,对页面的显示速度有提升...

    工程硕士学位论文 基于Android+HTML5的移动Web项目高效开发探究

    Chrome Frame 会把最新版的Chrome Webkit 内核和JavaScript 引擎注入到IE中, IE浏览器将获得Chrome的性能和功能 目录 摘要 I ABSTRACT II 专业名词清单 III 第一章 绪论 1 1.1 研究背景与意义 1 1.2国内外相关...

    5w(五维)网址导航源码 8.0 GBK.rar

    5w(五维)网址导航源码是国内专业的网址收集和分类网站。...即使是菜鸟站长,也能轻轻松松搭建一个完全属于自己的网址导航。 永久免费 从安装到使用,完全免费,永久免费,并且提供专业的客服服务。

    5w(五维)网址导航源码 8.0 UTF8.rar

    5w(五维)网址导航源码是国内专业的网址收集和分类网站。...即使是菜鸟站长,也能轻轻松松搭建一个完全属于自己的网址导航。 永久免费 从安装到使用,完全免费,永久免费,并且提供专业的客服服务。

    值类型和引用类型的区别

    • 值类型不能作为其它任何类型的基类型,因此不能向值类型中增加任何新的虚方法,更不该有任何抽象方法,所有的方法都是sealed的(不可重写); • 未装箱的值类型分配在栈上而不是堆上,而栈又不是GC的地盘儿,...

    入门学习Linux常用必会60个命令实例详解doc/txt

    在系统关机前使用 shutdown命令,系统管理员会通知所有登录的用户系统将要关闭,并且login指令会被冻结,即新的用户不能再登录。 halt 1.作用 halt命令的作用是关闭系统,它的使用权限是超级用户。 2.格式 halt...

    OS X10.13下载地址.txt

    macOS是苹果公司为Mac系列产品开发的专属操作系统。macOS是苹果Mac系列产品的预装系统,处处体现着简洁的宗旨。 macOS是全世界第一个基于FreeBSD系统采用“面向对象操作系统”的全面的操作系统。“面向对象操作系统...

    C#微软培训资料

    11.3 静态和非静态的方法.129 11.4 方法的重载.130 11.5 操作符重载.134 11.6 小 结.137 第十二章 域 和 属 性 .139 12.1 域 .139 12.2 属 性 .143 12.3 小 结 .146 第十三章 事件和索引指示器 .148 ...

Global site tag (gtag.js) - Google Analytics