您的位置:首页 > 编程语言 > Java开发

抽象类(abstract class)和接口(interface)分析

2017-11-24 22:22 363 查看
个人博客:www.letus179.com

概念

抽象类:包含抽象方法的类就称为 抽象类;

接口: 抽象方法的集合,方法没有具体实现即不包含方法体。

两者异同

相同点

不能
被实例化;

接口的实现类
抽象类的子类
必须实现
接口
抽象类中
的方法后才能被实例化

不同点

接口
中的方法是高度抽象的,只有定义,没有具体的实现;
抽象类
中可以有定义也可以有实现;

接口
中的方法默认为
public abstract
, 可以直接写
public
, 可以都省略不写;
接口
中方法修饰符不能是
private
, 接口需要实现,所以私有的方法没有意义;
抽象类
中的具体实现的方法和普通的类一样,而只有定义的方法必须用
abstract
修饰,不然
编译不通过
;而且
抽象方法
的修饰符不能是
private
static
synchronized
native
,能用
默认的
public
protected


接口
中定义变量默认为
public static final
, 并且要赋予
初始值
,不然编译不通过;
抽象类
和普通的类一样,可以有自己的成员变量,可以重新赋值;

接口
需要
实现(implements)
抽象类
需要
继承(extends)
,一个类可以实现多个接口,但是只能继承一个抽象类(单继承多实现)。

接口三问

接口方法能否用
private
修饰

不能。因为接口是对外开放的,需要具体的类来实现其中的方法,私有的方法作用范围为本类,在接口中定义私有方法没有任何意义,编译不会通过。

接口方法能否用
synchronized
修饰

不能。
synchronized
是一种
同步锁
,在修饰方法时,需要具体逻辑,而接口只是定义,因为直接修饰接口中的方法没意义,可以用来修饰接口方法的
具体实现


接口方法能否用
static
修饰

这和jdk版本有关。jdk8之前:不能;jdk8新特性: 能。

——参见JDK8新特性之接口的静态方法和默认方法

举例

这里提供两种方式:
jad反编译
反射
来获取成员变量和方法的相关内容。

jad反编译

下面先给出对应源码,再用
jad
反编译
.class
文件。反编译执行命令如下:

jad -a -o -s java 类名.class


jad
详细命令参见反编译小工具:jad常用命令介绍

接口.java源码

MyInterface.java
接口源码如下:

public interface MyInterface {

String name = "MyInterface";

void add();
}


接口.class反编译

MyInterface.class
反编译结果如下:

public interface MyInterface {

public abstract void add();

public static final String name = "MyInterface";
}


可以看到,

1.在成员变量(常量)中默认的修饰符是
public static final
;

2.在方法中,默认的修饰符是
public abstract


抽象类.java源码

MyAbstract
抽象类源码如下:

public abstract class MyAbstract {

public String name;

void get() {
System.out.println("MyAbstract get() ");
}

// 抽象类中的没有实现的方法必须是“abstract”
abstract void delete();
}


抽象类.class反编译

public abstract class MyAbstract {

public MyAbstract() {

}

void get() {
System.out.println("MyAbstract get() ");
}

abstract void delete();

public String name;
}


可以看到,成员方法和成员变量和普通类一样,是什么修饰就是什么。

反射获取

这里新建一个
MyTest
类,
继承
抽象类
MyAbstract
,并且
实现
接口
MyInterface


反射代码

import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;

public class MyTest extends MyAbstract implements MyInterface {

public static void main(String[] args) {

Field[] abstractFields = MyAbstract.class.getDeclaredFields();
Method[] abstractMethods = MyAbstract.class.getDeclaredMethods();

System.out.println("抽象类MyAbstract成员变量反射信息:");
for (Field f : abstractFields) {
System.out.println("变量名:" + f.getName());
System.out.println("修饰符:" + Modifier.toString(f.getModifiers()));
System.out.println("变量类型:" + f.getType());
}

System.out.println();
System.out.println("抽象类MyAbstract成员方法反射信息:");
for (Method m : abstractMethods) {
System.out.println("方法名:" + m.getName());
System.out.println("修饰符:" + Modifier.toString(m.getModifiers()));
System.out.println("返回类型:" + m.getReturnType()  + "\n");
}

Field[] interfaceFields = MyInterface.class.getDeclaredFields();
Method[] interfaceMethods = MyInterface.class.getDeclaredMethods();

System.out.println();
System.out.println("接口MyInterface成员变量反射信息:");
for (Field f : interfaceFields) {
System.out.println("变量名:" + f.getName());
System.out.println("修饰符:" + Modifier.toString(f.getModifiers()));
System.out.println("变量类型:" + f.getType());
}

System.out.println();
System.out.println("接口MyInterface成员方法反射信息:");
for (Method m : interfaceMethods) {
System.out.println("方法名:" + m.getName());
System.out.println("修饰符:" + Modifier.toString(m.getModifiers()));
System.out.println("返回类型:" + m.getReturnType());
}

}

@Override
public void add() {

}

@Override
void delete() {

}
}


运行结果

抽象类MyAbstract成员变量反射信息:
变量名:name
修饰符:public
变量类型:class java.lang.String

抽象类MyAbstract成员方法反射信息:
方法名:get
修饰符:
返回类型:void

方法名:delete
修饰符:abstract
返回类型:void

接口MyInterface成员变量反射信息:
变量名:name
修饰符:public static final
变量类型:class java.lang.String

接口MyInterface成员方法反射信息:
方法名:add
修饰符:public abstract
返回类型:void


可以看到,和
jad
反编译的结果是一样的。

具体的
反射机制
请参见另一篇博文反射机制基础解析
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息