背景介绍
什么是抽象类和接口
特点与区别
抽象类的特点
接口的特点
栗子
小结
如何选择
抽象与多态
面向接口编程
多态
继承和组合
总结
Milo
Struggle
shixinzhang
抽象类和接口
内部类
修饰符
装箱拆箱
注解
反射
泛型
异常
集合
IO
字符串
其他
抽象类和接口之间的区别?
什么时候创建抽象类?什么时候创建接口?
设计框架时该如何选择?
public abstract void f(); //没有内容
public abstract class BaseActivity {
private final String TAG = this.getClass().getSimpleName(); //抽象类可以有成员
void log(String msg){ //抽象类可以有具体方法
System.out.println(msg);
}
// abstract void initView(); //抽象类也可以没有抽象方法
}
public interface OnClickListener {
void onClick(View v);
}
抽象类是由子类具有相同的一类特征抽象而来,也可以说是其基类或者父类
抽象方法必须为 public 或者 protected(因为如果为 private,则不能被子类继承,子类便无法实现该方法),缺省情况下默认为 public
抽象类不能用来创建对象
抽象方法必须由子类来实现
如果一个类继承于一个抽象类,则子类必须实现父类的抽象方法,如果子类没有实现父类的抽象方法,则必须将子类也定义为抽象类
抽象类还是很有用的重构工具,因为它们使得我们可以很容易地将公共方法沿着继承层次结构向上移动
接口的所有方法访问权限自动被声明为 public
接口中可以定义“成员变量”,会自动变为 public static final 修饰的**静态常量**
可以通过类命名直接访问:ImplementClass.name
不推荐使用接口创建常量类
实现接口的非抽象类必须实现接口中所有方法,抽象类可以不用全部实现
接口不能创建对象,但可以申明一个接口变量,方便调用
完全解耦,可以编写可复用性更好的代码
public class BaseActivity extends Activity {
private final String TAG = this.getClass().getSimpleName();
void toast(String msg) {
Toast.makeText(this, msg, Toast.LENGTH_SHORT).show();
}
//其他重复的工作,比如设置标题栏、沉浸式状态栏、检测网络状态等等
}
public abstract class BaseActivity extends Activity {
private final String TAG = this.getClass().getSimpleName();
@Override
protected void onCreate(final Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(getContentViewLayoutId());
initView(); //这里初始化布局
loadData(); //这里加载数据
}
/**
* 需要子类实现的方法
* @return
*/
protected abstract int getContentViewLayoutId();
protected abstract void initView();
protected abstract void loadData();
void toast(String msg) {
Toast.makeText(this, msg, Toast.LENGTH_SHORT).show();
}
}
public class MainActivity extends BaseActivity{
private TextView mTitleTv;
@Override
protected int getContentViewLayoutId() {
return R.layout.activity_main;
}
@Override
void initView() {
mTitleTv = (TextView) findViewById(R.id.main_title_tv);
mTitleTv.setOnClickListener(this);
}
@Override
protected void loadData() {
//这里加载数据
}
}
interface OnLocationChangeListener {
void onLocationUpdate(String locationInfo);
}
public class LocationObserver {
List mListeners;
public LocationObserver setListeners(final List listeners) {
mListeners = listeners;
return this;
}
public List getListeners() {
return mListeners;
}
public void notify(String locationInfo) {
if (mListeners != null) {
for (OnLocationChangeListener listener : mListeners) {
listener.onLocationUpdate(locationInfo);
}
}
}
interface OnLocationChangeListener {
void onLocationUpdate(String locationInfo);
}
}
public class MainActivity extends BaseActivity implements View.OnClickListener,
LocationObserver.OnLocationChangeListener {
private TextView mTitleTv;
@Override
protected int getContentViewLayoutId() {
return R.layout.activity_main;
}
@Override
public void onClick(final View v) {
int id = v.getId();
if (id == R.id.main_title_tv) {
toast("你点击了 title");
}
}
@Override
void initView() {
mTitleTv = (TextView) findViewById(R.id.main_title_tv);
mTitleTv.setOnClickListener(this);
}
@Override
protected void loadData() {
//这里加载数据
}
@Override
public void onLocationUpdate(final String locationInfo) {
mTitleTv.setText("现在位置是:" + locationInfo);
}
}
抽象层次不同
抽象类是对类抽象,而接口是对行为的抽象
抽象类是对整个类整体进行抽象,包括属性、行为,但是接口却是对类局部行为进行抽象
跨域不同
抽象类所跨域的是具有相似特点的类,而接口却可以跨域不同的类
抽象类所体现的是一种继承关系,考虑的是子类与父类本质**“是不是”**同一类的关系
而接口并不要求实现的类与接口是同一本质,它们之间只存在**“有没有这个能力”**的关系
设计层次不同
抽象类是自下而上的设计,在子类中重复出现的工作,抽象到抽象类中
接口是自上而下,定义行为和规范
若使用接口,我们可以同时获得抽象类以及接口的好处
所以假如想创建的基类没有任何方法定义或者成员变量,那么无论如何都愿意使用接口,而不要选择抽象类
如果事先知道某种东西会成为基础类,那么第一个选择就是把它变成一个接口
只有在必须使用方法定义或者成员变量的时候,才应考虑采用抽象类
通过构造函数传递依赖对象
比如在构造函数中的需要传递的参数是抽象类或接口的方式实现
通过 setter 方法传递依赖对象
即在我们设置的 setXXX 方法中的参数为抽象类或接口,来实现传递依赖对象
接口声明实现依赖对象,也叫接口注入
即在函数声明中参数为抽象类或接口,来实现传递依赖对象,从而达到直接使用依赖对象的目的。
接口实现
继承父类重写方法
同一类中进行方法重载
public class LocationObserver {
List mListeners;
public LocationObserver setListeners(final List listeners) {
mListeners = listeners;
return this;
}
public List getListeners() {
return mListeners;
}
public void notify(String locationInfo) {
if (mListeners != null) {
for (OnLocationChangeListener listener : mListeners) {
listener.onLocationUpdate(locationInfo);
}
}
}
}