在网上看到过这么一篇文章,是关于抽象方法不能是static或native或synchroniz 的原因。其中提到了这些关键字的意义以及与 abstract 关键字的冲突,大体内容如下:

1、abstract是抽象的,指的是方法只有声明而没有实现,他的实现要放入声明该类的子类中实现。

2、static是静态的,是一种属于类而不属于对象的方法或者属性,而我们知道,类其实也是一个对象,他是在class文件加载到虚拟机以后就会产生的对象,通常来说它是单例的,就是整个虚拟机中只有一个这样的类对象(当然,如果用新的类加载器也会生成新的类的对象)。

3、synchronized 是同步,是一种相对线程的锁。

4、native 本地方法,这种方法和抽象方法及其类似,它也只有方法声明,没有方法实现,但是它与抽象方法不同的是,它把具体实现移交给了本地系统的函数库,而没有通过虚拟机,可以说是Java与其它语言通讯的一种机制。

然后作者逐个分析了冲突的原因:

首先abstract与static,其实一看他们的作用和属性就很容易辨别,abstract是没有实现的,而static一定要有实现,因为 abstract的类不能生产对象,但是static是属于类,而类已经是一个存在的对象,这两个关键字在这上面有一个关键的矛盾点。

synchronized 是同步,然而同步是需要有具体操作才能同步的,如果像abstract只有方法声明,那同步一些什么东西就会成为一个问题了,当然抽象方法在被子类继承以后,可以添加同步。

native,这个东西本身就和abstract冲突,他们都是方法的声明,只是一个吧方法实现移交给子类,另一个是移交给本地操作系统。如果同时出现,就相当于即把实现移交给子类,又把实现移交给本地操作系统,那到底谁来实现具体方法呢?

作者对于 synchronized 和 native 关键字冲突的原因分析笔者是没有异议的,关键就在于 static 冲突的原因。

在第三段中红色文字标出的部分中,作者说“类其实也是一个对象”,只要是对 JVM类加载机制懂一点的人来说,这个是没问题的。而在后面分析原因部分,作者说“abstract 的类不能产生对象,但是static属于类,类已经是一个存在的对象”,这个也是没有异议的。关键在于后面,作者又说 ”这两个关键字在这一个关键点上有矛盾“。对于这句话,作者混淆了类对象和实例对象的概念了。

不管是不是抽象类,只要使用到了该类,虚拟机总是会在方法区中为该类创建一个 Class 对象,用来描述该类的运行时结构。我们写一段代码做一个简单的测试,如下:

  1. public class MonitorVehicleTracker {
  2. public static void main(String[] args){
  3. System.out.print(Door.class.getClassLoader());
  4. }
  5. }
  6. abstract class Door{
  7. public static  void set() {
  8. System.out.print("123");
  9. }
  10. }

运行结果为:

sun.misc.Launcher$AppClassLoader@15253d5

我们可以看到,抽象类 Door 确实被加载了(因为我们可以访问到它的 Class 对象),而且,它是由应用程序类加载器加载的。

也就是说,”abstract 类不能产生对象“的意思应该是 abstract 类在方法区有它对应的Class 对象,但是该Class 对象不能产生实例对象。因此,作者在这一点上分析 abstract 和 static 的矛盾是不正确的。

那么,abstract 和 static 不能同时使用的原因究竟是什么呢?

我们知道,抽象方法存在的意义便是被子类覆盖,实现多态性。而静态的方法在内存中只能有一份,所以子类可以继承,但不可以重写。在利用引用访问对象的字段或静态方法时,是引用类型(type)决定了事实上访问的是哪个字段,而非当前引用实际代表的是哪个类。子类的静态方法完全体现不出多态。因此,如果方法即是抽象的并且是静态,这就颠覆了抽象类,抽象方法本身存在的意义!

关于子类不能覆盖父类的静态方法,引用类型决定了访问哪个类的静态方法,测试代码如下:

public class Test {

