接口
- 如果抽象类中的方法都是抽象方法可以把抽象类转成接口来表示(interface)
- 通过implements让类与接口之间产生实现的关系,支持多实现。
- 接口与接口之间通过extends产生了继承关系,支持多继承。
注意:
-
类实现接口需要重写所有的抽象方法,但是如果不想都重写,可以把类变成抽象类
-
接口里都是抽象方法
-
接口不能定义构造方法,因此也不能创建对象
-
接口可以定义属性,属性是被public final static共同修饰
-
抽象方法默认被public abstract共同修饰
-
接口可以在编译期间接受所有类的对象的赋值,但是在运行时期还是要检测实际创建类和接口是否有实现关系
public class InterfaceDemo2 { public static void main(String[] args) { // 向上造型 B b = new C(); C c = (C) b; // 向下造型(强制类型转换) 向下造型前提是有向上造型 // 编译和执行都没有问题 // 如果在进行对象的赋值操作,在编译时期会检测两个对象的声明类是否有继承关系 // 如果有继承关系,编译就通过 // 在运行时期会去检测两个对象的实际创建类是否是同一个 // 如果实际创建类是同一个就运行成功 // D d = (D) b; // 编译没错,运行有错 ClassCastException --- 类型转换异常 // b对象声明的类是B类,d对象的声明类是D类,有继承关系编译通过 // b对象的实际创建类是C类,d对象的实际创建类是D类不是同一个类运行报错 // D d1 = (D) c; // 编译报错 // c对象的声明类是C类,d对象的声明类是D类,没有继承关系所以编译报错 // 类与类之间支持单继承形成的是树状图可以快速检测类与接口之间的关系 // 类和接口之间是多实现形成网状图不能快速检测类与接口之间的关系 // 索性就放弃了编译时期的检测只在运行时期进行检测 // 运行时期检测的是实际创建类和接口是否有实现关系,如果有才通过 A a1 = (A) b; A a2 = (A) (new C()); } } interface A{ } class B{} class C extends B implements A{} class D extends B{}
抽象类与接口
- 接口的本质不是类
- 抽象类单继承,接口多继承与多实现
- 接口里不能定义构造方法
- 接口里都是抽象方法,抽象类中可以有其他普通方法
- 接口里的属性都是静态常量
- 抽象类是为了延展类的继承结构,接口是为了注入新的特性
接口的优点:模板、约束
内部类
- 概念:类或者接口里再次定义一个类
- 为了满足类描述信息不完整的情况
- 分类:方法内部类、成员内部类、静态内部类、匿名内部类
方法内部类
- 方法内定义一个类
- 可以定义所有的非静态属性和方法以及静态常量(不能定义静态变量)
- 可以进行正常的继承与实现
- 不能被访问权限修饰符修饰,但可以被abstract和final修饰
- 可以直接获取外部类的所有信息
- 只能获取当前方法的常量 (默认用final修饰)
public class InnerDemo { // 公共类
public static void main(String[] args) {
// 创建外部类对象调用fun()执行创建内部类语句
new Outer1().fun();
}
}
// 外部类, 只能由public和默认修饰,不能用private和protected修饰
class Outer1{ // 普通类
// 属性
int i = 1;
static int k;
// 方法
public void fun(){
int x = 10; // 默认底层会加上final进行修饰 --- 隐式常量(jdk1.8)
// jdk1.8以前需要手动加上final --- 显式常量
// 方法内部类只能获取本方法中的常量
// 没有被访问权限修饰符修饰(不是默认)
// 可以被abstract和final修饰
class Inner1 { // 内部类
// static int j; // error
static final int j = 2;
// 可以定义所有的非静态属性和方法以及静态常量
// 可以进行正常的继承和实现
public void innerFun(){
// 可以直接获取外部类的所有信息
System.out.println(++i + ","+k++);
System.out.println(x);
}
}
// 创建方法内部类对象
Inner1 in = new Inner1();
in.innerFun();
}
}
成员内部类
- 类内方法外定义一个类
- 可以定义所有的非静态属性和方法以及静态变量
- 可以进行继承与实现
- 可以被所有的访问权限修饰符以及abstract和final修饰
- 可以直接获取外部类所有的信息
- 创建成员内部类对象:Outer.Inner in = new Outer().new Inner();
public class InnerDemo2 {
public static void main(String[] args) {
// 创建成员内部类的对象
Outer2.Inner2 in; // 内部类的声明
in = new Outer2().new Inner2();
}
}
class Outer2{
// 属性
int i = 1;
// 成员内部类
// 只能定义所有的非静态属性和方法以及静态变量
// 可以进行正常的继承和实现
// 可以被访问权限修饰符以及final和abstract修饰
class Inner2 extends Object implements Cloneable{
static final int j = 2;
int k = 0;
public void innerFun(){
System.out.println(i);
System.out.println(k++);
fun();
}
}
// 方法
public static void fun(){}
}
静态内部类
-
在成员内部类前加static就是静态内部类
-
可以定义所有的属性和方法以及静态常量
-
可以进行继承和实现
-
可以被所有的访问权限修饰符以及abstract和final修饰
-
只能获取外部类的静态属性和方法
-
创建内部内部类对象:Outer.Inner in = new Outer.Inner();
public class InnerDemo3 {
public static void main(String[] args) {
// 创建静态内部类
Outer3.Inner3 in = new Outer3.Inner3(); // 外部类.内部类
// 获取静态类的静态信息
System.out.println(Outer3.Inner3.j);
}
}
class Outer3{
// 属性
int i = 1;
static int si;
// 静态内部类
// 可以定义所有的属性和方法以及静态常量
// 可以进行继承和实现
// 可以被所有访问权限修饰符以及final和abstract修饰
public static class Inner3 extends Object implements Cloneable{
static int j = 3;
int k = 4;
// 只能获取外部类的静态属性和方法
public void Innerfun(){
// System.out.println(i); // error
// fun(); // error
System.out.println(si);
}
}
public void fun(){}
}
匿名内部类
- 位置:如果匿名内部类在方法内就和方法内部类使用一致;如果在成员就和成员内部类使用一致;如果是静态就和静态内部类使用一致
- 功能:用于去继承类(除了最终类)和实现接口,重写方法
- 只能使用一次,使用起来方便
public class InnerDemo4 {
A a = new A() {
};
public static void main(String[] args) {
// {} --- 匿名内部类
// 功能:继承抽象类并对抽象方法进行重写
// c 是匿名内部类的对象
// 如果匿名内部类在方法内就和方法内部类使用一致;如果在成员就和成员内部类使用一直
// 如果是静态就和静态内部类使用一致
C c = new C() {
@Override
public void fun() {
System.out.println("C c");
}
};
c.fun();
D d = new D();
d.fun();
// 创建B类对象
// 支持匿名内部类
// 功能:继承普通类并对方法进行重写
// 最终类没有匿名内部类的形式(不能继承)
B b = new B(){
@Override
public void funB() {
super.funB();
}
};
// 功能:实现接口
A a = new A() {};
// 调用方法
m (new D()); // 向上造型
m(new C() {
@Override
public void fun() {
}
}); // C是抽象类没有对象 -- 把匿名内部类的对象当做C类对象传入
}
public static void m(C c){ } // 形参 -- 引用数据类型 -- 只能接受对象
}
interface A{}
class B{
public void funB(){}
}
abstract class C{
public abstract void fun();
}
class D extends C{
@Override
public void fun() {
System.out.println("D");
}
}
- 接口里定义一个类或者接口,默认会被static修饰
public class InnerDemo5 {
public static void main(String[] args) {
System.out.println(Outer5.Inner5.i);
}
}
interface Outer5{
// 接口里定义一个类
// 接口没有对象,默认被static修饰,静态内部类
class Inner5{
static int i = 1;
}
// 内部接口,默认被static修饰
interface Inner6{ }
}
Lambda表达式
-
jdk1.8的新特性
-
Lambda表达式用于实现接口重写抽象方法
-
Lambda表达式只有针对函数式接口才能使用
-
书写简单、格式优美
public class LambdaDemo1 {
public static void main(String[] args) {
Calc c = new Calc() {
@Override
public int sum(int x, int y) {
return x+y;
}
};
System.out.println(c.sum(2,3));
// Lambda表达式
// 只有接口中只有一个抽象方法时,才能使用
// (参数列表) ->{}方法体
// Calc c1 = (int x, int y) -> {return x+y;};
// 如果方法体只有一句话可以省略return和{}不写
Calc c2 = (int x, int y) -> x+y;
System.out.println(c2.sum(2,3));
// 参数类型可以由抽象方法的参数类型推导出来可以省略参数类型不写
Calc c3 = (x,y) -> x+y;
System.out.println(c3.sum(2,3));
int []arr = {1,9,7,2,3,4};
// 只有一个参数,省略()
// ArrarySort a = arr1 -> Arrays.sort(arr1);
// ::代表的是传递静态方法,最简形式
ArrarySort a = Arrays :: sort;
a.arrSort(arr);
System.out.println(Arrays.toString(arr));
}
}
// 函数式接口 --- 用于函数式编程
@FunctionalInterface
interface Calc{
// 求整数和
int sum (int x, int y);
}
// 接口 -- 排序
interface ArrarySort{
void arrSort(int[] arr);
}