Java中的接口和抽象类

Posted lxyz

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Java中的接口和抽象类相关的知识,希望对你有一定的参考价值。

接口的概念
    在Java中接口是一个全部由抽象方法组成的集合,接口需要用interface定义,里面只能有抽象的方法和常量。

接口体现的是事物扩展的功能,在Java中,类定义了一个实体,包括实体的属性,实体的行为。而接口定义了一个实体可能发生的动作,只有一个声明,没有具体的行为。

    当一个方法在很多类中有不同的体现是时候这个时候就可以将这个方法抽象出来做成一个接口。

    接口里面只能有不可修改的全局常量,只能有抽象的方法,接口没有构造方法。

定义一个接口:

interface Inter {
public static final int i=10; //全局常量前缀public static final
public abstract void eat(); //抽象的方法
}
接口的特点
定义接口时使用interface定义,区别于抽象类,不需要加class。
接口不能被实例化,不能直接创建对象,因为接口里面只有抽象的方法,没有具体的功能。
接口可以继承接口,接口要实现具体的功能必须有实现他的子类,实现接口的子类中必须重写接口全部的抽象方法。
接口和接口之间可以多继承。
接口的子类可以是抽象类,但是没有实际的意义。
一个子类可以实现多个接口,通过implements关键字去实现。
接口需要通过多态才能创建对象。
如下:

interface A {
public static final int i = 10; //接口只能定义全局常量需要加public static final如果不加系统默认给出,推荐加。
                                                
public abstract void eat();
}

interface B extends A { // 接口可以继承接口
public abstract void sleep();
}

interface C {
public abstract void look();
}

abstract class D {        //定义一个抽象类
public void run() {
System.out.println("跑起来");
}

public abstract void learn();
}

public class Text extends D implements B, C { //一个子类可以继承一个抽象类同时实现多个接口
//子类如果不是抽象类就必须实现所有的抽象方法

public void eat() { //实现接口A中的抽象方法
System.out.println("吃东西");
}

public void look() { //实现接口C中的抽象方法
System.out.println("看风景");
}

public void sleep() { //实现接口B中的抽象方法
System.out.println("睡懒觉");
}

@Override
public void learn() { //重写抽象类D中的抽象方法
System.out.println("学Java");
}

public static void main(String[] args) {
B b=new Text(); //多态,接口的引用指向子类的对象
b.eat();
b.sleep();
System.out.println(B.i);    //静态常量通过接口名去访问,不推荐用对象去调用
                C c=new Text();
c.look();
D d=new Text();
d.learn();

}
}
/**
* 输出为:
吃东西
睡懒觉
10
看风景
学Java
*/
接口作为形式参数
如果一个方法的形式参数为接口如下:

interface Inter{
public abstract void learn();
}
class B{
public void student(Inter a) {        //形式参数为接口
a.learn();
}
}
public class Text{
public static void main(String[] args) {

}
}
此时我们想调用B类中的student方法怎么做?我们有两种方法

因为接口不能创建对象所以我们需要给出他的子实现类创建子实现类的对象去调用其中的方法。
可以通过内部类的方式,不需要提供子实现类。
创建子实现类的方式:

interface Inter{
public abstract void learn();
}
class B{
public void student(Inter a) {
a.learn();
}
}
class InterImpl implements Inter{ //创建Inter的子实现类

public void learn() {
System.out.println("学习");
}

}
public class Text{
public static void main(String[] args) {
Inter i=new InterImpl(); //通过多态创建接口的对象
B b=new B(); //创建B类的对象
b.student(i); //传递对象到Student方法内去调用learn方法
}
}
/**
* 输出为:
学习
*/
内部类
        如果一个类被定义到了另一个类的里面或者方法里面这个类就叫做内部类,内部类包括成员内部类、局部内部类、匿名内部类和静态内部类四种。

成员内部类
        成员内部类在外部类的成员位置,成员内部类可以无条件访问外部类的所有内容包括static静态的和private私有的。

public class Outside {
int a = 10;
private int b = 20;

class inside { // inside就是成员内部类
public void show() { // 内部类的方法
System.out.println(a);
System.out.println(b);
}
}
}
注意:

当内部类定义了和外部类相同的成员变量和方法时,就近原则优先访问内部类的变量和方法,如果需要使用外部类的成员和方法需要使用this关键字

外部类.this.成员变量
外部类.this.成员方法
外部类不能直接访问内部类的变量和方法,需要通过创建内部类的对象来访问:

public class Outside {
int a = 10;
private int b = 20;

class Inside { // inside就是成员内部类
public void show() { // 内部类的方法
System.out.println(a);
System.out.println(b);
}
}
public void show2() {
Inside i=new Inside();
i.show();
}
}
成员内部类是依附于外部类而存在的,也就是说如果想要创建一个内部类的对象前提需要有一个外部类的对象,其他类中需要访问成员内部类的方法或者变量需要通过:

外部类名.内部类名 对象名 = 外部类对象.内部类对象

来创建成员内部类的对象:

class Outside {
int a = 10;
private int b = 20;

class Inside { // inside就是成员内部类
public void show() { // 内部类的方法
System.out.println(a);
System.out.println(b);
}
}

}

public class Text2 {
public static void main(String[] args) {
Outside.Inside i=new Outside().new Inside();    //创建内部类的对象的格式
i.show();
}
}
/**
输出为:
10
20
 */
如果成员内部类的访问权限是private,那么这个内部类只能在外部类中访问,其他类中不能通过上面的方法来创建私有内部类的对象。

