Java面向对象 —— 抽象类接口内部类匿名内部类
Posted 行稳方能走远
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Java面向对象 —— 抽象类接口内部类匿名内部类相关的知识,希望对你有一定的参考价值。
目录
抽象类(abstract)
java中可以定义没有方法体(只有方法头)的方法,该方法由子类来具体实现。该没有方法体的方法我们称之为抽象方法,含有抽象方法的类我们称之为抽象类。
有抽象方法的类,一定是抽象类。即抽象方法只能放在抽象类中。
但是抽象类中可以有具体方法,可以没有抽象方法。
特点:
(1)抽象方法不能被调用
抽象方法代表一种不确定的操作或行为
(2)抽象类不能被实例化
虽然按照提示也能完成方法体实例化,但这是不靠谱的使用方式(这种不靠谱的方式也是后面提及的匿名的内部类)
(3)抽象方法用abstract来修饰
不可以被实例化,那怎么使用这个抽象类呢?
抽象类的使用方法
做一个类来继承这个抽象类,继承的时候把方法体实现了,如下:
//抽象方法只能放到抽象类里面,因此前面也要加abstract
abstract class Test1
{
abstract void printInfo(); //在抽象类里面的方法,要么完善方法体,要么作为抽象方法
} //没有方法体的方法,该方法由子类来具体实现
//类似C语言中对函数的声明
class Test2 extends Test1 //继承抽象类,从而使用抽象类
{
@Override
public void printInfo() {
System.out.println("来自:test2");
}
}
public class Demo1 {
public static void main(String[] args){
Test2 t2 = new Test2();
t2.printInfo();
}
}
抽象类的应用:模板方法模式
模板方法模式定义:
父类抽象(abstract)化定义一系列方法作为模板(不具体),把一些步骤推迟到子类去实现,子类将重写这些方法以提供具体行为。
之前做的智能家居可以运行在多个平台上,比如51,32,树莓派,现在就定义在每个平台上完成这个项目的通用模板,然后再在具体平台实现,以51为例子(当然这只是一个类比,java在51单片机上不能运行):
abstract class Control
{
abstract void getCommand(); //是概括了在不同平台上完成智能家居项目的模板
abstract void socketCommand(); //抽象化这些方法,在子类(类比于具体平台)
abstract void lightControl(); //中再进行具体化
abstract void cameraControl();
public void work(){ //控制的基本流程
getCommand(); //接收指令
socketCommand(); //来自socket的指令
lightControl(); //灯的控制
cameraControl(); //相机的控制
}
}
class C51platform extends Control //当这个地方出现红色波浪线的时候
{ //光标放上去,可以看到解决方法的快捷键
@Override //把抽象方法重写,全部具体实现
void getCommand() {
System.out.println("getcommand in 51");
}
@Override
void socketCommand() {
System.out.println("socketcommand in 51");
}
@Override
void lightControl() {
System.out.println("lightcontrol in 51");
}
@Override
void cameraControl() {
System.out.println("cameracontrol in 51");
}
}
public class Test {
public static void main(String[] args) {
C51platform c51 = new C51platform(); //实例化出一个对象
c51.work(); //执行具体流程
}
}
运行结果:
getcommand in 51
socketcommand in 51
lightcontrol in 51
cameracontrol in 51
接口
接口的概念
接口(Interface),在JAVA中是一个抽象类型,是抽象方法的集合(重点强调的是方法、是行为,而不是属性、特征)。
interface 接口名{
//公有静态常量、抽象方法(抽象方法用的比较多)
}
class 类名{
}
接口并不是类,编写接口的方式和类很相似,但是它们属于不同的概念。类描述对象的属性和方法。接口则包含类要实现的方法。
接口与类的区别:————————
(1) 接口不能用于实例化对象
(2) 接口没有构造方法
而类是默认都有构造方法的(系统默认的参数为空的构造方法)
(3)接口中所有的方法必须是抽象方法
可以不指定修饰符,就默认为隐式抽象
(4)接口不能包含成员变量,除了 static 和 final 变量
接口中也一般不适用成员变量,以方法为主。
(5)接口不是被类继承了,而是要被类实现。而接口可以继承接口。
说法上的东西罢了,不用太纠结,具体看编程
接口的特点
接口中每一个方法也是隐式抽象的,接口中的方法会被隐式的指定为 public abstract(只能是 public abstract,其他修饰符都会报错)。
就像下图,只要你不写修饰符,那就默认为隐式抽象为public abstract,可以编译通过。但凡你使用别的修饰符,马上报错。
接口的使用
一个类通过继承接口的方式,从而来继承接口的抽象方法。
接口无法被实例化,但是可以被实现。一个实现接口的类,必须实现接口内所描述的所有方法(包括接口继承过来的方法),否则就必须声明为抽象类。
继承是有亲属关系的,is的关系;而接口是双方都有的行为,比如人和狗都要吃东西。
下面的例子是以一些人和狗子都具有的行为作为接口,用Man类和Dog类具体实现:
interface Behavior //接口,更注重方法
{
void eat(); //在接口中,不写修饰符,默认为隐式抽象
abstract void drink(); //当然写也无问题
}
class Man implements Behavior //一个类实现了这个接口
{ //从而来继承接口的抽象方法
@Override
public void eat() {
System.out.println("人吃米");
}
@Override
public void drink() {
System.out.println("人喝饮料");
}
}
class Dog implements Behavior //一个类实现了这个接口
{ //从而继承接口的抽象方法
@Override
public void eat() {
System.out.println("狗喜欢吃骨头");
}
@Override
public void drink() {
System.out.println("狗喝水");
}
}
public class Test {
public static void main(String[] args) {
new Man().eat(); //new就是实例化一个对象,所以new Man()已经是一个对象了
new Man().drink();
new Dog().eat();
new Dog().drink();
}
}
接口实现与抽象类继承的区别
1)抽象类和具体实现之间是一个继承关系,也就是如果采用抽象类的方式,则父类和子类在概念上应该是相同的 ,是is -a的关系。
比如父类为
老师
,子类为语文老师
,那么可以说语文老师是(is)一个(a)老师
。
(2)接口和实现类之间在概念上不要求相同,接口不去关注类之间的关系,它可以使没有层次关系的类具有相同的行为
抽象类是对一组具有相同属性和行为的逻辑上有关系的事物的一种抽象。
而接口则重点对一组具有相同行为的事物的一种抽象。
(3)抽象类中的方法可以有方法体,就是能实现方法的具体功能,但是接口中的方法不行。
(4)抽象类中的成员变量可以是各种类型的,而接口中的成员变量只能是 public static final 类型的。(但接口强调行为,少用变量)
(5)接口中不能含有静态代码块以及静态方法(用 static 修饰的方法),而抽象类是可以有静态代码块和静态方法。
(6)一个类只能继承一个抽象类,而一个类却可以实现多个接口
class People implements Survival,EnjoyLife //people这个类实现了多个接口
- 1
其实到后面你可以发现,一个类实现多个接口和接口的多继承再被类实现很像。
接口的多继承
在Java中,类的多继承是不合法,但接口允许多继承。
在接口的多继承中extends关键字只需要使用一次,在其后跟着继承接口。 如下:(足球这一接口继承了其他接口)
public interface Sport extends Basketball, Football,Ping_pong
- 1
继承过来后,类依旧要完成所有接口的抽象方法。
举个简单的小例子:
interface Survival //人关于生存的行为
{
void eat();
void drink();
}
interface EnjoyLife //人享受生活的行为
{
void seeMovie();
}
interface HowPeopleLive extends Survival,EnjoyLife //这个接口继承了上面两个接口
{
void happy();
/*void life(){ 接口中不允许有方法体
}*/
void life(); //只能在类的实现中赋予方法体
}
class People implements HowPeopleLive
{
//当一个类实现接口时,就要把接口里所有的抽象方法实现,具体化
@Override
public void eat() {
System.out.println("主要吃大米饭");
}
@Override
public void drink() {
System.out.println("主要喝白开水");
}
@Override
public void seeMovie() {
System.out.println("看电影感悟生活");
}
@Override
public void happy() {
System.out.println("你开心就好");
}
@Override
public void life() { //实现接口的方法体
eat();
drink();
seeMovie();
happy();
}
}
public class Demo1 {
public static void main(String[] args) {
People man = new People();
man.life();
}
}
运行结果:
主要吃大米饭
主要喝白开水
看电影感悟生活
你开心就好
内部类
概念
所谓内部类(Inner Class),就是讲一个类定义在另一个类的内部,内部的类就称为内部类。
public class Outer{
class Inner{
}
}
内部类可以很好地实现隐藏,成员内部类属于外部类的实例成员,成员内部类可以有权限修饰符。
可以使用protected private
修饰符内部类可以直接访问外部类的所有成员,包括私有的成员。
外部类不能直接访问内部类的成员,必须首先建立内部类的对象才能访问。
成员内部类(使用较多)及应用
创建成员内部类的实例
外部类名.内部类名 实例 = 外部类实例名.new 内部类构造方法(参数)
- 1
下面以访问内部类的方法为例子:
class Outer
{
int data;
void printData(){
System.out.println("外部类打印");
}
class Inner
{
int data;
void innerPrint(){
System.out.println("内部类打印");
}
}
}
public class Test {
public static void main(String[] args) {
Outer ou = new Outer(); //要使用内部类的方法,必须先实例化一个外部类的对象
Outer.Inner in = ou.new Inner();//再通过这个外部类的对象实例化一个内部类的对象
in.innerPrint(); //在进行访问方法即可
}
}
在成员内部类中访问外部类的成员方法和属性
外部类名.this.成员方法
//或者
外部类名.this.成员属性
例如:
class Outer
{
int data;
void printData(){
System.out.println("外部类打印");
}
class Inner
{
int data;
void innerPrint(){
System.out.println("内部类打印");
Outer.this.printData(); //内部类对外部类方法的访问
System.out.println("内部类访问外部类的属性:data="+Outer.this.data);//对属性的访问
}
}
}
外部类不能直接访问内部类的成员,必须先建立内部类的对象才能访问
(意义不大,用的较多的还是内部类访问外部类)
class Outer
{
int data;
void printData(){
System.out.println("外部类打印");
}
//外部类不能直接访问内部类的成员,必须先建立内部类的对象才能访问
void visitInner(){
Inner in = new Inner();//先建立内部类的对象
in.innerPrint(); //通过内部类的对象进行访问
}
class Inner
{
int data;
void innerPrint(){
System.out.println("内部类打印");
}
}
}
public class Test {
public static void main(String[] args) {
Outer ou = new Outer(); //要使用内部类的方法,必须先实例化一个外部类的对象
Outer.Inner in = ou.new Inner();//再通过这个外部类的对象实例化一个内部类的对象
ou.visitInner(); //外部类访问内部类打印
}
}
成员内部类有以下限制
(1)成员内部类不能和外部类重名
(2)不能在成员内部类中定义static属性、方法、类。(static final形式的常量定义除外)
因为一个成员内部类实例必然与一个外部类实例关联,static成员完全可以移到其外部类中去。
匿名内部类
概念
匿名内部类是没有名称的内部类,没办法引用它们。必须在创建时,作为new语句的一部分来声明并创建它们的实例。
这种形式的new语句声明一个新的匿名类,它对一个给定的类进行扩展,或者实现一个给定的接口,并同时创建该匿名类的一个新实例。
匿名内部类的创建与访问
匿名内部类必须继承一个类(抽象的,非抽象的都可以),或者实现一个接口,所有父类(或者父接口)是抽象类,则匿名内部类必须实现其所有抽象方法。
语法:
new interface/superclass(){类体}
- 1
例如:
(1)创建后立即访问
abstract class Demo1 //声明了一个抽象类
{
abstract void printInfo();//声明了一个抽象方法
}
public class Test {
public static void main(String[] args) {
new Demo1(){//既初始化又要实现内部的方法 不是实例化 而是创建了匿名内部类并实例化匿名内部类
void printInfo(){ //匿名内部类必须实现继承的类的所有方法
System.out.println("这不是demo1,而是匿名内部类的方法");
}
}.printInfo();//new的返回值就是一个对象,所以可以直接通过“.”这样访问匿名内部类的方法
}
}
运行结果:
这不是demo1,而是匿名内部类的方法
- 1
(2)当然,也可以用“多态”进行访问(目前我也不知道多态是啥)
abstract class Demo1
{
abstract void printInfo();
}
public class Test {
public static void main(String[] args) {
Demo1 d = new Demo1(){ //这感觉像是实例化了一个Demo1得到对象d,实际上得出的这个Demo1是抽象类的子类
void printInfo(){ //匿名内部类必须实现继承的类的所有方法
System.out.println("这不是demo1,而是匿名内部类的方法");
}
};
d.printInfo();
}
}
运行结果:
这不是demo1,而是匿名内部类的方法
- 1
(3)匿名内部类实现一个接口
这种用法可能会在安卓的线程,按键响应做这样的事情。
interface Demo2 //接口
{
abstract void interprint();
}
public class Test {
public static void main(String[] args) {
new Demo2(){
public void interprint(){ //这里不使用public就报错了
System.out.println("这不是接口的实例,而是匿名内部类的方法");
}
}.interprint();
}
}
运行结果:
这不是接口的实例,而是匿名内部类的方法
- 1
以上是关于Java面向对象 —— 抽象类接口内部类匿名内部类的主要内容,如果未能解决你的问题,请参考以下文章
JAVA07 面向对象(高级)类变量类方法代码块final抽象类接口内部类
JAVA07 面向对象(高级)类变量类方法代码块final抽象类接口内部类