Java面向对象知识点总结04---接口 内部类

1、接口

接口:只提供形式,不提供任何的具体实现。
接口中只有抽象方法和常量,不可能有非抽象方法,常量必须被赋值。

  • 常量默认被public static final修饰
  • 方法默认被public static abstractl修饰
  • 接口不能被实例化
  • 子类必须重写接口中的所有方法,否则只能是抽象类,但是子类继承了该抽象类必须重写接口中的方法。
  • 接口可以多继承接口
  • 当实现接口中的方法时,返回值类型和形参列表不能变

2、内部类

内部类是在一个类的内部定义的类

  • 当某个类只为一个类提供服务时,可以将这个类定义成内部类

  • 可以解决接口或者抽象类不能实例化的问题

内部类分为成员内部类静态内部类局部内部类匿名内部类四种

成员内部类

一个类可以拥有一个类(注意不是对象)作为成员

public class memberTest {
	int a;//成员变量
	class b {
		//成员内部类
	}
	void fuunc c() {
		//方法
	}
}
  • 内部类可以直接调用外部类的属性和方法(包括私有的)
  • 外部类要想调用内部类的属性和方法,需要通过实例化内部类的对象去调用
  • 要想在别的类中创建一个内部类,需要先实例化一个外部类的实例再实例化内部类(成员内部类是实例相关的),创建内部类对象格式:
外部类名 outer = new 外部类名();  内部类名 inner = outer.new 内部类名();
外部类名.内部类名 in = new 外部类名().new 内部类名(); //两者等价
  • 当外部类和内部类的属性或方法重名时,在内部类可以通过外部类名.this.属性名(方法名)访问外部类的属性和方法
  • 非静态内部类不能有静态变量,但可以访问外部类静态变量

静态内部类

静态内部类就是使用static关键字修饰的成员内部类。静态内部类只能访问外部类的静态成员。

  • 要想在别的类中创建一个静态内部类不需要先实例化一个外部类的实例再实例化内部类(静态成员内部类是类相关的),创建静态内部类对象格式:
  • 静态内部类不可以直接调用外部类的非静态属性和方法
  • 静态内部类可以有非静态成员变量或成员方法
外部类名.静态内部类名 staticInner = new 外部类名.静态内部类名();

局部内部类

Java中的方法可以返回一个类或接口或者其实例化对象,我们可以在方法的内部创建一个类或接口然后将其返回,这种在方法内声明的类就称作局部内部类,又称“方法内部类”。
下面就是一个局部内部类的测试,我们使用局部内部类的方法来实现一个简易的计算器程序,innerClassTest()方法用以根据输入的运算符来返回一个内部类。其中使用了反射的知识,见这里

import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;

class InnerTest {
    public static Class<?> innerClassTest(char a) {
        switch (a) {
            case '+' -> {
                class inner extends ClassA {
                    @Override
                    public int calc(int i, int j) {
                        return i + j;
                    }

                    public inner() {
                    }
                }
                return inner.class;
            }
            case '-' -> {
                class inner extends ClassA {
                    @Override
                    public int calc(int i, int j) {
                        return i - j;
                    }

                    public inner() {
                    }
                }
                return inner.class;
            }
            case '*' -> {
                class inner extends ClassA {
                    @Override
                    public int calc(int i, int j) {
                        return i * j;
                    }

                    public inner() {
                    }
                }
                return inner.class;
            }
            case '/' -> {
                class inner extends ClassA {
                    @Override
                    public int calc(int i, int j) {
                        return i / j;
                    }

                    public inner() {
                    }
                }
                return inner.class;
            }
            default -> System.out.println("ERROR");
        }

        return ClassA.class;
    }

    public static void main(String[] args) throws InvocationTargetException, InstantiationException, IllegalAccessException, NoSuchMethodException {
        Class<?> clazz = innerClassTest('*');
        Constructor<?> constructor = clazz.getConstructor();

        ClassA a = new ClassA();
        ClassA b = (ClassA) constructor.newInstance();

        System.out.println(a.calc(3, 4)); //输出-666
        System.out.println(b.calc(3, 4)); //输出12
    }
}

class ClassA{
    public ClassA() {
    }

    public int calc(int i, int j) {
        return -666;
    }
}

匿名内部类

在java中调用某个方法时,如果该方法的参数是一个接口类型,除了可以传入一个接口实现类作为参数,还可以使用匿名内部类实现接口来作为该方法的参数。匿名内部类其实就是没有名称的内部类,在调用含有接口类型参数的方法时,通常为了简化代码,我们不会创建一个接口的实现类作为方法参数传入,而是直接通过匿名内部类的形式传入一个接口类型参数,在匿名内部类中完成方法的实现。

对于上述计算器的例子,由于我们不需要知道局部内部类的具体名称,所以我们可以使用匿名内部类来实现:

class InnerTest {
    public static ClassA innerClassTest(char a) {
        ClassA inner = null;

        switch (a) {
            case '+' -> inner = (int i, int j) -> i + j;
            case '-' -> inner = (int i, int j) -> i - j;
            case '*' -> inner = (int i, int j) -> i * j;
            case '/' -> inner = (int i, int j) -> i / j;
        }

        return inner;
    }

    public static void main(String[] args) {
        ClassA a = innerClassTest('*');
        System.out.println(a.calc(3, 4)); //输出12
    }
}

@FunctionalInterface
interface ClassA {
    int calc(int i, int j);
}

除此之外,当我们某一个方法需要传入一个类的时候,我们可以使用匿名内部类的方法来实现:

public class Test {
    public static void innerFuncClassTest(ClassA a){
        a.out();
    }

    public static void main(String[] args) {
        innerFuncClassTest(new ClassA(){
            @Override
            public void out(){System.out.println("2");}
        });
    }
}

class ClassA{
    public void out(){}
}

这样的效果也可以使用Lambda表达式来实现,通过lambda表达式可以建议的实现接口。
注意,可以lambda表达式的接口只能是函数式接口,也就是只有一个方法的接口(可以有成员变量,只能由JVM自动将其解析为静态变量),可以用@FunctionalInterface来注释函数式接口,这样编译器会检测是否满足上述要求。

@FunctionalInterface//被该字段注释的接口只能有一个方法
public interface Face {
	int A = 0;//这里有一个成员变量
	//注意interface里的成员变量自动且必须由public static final修饰
    int test(int i);//这里有一个方法
    //注意interface里的非静态方法自动且必须由public abstract修饰


    public static void main(String[] args) {
        Face invoke = (int i)->-i;
        //这里使用lambda表达式来实现接口
        //lambda表达式相当于重写了接口中的test方法
        System.out.println(invoke.test(1) + " " + invoke.A);//输出为“-1 0”
    }
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

LXTTTTTTTT

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值