Java基础之接口与抽象类及多态、内部类
final关键字
- 被其修饰的类,不能被继承。
- 被其修饰的方法,不能被覆盖。
- 被其修饰的变量,是一个常量,不能被修改,所以定义时必须初始化(和C++的const类似)。
一般有final,会搭配static使用。如
final static double PI = 3.14;
- 常量的命名规则 --> 所有字母大写,多个单词,中间用下划线连接。
抽象类
猫和狗有共性,将共性抽取出来,放入Animal中,Animal是抽象的(想象不出实体是什么)。
public abstract class Animal {
// 抽象类也有构造函数,给子类初始化用
public Animal() {
System.out.println("我们都是动物");
}
public abstract void eat();
}
// 也可以存在非抽象函数
public void sleep() {
System.out.println("睡觉了zzz~");
}
}
class Cat extends Animal {
Cat() {
System.out.println("我是一只小猫咪");
}
@Override
public void eat() {
System.out.println("小猫吃鱼");
}
}
class Dog extends Animal {
Dog() {
System.out.println("我是一条小狗狗");
}
@Override
public void eat() {
System.out.println("狗狗啃骨头");
}
}
public class Demo {
public static void main(String args[]) {
public static void main(String[] args) {
Animal a = new Cat();
a.eat();
a.sleep();
// 打印如下内容
// 我们都是动物
// 我是一只小猫咪
// 小猫吃鱼
// 睡觉了zzz~
}
}
因为类Cat、类Dog或者其他类要继承类Animal,且类Animal的show()是抽象的未被定义的,子类必须覆盖父类的方法,定义自己特有的eat()
方法(猫和狗吃的东西不全一样),故在抽象类中的方法只是声明。
抽象类的特点
- 方法只有声明没有实现,为抽象方法,修饰符abstract,抽象方法必须在抽象类中。
- 抽象类不可以实例化,即不能new。因为调用抽象方法没有意义。
- 子类必须覆盖抽象类的所有抽象方法后,该子类才能实例化,否则还是抽象类。
Q:抽象类有没有构造函数?
A:有,用来给子类初始化,如上例,最先打印我们都是动物。
Q:可以没有抽象方法吗,或者说,可以不全是抽象方法吗?
A;可以。但是接口interface必须全是抽象方法。
abstract关键字不能和哪些关键字共存
- private:因为子类要覆盖抽象类的抽象方法,私有后不可访问,怎么覆盖?
- static:抽象类中只是声明了,子类需要重写抽象类的方法。而静态方法不能被重写,所有矛盾了。
- final:final修饰的方法不能被覆盖,子类要覆盖啊,所以不能加。
接口-interface
当一个抽象类中全部是抽象方法时,可将其定义为interface。
- 变量规定为:public static final,即使写成int a,也被认为是
public static final int a;
- 方法规定为:public abstract
- 接口中的成员,都是public的
接口和抽象类一样,不可实例化,用来给其他类扩展功能,接口与接口之间为继承关系,接口可以多继承。Java不支持直接多继承,改成了多实现,即一个子类多个接口,解决了单继承的局限性。
抽象类和接口
抽象类只能被单继承,接口可以背多实现。
抽象类中也可以定义非抽象方法,子类可以直接用非抽象方法。接口中只能定义抽象方法。共同点是,其抽象方法都必须被重写。
抽象类定义基本的共性内容,接口是定义额外的功能。
多态
对于Animal a = new Cat()
,new出子类,却让父类指向子类,就叫多态。
public void method(Animal a) {
a.eat(); // 运行时根据具体传入的实参,来调用对应的方法
// 若Dog和Cat都继承了Animal,参数传入Dog就执行dog.eat(),传入Cat就执行cat.eat()
// 这有点像C++中的动态绑定
}
// 和以下函数重载比较起来,是不是方便了
public void method(Dog a) {
a.eat()
}
public void method(Cat a) {
a.eat();
}
多态好处
从上例可以看出,多态的好处:前期定义的代码可以用于后期,比如再来一个Wolf类继承Animal,就可以传入wolf调用以上函数,传入的就是wolf了。
多态缺点
前期定义的内容,不可调用后期子类的特有内容。举个例子
public void method(Animal a) {
a.eat(); // 父类定义了该方法
a.catchMouse(); // Animal没有定义“抓老鼠”的方法,若是传入的参数不是Cat,则报错
}
// 怎么解决?强转回来!如下
public void method(Animal a) {
a.eat();
// 先判断传入的实参,若是Cat,进行强转回Cat后,再执行“抓老鼠”
if (a instanceof Cat){
Cat c = (Cat)a;,
c.catchMouse();
}
// 若传入的是狗,就执行“叫”
if (a instanceof Dog) {
Dog d = (Dog)a;
d.bark();
}
}
Animal a = new Cat();
- 若子类没有覆盖父类的方法,就调用父类自己的方法。
- 若子类调用了自己特有的方法,父类并没有定义该方法,则编译不通过。Cat类型提升为Animal后,Cat特有的方法会被舍弃,与Animal同名的函数被覆盖。
换个说法,a是Animal,它只能用Animal定义过的方法和变量,但执行函数时实际执行的是Cat的重写方法。总的来说,如下
- 对于成员变量,和静态函数:编译和运行都是看父类是否具有该变量和静态,若a调用了Cat独有的变量,则报错。
- 对于成员函数,编译时候检查Animal是否定义该方法,运行时候执行子类重写的方法,若子类没有重写,自然执行父类的。
内部类-嵌套类
public class Out {
private String out;
private class In {
private String in;
}
}
- 内部类可以直接访问外部类的成员(private的也行)
- 但是外部类要访问内部类,必须建立内部类的对象。
- 内部类也可以是static的,这是,内部类随着外部类的加载而加载,相当于是外部类。
Out.In in = new Out().new In(); // 非static内部类的实例化
Out.In in = new Out.In(); // static内部类可以这样实例化
In in = new In(); // static内部类也可以这样实例化,相当于外部类了,仅在本例有效
如果内部类用到了静态成员,则内部类必须是static的。
同名变量的访问。
public class Out {
private int num = 1;
private class In {
int num= 2;
public void show() {
int num = 3;
System.out.println(num); // 打印3
System.out.println(this.num); // 打印2
System.out.println(Out.this.num); // 打印1
}
}
}
方法内部的内部类
public class Out {
public void func() {
// num是func方法中的局部变量,func中又定义了内部类,用到这个num,该num必须是final的
final int num = 1;
// java8中,会默认加上final,所以可以直接int num = 1;
class In {
public void show() {
System.out.println(num);
}
}
}
}
方法里的内部类不能访问外部类方法中的局部变量,除非变量被声明为final类型,因为内部类对象的生命周期超过局部变量的生命周期。有可能出现成员方法已调用结束,局部变量已死亡,但匿名内部类的对象仍然活着。
Java 8中:如果局部变量被匿名内部类访问,那么该局部变量相当于自动使用了final修饰。
匿名内部类
若一个程序的某个类只使用了一次,则可定义为匿名内部类,用完就消亡。条件是必须继承或者实现一个外部类或者接口。
abstract class Person {
public abstract void eat();
}
// 不用内部类的情况,需要再写一个类继承Person覆盖方法
class Child extends Person {
@Override
public abstract void eat() {
System.out.println("Child eat");
}
}
public class Out {
public static void main(String[] args) {
// 匿名内部类,这里相当于继承了抽象类Person,新写了一个无名的子类,并覆盖了eat方法
new Person() {
public void eat() {
System.out.println("eat something");
}
}.eat();
}
}
下面内容转自Nerxious-博客园,总得得不错,特地搬过来。
// 不使用匿名内部类
abstract class Person {
public abstract void eat();
}
class Child extends Person {
public void eat() {
System.out.println("eat something");
}
}
public class Demo {
public static void main(String[] args) {
Person p = new Child();
p.eat();
}
}
//运行结果:eat something
// 可以看到,我们用Child继承了Person类,然后实现了Child的一个实例,将其向上转型为Person类的引用但是,如果此处的Child类只使用一次,那么将其编写为独立的一个类岂不是很麻烦?这个时候就引入了匿名内部类
// 匿名内部类的基本实现
abstract class Person {
public abstract void eat();
}
public class Demo {
public static void main(String[] args) {
Person p = new Person() {
public void eat() {
System.out.println("eat something");
}
};
p.eat();
}
}
//运行结果:eat something
// 可以看到,我们直接将抽象类Person中的方法在大括号中实现了这样便可以省略一个类的书写并且,匿名内部类还能用于接口上
// 在接口上使用匿名内部类
interface Person {
public void eat();
}
public class Demo {
public static void main(String[] args) {
Person p = new Person() {
public void eat() {
System.out.println("eat something");
}
};
p.eat();
}
}
//运行结果:eat something
// 由上面的例子可以看出,只要一个类是抽象的或是一个接口,那么其子类中的方法都可以使用匿名内部类来实现。最常用的情况就是在多线程的实现上,因为要实现多线程必须继承Thread类或是继承Runnable接口
// Thread类的匿名内部类实现
public class Demo {
public static void main(String[] args) {
Thread t = new Thread() {
public void run() {
for (int i = 1; i <= 5; i++) {
System.out.print(i + " ");
}
}
};
t.start();
}
}
// 运行结果:1 2 3 4 5
// Runnable接口的匿名内部类实现
public class Demo {
public static void main(String[] args) {
Runnable r = new Runnable() {
public void run() {
for (int i = 1; i <= 5; i++) {
System.out.print(i + " ");
}
}
};
Thread t = new Thread(r);
t.start();
}
}
// 运行结果:1 2 3 4 5
by @sunhiayu
2016.12.11
Java基础之接口与抽象类及多态、内部类的更多相关文章
- 【Java基础】接口和抽象类之间的对比
Java 中的接口和抽象类之间的对比 一.接口 Interface,将其翻译成插座可能就更好理解了.我们通常利用接口来定义实现类的行为,当你将插座上连接笔记本的三角插头拔掉,换成微波炉插上去的时候,你 ...
- Java基础——关于接口和抽象类的几道练习题
呃,一定要理解之后自己敲!!!这几道题,使我进一步了解了接口和抽象类. 1.设计一个商品类 字段: 商品名称,重量,价格,配件数量,配件制造厂商(是数组,因为可能有多个制造厂商) 要求: 有构造函数 ...
- Java基础(四)--接口和抽象类
接口和抽象类能够体现OOP的抽象,而接口和抽象类也是日常开发中经常用到的 抽象方法: 抽象方法就是被abstract修饰的方法,只有声明,没有实现,也就是没有方法体 public abstract v ...
- java基础之接口(抽象类与接口的区别)
概述 猫狗案例,我们想想狗一般就是看门,猫一般就是作为宠物了,对不.但是,现在有很多的驯养员或者是驯的,这应该属于经过特殊的培训训练出来的,对不.所以,这些额外的动作定义到动物类中就不合适,也不适合直 ...
- 【java基础】接口VS抽象类
1.至少有一个被abstract修饰的方法,同时修饰类名的类为抽象类,抽象的方法必须被子类覆盖,抽象的类必须被继承,抽象的类可以包含非抽象方法,只能单继承. 2.接口中所有的变量是static fin ...
- 30.Java基础_接口_抽象类_具体类实现案例
public interface SpeakEnglish { public abstract void speak(); } public abstract class Person { priva ...
- 第二十八节:Java基础-进阶继承,抽象类,接口
前言 Java基础-进阶继承,抽象类,接口 进阶继承 class Stu { int age = 1; } class Stuo extends Stu { int agee = 2; } class ...
- Java基础-面向对象第三大特性之多态(polymorphism)
Java基础-面向对象第三大特性之多态(polymorphism) 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 一.多态概述 多态是继封装,继承之后,面向对象的第三大特性,多态的 ...
- Java基础十--接口
Java基础十--接口 一.接口的定义和实例 /* abstract class AbsDemo { abstract void show1(); abstract void show2(); } 8 ...
随机推荐
- Cordova各个插件使用介绍系列(四)—canvas2ImagePlugin保存二维码到手机本地
详情链接地址:http://www.ncloud.hk/%E6%8A%80%E6%9C%AF%E5%88%86%E4%BA%AB/cordova-4-canvas2imageplugin/ 在前面几篇 ...
- ionic中点击图片看大图的实现
在页面上显示了几张图片后,因为是手机端,图片会有点小的感觉,就想着怎么样才能让用户点击小图片看到大图呢,项目中ionic结合angularjs实现了这个功能 1.首先是三张小图上应添加一个函数,当点击 ...
- React.js 小书介绍
React.js 小书 Github 关于作者 这是一本关于 React.js 的小书. 因为工作中一直在使用 React.js,也一直以来想总结一下自己关于 React.js 的一些知识.经验.于是 ...
- [leetcode-606-Construct String from Binary Tree]
You need to construct a string consists of parenthesis and integers from a binary tree with the preo ...
- 【LeetCode】105 & 106. Construct Binary Tree from Inorder and Postorder Traversal
题目: Given inorder and postorder traversal of a tree, construct the binary tree. Note:You may assume ...
- 【Android Developers Training】 103. 查询当前地点
注:本文翻译自Google官方的Android Developers Training文档,译者技术一般,由于喜爱安卓而产生了翻译的念头,纯属个人兴趣爱好. 原文链接:http://developer ...
- 【Android Developers Training】 24. 保存键值对
注:本文翻译自Google官方的Android Developers Training文档,译者技术一般,由于喜爱安卓而产生了翻译的念头,纯属个人兴趣爱好. 原文链接:http://developer ...
- 5.Smart使用内置函数或者自定义函数
1.使用内置函数 例如使用date函数 {"Y-m-d"|date:$time}格式{第一个参数|方法:第二个参数:第三个参数}即可转换成 2016-07-19 2.使用resi ...
- hadoop伪分布式环境搭建
环境:Centos6.9+jdk+hadoop1.下载hadoop的tar包,这里以hadoop2.6.5版本为例,下载地址https://archive.apache.org/dist/hadoop ...
- xUtils使用详细介绍
xUtils3使用详解 一.xUtils简介: xUtils是基于Afinal开发的目前功能比较完善的一个Android开源框架,官网:https://github.com/wyouflf/xUtil ...