    public static void main(String[] args) {
Door door = new AlarmDoor();
door.get();
}
} abstract class Door {
public static void get() {
System.out.print("Door");
}
abstract void set();
} class AlarmDoor extends Door {
public static void get() {
System.out.print("AlarmDoor");
} @Override
public void set() {
// TODO Auto-generated method stub }
}

输出结果:  Door

【Java基础】13、抽象方法不能是static或native或synchroniz 原因及误解的更多相关文章

  1. 抽象方法不能是static或native或synchroniz

    abstract 是抽象了,只有声明,没有具体的实现方法 static是静态的,是一种属于类而不属于对象的方法或者属性,而我们知道,类其实也是一个对象,他是在class文件加载到虚拟机以后就会产生的对 ...

  2. Java基础13:反射与注解详解

    Java基础13:反射与注解详解 什么是反射? 反射(Reflection)是Java 程序开发语言的特征之一,它允许运行中的 Java 程序获取自身的信息,并且可以操作类或对象的内部属性. Orac ...

  3. Java基础13:反射详解

    本节主要介绍Java反射的原理,使用方法以及相关的技术细节,并且介绍了关于Class类,注解等内容. 具体代码在我的GitHub中可以找到 https://github.com/h2pl/MyTech ...

  4. 【java基础 13】两种方法判断hashmap中是否形成环形链表

    导读:额,我介绍的这两种方法,有点蠢啊,小打小闹的那种,后来我查了查资料,别人都起了好高大上的名字,不过,本篇博客,我还是用何下下的风格来写.两种方法,一种是丢手绢法,另外一种,是迷路法. 这两种方法 ...

  5. java基础(13):static、final、匿名对象、内部类、包、修饰符、代码块

    1. final关键字 1.1 final的概念 继承的出现提高了代码的复用性,并方便开发.但随之也有问题,有些类在描述完之后,不想被继承,或者有些类中的部分方法功能是固定的,不想让子类重写.可是当子 ...

  6. java基础复习:final,static,以及String类

    2.final 1)为啥String是final修饰的呢? 自己答: 答案: 主要是为了“效率” 和 “安全性” 的缘故.若 String允许被继承, 由于它的高度被使用率, 可能会降低程序的性能,所 ...

  7. Java基础学习笔记十 Java基础语法之final、static、匿名对象、内部类

    final关键字 继承的出现提高了代码的复用性,并方便开发.但随之也有问题,有些类在描述完之后,不想被继承,或者有些类中的部分方法功能是固定的,不想让子类重写.可是当子类继承了这些特殊类之后,就可以对 ...

  8. java基础13 接口(及关键字:interface、implements)

    接口 1.接口的定义格式 interface 接口名{ } interface :接口的关键字 implements:实现接口的关键字 2.接口的作用 1.程序的解耦.(低耦合)        2.定 ...

  9. Java基础:关键字final,static

    一 . final 含义:adj.最后的,最终的; 决定性的; 不可更改的.在Java中是一个保留的关键字,可以声明成员变量.方法.类以及本地变量.一旦你将引用声明作final,你将不能改变这个引用了 ...

随机推荐

  1. Paper | Batch Normalization

    目录 1. PROBLEM 1.1. Introduction 1.2. Analysis 2. SOLUTION 2.1. Batch Normalization 及其问题 2.2. 梯度修正及其问 ...

  2. 基于UML的文献管理系统建模研究

    一.基本信息 标题:基于UML的文献管理系统建模研究 时间:2016 出版源:信息与电脑(理论版) 领域分类:UML:文献管理系统:系统建模: 二.研究背景 问题定义:图书的管理与规划 难点:系统和管 ...

  3. iOS 系统通知

    iOS相当多一部分系统事件实际上都是通过通知来完成的,依赖于通知的广播形式,我们可以在AppDelegate中通过添加空通知来捕捉所有通知: static NSString *const MYNOTI ...

  4. 配置docker官方源并用yum安装docker

    一.docker的官方安装文档: https://docs.docker.com/engine/installation/linux/centos/ 由docker给的文档可以看出它也只是去配置了一个 ...

  5. Dev修改gridview 背景色

    private void gridView1_RowCellStyle(object sender, DevExpress.XtraGrid.Views.Grid.RowCellStyleEventA ...

  6. Nhibernate入门篇连接Sqlserver的增删查改

    第一步:创建数据库 create table Emp( EmpId int primary key identity, EmpName ), EmpDate date ) 第二步:去官网下载:http ...

  7. JQuery Mobile - 固定住页面和页脚

    在点击页面空白时候,页眉和页脚会隐藏,在页眉和页脚加入以下代码就可以了: data-tap-toggle ="false" 例子: <div data-role=" ...

  8. 「ZJOI2018」胖(ST表+二分)

    「ZJOI2018」胖(ST表+二分) 不开 \(O_2\) 又没卡过去是种怎么体验... 这可能是 \(ZJOI2018\) 最简单的一题了...我都能 \(A\)... 首先我们发现这个奇怪的图每 ...

  9. Linux快速目录间切换cd pushd popd

    1.   cd -     当前目录和之前所在的目录之间的切换 2.   cd + Alt . 用上次命令的最后一个目录路径 要用上上次命令的最后一个目录,就Alt+.两次就可以了 3.   push ...

  10. javascript编程中this解析

    一.为什么要使用this? this 提供了一种更优雅的方式来隐式"传递"一个对象引用,因此可以将 API 设计得更加简洁并且易于复用.随着你的使用模式越来越复杂,显式传递上下文对 ...