Java入门系列之重写
前言
关于所有Java系列文章面向有一定基础的童鞋,所写每一篇希望有一定含金量,有些内容可能会从Java整个语法全局考虑穿插后续要讲解的内容以成系统,若不理解,请看完后再学习。上一节我们讲解完了final关键字,本节我们继续来对比讲解Java和C#中的重写,二者语言的重写区分非常清晰,Java子类中基类方法签名一样或通过注解@Override显式声明,C#中基类通过virtual关键字修饰,子类通过ovveride关键字表示重写,具体细节请往下看。
重写
既然是重写必然就涉及到继承,我们首先来看看Java中的重写是怎样的呢?如下:
public class Main {
public void f() {
System.out.println("Main.f");
}
public static void main(String[] args) {
Main main = new Sub();
main.f();
}
}
class Sub extends Main {
public void f() {
System.out.println("Sub.f");
}
}

当调用基类的f方法时,此时发现已被子类所重写,所以如上正常打印出Sub.f,要是我们将上述基类中方法修改为私有的呢


可能我们期待输出子类中的打印结果,但是修改为私有后,说明此时对子类不再可见,也就相当于使用了final,在这种情况下,子类中方法则是一个全新的方法,很显然说明:只有非私有方法才可以被重写。对于这种情况下编译不会报错, 但是也不会按照我们所期望的结果来执行,所以建议对于基类中的私有方法命名为和子类不同的名字,为了让重写一目了然或更加明确,在1.5版本发布了注解功能,我们可以通过注解来显式声明要重写基类方法,若基类为私有,此时通过注解则会编译报错,因为找不到要重写的方法,这种体验更加友好,比如如下:
public class Main {
private void f() {
System.out.println("Main.f");
}
public static void main(String[] args) {
Main main = new Sub();
main.f();
}
}
class Sub extends Main {
//编译错误,未找到基类(超类)中要重写的方法
@Override
public void f() {
System.out.println("Sub.f");
}
}
举一反三,我们来思考一个问题,是不是方法签名一致,子类就可以重写基类方法呢?很显然不是,若是静态方法,必然不能被重写,如果通过注解@Override声明那么必然编译报错,否则调用基类方法,对于接口中的静态方法同理。所以还是建议使用注解来声明重写。那么为什么通过注解显式声明重写基类方法或通过关键字final修饰方法就会在编译阶段报错呢?因为它们在编译阶段就完成了静态绑定,而不是运行时动态绑定。问题又来了,上述我们讲解到若在子类中不通过注解显式声明重写,同时在基类中方法私有,此时一定可以编译通过(上述已演示),并且会调用基类方法并打印出结果,事实情况一定是这样吗?很显然也不是如此,如下示例:
class Super {
private void f() {
System.out.println("Super.f");
}
}
class Derived extends Super {
public void f() {
System.out.println("Derived.f");
}
public static void main(String[] args) {
Super aSuper = new Derived();
//编译报错(因为基类方法私有)
aSuper.f();
}
}
初一看,这不是一样么,其实是不一样,上述可以那是因为调用方在基类里面,当然可以调用内部的私有方法,如上情况只对基类内部私有, 当然也就不能调用,这里就又引出一个问题,是不是声明为基类的私有方法,子类就无法进行重写呢?根据我们上述打印的结果来看,理论上不可行,事实情况是可以的,通过内部类(后续会出文章详细讲解)来实现。
class Main {
private void f() {
System.out.println("Main.f");
}
class Inner extends Main {
private void f() {
System.out.println("Inner.f");
}
}
public static void main(String args[]) {
//内部类实例必须通过外部类实例创建
Main outer = new Main();
Inner inner = outer.new Inner();
//内部类可以在内部访问外部的所有成员(包括私有)
inner.f();
// 调用外部类方法
outer = inner;
outer.f();
}
}

