接口,实际上可以看做是一种规范
interface
来定义:public interface MyInterface{}
public static final
的,但是书写时,可以省略不写public abstract
的,省略不写static
)、默认方法(default
)
public static
,public
可以不写,实现类不可重写default
,提供基本的方法实现,子类可根据需求选择是否重写implements
的方式来使用
class AA extends BB implements CC,DD,EE
public interface MyInterface {
// 全局常量
String MSG = "hello interface";
// 抽象方法
void method1();
// 静态方法
static void method2(){
System.out.println(MSG);
}
// 默认方法
default void method3(){
System.out.println(MSG);
}
}
接口中定义的静态方法,只能通过接口来调用。
通过实现类的对象,可以调用接口中的默认方法。如果实现类重写了接口中的默认方法,调用时,仍然调用的是重写以后的方法
如果子类(或实现类)继承的父类和实现的接口中声明了同名同参数的默认方法,那么子类在没重写此方法的情况下,默认调用的是父类中的同名同参数的方法。类优先原则
如果实现类实现了多个接口,而这多个接口中定义了同名同参数的默认方法,那么在实现类在没重写此方法的情况下会报错。接口冲突。这就需要我们必须在实现类中重写此方法
如何在子类(或实现类)的方法中调用父类、接口中被重写的方法
public void myMethod(){
method3();//调用自己定义的重写的方法
super.method3();//调用的是父类中声明的
//调用接口中的默认方法
CompareA.super.method3();
CompareB.super.method3();
}
is a
的原则,但是抽象类是属于继承体系,需要满足is a
的原则定义:Java中允许将一个类A声明在另一个类B中,则类A就是内部类,类B称为外部类
一方面,作为外部类的成员:
调用外部类的结构
可以被static
修饰
可以被4种不同的权限修饰
另一方面,作为一个类:
内可以定义属性、方法、构造器等
可以被final
修饰,表示此类不能被继承。言外之意,不使用final
,就可以被继承
可以被abstract
修饰
可以访问外部类所有非静态成员和静态成员,不受权限修饰符影响
public class OuterClass {
// 可以使用权限修饰符
private class InerClass{
}
}
// 实例化,由于属于外部类的非静态类成员,所以需要外部类的实例
OuterClass outerClass = new OuterClass();
InerClass inerClass = outerClass.new InerClass();
只能访问外部类的静态成员,不受权限修饰符影响
public class OuterClass {
private static class InerClass{
}
}
// 实例化,属于外部类的静态成员,所以需要类名.来访问
OuterClass.InerClass inerClass = new OuterClass.InerClass();
可以直接访问其所在的外部类的所有非静态的成员和静态的成员,不受权限修饰符影响
public class OuterClass {
public void test(){
// 不可以使用权限修饰符
class InnerClass{
}
// 实例化
InnerClass innerClass = new InnerClass();
}
}
匿名内部类是成员内部类的一种,只是一种对接口(或抽象类)实现的形式
public interface MyInterface {
void func1();
void func2();
}
public class OuterClass {
public static void test(MyInterface i){
}
public static void main(String[] args) {
// 匿名内部类实现接口
test(new MyInterface(){
@Override
public void func1() {
}
@Override
public void func2() {
}
});
}
}
成员内部类和局部内部类,在编译以后,都会生成字节码文件。格式:
成员内部类:外部类$内部类名.class
局部内部类:外部类$数字编码 内部类名.class
外部类$数字编码.class
使用native关键字说明这个方法是原生函数,也就是这个方法是用 C/C++等非 Java 语言实现的,并且被编译成了动态链接库DLL,由java去调用
java使用起来非常方便,然而有些层次的任务用 java 实现起来不容易,或者我们对程序的效率很在意时,问题就来了
例如:**有时java应用需要与java外面的环境交互。**这是本地方法存在的主要原因,你可以想想java需要与一些底层系统如操作系统或某些硬件交换信息时的情况。本地方法正是这样一种交流机制: 它为我们提供了一个非常简洁的接口,而且我们无需去了解java应用之外的繁琐的细节
native声明的方法,对于调用者,可以当做和其他Java方法一样使用
一个native method方法可以返回任何java类型,包括非基本类型,而且同样可以进行异常控制
native method的存在并不会对其他类调用这些本地方法产生任何影响,实际上调用这些方法的其他类甚至不知道它所调用的是一个本地方法。JVM将控制调用本地方法的所有细节
如果一个含有本地方法的类被继承,子类会继承这个本地方法并且可以用java语言重写这个方法(如果需要的话)
public class JniDemo {
// native方法和abstract修饰的方法一样,只有签名
public static native void test();
static {
// 加载JniDemo.dll,不写文件的后缀,程序会自动加上.dll
System.loadLibrary("JniDemo");
}
public static void main(String[] args) {
// 调用方法
test();
}
}
# 编译,产生JniDemo.class
javac -encoding utf-8 JniDemo.java
#生成.h头文件
javah -jni JniDemo
打开生成的头文件JniDemo.h
JniDemo.java
文件中的test()
方法已经变成了JNIEXPORT void JNICALL Java_JniDemo_test(JNIEnv *, jclass);
,方法名是原来的包名_类名_方法名
。
/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class JniDemo */
#ifndef _Included_JniDemo
#define _Included_JniDemo
#ifdef __cplusplus
extern "C" {
#endif
/*
* Class: JniDemo
* Method: test
* Signature: ()V
*/
JNIEXPORT void JNICALL Java_JniDemo_test
(JNIEnv *, jclass);
#ifdef __cplusplus
}
#endif
#endif
#include <stdio.h>
#include "JniDemo.h"
JNIEXPORT void JNICALL Java_JniDemo_test (JNIEnv *, jclass){
printf("Hello Jni From Cpp!");
}
g++ -m64 -I"E:/Java/jdk1.8.0_301/include" -I"E:/Java/jdk1.8.0_301/include/win32" -shared -o JniDemo.dll JniDemo.cpp
java JniDemo
Hello Jni From Cpp!