class Outside {
int a = 10;

private class Inside { // 私有的成员内部类,只在外部类中可以使用。
public void show() { // 内部类的方法
System.out.println(a);
}
}

}

public class Text2 {
public static void main(String[] args) {
// Outside.Inside i=new Outside().new Inside();
// i.show();
// 出错,无法访问私有的内部类
}
}

局部内部类
局部内部类是定义在一个方法里的类,局部内部类的访问仅限于方法内或者该作用域内。

局部内部类访问局部变量时候需要给局部变量添加final

因为局部变量是在方法中定义的变量,当当前方法执行完毕后局部变量会被Java回收,此时如果局部内部类的对象对局部变量还存在引用的话就会出现对象指向了一个不存在的变量,因此局部内部类只能访问被final修饰的局部变量。

class Outside {
public void show() {
final int a=1;
class Inside{
public void show2() {
System.out.println(a); //局部内部类访问局部变量时候需要给局部变量添加final
//在jdk7以后如果不加会自动给出,但是会警告
}
}
}
}
局部内部类是不能有public,private,static这样的修饰词的。
静态内部类
格式上就是成员内部类前面加了static,他的特点是只能访问外部类中被static修饰的成员。

class Outside {
static int a = 10;

static class Inside { // 静态内部类
public void show() {
System.out.println(a); // 只能访问外部的静态成员
}

}

}

public class Text2 {
public static void main(String[] args) {
Outside.Inside i = new Outside.Inside(); // 静态内部类创建对象的方式
i.show();

}
}
/**
* 输出为: 10
*/
匿名内部类
匿名内部类在实际开发中用的最多,匿名内部类的前提条件是存在一个类或者接口,这个类可以为抽象类。

匿名内部类的格式为:

new 类名或接口名{
重写的方法;
}
匿名内部类本质上是继承了该类或实现了接口中的方法。

比如我们上面提到的形式参数是接口的问题就可以通过匿名内部类的方式来重写接口中抽象的方法而不需要通过创建子实现类。

interface Inter {
public abstract void learn();
}

class B {
public void student(Inter a) {
a.learn();
}
}

public class Text {
public static void main(String[] args) {
Inter a=new Inter() { //匿名内部类

public void learn() { //直接在匿名内部类中重写接口中抽象的方法不需要创建接口的子实现类
System.out.println("学习");
}
};
a.learn();        //调用learn方法
}
}
/**
* 输出为: 学习
*/
例题分析:
补齐代码
interface Inter { 
                        void show(); 
                }
class Outer { 
                        //补齐代码
                }
class OuterDemo {
public static void main(String[] args) {
Outer.method().show();
}
}
要求在控制台输出”HelloWorld”
这道题中先看主方法,主方法中
Outer.method()
这句话可以成立说明method方法是静态的,只有静态的方法才能直接被类名调用。继续看

Outer.method().show();
这句话可以成立说明method方法返回了个Inter的匿名对象,只有对象才能通过   .方法名来调用方法。

因为这里没有Inter接口的子实现类,所以我们要返回一个实现Inter接口的匿名内部类,在匿名内部类中去实现接口的抽象方法。

所以补齐之后的代码为:

interface Inter {
void show();
}

class Outer { 
// 补齐代码 
public static Inter method() {
return new Inter() { //返回的是实现接口的匿名内部类

public void show() {    /匿名内部类中实现show方法
System.out.println("Hello word");
}
};
}
}
class OuterDemo {
public static void main(String[] args) {
Outer.method().show();
}
}
/**
Hello word
* */


形式参数为抽象类中的问题
abstract class A{
public void sleep() {
System.out.println("睡觉");
}
}
class B{
public void cat(A a) {
a.sleep();
}
}
public class Text {
public static void main(String[] args) {

}
}
如果我们需要调用B类中的cat方法,因为A类是个抽象类,不能直接创建A类的对象,我们需要先给A类创建一个子类,然后用多态的方式创建A类的对象传入cat方法的形式参数部分。

abstract class A{
public void sleep() {
System.out.println("睡觉");
}
}
class B{
public void cat(A a) {
a.sleep();
}
}
class C extends A{

}
public class Text {
public static void main(String[] args) {
A a=new C();
a.sleep();
}
}
/**
* 输出为: 睡觉
*/
也可以用匿名内部类的方式,好处是不需要额外给出A类的子类

abstract class A{
public void sleep() {
System.out.println("睡觉");
}
}
class B{
public void cat(A a) {
a.sleep();
}
}
public class Text {
public static void main(String[] args) {
A a=new A() {
//匿名内部类,因为Sleep方法不是抽象方法,所以不需要重写。
};
a.sleep();
}
}
/**
* 输出为: 睡觉
*/


什么时候使用接口和抽象类


抽象类是对事物本身的抽象,比如教师类,学生类就可以抽象为人类。

接口是对行为的抽象,比如教师要学英语,学生也要学英语,学英语就可以抽象为接口。

抽象类表示的是这个对象是什么,接口是表示这个对象能干什么。

所以抽象类只能有一个子类,就比如教师和学生只能是人类不能是非人类。

而教师或者学生可以实现多个接口。他们既可以学英语也可以学数学。



































































































































































































































































































































































以上是关于Java中的接口和抽象类的主要内容,如果未能解决你的问题,请参考以下文章

Java中的抽象类和接口

java—抽象类和接口有什么区别

Java抽象类和接口

java中的接口和抽象类的异同

java中抽象类和接口的区别?

Java中的接口和抽象类