C#若明确需要重写,那么基类方法声明为虚有的virtual,子类通过ovverride关键字修饰方法达到重写目的,若没有这两个关键字,和Java中一样只是方法签名一致,那么说明编译器会提醒是否通过new关键字来表明隐藏基类的方法
class Program
{
public void F()
{
Console.WriteLine("Main.f");
} static void Main(string[] args)
{
Program program = new Sub();
program.F(); Console.ReadKey();
}
} class Sub : Program
{
public new void F()
{
Console.WriteLine("Sub.f");
}
}
总结
Java和C#中的重写区分度非常清晰,Java中只要方法签名一致就可以达到重写,不过建议通过注解方法来显式声明重写以免引起不必要的问题,同时,即使基类方法私有,我们也可借助于内部类来实现重写。
Java入门系列之重写的更多相关文章
- Java入门系列-26-JDBC
认识 JDBC JDBC (Java DataBase Connectivity) 是 Java 数据库连接技术的简称,用于连接常用数据库. Sun 公司提供了 JDBC API ,供程序员调用接口和 ...
- Java入门系列-19-泛型集合
集合 如何存储每天的新闻信息?每天的新闻总数是不固定的,太少浪费空间,太多空间不足. 如果并不知道程序运行时会需要多少对象,或者需要更复杂方式存储对象,可以使用Java集合框架. Java 集合框架提 ...
- Java入门系列之类继承、抽象类、接口(五)
前言 C#和Java关于类.抽象类.接口使用方式基本相似,只是对应关键字使用不同罢了,本节呢,我们只是对照C#和Java中关于这三个概念在具体使用时,看看有哪些不一样的地方. 类继承 C#和Java在 ...
- Java入门系列之hashCode和equals(十二)
前言 前面两节内容我们详细讲解了Hashtable算法和源码分析,针对散列函数始终逃脱不掉hashCode的计算,本节我们将详细分析hashCode和equals,同时您将会看到本节内容是从<E ...
- Java入门系列之字符串创建方式、判断相等(一)
前言 陆续从0开始学习Java出于多掌握一门语言以后的路也会更宽,.NET和Java兼顾,虽然路还很艰难,但事在人为.由于Java和C#语法相似,所以关于一些很基础的内容不会再重头讲,Java系列中所 ...
- Java入门系列(九)Java API
String,StringBuilder,StringBuffer三者的区别 1.首先说运行速度,或者说是执行速度 在这方面运行速度快慢为:StringBuilder > StringBuffe ...
- Java入门系列(七)Java 集合框架(JCF, Java Collections Framework)
Java 集合概述 List.Set.Map可以看做集合的三大类 java集合就像一个容器,可以将多个对象的引用丢进该容器中. Collection和Map是java集合的根接口. List List ...
- Java入门系列(五)JVM内存模型
概述 根据<Java 虚拟机规范>中的说法,Java 虚拟机的内存结构可以分为公有和私有两部分. 公有指的是所有线程都共享的部分,指的是 Java 堆.方法区.常量池. 私有指的是每个线程 ...
- Java入门系列(四)内部类
为什么需要内部类? 真正的原因是这样的,java中的内部类和接口加在一起,可以的解决常被C++程序员抱怨java中存在的一个问题没有多继承.实际上,C++的多继承设计起来很复杂,而java通过内部类加 ...
随机推荐
- AntD框架的upload组件上传图片时使用customRequest方法自定义上传行为
本次做后台管理系统,采用的是 AntD 框架.涉及到图片的上传,用的是AntD的 upload 组件. 我在上一篇文章<AntD框架的upload组件上传图片时使用customRequest方法 ...
- SSM框架处理跨域问题
什么是跨域 跨域是指从一个域名的网页去请求另一个域名的资源.比如从www.baidu.com 页面去请求 www.google.com 的资源.跨域的严格一点的定义是:只要 协议,域名,端口有任何一个 ...
- [noi.ac省选模拟赛]第11场题解集合
题目 比赛界面. T1 比较简单.容易想到是求鱼竿的最大独立集.由于题目的鱼竿可以被分割为二分图,就可以想到最大匹配. 尝试建边之后会发现边的数量不小,但联系题目性质会发现对于一条鱼竿,它 ...
- flutter pdf 文件浏览
说明 flutter_full_pdf_viewer 可以实现从网络上下载 pdf 文件并且显示出来. 包地址:flutter_full_pdf_viewer: ^1.0.6 使用方法 1.在 pub ...
- Vugen使用技巧
调整各种选项的超时时间
- NAT网络地址转化和DHCP
DHCP(Dynamic Host Configuration Protocol,动态主机配置协议)通常被应用在大型的局域网络环境中,主要作用是集中的管理.分配IP地址,使网络环境中的主机动态的获得I ...
- 大众点评cat实时监控简介及部署
简介 背景 CAT(Central Application Tracking)是由吴其敏(前大众点评首席架构师,现携程架构负责人)主导设计基于Java开发打造的实时应用监控平台,为大众点评网提供了全面 ...
- MySQL语句的使用
进入数据库 mysql -u root -pmysql (u用户名,p密码)#如果不想让其他人看到就直接一个p然后回车再打密码 select version(); 查看数据库版本 sele ...
- c++ 对vector和deque进行逆序排序问题
1.vector vector<int> data1; 2.deque deque <int> data2; 逆序排序方式: 方式1.使用reverse函数 (内置数据类型 ...
- python0.1
python基础 python是一种高级编程语言,而编程语言分为3种 编程语言 编程语言是一种人与计算机沟通的工具. 编程就是就将人的需求通过攥写编程语言命令计算机完成指令. 编程的意义在于将人类的生 ...